mirror of
https://github.com/langgenius/dify.git
synced 2026-06-07 16:32:01 +08:00
chore: split to single app_dsl_version API (#36864)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
129af96c23
commit
04f5555580
@ -2,13 +2,25 @@ from flask_restx import Resource
|
||||
from werkzeug.exceptions import Unauthorized
|
||||
|
||||
from controllers.common.schema import register_response_schema_models
|
||||
from fields.base import ResponseModel
|
||||
from libs.helper import dump_response
|
||||
from libs.login import current_user, login_required
|
||||
from services.feature_service import FeatureModel, FeatureService, LimitationModel, SystemFeatureModel
|
||||
from services.feature_service import (
|
||||
FeatureModel,
|
||||
FeatureService,
|
||||
LimitationModel,
|
||||
SystemFeatureModel,
|
||||
)
|
||||
|
||||
from . import console_ns
|
||||
from .wraps import account_initialization_required, cloud_utm_record, setup_required, with_current_tenant_id
|
||||
|
||||
register_response_schema_models(console_ns, FeatureModel, LimitationModel, SystemFeatureModel)
|
||||
|
||||
class AppDslVersionResponse(ResponseModel):
|
||||
app_dsl_version: str
|
||||
|
||||
|
||||
register_response_schema_models(console_ns, AppDslVersionResponse, FeatureModel, LimitationModel, SystemFeatureModel)
|
||||
|
||||
|
||||
@console_ns.route("/features")
|
||||
@ -54,6 +66,23 @@ class FeatureVectorSpaceApi(Resource):
|
||||
return FeatureService.get_vector_space(current_tenant_id).model_dump()
|
||||
|
||||
|
||||
@console_ns.route("/app-dsl-version")
|
||||
class AppDslVersionApi(Resource):
|
||||
@console_ns.doc("get_app_dsl_version")
|
||||
@console_ns.doc(description="Get current app DSL version")
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Success",
|
||||
console_ns.models[AppDslVersionResponse.__name__],
|
||||
)
|
||||
def get(self):
|
||||
"""Get current app DSL version for workflow clipboard compatibility."""
|
||||
return dump_response(
|
||||
AppDslVersionResponse,
|
||||
{"app_dsl_version": FeatureService.get_app_dsl_version()},
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/system-features")
|
||||
class SystemFeatureApi(Resource):
|
||||
@console_ns.doc("get_system_features")
|
||||
|
||||
@ -599,6 +599,23 @@ Update API-based extension
|
||||
| ---- | ----------- |
|
||||
| 204 | Binding deleted successfully |
|
||||
|
||||
### /app-dsl-version
|
||||
|
||||
#### GET
|
||||
##### Summary
|
||||
|
||||
Get current app DSL version for workflow clipboard compatibility
|
||||
|
||||
##### Description
|
||||
|
||||
Get current app DSL version
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | [AppDslVersionResponse](#appdslversionresponse) |
|
||||
|
||||
### /app/prompt-templates
|
||||
|
||||
#### GET
|
||||
@ -11379,6 +11396,12 @@ Enum class for api provider schema type.
|
||||
| use_icon_as_answer_icon | boolean | | No |
|
||||
| workflow | [WorkflowPartial](#workflowpartial) | | No |
|
||||
|
||||
#### AppDslVersionResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| app_dsl_version | string | | Yes |
|
||||
|
||||
#### AppExportQuery
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -15250,7 +15273,6 @@ Default configuration for form inputs.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| app_dsl_version | string | | Yes |
|
||||
| branding | [BrandingModel](#brandingmodel) | | Yes |
|
||||
| enable_change_email | boolean | | Yes |
|
||||
| enable_collaboration_mode | boolean | | Yes |
|
||||
|
||||
@ -1323,7 +1323,6 @@ Returns Server-Sent Events stream.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| app_dsl_version | string | | Yes |
|
||||
| branding | [BrandingModel](#brandingmodel) | | Yes |
|
||||
| enable_change_email | boolean | | Yes |
|
||||
| enable_collaboration_mode | boolean | | Yes |
|
||||
|
||||
@ -160,7 +160,6 @@ class PluginManagerModel(FeatureResponseModel):
|
||||
|
||||
|
||||
class SystemFeatureModel(FeatureResponseModel):
|
||||
app_dsl_version: str = ""
|
||||
sso_enforced_for_signin: bool = False
|
||||
sso_enforced_for_signin_protocol: str = ""
|
||||
enable_marketplace: bool = False
|
||||
@ -248,7 +247,6 @@ class FeatureService:
|
||||
@classmethod
|
||||
def get_system_features(cls, is_authenticated: bool = False) -> SystemFeatureModel:
|
||||
system_features = SystemFeatureModel()
|
||||
system_features.app_dsl_version = CURRENT_APP_DSL_VERSION
|
||||
|
||||
cls._fulfill_system_params_from_env(system_features)
|
||||
|
||||
@ -267,6 +265,10 @@ class FeatureService:
|
||||
|
||||
return system_features
|
||||
|
||||
@classmethod
|
||||
def get_app_dsl_version(cls) -> str:
|
||||
return CURRENT_APP_DSL_VERSION
|
||||
|
||||
@classmethod
|
||||
def _fulfill_system_params_from_env(cls, system_features: SystemFeatureModel):
|
||||
system_features.enable_email_code_login = dify_config.ENABLE_EMAIL_CODE_LOGIN
|
||||
|
||||
@ -46,6 +46,21 @@ class TestFeatureVectorSpaceApi:
|
||||
get_vector_space.assert_called_once_with("tenant_123")
|
||||
|
||||
|
||||
class TestAppDslVersionApi:
|
||||
def test_get_app_dsl_version_success(self, mocker: MockerFixture):
|
||||
from controllers.console.feature import AppDslVersionApi
|
||||
|
||||
get_app_dsl_version = mocker.patch("controllers.console.feature.FeatureService.get_app_dsl_version")
|
||||
get_app_dsl_version.return_value = "0.6.0"
|
||||
|
||||
api = AppDslVersionApi()
|
||||
|
||||
result = api.get()
|
||||
|
||||
assert result == {"app_dsl_version": "0.6.0"}
|
||||
get_app_dsl_version.assert_called_once_with()
|
||||
|
||||
|
||||
class TestSystemFeatureApi:
|
||||
def test_get_system_features_authenticated(self, mocker: MockerFixture):
|
||||
"""
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
from constants.dsl_version import CURRENT_APP_DSL_VERSION
|
||||
from services.feature_service import FeatureService
|
||||
|
||||
|
||||
def test_get_system_features_excludes_app_dsl_version():
|
||||
result = FeatureService.get_system_features().model_dump()
|
||||
|
||||
assert "app_dsl_version" not in result
|
||||
|
||||
|
||||
def test_get_app_dsl_version_returns_current_version():
|
||||
result = FeatureService.get_app_dsl_version()
|
||||
|
||||
assert result == CURRENT_APP_DSL_VERSION
|
||||
@ -0,0 +1,30 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import { oc } from '@orpc/contract'
|
||||
|
||||
import { zGetAppDslVersionResponse } from './zod.gen'
|
||||
|
||||
/**
|
||||
* Get current app DSL version for workflow clipboard compatibility
|
||||
*
|
||||
* Get current app DSL version
|
||||
*/
|
||||
export const get = oc
|
||||
.route({
|
||||
description: 'Get current app DSL version',
|
||||
inputStructure: 'detailed',
|
||||
method: 'GET',
|
||||
operationId: 'getAppDslVersion',
|
||||
path: '/app-dsl-version',
|
||||
summary: 'Get current app DSL version for workflow clipboard compatibility',
|
||||
tags: ['console'],
|
||||
})
|
||||
.output(zGetAppDslVersionResponse)
|
||||
|
||||
export const appDslVersion = {
|
||||
get,
|
||||
}
|
||||
|
||||
export const contract = {
|
||||
appDslVersion,
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
export type ClientOptions = {
|
||||
baseUrl: `${string}://${string}/console/api` | (string & {})
|
||||
}
|
||||
|
||||
export type AppDslVersionResponse = {
|
||||
app_dsl_version: string
|
||||
}
|
||||
|
||||
export type GetAppDslVersionData = {
|
||||
body?: never
|
||||
path?: never
|
||||
query?: never
|
||||
url: '/app-dsl-version'
|
||||
}
|
||||
|
||||
export type GetAppDslVersionResponses = {
|
||||
200: AppDslVersionResponse
|
||||
}
|
||||
|
||||
export type GetAppDslVersionResponse = GetAppDslVersionResponses[keyof GetAppDslVersionResponses]
|
||||
@ -0,0 +1,15 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import * as z from 'zod'
|
||||
|
||||
/**
|
||||
* AppDslVersionResponse
|
||||
*/
|
||||
export const zAppDslVersionResponse = z.object({
|
||||
app_dsl_version: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zGetAppDslVersionResponse = zAppDslVersionResponse
|
||||
@ -6,6 +6,7 @@ import { agents } from './agents/orpc.gen'
|
||||
import { allWorkspaces } from './all-workspaces/orpc.gen'
|
||||
import { apiBasedExtension } from './api-based-extension/orpc.gen'
|
||||
import { apiKeyAuth } from './api-key-auth/orpc.gen'
|
||||
import { appDslVersion } from './app-dsl-version/orpc.gen'
|
||||
import { app } from './app/orpc.gen'
|
||||
import { apps } from './apps/orpc.gen'
|
||||
import { auth } from './auth/orpc.gen'
|
||||
@ -55,6 +56,7 @@ export const contract = {
|
||||
apiBasedExtension,
|
||||
apiKeyAuth,
|
||||
app,
|
||||
appDslVersion,
|
||||
apps,
|
||||
auth,
|
||||
billing,
|
||||
|
||||
@ -5,7 +5,6 @@ export type ClientOptions = {
|
||||
}
|
||||
|
||||
export type SystemFeatureModel = {
|
||||
app_dsl_version: string
|
||||
branding: BrandingModel
|
||||
enable_change_email: boolean
|
||||
enable_collaboration_mode: boolean
|
||||
|
||||
@ -87,7 +87,6 @@ export const zWebAppAuthModel = z.object({
|
||||
* SystemFeatureModel
|
||||
*/
|
||||
export const zSystemFeatureModel = z.object({
|
||||
app_dsl_version: z.string().default(''),
|
||||
branding: zBrandingModel,
|
||||
enable_change_email: z.boolean().default(true),
|
||||
enable_collaboration_mode: z.boolean().default(true),
|
||||
|
||||
@ -218,7 +218,6 @@ export type SuggestedQuestionsResponse = {
|
||||
}
|
||||
|
||||
export type SystemFeatureModel = {
|
||||
app_dsl_version: string
|
||||
branding: BrandingModel
|
||||
enable_change_email: boolean
|
||||
enable_collaboration_mode: boolean
|
||||
|
||||
@ -364,7 +364,6 @@ export const zWebAppAuthModel = z.object({
|
||||
* SystemFeatureModel
|
||||
*/
|
||||
export const zSystemFeatureModel = z.object({
|
||||
app_dsl_version: z.string().default(''),
|
||||
branding: zBrandingModel,
|
||||
enable_change_email: z.boolean().default(true),
|
||||
enable_collaboration_mode: z.boolean().default(true),
|
||||
|
||||
@ -12,6 +12,22 @@ type DeepPartial<T> = T extends Array<infer U>
|
||||
? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
: T
|
||||
|
||||
type QueryKeyProvider = {
|
||||
queryKey: () => readonly unknown[]
|
||||
}
|
||||
|
||||
type AppDslVersionQueryProvider = {
|
||||
get?: QueryKeyProvider
|
||||
}
|
||||
|
||||
const fallbackAppDslVersionQueryKey = ['console', 'appDslVersion', 'get'] as const
|
||||
|
||||
const getAppDslVersionQueryKey = () => {
|
||||
const appDslVersionQuery = (consoleQuery as { appDslVersion?: AppDslVersionQueryProvider }).appDslVersion
|
||||
|
||||
return appDslVersionQuery?.get?.queryKey() ?? fallbackAppDslVersionQueryKey
|
||||
}
|
||||
|
||||
const buildSystemFeatures = (
|
||||
overrides: DeepPartial<SystemFeatures> = {},
|
||||
): SystemFeatures => {
|
||||
@ -70,6 +86,13 @@ export const seedSystemFeatures = (
|
||||
return data
|
||||
}
|
||||
|
||||
export const seedAppDslVersion = (
|
||||
queryClient: QueryClient,
|
||||
appDslVersion = '0.6.0',
|
||||
) => {
|
||||
queryClient.setQueryData(getAppDslVersionQueryKey(), { app_dsl_version: appDslVersion })
|
||||
}
|
||||
|
||||
type SystemFeaturesTestOptions = {
|
||||
/**
|
||||
* Partial overrides for the systemFeatures payload. When omitted, the cache
|
||||
@ -78,6 +101,11 @@ type SystemFeaturesTestOptions = {
|
||||
* keep the systemFeatures query in the pending state.
|
||||
*/
|
||||
systemFeatures?: DeepPartial<SystemFeatures> | null
|
||||
/**
|
||||
* Seed the workflow clipboard DSL version query only for tests that need it.
|
||||
* Omit or pass `null` to leave it unseeded.
|
||||
*/
|
||||
appDslVersion?: string | null
|
||||
queryClient?: QueryClient
|
||||
}
|
||||
|
||||
@ -94,6 +122,8 @@ export const createSystemFeaturesWrapper = (
|
||||
const systemFeatures = options.systemFeatures === null
|
||||
? null
|
||||
: seedSystemFeatures(queryClient, options.systemFeatures)
|
||||
if (options.appDslVersion !== undefined && options.appDslVersion !== null)
|
||||
seedAppDslVersion(queryClient, options.appDslVersion)
|
||||
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
)
|
||||
@ -104,9 +134,10 @@ export const renderWithSystemFeatures = (
|
||||
ui: ReactElement,
|
||||
options: SystemFeaturesTestOptions & Omit<RenderOptions, 'wrapper'> = {},
|
||||
): RenderResult & { queryClient: QueryClient, systemFeatures: SystemFeatures | null } => {
|
||||
const { systemFeatures: sf, queryClient: qc, ...renderOptions } = options
|
||||
const { systemFeatures: sf, appDslVersion, queryClient: qc, ...renderOptions } = options
|
||||
const { wrapper, queryClient, systemFeatures } = createSystemFeaturesWrapper({
|
||||
systemFeatures: sf,
|
||||
appDslVersion,
|
||||
queryClient: qc,
|
||||
})
|
||||
const rendered = render(ui, { wrapper, ...renderOptions })
|
||||
@ -117,9 +148,10 @@ export const renderHookWithSystemFeatures = <Result, Props = void>(
|
||||
callback: (props: Props) => Result,
|
||||
options: SystemFeaturesTestOptions & Omit<RenderHookOptions<Props>, 'wrapper'> = {},
|
||||
): RenderHookResult<Result, Props> & { queryClient: QueryClient, systemFeatures: SystemFeatures | null } => {
|
||||
const { systemFeatures: sf, queryClient: qc, ...hookOptions } = options
|
||||
const { systemFeatures: sf, appDslVersion, queryClient: qc, ...hookOptions } = options
|
||||
const { wrapper, queryClient, systemFeatures } = createSystemFeaturesWrapper({
|
||||
systemFeatures: sf,
|
||||
appDslVersion,
|
||||
queryClient: qc,
|
||||
})
|
||||
const rendered = renderHook(callback, { wrapper, ...hookOptions })
|
||||
|
||||
@ -69,7 +69,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, renderHook } from '@testing-library/react'
|
||||
import * as React from 'react'
|
||||
import ReactFlow, { ReactFlowProvider } from 'reactflow'
|
||||
import { seedSystemFeatures } from '@/__tests__/utils/mock-system-features'
|
||||
import { seedAppDslVersion, seedSystemFeatures } from '@/__tests__/utils/mock-system-features'
|
||||
import { WorkflowContext } from '../context'
|
||||
import { HooksStoreContext } from '../hooks-store/provider'
|
||||
import { createHooksStore } from '../hooks-store/store'
|
||||
@ -168,6 +168,8 @@ function createWorkflowWrapper(
|
||||
})
|
||||
if (!externalQueryClient)
|
||||
seedSystemFeatures(queryClient)
|
||||
if (!externalQueryClient)
|
||||
seedAppDslVersion(queryClient)
|
||||
|
||||
return ({ children }: { children: React.ReactNode }) => {
|
||||
let inner: React.ReactNode = children
|
||||
|
||||
@ -14,7 +14,7 @@ import type { VariableAssignerNodeType } from '../nodes/variable-assigner/types'
|
||||
import type { Edge, Node, OnNodeAdd } from '../types'
|
||||
import type { RAGPipelineVariables } from '@/models/pipeline'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { produce } from 'immer'
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -23,7 +23,7 @@ import {
|
||||
getOutgoers,
|
||||
useReactFlow,
|
||||
} from 'reactflow'
|
||||
import { systemFeaturesQueryOptions } from '@/service/system-features'
|
||||
import { consoleQuery } from '@/service/client'
|
||||
import { collaborationManager } from '../collaboration/core/collaboration-manager'
|
||||
import {
|
||||
CUSTOM_EDGE,
|
||||
@ -145,10 +145,10 @@ const isNoteLinkClickTarget = (target: EventTarget | null, node: Node) => {
|
||||
|
||||
export const useNodesInteractions = () => {
|
||||
const { t } = useTranslation()
|
||||
const { data: appDslVersion } = useSuspenseQuery({
|
||||
...systemFeaturesQueryOptions(),
|
||||
select: s => s.app_dsl_version,
|
||||
})
|
||||
const { data: appDslVersion = '' } = useQuery(consoleQuery.appDslVersion.get.queryOptions({
|
||||
staleTime: Infinity,
|
||||
select: data => data.app_dsl_version,
|
||||
}))
|
||||
const collaborativeWorkflow = useCollaborativeWorkflow()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const reactflow = useReactFlow()
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import type { MouseEvent } from 'react'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useCallback } from 'react'
|
||||
import { systemFeaturesQueryOptions } from '@/service/system-features'
|
||||
import { consoleQuery } from '@/service/client'
|
||||
import { useWorkflowStore } from '../store'
|
||||
import { readWorkflowClipboard } from '../utils'
|
||||
|
||||
export const usePanelInteractions = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const { data: appDslVersion } = useSuspenseQuery({
|
||||
...systemFeaturesQueryOptions(),
|
||||
select: s => s.app_dsl_version,
|
||||
})
|
||||
const { data: appDslVersion = '' } = useQuery(consoleQuery.appDslVersion.get.queryOptions({
|
||||
staleTime: Infinity,
|
||||
select: data => data.app_dsl_version,
|
||||
}))
|
||||
|
||||
const handlePaneContextMenu = useCallback((e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
@ -28,7 +28,6 @@ type License = {
|
||||
}
|
||||
|
||||
export type SystemFeatures = {
|
||||
app_dsl_version: string
|
||||
trial_models: ModelProviderQuotaGetPaid[]
|
||||
plugin_installation_permission: {
|
||||
plugin_installation_scope: InstallationScope
|
||||
@ -70,7 +69,6 @@ export type SystemFeatures = {
|
||||
}
|
||||
|
||||
export const defaultSystemFeatures: SystemFeatures = {
|
||||
app_dsl_version: '',
|
||||
trial_models: [],
|
||||
plugin_installation_permission: {
|
||||
plugin_installation_scope: InstallationScope.ALL,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user