From 3a7e9a3cea6bfa1fbe9599d5e8cbe225caf0b536 Mon Sep 17 00:00:00 2001 From: shaohuzhang1 Date: Tue, 8 Oct 2024 16:58:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=BA=93=E8=84=9A=E6=9C=AC=E4=BB=A3=E7=A0=81=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../serializers/py_lint_serializer.py | 57 +++++++++++++++++++ apps/function_lib/swagger_api/py_lint_api.py | 23 ++++++++ apps/function_lib/urls.py | 3 +- apps/function_lib/views/__init__.py | 1 + apps/function_lib/views/py_lint.py | 31 ++++++++++ pyproject.toml | 1 + ui/package.json | 5 +- ui/src/api/function-lib.ts | 6 +- ui/src/components/codemirror-editor/index.vue | 54 +++++++++++++----- ui/src/styles/app.scss | 18 ------ ui/src/styles/variables.scss | 2 +- .../component/FunctionFormDrawer.vue | 11 +++- ui/src/workflow/nodes/function-node/index.vue | 11 +++- 13 files changed, 185 insertions(+), 38 deletions(-) create mode 100644 apps/function_lib/serializers/py_lint_serializer.py create mode 100644 apps/function_lib/swagger_api/py_lint_api.py create mode 100644 apps/function_lib/views/py_lint.py diff --git a/apps/function_lib/serializers/py_lint_serializer.py b/apps/function_lib/serializers/py_lint_serializer.py new file mode 100644 index 000000000..8d893a93f --- /dev/null +++ b/apps/function_lib/serializers/py_lint_serializer.py @@ -0,0 +1,57 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: py_lint_serializer.py + @date:2024/9/30 15:38 + @desc: +""" +import os +import uuid + +from pylint.lint import Run +from pylint.reporters import JSON2Reporter +from rest_framework import serializers + +from common.util.field_message import ErrMessage +from smartdoc.const import PROJECT_DIR + + +class PyLintInstance(serializers.Serializer): + code = serializers.CharField(required=True, error_messages=ErrMessage.char("函数名称")) + + +def to_dict(message, file_name): + return {'line': message.line, + 'column': message.column, + 'endLine': message.end_line, + 'endColumn': message.end_column, + 'message': (message.msg or "").replace(file_name, 'code'), + 'type': message.category} + + +def get_file_name(): + file_name = f"{uuid.uuid1()}" + py_lint_dir = os.path.join(PROJECT_DIR, 'data', 'py_lint') + if not os.path.exists(py_lint_dir): + os.makedirs(py_lint_dir) + return os.path.join(py_lint_dir, file_name) + + +class PyLintSerializer(serializers.Serializer): + + def pylint(self, instance, is_valid=True): + if is_valid: + self.is_valid(raise_exception=True) + PyLintInstance(data=instance).is_valid(raise_exception=True) + code = instance.get('code') + file_name = get_file_name() + with open(file_name, 'w') as file: + file.write(code) + reporter = JSON2Reporter() + Run([file_name, + "--disable=line-too-long", + '--module-rgx=[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'], + reporter=reporter, exit=False) + os.remove(file_name) + return [to_dict(m, os.path.basename(file_name)) for m in reporter.messages] diff --git a/apps/function_lib/swagger_api/py_lint_api.py b/apps/function_lib/swagger_api/py_lint_api.py new file mode 100644 index 000000000..40c44a498 --- /dev/null +++ b/apps/function_lib/swagger_api/py_lint_api.py @@ -0,0 +1,23 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: py_lint_api.py + @date:2024/9/30 15:48 + @desc: +""" +from drf_yasg import openapi + +from common.mixins.api_mixin import ApiMixin + + +class PyLintApi(ApiMixin): + @staticmethod + def get_request_body_api(): + return openapi.Schema( + type=openapi.TYPE_OBJECT, + required=['code'], + properties={ + 'code': openapi.Schema(type=openapi.TYPE_STRING, title="函数内容", description="函数内容") + } + ) diff --git a/apps/function_lib/urls.py b/apps/function_lib/urls.py index a393fd552..784b48093 100644 --- a/apps/function_lib/urls.py +++ b/apps/function_lib/urls.py @@ -6,7 +6,8 @@ app_name = "function_lib" urlpatterns = [ path('function_lib', views.FunctionLibView.as_view()), path('function_lib/debug', views.FunctionLibView.Debug.as_view()), + path('function_lib/pylint', views.PyLintView.as_view()), path('function_lib/', views.FunctionLibView.Operate.as_view()), path("function_lib//", views.FunctionLibView.Page.as_view(), - name="function_lib_page"), + name="function_lib_page") ] diff --git a/apps/function_lib/views/__init__.py b/apps/function_lib/views/__init__.py index aadec353e..ad3240be1 100644 --- a/apps/function_lib/views/__init__.py +++ b/apps/function_lib/views/__init__.py @@ -7,3 +7,4 @@ @desc: """ from .function_lib_views import * +from .py_lint import * diff --git a/apps/function_lib/views/py_lint.py b/apps/function_lib/views/py_lint.py new file mode 100644 index 000000000..15fc45a9a --- /dev/null +++ b/apps/function_lib/views/py_lint.py @@ -0,0 +1,31 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: py_lint.py + @date:2024/9/30 15:35 + @desc: +""" +from drf_yasg.utils import swagger_auto_schema +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.views import APIView + +from common.auth import TokenAuth, has_permissions +from common.constants.permission_constants import RoleConstants +from common.response import result +from function_lib.serializers.py_lint_serializer import PyLintSerializer +from function_lib.swagger_api.py_lint_api import PyLintApi + + +class PyLintView(APIView): + authentication_classes = [TokenAuth] + + @action(methods=['POST'], detail=False) + @swagger_auto_schema(operation_summary="校验代码", + operation_id="校验代码", + request_body=PyLintApi.get_request_body_api(), + tags=['函数库']) + @has_permissions(RoleConstants.ADMIN, RoleConstants.USER) + def post(self, request: Request): + return result.success(PyLintSerializer(data={'user_id': request.user.id}).pylint(request.data)) diff --git a/pyproject.toml b/pyproject.toml index 6493356ea..a421f2888 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ celery = { extras = ["sqlalchemy"], version = "^5.4.0" } django-celery-beat = "^2.6.0" celery-once = "^3.0.1" anthropic = "^0.34.2" +pylint = "3.1.0" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/ui/package.json b/ui/package.json index 0e7449a67..e8f21d5c7 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,6 +13,7 @@ "format": "prettier --write src/" }, "dependencies": { + "@codemirror/theme-one-dark": "^6.1.2", "@ctrl/tinycolor": "^4.1.0", "@logicflow/core": "^1.2.27", "@logicflow/extension": "^1.2.27", @@ -37,14 +38,14 @@ "nprogress": "^0.2.0", "pinia": "^2.1.6", "pinyin-pro": "^3.18.2", + "recorder-core": "^1.3.24040900", "screenfull": "^6.0.2", "use-element-plus-theme": "^0.0.5", "vue": "^3.3.4", "vue-clipboard3": "^2.0.0", "vue-codemirror": "^6.1.1", "vue-i18n": "^9.13.1", - "vue-router": "^4.2.4", - "recorder-core": "^1.3.24040900" + "vue-router": "^4.2.4" }, "devDependencies": { "@rushstack/eslint-patch": "^1.3.2", diff --git a/ui/src/api/function-lib.ts b/ui/src/api/function-lib.ts index c68b6a9ad..c6a8200ed 100644 --- a/ui/src/api/function-lib.ts +++ b/ui/src/api/function-lib.ts @@ -95,6 +95,9 @@ const getFunctionLibById: ( ) => Promise> = (function_lib_id, loading) => { return get(`${prefix}/${function_lib_id}`, undefined, loading) } +const pylint: (code: string, loading?: Ref) => Promise> = (code, loading) => { + return post(`${prefix}/pylint`, { code }, {}, loading) +} export default { getFunctionLib, @@ -103,5 +106,6 @@ export default { postFunctionLibDebug, getAllFunctionLib, delFunctionLib, - getFunctionLibById + getFunctionLibById, + pylint } diff --git a/ui/src/components/codemirror-editor/index.vue b/ui/src/components/codemirror-editor/index.vue index 857fef4ce..b8f46d9b1 100644 --- a/ui/src/components/codemirror-editor/index.vue +++ b/ui/src/components/codemirror-editor/index.vue @@ -1,27 +1,55 @@ diff --git a/ui/src/styles/app.scss b/ui/src/styles/app.scss index 15529eae4..27dc2746b 100644 --- a/ui/src/styles/app.scss +++ b/ui/src/styles/app.scss @@ -721,24 +721,6 @@ h5 { background: var(--el-color-primary-light-9) !important; } -// Codemirror 编辑器 -.function-CodemirrorEditor { - border: 1px solid #bbbfc4; - border-radius: 4px; - position: relative; - padding-bottom: 20px; - &__footer { - .magnify { - position: absolute; - bottom: 5px; - right: 5px; - } - } - .cm-gutters { - display: none !important; - } -} - .edit-avatar { position: relative; .edit-mask { diff --git a/ui/src/styles/variables.scss b/ui/src/styles/variables.scss index 0c1d7b69e..4f7a918dd 100644 --- a/ui/src/styles/variables.scss +++ b/ui/src/styles/variables.scss @@ -9,7 +9,7 @@ --app-view-padding: 24px; --app-view-bg-color: #ffffff; --app-border-color-dark: #bbbfc4; - + --md-bk-hover-color:var(--el-border-color-hover); /** header 组件 */ --app-header-height: 56px; --app-header-padding: 0 20px; diff --git a/ui/src/views/function-lib/component/FunctionFormDrawer.vue b/ui/src/views/function-lib/component/FunctionFormDrawer.vue index 92da6eeb9..61bc85305 100644 --- a/ui/src/views/function-lib/component/FunctionFormDrawer.vue +++ b/ui/src/views/function-lib/component/FunctionFormDrawer.vue @@ -305,4 +305,13 @@ defineExpose({ open }) - + diff --git a/ui/src/workflow/nodes/function-node/index.vue b/ui/src/workflow/nodes/function-node/index.vue index 6f4c226ed..6fb838799 100644 --- a/ui/src/workflow/nodes/function-node/index.vue +++ b/ui/src/workflow/nodes/function-node/index.vue @@ -221,4 +221,13 @@ onMounted(() => { }, 100) }) - +