Beispiel #1
0
def generate(target_path, project):
    for app_name, application in project.applications.items():

        if not application.models_support(AdminModelExtension):
            continue

        imports = ImportSet()
        imports.add('django.contrib', 'admin')
        imports.add('django', 'forms')

        for model in application.models_with(AdminModelExtension):
            imports.add('{}.models'.format(app_name), model.class_name)

            for class_import in model[AdminModelExtension].classes:
                imports.add(*class_import)

            if model.polymorphic:
                for child in model.child_models:
                    imports.add('{}.models'.format(app_name), child.class_name)

            # inlines
            for inline in model[AdminModelExtension].inlines:
                for declaration in inline.type_declarations:
                    imports.add(*declaration)

                if inline.inline_type == 'polymorphic':
                    for target_model in inline.target_model.child_models:

                        if target_model.translatable:
                            imports.add('cratis_i18n.admin',
                                        'TranslatableInlineModelAdmin')

                        imports.add('{}.models'.format(app_name),
                                    target_model.class_name)

                imports.add('{}.models'.format(app_name),
                            inline.target_model.class_name)

            for field in model.fields.values():
                if field.get_admin_widget():
                    import_data, model_field = field.get_admin_widget()

                    for source, what in import_data:
                        imports.add(source, what)

        generate_file(
            target_path, '{}/admin.py'.format(app_name), 'admin.py.tpl', {
                'imports':
                imports.import_sting(),
                'ext':
                AdminModelExtension,
                'application':
                application,
                'models': [(name, model)
                           for name, model in application.models.items()
                           if model.supports(AdminModelExtension)]
            })
Beispiel #2
0
def generate(target_path, project):
    for app_name, application in project.applications.items():
        if not len(application.models):
            continue

        imports = ImportSet()
        imports.add('django.db', 'models')

        for model in application.models.values():  # type: ModelDef

            for handlers, code in model.signal_handlers:
                for signal_import in handlers:
                    imports.add('django.dispatch', 'receiver')
                    imports.add(*signal_import)

            if model.polymorphic and model.tree:
                imports.add('polymorphic_tree.models', 'PolymorphicMPTTModel',
                            'PolymorphicTreeForeignKey')
            else:
                if model.polymorphic:
                    imports.add('polymorphic.models', 'PolymorphicModel')

                if model.tree:
                    imports.add('mptt.models', 'MPTTModel', 'TreeForeignKey')

            if model.validators:
                imports.add('django.core.exceptions', 'ValidationError')

            if model.mixin_classes:
                for import_decl in model.mixin_classes:
                    pkg, cls, alias = import_decl
                    if alias != cls:
                        cls = '{} as {}'.format(cls, alias)
                    imports.add(*(pkg, cls))

            for field in model.own_fields:  # type: FieldDef
                model_field = field.get_model_field()
                if model_field:
                    import_data, model_field = model_field  # type: FieldDeclaration

                    for source, what in import_data:
                        imports.add(source, what)

        generate_file(
            target_path, '{}/models.py'.format(app_name), 'models.py.tpl', {
                'imports': imports.import_sting(),
                'application': application,
                'models': application.models.items()
            })
Beispiel #3
0
def generate(target_path, project):
    if not project.applications_support(ChannelsAppExtension):
        return

    streams = []
    imports = ImportSet()
    for app in project.applications.values():
        for page in app.pages_with(StreamPageExtension):
            streams.append((app, page))
            imports.add(f'{app.app_name}.channels', f'{page.view_name}Consumer')

    generate_file(target_path, f'app/routing.py', 'channels.routing_main.tpl', context={
        'streams': streams,
        'imports': imports,
    })

    for app in project.applications.values():
        if app.pages_support(StreamPageExtension):
            imports = ImportSet()
            imports.add('channels.layers', 'get_channel_layer')
            imports.add('channels.generic.websocket', 'AsyncWebsocketConsumer')
            imports.add('django.db.models.signals', 'post_save', 'm2m_changed', 'post_delete')
            imports.add('django_query_signals', 'post_bulk_create', 'post_delete as post_delete_bulk',
                        'post_get_or_create', 'post_update_or_create', 'post_update')
            imports.add('channels.db', 'database_sync_to_async')
            imports.add('asgiref.sync', 'async_to_sync')
            imports.add('asyncio', 'sleep')
            imports.add('django.dispatch', 'receiver')
            imports.add('app.utils.rest', 'ZmeiJsonEncoder')

            pages = app.pages_with(StreamPageExtension)

            for page in pages:
                for model in page[StreamPageExtension].models:
                    imports.add(f'{model.model_app_name}.models', model.model_class_name)
                imports.add(f'.views', page.view_name)

            generate_file(target_path, f'{app.app_name}/channels.py', 'channels.py.tpl', context={
                'pages': pages,
                'ext': StreamPageExtension,
                'imports': imports,
            })
Beispiel #4
0
def generate(target_path, project):
    for app_name, application in project.applications.items():
        has_i18n = any([x.translatable for x in application.models.values()])
        if not has_i18n:
            continue

        imports = ImportSet()
        imports.add('modeltranslation.translator', 'translator')
        imports.add('modeltranslation.translator', 'TranslationOptions')

        for col in application.models.values():
            if not col.translatable:
                continue

            imports.add('{}.models'.format(app_name), col.class_name)

        generate_file(target_path, '{}/translation.py'.format(app_name), 'translation.py.tpl', {
            'imports': imports.import_sting(),
            'models': [(name, col) for name, col in application.models.items() if col.translatable]
        })
Beispiel #5
0
 def generate(cls, apps, target_path):
     generate_file(target_path,
                   'app/celery.py',
                   template_name='celery.py.tpl')
     generate_file(target_path,
                   'app/tasks.py',
                   template_name='celery_tasks.py.tpl')
     generate_file(target_path,
                   'app/__init__.py',
                   template_name='celery_init.py.tpl')
Beispiel #6
0
def generate(target_path, project):
    for application in project.applications_with(GitlabAppExtension):
        for file in ['.gitlab-ci.yml', '.gitignore', 'README.md']:
            generate_file(target_path, file, f"gitlab/{file.strip('.')}.tpl", {
                'gitlab': application[GitlabAppExtension],
            })
        if application[GitlabAppExtension].test:
            for file in [
                    'conftest.py', 'pytest.ini', 'requirements.dev.txt',
                    '.flake8', '.coveragerc'
            ]:
                generate_file(target_path, file,
                              f"gitlab/{file.strip('.')}.tpl", {
                                  'gitlab': application[GitlabAppExtension],
                              })

            generate_file(target_path,
                          'app/settings_test.py',
                          template_name='settings.py.tpl')
Beispiel #7
0
def generate(target_path, project):
    has_views = False

    for app_name, application in project.applications.items():
        if not len(application.pages):  # and not application.rest:
            continue
        has_views = True

        imports = ImportSet()

        for col in application.models.values():
            imports.add('{}.models'.format(app_name), col.class_name)

        generated_templates = []
        if len(application.pages.items()) > 0:
            imports.add('django.views.generic', 'TemplateView')

            for page in application.pages.values():

                if not page.parent_name:
                    imports.add('app.utils.views', 'Data')

                for import_spec in page.get_imports():
                    imports.add(*import_spec)

                for item in page.page_items.values():
                    for import_spec in item.get_imports():
                        imports.add(*import_spec)

                if page.template:
                    template = page.defined_template_name
                    if template:
                        template_name = f'{app_name}/templates/{template}'

                        generate_file(
                            target_path, template_name, 'theme/default.html', {
                                'app_name':
                                app_name,
                                'page':
                                page,
                                'parent':
                                application.resolve_page(page.parent_name)
                                if page.parent_name else None
                            })

                        generated_templates.append(template_name)

        generate_file(
            target_path, '{}/views.py'.format(app_name), 'views.py.tpl', {
                'imports': imports.import_sting(),
                'application': application,
                'pages': application.pages.values()
            })

        # urls
        pages_i18n = [
            page for page in application.pages.values()
            if page.has_uri and page.i18n
        ]
        if len(pages_i18n) > 0:
            generate_urls_file(target_path,
                               app_name,
                               application,
                               pages_i18n,
                               i18n=True)

        # urls i18n
        pages = [
            page for page in application.pages.values()
            if page.has_uri and not page.i18n
        ]
        if application.pages:
            generate_urls_file(target_path,
                               app_name,
                               application,
                               pages,
                               i18n=False)

        if len(application.pages) > 0:
            generate_file(target_path,
                          '{}/templates/{}/_base.html'.format(
                              app_name, app_name),
                          template_name='theme/base_app.html',
                          context={
                              'application': application,
                          })

    if has_views:
        generate_package('app.utils', path=target_path)
        generate_file(target_path,
                      'app/utils/views.py',
                      template_name='views.utils.py.tpl')
Beispiel #8
0
def generate(target_path, project):
    apps = project.applications

    has_flutter = any([
        app.pages_support(FlutterPageExtension)
        for app in project.applications.values()
    ])

    if not has_flutter:
        return

    generate_file(target_path, 'flutter/pubspec.yaml',
                  'flutter.pubspec.yaml.tpl')
    generate_file(target_path, 'flutter/lib/main.dart',
                  'flutter.main.dart.tpl',
                  {'host': os.environ.get('ZMEI_SERVER_HOST')})

    for app_name, application in apps.items():

        if application.models:
            imports = set()
            for col in application.models.values():
                for field in col.fields.values():

                    if isinstance(field,
                                  ReferenceField) and field.target_model:
                        if field.target_model.application != application:
                            imports.add(
                                field.target_model.application.app_name)

                    elif isinstance(field, RelationDef) and field.ref_model:
                        if field.ref_model.application != application:
                            imports.add(field.ref_model.application.app_name)

            generate_file(
                target_path, f'flutter/lib/src/models/{app_name}.dart',
                'flutter.model.dart.tpl', {
                    'app_name': app_name,
                    'application': application,
                    'to_camel_case': to_camel_case,
                    'imports': imports
                })

        if application.pages_support(FlutterPageExtension):
            for name, page in application.pages.items():

                if page.get_own_or_parent_extension(FlutterPageExtension):
                    imports = set()
                    extra_imports = ''

                    page_items = {}
                    for item_name in page.own_item_names:
                        item = page.page_items[item_name]

                        if item.model_name:
                            col = application.resolve_model(item.model_name)
                            # if col.application != application:
                            imports.add(col.application.app_name)

                            page_items[item_name] = (item, col)
                        else:
                            page_items[item_name] = (item, None)

                    blocks_rendered = {}
                    for area, blocks in page.get_blocks(
                            platform=FlutterPageExtension).items():
                        blocks_rendered[area] = []
                        for index, block in enumerate(blocks):
                            rendered = block.render(area=area, index=index)

                            filtered = ''
                            for line in rendered.splitlines():
                                if re.match("^\s*import\s+'[^']+'\s*;\s*$",
                                            line):
                                    extra_imports += f"{line.strip()}\n"
                                else:
                                    filtered += f"{line.strip()}\n"

                            blocks_rendered[area].append((block.ref, filtered))

                    generate_file(
                        target_path,
                        f'flutter/lib/src/pages/{app_name}/{name}.dart',
                        'flutter.page.dart.tpl', {
                            'app_name': app_name,
                            'app': application,
                            'page': page,
                            'blocks': blocks_rendered,
                            'crud_ext': CrudPageExtension,
                            'menu_ext': MenuPageExtension,
                            'stream_ext': StreamPageExtension,
                            'page_items': page_items,
                            'imports': imports,
                            'extra_imports': extra_imports,
                            'format_uri': format_uri,
                            'to_camel_case': to_camel_case,
                            'to_camel_case_classname': to_camel_case_classname,
                        })
                    generate_file(
                        target_path,
                        f'flutter/lib/src/ui/{app_name}/{name}_ui.dart',
                        'flutter.page.ui.dart.tpl', {
                            'app_name': app_name,
                            'app': application,
                            'page': page,
                            'to_camel_case': to_camel_case,
                            'to_camel_case_classname': to_camel_case_classname,
                        })
    generate_file(target_path, 'flutter/lib/src/components/menu.dart',
                  'flutter.cmp.menu.dart.tpl')
    generate_file(target_path, 'flutter/lib/src/state.dart',
                  'flutter.state.dart.tpl')
    generate_file(target_path, 'flutter/lib/src/utils.dart',
                  'flutter.utils.dart.tpl')

    generate_file(target_path, f'flutter/lib/src/app.dart',
                  'flutter.app.dart.tpl', {
                      'apps': apps,
                  })

    max_len = 0
    app_routes = {}
    for app_name, app in apps.items():
        if app.pages_support(FlutterPageExtension):
            for name, page in app.pages.items():
                if page.get_own_or_parent_extension(
                        FlutterPageExtension) and page.uri:
                    uri = format_uri(page.uri)
                    app_routes[uri] = f'{page.view_name}StateUi'
                    max_len = max(max_len, len(uri))

    generate_file(
        target_path, f'flutter/lib/src/routes.dart', 'flutter.routes.dart.tpl',
        {
            'apps': apps,
            'app_routes': app_routes,
            'max_len': max_len,
            'len': len,
            'ext': FlutterPageExtension,
            'format_uri': format_uri,
            'to_camel_case': to_camel_case,
            'to_camel_case_classname': to_camel_case_classname,
        })

    flutter_dir = os.path.join(target_path, 'flutter')
    if os.path.exists(flutter_dir):
        subprocess.check_call(['dartfmt', '-w', '-l', '120', flutter_dir],
                              stdout=subprocess.DEVNULL)
Beispiel #9
0
def generate(target_path, project):
    # config
    has_rest = False
    has_i18n_pages = False
    has_normal_pages = False

    i18n_langs = []

    # urls
    imports = set()
    urls = ['urlpatterns = [']
    urls += [
        "    url(r'^admin/', admin.site.urls),",
    ]

    # Sort applications alphabetically
    temp_dict = {}
    for key in sorted(project.applications):
        temp_dict.update({key: project.applications[key]})
    project.applications = temp_dict

    for app_name, application in project.applications.items():
        generate_package(app_name, path=target_path)

    for app_name, application in project.applications.items():
        for import_def, url_def in application.get_required_urls():
            urls.append(url_def)
            if import_def:
                imports.add(import_def)

        if application.pages:
            # Sort urls alphabetically
            temp_dict = {}
            for key in sorted(application.pages):
                temp_dict.update({key: application.pages[key]})
            application.pages = temp_dict
            for page in application.pages.values():
                if page.i18n:
                    has_i18n_pages = True
                else:
                    has_normal_pages = True

            if has_normal_pages:
                urls.append(f"    url(r'^', include({app_name}.urls)),")
                imports.add(f'{app_name}.urls')

    urls.append(']')

    for app_name, application in project.applications.items():
        if any([page.i18n for page in application.pages.values()]):
            urls += [
                'urlpatterns += i18n_patterns(',
                f"    url(r'^', include({app_name}.urls_i18n)),", ")"
            ]
            imports.add(f'{app_name}.urls_i18n')

    # sort url imports
    imports = sorted(imports)
    # urls
    with open(os.path.join(target_path, 'app/_urls.py'), 'w') as f:
        f.write('from django.conf.urls import url, include\n')
        f.write('from django.contrib import admin\n')

        f.write('\n')
        f.write('\n'.join([f'import {app_name}' for app_name in imports]))
        if has_i18n_pages:
            f.write('\nfrom django.conf.urls.i18n import i18n_patterns\n')
        f.write('\n\n')
        f.write('\n'.join(urls))

    generate_file(target_path, 'app/urls.py', template_name='urls_main.py.tpl')

    # settings
    req_settings = {}
    installed_apps = [
        app.app_name for app in project.applications.values()
        if len(app.pages) > 0 or len(app.models) > 0
    ]

    extension_classes = list()
    for application in sorted(project.applications.values(),
                              key=lambda x: x.app_name):
        installed_apps.extend(application.get_required_apps())
        req_settings.update(application.get_required_settings())

        for extension in application.extensions:
            if type(extension) not in extension_classes:
                extension_classes.append(type(extension))

    # sort apps alphabetically
    # prevent _settings repopulate
    installed_apps = sorted(installed_apps)

    # remove duplicates preserving order
    seen = set()
    seen_add = seen.add
    installed_apps = [
        x for x in installed_apps if not (x in seen or seen_add(x))
    ]

    with open(os.path.join(target_path, 'app/settings.py'), 'r') as fb:
        with open(os.path.join(target_path, 'app/_settings.py'), 'a') as f:
            f.write(fb.read())

            f.write('\nINSTALLED_APPS = [\n')
            f.write("\n    'app',\n")
            f.write('\n'.join(
                [f"    '{app_name}'," for app_name in installed_apps]))
            f.write('\n] + INSTALLED_APPS\n\n')  # settings

            for key, val in req_settings.items():
                f.write(f'{key} = {repr(val)}\n')

            for extension in extension_classes:
                extension.write_settings(project.applications, f)

    generate_file(target_path,
                  'app/settings.py',
                  template_name='settings.py.tpl')
    format_file(target_path, 'app/_settings.py')

    for extension in extension_classes:
        extension.generate(project.applications, target_path)

    # base template
    generate_file(target_path,
                  'app/templates/base.html',
                  template_name='theme/base.html')

    requirements = [
        'wheel',
        'django>2',
    ]

    for application in project.applications.values():
        requirements.extend(application.get_required_deps())

    requirements = list(sorted(set(requirements)))

    # requirements
    with open(os.path.join(target_path, '_requirements.txt'), 'w') as f:
        f.write('\n'.join(requirements))

    generate_file(target_path,
                  'requirements.txt',
                  template_name='requirements.txt.tpl')

    if i18n_langs:
        for lang in i18n_langs:
            os.makedirs(os.path.join(target_path, f'locale/{lang}'))
            with open(os.path.join(target_path, f'locale/{lang}/readme.txt'),
                      'w') as f:
                f.write('Collect translations:\n')
                f.write('django-admin makemessages --all\n')
                f.write('\n')
                f.write('Compile translations:\n')
                f.write('django-admin compilemessages\n')
Beispiel #10
0
def generate(target_path, project):
    has_api = False

    for application in project.applications.values():
        if not application.models_support(
                ApiModelExtension) and not application.models_support(
                    RestModelExtension):
            continue

        app_name = application.app_name

        has_api = True
        imports = ImportSet()
        imports.add('rest_framework', 'serializers')

        for model in application.models_with(RestModelExtension):
            for name, rest_conf in model[RestModelExtension].rest_conf.items():
                rest_conf.configure_model_imports(imports)

        generate_file(
            target_path, '{}/serializers.py'.format(app_name),
            'serializers.py.tpl', {
                'imports':
                imports.import_sting(),
                'application':
                application,
                'rest_ext':
                RestModelExtension,
                'api_ext':
                ApiModelExtension,
                'models':
                [(model.ref, model)
                 for model in application.models_with(RestModelExtension)],
            })

        url_imports = ImportSet()
        url_imports.add('django.conf.urls', 'url')
        url_imports.add('django.conf.urls', 'include')
        url_imports.add('rest_framework', 'routers')

        for model in application.models_with(RestModelExtension):
            for rest_conf in model[RestModelExtension].published_apis.values():
                url_imports.add('.views_rest',
                                f'{rest_conf.serializer_name}ViewSet')

        context = {
            'package_name': app_name,
            'application': application,
            'ext': RestModelExtension,
            'url_imports': url_imports.import_sting(),
        }
        filepath = os.path.join(package_to_path(app_name), 'urls_rest.py')
        generate_file(target_path, filepath, 'urls_rest.py.tpl', context)

        # views_rest.py

        imports = ImportSet()

        for model in application.models_with(RestModelExtension):
            for name, rest_conf in model[RestModelExtension].rest_conf.items():
                rest_conf.configure_imports(imports)

        generate_file(
            target_path, f'{app_name}/views_rest.py', 'views_rest.py.tpl', {
                'package_name':
                app_name,
                'application':
                application,
                'ext':
                RestModelExtension,
                'models': [(name, model)
                           for name, model in application.models.items()
                           if model.supports(RestModelExtension)],
                'imports':
                imports
            })

    has_pages = False
    for application in project.applications.values():
        if len(application.pages):
            has_pages = True

    if has_api or has_pages:
        generate_package('app.utils', path=target_path)
        generate_file(target_path,
                      'app/utils/rest.py',
                      template_name='rest.utils.py.tpl')
Beispiel #11
0
def generate(target_path, project: ZmeiProject):
    has_docker = any([
        app.supports(DockerAppExtension)
        for app in project.applications.values()
    ])
    has_celery = any([
        app.supports(CeleryAppExtension)
        for app in project.applications.values()
    ])
    has_channels = any([
        app.supports(ChannelsAppExtension)
        for app in project.applications.values()
    ])

    if not has_docker:
        return

    context = {
        'req_file':
        os.environ.get('ZMEI_REQUIREMNETS_FILE', 'requirements.txt'),
        'has_channels':
        has_channels,
        'has_celery':
        has_celery,
        'admin_pass':
        ''.join(
            random.choice(string.ascii_letters + string.digits +
                          string.punctuation.replace('"', ''))
            for _ in range(16)),
        'admin_user':
        '******' + ''.join(
            random.choice(string.ascii_letters + string.digits)
            for _ in range(4)),
    }

    generate_file(target_path, 'requirements.prod.txt',
                  'docker/requirements.prod.txt.tpl', context)
    generate_file(target_path, 'app/settings_prod.py',
                  'docker/settings_prod.py.tpl', context)
    generate_file(target_path, 'Dockerfile', 'docker/dockerfile.tpl', context)
    generate_file(target_path, '.dockerignore', 'docker/dockerignore.tpl',
                  context)
    generate_file(target_path, 'docker-compose.yaml',
                  'docker/docker-compose.yaml.tpl', context)
    generate_file(target_path, 'deploy/init.sh', 'docker/init.sh.tpl', context)
    generate_file(target_path, 'deploy/nginx.conf', 'docker/nginx.conf.tpl',
                  context)
    if not has_channels:
        generate_file(target_path, 'deploy/uwsgi.ini', 'docker/uwsgi.ini.tpl',
                      context)
    else:
        generate_file(target_path, 'app/asgi.py', 'docker/asgi.py.tpl',
                      context)
Beispiel #12
0
def generate(target_path, project):
    has_react = False

    react_pages = []
    react_pages_by_app = {}
    index_imports = ImportSet()

    for app_name, application in project.applications.items():
        if not application.pages_support(ReactPageExtension):
            continue

        has_react = True

        react_pages_by_app[app_name] = {}

        app_cmp_name = to_camel_case(app_name)

        for name, page in application.pages.items():
            ext = page.get_own_or_parent_extension(ReactPageExtension)
            if not ext:
                continue

            page_cmp_name = to_camel_case(page.name)

            name = f'{page_cmp_name}Page'
            name_ui = f'{page_cmp_name}Ui'

            if page.uri:
                react_pages.append(
                    (app_cmp_name, name_ui, format_uri(page.uri)))
                react_pages_by_app[app_name][page.name] = format_uri(page.uri)

            page_component_name = f'Page{page_cmp_name}'

            react_components_imports = ImportSet()
            react_components_imports.add('react', 'React')
            # react_components_imports.add(f'../Components/{el.tag}', '*' + el.tag)

            imports = ImportSet()
            imports.add('react', 'React')
            imports.add(f'../../layout', 'BaseLayout')
            imports.add(f'../layouts/{app_cmp_name}Layout',
                        f'{app_cmp_name}Layout')

            react_components_imports.add(
                f'../Reducers/{page_component_name}Reducers',
                f'*reloadPageDataAction')

            index_imports.add(f'./pages/{name}', '*' + name)

            wrappers = [
                f'PageContextProvider', f'BaseLayout', f'{app_cmp_name}Layout'
            ]

            def wrap(source, cmp_list):
                source = indent(source, '    ')

                if not len(cmp_list):
                    return dedent(source)

                w = cmp_list.pop()

                return wrap(
                    f'<{w} {{...this.props}} page={{this}}>\n{source}\n</{w}>',
                    wrappers)

            blocks_rendered = {}
            for area, blocks in page.get_blocks(
                    platform=ReactPageExtension).items():
                blocks_rendered[area] = []
                for index, block in enumerate(blocks):

                    rendered = block.render(area=area, index=index)

                    try:
                        import_section, rendered = rendered.split('<',
                                                                  maxsplit=1)
                    except ValueError:
                        pass
                    else:
                        for im in REACT_IMPORT_RX.findall(import_section):
                            what = [
                                '*' + x.strip() for x in im[3].split(',')
                                if x != ''
                            ]
                            def_what = im[0].strip(' ,')

                            if len(def_what):
                                what.append(def_what)
                            src = im[5]

                            imports.add(src, *what)

                        rendered = '<' + rendered

                        blocks_rendered[area].append((block.ref, rendered))

            streams = page.list_own_or_parent_extensions(StreamPageExtension)
            generate_file(
                target_path,
                'react/src/{}/pages/{}.jsx'.format(app_name, name),
                'react/page.jsx.tpl', {
                    'imports': imports.import_sting_js(),
                    'name': name,
                    'page': page,
                    'blocks': blocks_rendered,
                    'ext': ReactPageExtension,
                    'app_name': app_name,
                    'streams': streams,
                    'to_camel_case': to_camel_case,
                    'source': wrap('{this.renderContent()}', wrappers)
                })

            ui_imports = ImportSet()
            ui_imports.add('react', 'React')
            ui_imports.add(f'../pages/{name}', name)

            generate_file(
                target_path, f'react/src/{app_name}/ui/{name_ui}.jsx',
                'react/ui.jsx.tpl', {
                    'imports': ui_imports.import_sting_js(),
                    'parent': name,
                    'name': name_ui
                })

        generate_file(
            target_path,
            f'react/src/{app_name}/layouts/{app_cmp_name}Layout.jsx',
            'react/cmp.jsx.tpl', {
                'name': f'{app_cmp_name}Layout',
                'source': '<>{children}</>'
            })

        if not len(react_pages_by_app[app_name]):
            del react_pages_by_app[app_name]

    # sort react_pages
    react_pages = sorted(react_pages)

    # sort routes
    temp_dict = {}
    for key in sorted(react_pages_by_app):
        temp_dict.update({key: react_pages_by_app[key]})
    react_pages_by_app = temp_dict

    if has_react:
        generate_file(target_path, f'react/src/layout.jsx',
                      'react/cmp.jsx.tpl', {
                          'name': f'BaseLayout',
                          'source': '<>{children}</>'
                      })
        generate_file(target_path, f'react/src/index.scss',
                      'react/index.scss.tpl', {'pages': react_pages})
        generate_file(target_path, 'app/utils/react.py', 'react/utils.py.tpl')
        generate_file(target_path, 'react/src/index.jsx',
                      'react/index.jsx.tpl')
        generate_file(target_path, 'react/src/state.jsx', 'react/state.js.tpl')
        generate_file(target_path, 'react/src/streams.jsx',
                      'react/streams.js.tpl')
        generate_file(target_path, 'react/src/reducer.jsx',
                      'react/reducer.js.tpl', {'name': 'Root'})
        generate_file(
            target_path, 'react/src/router.jsx', 'react/router.jsx.tpl', {
                'name': 'Root',
                'pages': react_pages,
                'pages_index': react_pages_by_app,
                'to_camel_case': to_camel_case
            })

        generate_file(target_path, 'react/package.json',
                      'react/package.json.tpl', {'packages': {}})
        generate_file(target_path, 'react/webpack.config.js',
                      'react/webpack.config.js.tpl',
                      {'entries': {
                          'all': f'./src/index.jsx'
                      }})