#!/usr/bin/env python3 """ Create frontend JavaScript file for base configuration. """ import sys import os import argparse import re from pathlib import Path # Add parent directory to path sys.path.insert(0, str(Path(__file__).parent.parent)) def create_base_frontend_js(tenant_id: str, api_port: int = 6002, output_file: str = "frontend/static/js/app_base.js"): """ Create frontend JavaScript file for base configuration. Args: tenant_id: Tenant ID api_port: API port output_file: Output file path """ # Read original app.js original_file = Path(__file__).parent.parent / "frontend/static/js/app.js" if not original_file.exists(): print(f"ERROR: Original frontend file not found: {original_file}") return 1 with open(original_file, 'r', encoding='utf-8') as f: content = f.read() # Replace API_BASE_URL api_url = f"http://localhost:{api_port}" content = content.replace( "const API_BASE_URL = 'http://120.76.41.98:6002';", f"const API_BASE_URL = '{api_url}';" ) # Add tenant_id constant at the beginning content = content.replace( "const API_BASE_URL =", f"const TENANT_ID = '{tenant_id}';\nconst API_BASE_URL =" ) # Update facets for base configuration base_facets = ''' const facets = [ { "field": "category_keyword", "size": 15, "type": "terms" }, { "field": "vendor_keyword", "size": 15, "type": "terms" }, { "field": "tags_keyword", "size": 10, "type": "terms" }, { "field": "min_price", "type": "range", "ranges": [ {"key": "0-50", "to": 50}, {"key": "50-100", "from": 50, "to": 100}, {"key": "100-200", "from": 100, "to": 200}, {"key": "200+", "from": 200} ] } ];''' # Find and replace facets definition (multiline match) facets_pattern = r'const facets = \[.*?\];' content = re.sub(facets_pattern, base_facets, content, flags=re.DOTALL) # Update fetch to include tenant_id header content = content.replace( "headers: {\n 'Content-Type': 'application/json',\n },", f"headers: {{\n 'Content-Type': 'application/json',\n 'X-Tenant-ID': TENANT_ID,\n }}," ) # Replace hits with results throughout content = re.sub(r'\bdata\.hits\b', 'data.results', content) content = re.sub(r'!data\.hits', '!data.results', content) # Replace hit loop with product loop content = re.sub( r'data\.hits\.forEach\(\(hit\) => \{', 'data.results.forEach((product) => {', content ) # Remove source extraction lines content = re.sub(r'const source = hit\._source;\s*\n', '', content) content = re.sub(r'const score = hit\._custom_score \|\| hit\._score;\s*\n', 'const score = product.relevance_score;\n', content) # Replace all source. references with product. content = re.sub(r'\bsource\.', 'product.', content) # Replace specific field names for base configuration # imageUrl -> image_url content = re.sub(r'product\.imageUrl', 'product.image_url', content) # name -> title content = re.sub(r'product\.name', 'product.title', content) content = re.sub(r'product\.enSpuName', 'product.title', content) # categoryName -> category content = re.sub(r'product\.categoryName', 'product.category', content) # brandName -> vendor content = re.sub(r'product\.brandName', 'product.vendor', content) # price -> price (already correct) # Remove moq and quantity fields (not in base config) content = re.sub(r'
.*?
\s*\n', '', content, flags=re.DOTALL) content = re.sub(r'
.*?
\s*\n', '', content, flags=re.DOTALL) # Add stock and variants display # Find the product-price div and add stock info after it stock_info = '''
${product.in_stock ? 'In Stock' : 'Out of Stock'} ${product.variants && product.variants.length > 0 ? `(${product.variants.length} variants)` : ''}
''' content = re.sub( r'(
.*?
\s*\n)', r'\1' + stock_info, content, flags=re.DOTALL ) # Update price display format content = re.sub( r'\$\{product\.price \? `\$\{product\.price\} ₽` : \'N/A\'\}', '${product.price ? `$${product.price.toFixed(2)}` : \'N/A\'}', content ) # Add compare_at_price if exists content = re.sub( r'(\$\{product\.price \? `\$\$\{product\.price\.toFixed\(2\)\}` : \'N/A\'\})', r'\1${product.compare_at_price && product.compare_at_price > product.price ? `$${product.compare_at_price.toFixed(2)}` : \'\'}', content ) # Update product-meta to use base config fields content = re.sub( r'
\s*\$\{product\.category \? escapeHtml\(product\.category\) : \'\'\}\s*\$\{product\.vendor \? \' \| \' \+ escapeHtml\(product\.vendor\) : \'\'\}\s*
', '
${product.vendor ? escapeHtml(product.vendor) : \'\'}${product.product_type ? \' | \' + escapeHtml(product.product_type) : \'\'}${product.category ? \' | \' + escapeHtml(product.category) : \'\'}
', content ) # Remove create_time display (not in base config) content = re.sub( r'\$\{product\.create_time \? `.*?\s*` : \'\'\}', '', content, flags=re.DOTALL ) # Add tags display if exists tags_display = ''' ${product.tags ? `
Tags: ${escapeHtml(product.tags)}
` : ''}''' # Add tags before closing product-card div content = re.sub( r'(\s*\s*`;\s*\n\s*\}\);)', tags_display + r'\n \n `;\n });', content, count=1 ) # Update displayFacets for base configuration field names content = re.sub( r"facet\.field === 'categoryName_keyword'", "facet.field === 'category_keyword'", content ) content = re.sub( r"facet\.field === 'brandName_keyword'", "facet.field === 'vendor_keyword'", content ) content = re.sub( r"facet\.field === 'supplierName_keyword'", "facet.field === 'tags_keyword'", content ) # Write output file output_path = Path(__file__).parent.parent / output_file output_path.parent.mkdir(parents=True, exist_ok=True) with open(output_path, 'w', encoding='utf-8') as f: f.write(content) print(f"Created base frontend JavaScript: {output_path}") return 0 def main(): parser = argparse.ArgumentParser(description='Create frontend JavaScript for base configuration') parser.add_argument('--tenant-id', default='1', help='Tenant ID') parser.add_argument('--api-port', type=int, default=6002, help='API port') parser.add_argument('--output', default='frontend/static/js/app_base.js', help='Output file') args = parser.parse_args() return create_base_frontend_js(args.tenant_id, args.api_port, args.output) if __name__ == '__main__': sys.exit(main())