Compare View

switch
from
...
to
 
Commits (5)

Changes

Showing 56 changed files Side-by-side Diff

... ... @@ -0,0 +1,3 @@
  1 +/components/adm/
  2 +/components/grid/
  3 +/components/vue/
__pycache__/main.cpython-310.pyc
No preview for this file type
__pycache__/routes.cpython-310.pyc
No preview for this file type
components/__pycache__/__init__.cpython-310.pyc
No preview for this file type
components/k2test/__pycache__/__init__.cpython-310.pyc
No preview for this file type
components/k2test/history.txt
... ... @@ -0,0 +1,2 @@
  1 +1.0.0.0 base component
  2 +1.0.0.1 add some routes
0 3 \ No newline at end of file
components/k2test/k2test/__pycache__/__init__.cpython-310.pyc
No preview for this file type
components/k2test/k2test/__pycache__/views.cpython-310.pyc
No preview for this file type
components/k2test/k2test/languages/en/LC_MESSAGES/messages.mo
No preview for this file type
components/k2test/k2test/languages/en/LC_MESSAGES/messages.po
1   -msgid "Installed components"
2   -msgstr "Installed components"
3   -
4   -msgid "Name"
5   -msgstr "Name"
6   -
7   -msgid "Description"
8   -msgstr "Description"
9   -
10   -msgid "Version"
11   -msgstr "Version"
12   -
13   -msgid "Dependencies"
14   -msgstr "Dependencies"
15   -
16   -msgid "Git Link"
17   -msgstr "Git Link"
18   -
19   -msgid "Install At"
20   -msgstr "Install At"
21   -
22   -msgid "Status"
23   -msgstr "Status"
24   -
25   -msgid "Action"
26   -msgstr "Action"
27   -
28   -msgid "Components Shop"
29   -msgstr "Components Shop"
30   -
31 1 msgid "New 2 page"
32   -msgstr "New 2 page"
  2 +msgstr "Нова сторінка 2"
  3 +msgid "title_menu_items"
  4 +msgstr "Test menu items"
33 5 \ No newline at end of file
components/k2test/k2test/languages/uk/LC_MESSAGES/messages.mo
No preview for this file type
components/k2test/k2test/languages/uk/LC_MESSAGES/messages.po
1 1 msgid "New 2 page"
2 2 msgstr "Нова сторінка 2"
  3 +msgid "title_menu_items"
  4 +msgstr "Тестова компонента"
3 5 \ No newline at end of file
components/k2test/k2test/views.py
1 1 from flask import render_template, redirect, request, jsonify
  2 +from flask_babel import gettext
2 3 from flask_login import login_user, current_user, logout_user, login_required
3 4 from flask import current_app as k2
4 5 from flask import Blueprint, json
5 6 from flask_sqlalchemy import SQLAlchemy
6 7  
7 8  
  9 +#bliueprint
  10 +k2test = Blueprint('k2test', __name__, template_folder='templates', static_folder='static')
8 11  
9   -k2test = Blueprint('k2test', __name__, template_folder='templates', static_folder='static',)
10   -
11   -
12   -
  12 +#component routes
13 13 @k2test.route('/new')
14 14 def new_component():
15 15 db = k2.extensions['sqlalchemy'].db
... ... @@ -33,12 +33,12 @@ def new_component3():
33 33 def new_component4():
34 34 return jsonify({'data': 'page new4'})
35 35  
36   -
37   -@k2test.route('/menu-items')
  36 +# menu items for admin
  37 +@k2test.route('/menu-admin-items')
38 38 def menu_items():
39 39 data = [
40 40 {
41   - 'title': 'Тестова компонента',
  41 + 'title': f"{gettext('title_menu_items')}",
42 42 'icon': {'icon': 'mdi-chart-timeline-variant'},
43 43 'children': [
44 44 {'title': 'Тест 3', 'to': 'k2test-new3'},
... ... @@ -47,4 +47,5 @@ def menu_items():
47 47 }
48 48  
49 49 ]
50   - return data
51 50 \ No newline at end of file
  51 + return data
  52 +
components/k2test/setup.py
... ... @@ -4,8 +4,8 @@ setup(
4 4 name='k2test',
5 5 version='1.0.0',
6 6 description='Description of my project',
7   - author='Your Name',
8   - author_email='yourname@example.com',
  7 + author='k2 cloud',
  8 + author_email='rs@corp2.net',
9 9 keywords="k2test, k2",
10 10 python_requires=">=3.7, <=3.11.2",
11 11 packages=['k2test'],
No preview for this file type
k2/__pycache__/__init__.cpython-310.pyc
No preview for this file type
k2/__pycache__/k2cfg.cpython-310.pyc
No preview for this file type
k2/__pycache__/k2comp.cpython-310.pyc
No preview for this file type
k2/__pycache__/k2obj.cpython-310.pyc
No preview for this file type
k2/__pycache__/k2rout.cpython-310.pyc
No preview for this file type
... ... @@ -9,11 +9,13 @@ import os
9 9 import sys
10 10 from flask import session
11 11  
  12 +
  13 +
12 14 class k2(k2obj):
13 15 version = '2.5.1.27'
14 16 db = SQLAlchemy()
15 17 domain = 'http://127.0.0.1:5000/'
16   - update_domain ='http://127.0.0.1:8001/'
  18 + update_domain ='http://127.0.0.1:8002/'
17 19 venv_bin_path = os.path.join(os.path.dirname(sys.prefix), 'venv/Scripts')
18 20 json_sort_keys = False
19 21 timezone = pytz.timezone('Europe/Kiev')
... ... @@ -21,6 +23,9 @@ class k2(k2obj):
21 23 default_language = 'en'
22 24 current_language = ''
23 25 babel_translation_directories = ''
  26 + components = ''
  27 +
  28 +
24 29  
25 30 def __init__(self):
26 31 super().__init__()
... ... @@ -52,12 +57,6 @@ class k2(k2obj):
52 57  
53 58 with open('languages/babel_translation_directories.yml', 'w') as f:
54 59 yaml.dump(data, f)
55   - @classmethod
56   - def get_menu_elenents(cls):
57   - with open('components/menu.yml', 'r') as f:
58   - yaml_data = yaml.load(f, Loader=yaml.FullLoader)
59   - cls.menu = yaml_data
60   -
61 60  
62 61 # load database settings from yml file
63 62 def init_db_uri(self):
... ... @@ -74,6 +73,3 @@ class k2(k2obj):
74 73 app.config['SQLALCHEMY_BINDS'] = {'db2': f'sqlite:///{db_path}'}
75 74 self.db.init_app(app)
76 75  
77   -
78   -
79   -
... ... @@ -0,0 +1,40 @@
  1 +import uuid
  2 +from datetime import datetime
  3 +from .k2cfg import k2
  4 +
  5 +db = k2.db
  6 +def generate_id():
  7 + generated_id = uuid.uuid4().hex[:32]
  8 + return ''.join([generated_id[i:i + 4] for i in range(0, len(generated_id), 4)])
  9 +class Component(db.Model):
  10 + __bind_key__ = 'db2'
  11 + __tablename__ = 'component'
  12 + __table_args__ = {'extend_existing': True}
  13 + id = db.Column(db.String(36), primary_key=True, default=generate_id)
  14 + name = db.Column(db.String(100), nullable=False)
  15 + description = db.Column(db.String(200))
  16 + version = db.Column(db.String(20))
  17 + git_link = db.Column(db.String(200))
  18 + dependencies = db.Column(db.String)
  19 + date_installed = db.Column(db.DateTime, default=datetime.utcnow)
  20 + installed = db.Column(db.Boolean, default=False)
  21 +
  22 + def __init__(self, name, description, version, git_link, dependencies, installed):
  23 + self.name = name
  24 + self.description = description
  25 + self.version = version
  26 + self.git_link = git_link
  27 + self.dependencies = dependencies
  28 + self.installed = installed
  29 + def __repr__(self):
  30 + return f"Component('{self.name}', '{self.version}')"
  31 + @classmethod
  32 + def get_repository_by_id(self,rep_id):
  33 + component = db.session.query(Component).filter(Component.id == rep_id).first()
  34 + return component
  35 + @classmethod
  36 + def get_repository_by_id(self,rep_id):
  37 + component = db.session.query(Component).filter(Component.id == rep_id).first()
  38 + return component
  39 +
  40 +
... ... @@ -16,6 +16,7 @@ class k2obj:
16 16 'cutpast': '0',
17 17 'enable': '0'
18 18 }
  19 + components = ''
19 20  
20 21  
21 22  
... ... @@ -0,0 +1,472 @@
  1 +import zipfile
  2 +from flask import Flask, Blueprint, jsonify, render_template, redirect, url_for, session, jsonify
  3 +import os
  4 +import shutil
  5 +from flask import request
  6 +from .k2cfg import k2
  7 +from .k2comp import Component
  8 +from flask_migrate import Migrate
  9 +import requests
  10 +import subprocess
  11 +from flask import current_app
  12 +import yaml
  13 +from functools import wraps
  14 +import os
  15 +import sys
  16 +
  17 +# initialize db
  18 +# migrate = Migrate(app, db)
  19 +
  20 +components_bp = Blueprint('components', __name__, template_folder='templates')
  21 +config = yaml.safe_load(open("db/first-login.yml"))
  22 +
  23 +db = k2.db
  24 +
  25 +
  26 +def first_login_required(view_func):
  27 + @wraps(view_func)
  28 + def decorated_view(*args, **kwargs):
  29 + if 'username' not in session:
  30 + return redirect(url_for('components.first_login'))
  31 + return view_func(*args, **kwargs)
  32 +
  33 + return decorated_view
  34 +
  35 +
  36 +# def append_to_yaml_file(file_path, data):
  37 +# with open(file_path, 'r') as f:
  38 +# existing_data = yaml.safe_load(f) or []
  39 +#
  40 +# if not existing_data:
  41 +# start_id = 1
  42 +# else:
  43 +# start_id = max(item.get('id', 0) for item in existing_data) + 1
  44 +#
  45 +# for i, item in enumerate(data, start=start_id):
  46 +# item['id'] = i
  47 +# existing_data.append(item)
  48 +#
  49 +# with open(file_path, 'w') as f:
  50 +# yaml.dump(existing_data, f, default_flow_style=False)
  51 +
  52 +
  53 +def remove_from_yaml_file(file_path, component_name):
  54 + with open(file_path, 'r') as f:
  55 + existing_data = yaml.safe_load(f) or []
  56 +
  57 + updated_data = [item for item in existing_data if item.get('component_name') != component_name]
  58 +
  59 + with open(file_path, 'w') as f:
  60 + yaml.dump(updated_data, f, default_flow_style=False)
  61 +
  62 +
  63 +@components_bp.route('/api/languages', methods=['GET'])
  64 +def find_language():
  65 + components = Component.query.all()
  66 + languages_paths = []
  67 + # Додаємо головну директорію languages
  68 + languages_paths.append('languages')
  69 + # Знаходимо шляхи до директорій languages всередині папки components
  70 + for component in components:
  71 + component_languages_directory = 'components/' + component.name + '/' + component.name + '/languages'
  72 + languages_paths.append(component_languages_directory)
  73 + result = ';'.join(languages_paths)
  74 + print(result)
  75 + return result
  76 +
  77 +
  78 +@components_bp.route('/home', methods=['GET', 'POST'])
  79 +@first_login_required
  80 +def home():
  81 + return redirect('/dashboard')
  82 +
  83 +
  84 +@components_bp.route('/first-login', methods=['GET', 'POST'])
  85 +def first_login():
  86 + if request.method == "POST":
  87 + username = request.form.get("username")
  88 + password = request.form.get("password")
  89 + for user in config["users"]:
  90 + if user["username"] == username and user["password"] == password:
  91 + session['username'] = username # Збереження ім'я користувача в сесії
  92 + return redirect(url_for('components.dashboard'))
  93 + return "Невірне ім'я користувача або пароль."
  94 + return render_template('first-login.html')
  95 +
  96 +
  97 +@components_bp.route('/change_language/<lang>')
  98 +def change_language(lang):
  99 + session['lang'] = lang
  100 + k2.current_language = lang
  101 + return redirect(url_for('components.dashboard'))
  102 +
  103 +
  104 +@components_bp.route('/dashboard')
  105 +@first_login_required
  106 +def dashboard():
  107 + # Компоненти доступні для встановлення
  108 + try:
  109 + # GET-запит до API
  110 + response = requests.get(f'{k2.update_domain}api/components')
  111 + json_data = response.json()
  112 + # Перетворення JSON-об'єкту на масив
  113 + component_server = [item for item in json_data]
  114 + except:
  115 + component_server = None
  116 +
  117 + # Встановлені компоненти
  118 + components = Component.query.all()
  119 + components_names = [component.name for component in components]
  120 + # Отримання значення пошукового запиту з параметрів URL
  121 + search_query = request.args.get('search_query')
  122 + # print(search_query)
  123 + filtered_components = []
  124 + if search_query:
  125 + filtered_components = [component for component in component_server if
  126 + (search_query.lower() in component['name'].lower() if component['name'] else False) or
  127 + (search_query.lower() in component['description'].lower() if component[
  128 + 'description'] else False)]
  129 + else:
  130 + filtered_components = component_server
  131 + current_language = k2.current_language
  132 +
  133 + return render_template('dashboard.html', components=components,
  134 + components_names=components_names, component_server=filtered_components,
  135 + search_query=search_query, language=k2.menu)
  136 +
  137 +
  138 +@components_bp.route('/show_components/<string:component_id>')
  139 +def show_components(component_id):
  140 + response = requests.get(f'{k2.update_domain}api/components')
  141 + json_data = response.json()
  142 + selected_component = next((component for component in json_data if component['id'] == component_id), None)
  143 + return render_template('component-info.html', selected_component=selected_component)
  144 +
  145 +
  146 +@components_bp.route('/install_components_git/<string:component_id>')
  147 +def install_components_git(component_id):
  148 + # Шлях до головної папки проекту
  149 + project_folder = 'components'
  150 + # component = Component.get_repository_by_id(component_id)
  151 + response = requests.get(f'{k2.update_domain}api/components')
  152 + json_data = response.json()
  153 + selected_component = next((component for component in json_data if component['id'] == component_id), None)
  154 + # Назва репозиторія
  155 + repository_name = selected_component['name']
  156 + # Шлях до папки репозиторія в межах проекту
  157 + repository_folder = os.path.join(project_folder, repository_name)
  158 + # URL репозиторія
  159 +
  160 + git_repo_url = selected_component['git_link']
  161 + try:
  162 + # Перевірка наявності папки репозиторія
  163 + if not os.path.exists(repository_folder):
  164 + # Створення папки репозиторія
  165 + os.makedirs(repository_folder)
  166 + # Шлях до файлу __init__.py
  167 + init_file = os.path.join(repository_folder, '__init__.py')
  168 + # Перевірка наявності файлу __init__.py
  169 + if not os.path.exists(init_file):
  170 + # Створення пустого файлу __init__.py
  171 + open(init_file, 'a').close()
  172 + # підключення до приватного репозиторію
  173 + # os.environ['GITLAB_PRIVATE_TOKEN'] = '8xxTpxrKVDGoXD5ynjiW'
  174 + # git_repo_url_with_token = git_repo_url.replace('https://',
  175 + # f'https://oauth2:{os.environ["GITLAB_PRIVATE_TOKEN"]}@')
  176 +
  177 + # Команда для встановлення з використанням git_repo_url і повного шляху до папки репозиторія
  178 + command = ['venv/Scripts/python.exe', '-m', 'pip', 'install', '--use-pep517', 'git+' + git_repo_url,
  179 + '--target=' + repository_folder]
  180 + # Виконуємо команду встановлення
  181 + subprocess.check_call(command)
  182 +
  183 + # Шлях до файлу, до якого потрібно додати код
  184 + file_path = 'routes.py'
  185 + # Код, який потрібно додати
  186 + code = selected_component['dependencies']
  187 + # Відкриття файлу у режимі дозапису
  188 + with open(file_path, 'a') as file:
  189 + # Запис нового коду у файл
  190 + file.write('\n')
  191 + file.write(code)
  192 + file.write('\n')
  193 + component = Component.query.filter_by(name=selected_component['name']).first()
  194 + if not component:
  195 + new_component = Component(
  196 + name=selected_component['name'],
  197 + description=selected_component['description'],
  198 + version=selected_component['version'],
  199 + git_link=selected_component['git_link'],
  200 + dependencies=selected_component['dependencies'],
  201 + installed=True
  202 + )
  203 + # Add the new component to the database
  204 + db.session.add(new_component)
  205 + db.session.commit()
  206 +
  207 + # Повертаємо повідомлення про успішне встановлення
  208 + return f'Installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
  209 + except subprocess.CalledProcessError as e:
  210 + return 'Error installing : ' + str(e)
  211 +
  212 +
  213 +@components_bp.route('/install_components/<string:component_id>')
  214 +def install_component_from_archive(component_id):
  215 + # Шлях до головної папки проекту
  216 + project_folder = 'components'
  217 + # Отримати відповідну компоненту зі списку компонент
  218 + response = requests.get(f'{k2.update_domain}api/components')
  219 + json_data = response.json()
  220 + selected_component = next((component for component in json_data if component['id'] == component_id), None)
  221 + if selected_component is None:
  222 + return 'Component not found'
  223 + # Отримати посилання на архів компоненти та версію
  224 + archive_url = selected_component['latest_component_data']
  225 + version = selected_component['latest_version']
  226 + try:
  227 + # Створити шлях до папки компоненти згідно назви та версії
  228 + component_folder = os.path.join(project_folder)
  229 + os.makedirs(component_folder, exist_ok=True)
  230 + # Завантажити архів компоненти
  231 + response = requests.get(archive_url, stream=True)
  232 + response.raise_for_status()
  233 + # Шлях до завантаженого архіву
  234 + archive_path = os.path.join(component_folder, f"{selected_component['name']}.zip")
  235 + # Встановити залежності з файлу requirements.txt
  236 +
  237 + # Зберегти архів на диск
  238 + with open(archive_path, "wb") as file:
  239 + for chunk in response.iter_content(chunk_size=8192):
  240 + file.write(chunk)
  241 + # Розпакувати архів
  242 + with zipfile.ZipFile(archive_path, "r") as zip_ref:
  243 + zip_ref.extractall(component_folder)
  244 +
  245 + # Видалити архів
  246 + os.remove(archive_path)
  247 +
  248 + # Шлях до файлу, до якого потрібно додати код
  249 + file_path = 'routes.py'
  250 + # Код, який потрібно додати
  251 + code = f'''from components.{selected_component['name']}.{selected_component['name']}.views import {selected_component['name']}\napp.register_blueprint({selected_component['name']}, url_prefix='/{selected_component['name']}')'''
  252 + # selected_component['dependencies']
  253 +
  254 + # Відкриття файлу у режимі дозапису
  255 + with open(file_path, 'a') as file:
  256 + # Запис нового коду у файл
  257 + file.write('\n')
  258 + file.write(code)
  259 + file.write('\n')
  260 +
  261 + # Update database with the installed component
  262 + component = Component.query.filter_by(name=selected_component['name']).first()
  263 + if not component:
  264 + component = Component(
  265 + name=selected_component['name'],
  266 + description=selected_component['description'],
  267 + version=version,
  268 + git_link=selected_component['git_link'],
  269 + dependencies=code,
  270 + installed=True
  271 + )
  272 + db.session.add(component)
  273 + else:
  274 + component.version = version
  275 + component.git_link = selected_component['git_link']
  276 + component.dependencies = code
  277 + component.installed = True
  278 +
  279 + db.session.commit()
  280 +
  281 + # add language folders
  282 + k2.search_babel_translation_directories()
  283 + return f'''Component installed successfully: {selected_component["name"]} v{version} {k2.babel_translation_directories},
  284 + \n \n please wait installing requirments...
  285 + <meta http-equiv="refresh" content="0;url=/install-requirments/{selected_component["name"]}" />'''
  286 +
  287 + except Exception as e:
  288 + return f'Error installing component: {str(e)}'
  289 +
  290 +
  291 +@components_bp.route('/install-requirments/<string:selected_component_name>', methods=['GET'])
  292 +def install_requirments(selected_component_name):
  293 + # menu items
  294 + get_admin_menu()
  295 +
  296 + # install requirements
  297 + requirements_file = os.path.join('components', selected_component_name, "requirements.txt")
  298 + if os.path.isfile(requirements_file):
  299 + pip_command = f"{k2.venv_bin_path}/python -m pip install -r {requirements_file}"
  300 + subprocess.run(pip_command, shell=True, check=True)
  301 + return f'''Requirements installed successfully
  302 + \n \n please wait installing requirments components...
  303 + <meta http-equiv="refresh" content="1;url=/install-requirments-components" />'''
  304 +
  305 +
  306 +@components_bp.route('/install-requirments-components')
  307 +def install_requirements_components():
  308 + # Откриття файлу requirements_components.txt
  309 + requirements_file = 'requirements_components.txt'
  310 + component_ids = None
  311 + if os.path.isfile(requirements_file):
  312 + with open('requirements_components.txt', 'r') as file:
  313 + component_ids = file.read().splitlines()
  314 + if component_ids:
  315 + for component_id in component_ids:
  316 + # Виклик роуту '/install_components/<string:component_name>' для кожної назви компоненти
  317 + response = requests.get(
  318 + f'/install_components/{component_id}')
  319 + return f'Requirements components installed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
  320 + else:
  321 + return f'<meta http-equiv="refresh" content="1;url=/dashboard" />'
  322 + # Опрацювання відповіді (за потреби)
  323 +
  324 +
  325 +@components_bp.route('/remove_dependencies/<string:component_id>', methods=['GET'])
  326 +def remove_dependencies(component_id):
  327 + # Знаходимо компоненту за її ID
  328 + component = Component.query.get(component_id)
  329 + if not component:
  330 + return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />'
  331 + # remove menu items
  332 + component_name = component.name
  333 + # file_path = "components/menu.yml"
  334 + # remove_from_yaml_file(file_path, component_name)
  335 + requests.get(f"{k2.domain}api/add-to-menu")
  336 + # remove routes
  337 + file_path = 'routes.py'
  338 + with open(file_path, 'r') as file:
  339 + lines = file.readlines()
  340 +
  341 + updated_lines = [line for line in lines if line.strip() not in component.dependencies]
  342 + with open(file_path, 'w') as file:
  343 + file.writelines(updated_lines)
  344 +
  345 + component.installed = False
  346 + db.session.commit()
  347 +
  348 + return 'Component successfully turn off <meta http-equiv="refresh" content="1;url=/dashboard" />'
  349 +
  350 +
  351 +@components_bp.route('/add_dependencies/<string:component_id>', methods=['GET'])
  352 +def add_dependencies(component_id):
  353 + # Знаходимо компоненту за її ID
  354 + component = Component.query.get(component_id)
  355 + if not component:
  356 + return 'Component not found <meta http-equiv="refresh" content="1;url=/dashboard" />'
  357 +
  358 + file_path = 'routes.py'
  359 + code = component.dependencies
  360 + # Відкриття файлу у режимі дозапису
  361 + with open(file_path, 'a') as file:
  362 + # Запис нового коду у файл
  363 + file.write(code)
  364 +
  365 + # Оновлюємо статус компоненти
  366 + component.installed = True
  367 + db.session.commit()
  368 + return 'Dependencies added successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
  369 +
  370 +
  371 +@components_bp.route('/remove-component/<string:component_id>')
  372 +def remove_component(component_id):
  373 + # Шлях до головної папки проекту
  374 + project_folder = 'components'
  375 + component = Component.query.get(component_id)
  376 + # Назва репозиторія
  377 + repository_name = component.name
  378 + # Шлях до папки репозиторія в межах проекту
  379 + repository_folder = os.path.join(project_folder, repository_name)
  380 + try:
  381 + # Перевірка наявності папки репозиторія
  382 + if os.path.exists(repository_folder):
  383 + # Видалення папки репозиторія
  384 + shutil.rmtree(repository_folder)
  385 + # Видаляємо компоненту з бази
  386 + if component:
  387 + db.session.delete(component)
  388 + db.session.commit()
  389 +
  390 + # Повертаємо повідомлення про успішне видалення
  391 + return 'Component removed successfully <meta http-equiv="refresh" content="1;url=/dashboard" />'
  392 + except Exception as e:
  393 + # Повертаємо повідомлення про помилку видалення
  394 + return 'Error removing component: ' + str(e)
  395 +
  396 +
  397 +
  398 +
  399 +@components_bp.route('/component/add')
  400 +def component_add():
  401 + # components for install
  402 + try:
  403 + # GET-requests to API
  404 + response = requests.get(f'{k2.update_domain}api/components')
  405 + json_data = response.json()
  406 + for item in json_data:
  407 + item['button'] = f"{k2.domain}/install_components/{item['id']}"
  408 +
  409 + except:
  410 + json_data = None
  411 + return jsonify(json_data)
  412 +
  413 +
  414 +@components_bp.route('/component/list')
  415 +def component_list():
  416 + # Встановлені компоненти
  417 + component_list = []
  418 + components = Component.query.all()
  419 + for component in components:
  420 + component_dict = {}
  421 + component_dict['name'] = component.name
  422 + component_dict['id'] = component.id
  423 + component_dict['description'] = component.description
  424 + component_dict['version'] = component.version
  425 + component_dict['button_off'] =f"{k2.domain}/remove_dependencies/{component.id}"
  426 + component_dict['button_on'] = f"{k2.domain}/add_dependencies/{component.id}"
  427 + component_dict['button_del'] = f"{k2.domain}/remove-component/{component.id}"
  428 + component_list.append(component_dict)
  429 + return jsonify(component_list)
  430 +
  431 +# menu
  432 +@components_bp.route('/api/add-to-menu', methods=['GET'])
  433 +def add_to_menu():
  434 + data = []
  435 + response = requests.get(f"{k2.domain}/menu-admin-items")
  436 + data.append(response.json()[0])
  437 + components = Component.query.all()
  438 + components_names = [component.name for component in components]
  439 + for components_names in components_names:
  440 + response = requests.get(f"{k2.domain}{components_names}/menu-admin-items")
  441 + print(response)
  442 + if response.status_code == 200:
  443 + data.append(response.json()[0])
  444 + else:
  445 + data
  446 + # add component_name key for menu items
  447 + for item in data:
  448 + item['component_name'] = components_names
  449 + k2.menu = data
  450 + return k2.menu
  451 +
  452 +
  453 +@components_bp.route('/api/main-menu/')
  454 +def get_admin_menu():
  455 + requests.get(f"{k2.domain}api/add-to-menu")
  456 + return k2.menu
  457 +
  458 +
  459 +@components_bp.route('/menu-admin-items')
  460 +def menu_items():
  461 + menu = [
  462 + {
  463 + "title": 'Add components',
  464 + "icon": {"icon": 'mdi-account-circle-outline'},
  465 + "children": [
  466 + {'title': 'Install components', 'to': 'component-add'},
  467 + {'title': 'Installed components', 'to': 'component-list'},
  468 +
  469 + ],
  470 + }]
  471 + return menu
  472 +
languages/babel_translation_directories.yml
1   -babel_translation_directories: languages;components/k2test/k2test/languages
  1 +babel_translation_directories: languages;components/k2test/k2test/languages;components/grid/grid/languages;components/adm/adm/languages
... ... @@ -8,7 +8,7 @@ from k2.k2cfg import k2
8 8 # configure flask app
9 9 app = Flask(__name__)
10 10 app.config['SECRET_KEY'] = k2.secret_key
11   -
  11 +app.json.sort_keys = k2.json_sort_keys
12 12 #app.config.from_object(k2)
13 13  
14 14 # init db
... ... @@ -22,9 +22,6 @@ app.config[&#39;BABEL_TRANSLATION_DIRECTORIES&#39;] = k2.babel_translation_directories
22 22 babel = Babel(app)
23 23 babel.init_app(app, locale_selector=k2.get_locale)
24 24  
25   -#menu
26   -k2.get_menu_elenents()
27   -
28 25 # flask routing
29 26 from routes import *
30 27  
1 1 Binary files a/requirements.txt and b/requirements.txt differ
1   -from flask import Flask
2 1 #app = Flask(__name__)
3   -from main import app, babel
4   -from k2.k2inst import components_bp
  2 +from main import app
  3 +from k2.k2rout import components_bp
5 4 app.register_blueprint(components_bp)
6   -
7 5 from components.k2test.k2test.views import k2test
8 6 app.register_blueprint(k2test, url_prefix='/k2test')
9   -
10   -from components.adm.adm.views import adm
11   -app.register_blueprint(adm, url_prefix='/adm')
  7 +from components.grid.grid.views import grid
  8 +app.register_blueprint(grid, url_prefix='/grid')
  9 +from components.vue.vue.views import vue2
  10 +app.register_blueprint(vue2, url_prefix='/')
templates/dashboard.html
... ... @@ -112,7 +112,7 @@
112 112  
113 113  
114 114 <div class="container px-4 py-5" id="hanging-icons">
115   - <h2 class="pb-2 border-bottom">{{_('Components Shop')}}</h2>
  115 + <h2 class="pb-2 border-bottom">{{_('ADD Components')}}</h2>
116 116 <form action="{{ url_for('components.dashboard') }}" method="GET" class="search-form">
117 117 <div class="input-group">
118 118 <input type="text" name="search_query" class="form-control" placeholder="Search components">
templates/first-login.html
... ... @@ -64,7 +64,7 @@
64 64 <img class="logo" src="{{ url_for('static', filename='img/logo-k2.png')}}" alt="" width="250">
65 65 <h1>K2CloudERP-2.5.1.27</h1>
66 66  
67   - <form method="post" action="/login">
  67 + <form method="post" action="/first-login">
68 68 <div class="form-group">
69 69 <p><input type="text" name="username" placeholder="Ім'я користувача"></p>
70 70 </div>