diff --git a/api/controllers/console/feature.py b/api/controllers/console/feature.py index ae4b457fa5..b221db697b 100644 --- a/api/controllers/console/feature.py +++ b/api/controllers/console/feature.py @@ -16,11 +16,22 @@ from . import console_ns from .wraps import account_initialization_required, cloud_utm_record, setup_required, with_current_tenant_id +class TrialModelsResponse(ResponseModel): + trial_models: list[str] + + class AppDslVersionResponse(ResponseModel): app_dsl_version: str -register_response_schema_models(console_ns, AppDslVersionResponse, FeatureModel, LimitationModel, SystemFeatureModel) +register_response_schema_models( + console_ns, + AppDslVersionResponse, + FeatureModel, + LimitationModel, + SystemFeatureModel, + TrialModelsResponse, +) @console_ns.route("/features") @@ -66,6 +77,26 @@ class FeatureVectorSpaceApi(Resource): return FeatureService.get_vector_space(current_tenant_id).model_dump() +@console_ns.route("/trial-models") +class TrialModelsApi(Resource): + @console_ns.doc("get_trial_models") + @console_ns.doc(description="Get hosted trial model provider configuration") + @console_ns.response( + 200, + "Success", + console_ns.models[TrialModelsResponse.__name__], + ) + @setup_required + @login_required + @account_initialization_required + def get(self): + """Get hosted trial model provider configuration for model-provider pages.""" + return dump_response( + TrialModelsResponse, + {"trial_models": FeatureService.get_trial_models()}, + ) + + @console_ns.route("/app-dsl-version") class AppDslVersionApi(Resource): @console_ns.doc("get_app_dsl_version") diff --git a/api/openapi/markdown/console-swagger.md b/api/openapi/markdown/console-swagger.md index 1ce3ac3d1a..b76172e996 100644 --- a/api/openapi/markdown/console-swagger.md +++ b/api/openapi/markdown/console-swagger.md @@ -8258,6 +8258,23 @@ Stop workflow task | ---- | ----------- | | 200 | Success | +### /trial-models + +#### GET +##### Summary + +Get hosted trial model provider configuration for model-provider pages + +##### Description + +Get hosted trial model provider configuration + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [TrialModelsResponse](#trialmodelsresponse) | + ### /website/crawl #### POST @@ -15292,7 +15309,6 @@ Default configuration for form inputs. | plugin_manager | [PluginManagerModel](#pluginmanagermodel) | | Yes | | sso_enforced_for_signin | boolean | | Yes | | sso_enforced_for_signin_protocol | string | | Yes | -| trial_models | [ string ] | | Yes | | webapp_auth | [WebAppAuthModel](#webappauthmodel) | | Yes | #### Tag @@ -15519,6 +15535,12 @@ Tag type | tool_name | string | | No | | type | string | | No | +#### TrialModelsResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| trial_models | [ string ] | | Yes | + #### TrialPipelineVariable | Name | Type | Description | Required | diff --git a/api/openapi/markdown/web-swagger.md b/api/openapi/markdown/web-swagger.md index 34d245e09a..a7585d5b14 100644 --- a/api/openapi/markdown/web-swagger.md +++ b/api/openapi/markdown/web-swagger.md @@ -1342,7 +1342,6 @@ Returns Server-Sent Events stream. | plugin_manager | [PluginManagerModel](#pluginmanagermodel) | | Yes | | sso_enforced_for_signin | boolean | | Yes | | sso_enforced_for_signin_protocol | string | | Yes | -| trial_models | [ string ] | | Yes | | webapp_auth | [WebAppAuthModel](#webappauthmodel) | | Yes | #### TextToAudioPayload diff --git a/api/services/feature_service.py b/api/services/feature_service.py index 4486e5f94a..4d460c288a 100644 --- a/api/services/feature_service.py +++ b/api/services/feature_service.py @@ -177,7 +177,6 @@ class SystemFeatureModel(FeatureResponseModel): plugin_installation_permission: PluginInstallationPermissionModel = PluginInstallationPermissionModel() enable_change_email: bool = True plugin_manager: PluginManagerModel = PluginManagerModel() - trial_models: list[str] = [] enable_creators_platform: bool = False enable_trial_app: bool = False enable_explore_banner: bool = False @@ -278,7 +277,6 @@ class FeatureService: system_features.is_allow_register = dify_config.ALLOW_REGISTER system_features.is_allow_create_workspace = dify_config.ALLOW_CREATE_WORKSPACE system_features.is_email_setup = dify_config.MAIL_TYPE is not None and dify_config.MAIL_TYPE != "" - system_features.trial_models = cls._fulfill_trial_models_from_env() system_features.enable_trial_app = dify_config.ENABLE_TRIAL_APP system_features.enable_explore_banner = dify_config.ENABLE_EXPLORE_BANNER @@ -293,6 +291,11 @@ class FeatureService: ) ] + @classmethod + def get_trial_models(cls) -> list[str]: + """Return hosted trial provider ids without requiring the full system-features payload.""" + return cls._fulfill_trial_models_from_env() + @classmethod def _fulfill_params_from_env(cls, features: FeatureModel): features.can_replace_logo = dify_config.CAN_REPLACE_LOGO diff --git a/api/tests/unit_tests/controllers/console/test_feature.py b/api/tests/unit_tests/controllers/console/test_feature.py index 9d314920fb..d92454d6d8 100644 --- a/api/tests/unit_tests/controllers/console/test_feature.py +++ b/api/tests/unit_tests/controllers/console/test_feature.py @@ -46,6 +46,22 @@ class TestFeatureVectorSpaceApi: get_vector_space.assert_called_once_with("tenant_123") +class TestTrialModelsApi: + def test_get_trial_models_success(self, mocker: MockerFixture): + from controllers.console.feature import TrialModelsApi + + get_trial_models = mocker.patch("controllers.console.feature.FeatureService.get_trial_models") + get_trial_models.return_value = ["langgenius/openai/openai"] + + api = TrialModelsApi() + + raw_get = unwrap(TrialModelsApi.get) + result = raw_get(api) + + assert result == {"trial_models": ["langgenius/openai/openai"]} + get_trial_models.assert_called_once_with() + + class TestAppDslVersionApi: def test_get_app_dsl_version_success(self, mocker: MockerFixture): from controllers.console.feature import AppDslVersionApi diff --git a/api/tests/unit_tests/services/test_feature_service_trial_models.py b/api/tests/unit_tests/services/test_feature_service_trial_models.py new file mode 100644 index 0000000000..eac3d6235a --- /dev/null +++ b/api/tests/unit_tests/services/test_feature_service_trial_models.py @@ -0,0 +1,38 @@ +import pytest + +from enums.hosted_provider import HostedTrialProvider +from services import feature_service as feature_service_module +from services.feature_service import FeatureService + + +def test_get_system_features_excludes_trial_models(): + result = FeatureService.get_system_features().model_dump() + + assert "trial_models" not in result + + +def test_get_trial_models_returns_providers_enabled_for_paid_and_trial(monkeypatch: pytest.MonkeyPatch): + for provider in HostedTrialProvider: + monkeypatch.setattr( + feature_service_module.dify_config, + f"HOSTED_{provider.config_key}_PAID_ENABLED", + False, + raising=False, + ) + monkeypatch.setattr( + feature_service_module.dify_config, + f"HOSTED_{provider.config_key}_TRIAL_ENABLED", + False, + raising=False, + ) + + monkeypatch.setattr(feature_service_module.dify_config, "HOSTED_OPENAI_PAID_ENABLED", True, raising=False) + monkeypatch.setattr(feature_service_module.dify_config, "HOSTED_OPENAI_TRIAL_ENABLED", True, raising=False) + monkeypatch.setattr(feature_service_module.dify_config, "HOSTED_ANTHROPIC_PAID_ENABLED", True, raising=False) + monkeypatch.setattr(feature_service_module.dify_config, "HOSTED_ANTHROPIC_TRIAL_ENABLED", False, raising=False) + monkeypatch.setattr(feature_service_module.dify_config, "HOSTED_GEMINI_PAID_ENABLED", False, raising=False) + monkeypatch.setattr(feature_service_module.dify_config, "HOSTED_GEMINI_TRIAL_ENABLED", True, raising=False) + + result = FeatureService.get_trial_models() + + assert result == [HostedTrialProvider.OPENAI.value] diff --git a/eslint-suppressions.json b/eslint-suppressions.json index f495b77387..65c13dcb14 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -5537,11 +5537,6 @@ "count": 1 } }, - "web/types/feature.ts": { - "erasable-syntax-only/enums": { - "count": 3 - } - }, "web/types/lamejs.d.ts": { "ts/no-explicit-any": { "count": 3 diff --git a/packages/contracts/generated/api/console/orpc.gen.ts b/packages/contracts/generated/api/console/orpc.gen.ts index 18317a65f9..63a1e9185e 100644 --- a/packages/contracts/generated/api/console/orpc.gen.ts +++ b/packages/contracts/generated/api/console/orpc.gen.ts @@ -44,6 +44,7 @@ import { tagBindings } from './tag-bindings/orpc.gen' import { tags } from './tags/orpc.gen' import { test } from './test/orpc.gen' import { trialApps } from './trial-apps/orpc.gen' +import { trialModels } from './trial-models/orpc.gen' import { website } from './website/orpc.gen' import { workflow } from './workflow/orpc.gen' import { workspaces } from './workspaces/orpc.gen' @@ -93,6 +94,7 @@ export const contract = { tags, test, trialApps, + trialModels, website, workflow, workspaces, diff --git a/packages/contracts/generated/api/console/system-features/types.gen.ts b/packages/contracts/generated/api/console/system-features/types.gen.ts index ec917bf12f..4f2ef2fa94 100644 --- a/packages/contracts/generated/api/console/system-features/types.gen.ts +++ b/packages/contracts/generated/api/console/system-features/types.gen.ts @@ -24,7 +24,6 @@ export type SystemFeatureModel = { plugin_manager: PluginManagerModel sso_enforced_for_signin: boolean sso_enforced_for_signin_protocol: string - trial_models: Array webapp_auth: WebAppAuthModel } diff --git a/packages/contracts/generated/api/console/system-features/zod.gen.ts b/packages/contracts/generated/api/console/system-features/zod.gen.ts index 10e09e6b8e..bbd0882118 100644 --- a/packages/contracts/generated/api/console/system-features/zod.gen.ts +++ b/packages/contracts/generated/api/console/system-features/zod.gen.ts @@ -106,7 +106,6 @@ export const zSystemFeatureModel = z.object({ plugin_manager: zPluginManagerModel, sso_enforced_for_signin: z.boolean().default(false), sso_enforced_for_signin_protocol: z.string().default(''), - trial_models: z.array(z.string()).default([]), webapp_auth: zWebAppAuthModel, }) diff --git a/packages/contracts/generated/api/console/trial-models/orpc.gen.ts b/packages/contracts/generated/api/console/trial-models/orpc.gen.ts new file mode 100644 index 0000000000..f4f4af9a3b --- /dev/null +++ b/packages/contracts/generated/api/console/trial-models/orpc.gen.ts @@ -0,0 +1,30 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { oc } from '@orpc/contract' + +import { zGetTrialModelsResponse } from './zod.gen' + +/** + * Get hosted trial model provider configuration for model-provider pages + * + * Get hosted trial model provider configuration + */ +export const get = oc + .route({ + description: 'Get hosted trial model provider configuration', + inputStructure: 'detailed', + method: 'GET', + operationId: 'getTrialModels', + path: '/trial-models', + summary: 'Get hosted trial model provider configuration for model-provider pages', + tags: ['console'], + }) + .output(zGetTrialModelsResponse) + +export const trialModels = { + get, +} + +export const contract = { + trialModels, +} diff --git a/packages/contracts/generated/api/console/trial-models/types.gen.ts b/packages/contracts/generated/api/console/trial-models/types.gen.ts new file mode 100644 index 0000000000..48bc158066 --- /dev/null +++ b/packages/contracts/generated/api/console/trial-models/types.gen.ts @@ -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 TrialModelsResponse = { + trial_models: Array +} + +export type GetTrialModelsData = { + body?: never + path?: never + query?: never + url: '/trial-models' +} + +export type GetTrialModelsResponses = { + 200: TrialModelsResponse +} + +export type GetTrialModelsResponse = GetTrialModelsResponses[keyof GetTrialModelsResponses] diff --git a/packages/contracts/generated/api/console/trial-models/zod.gen.ts b/packages/contracts/generated/api/console/trial-models/zod.gen.ts new file mode 100644 index 0000000000..2956edc3de --- /dev/null +++ b/packages/contracts/generated/api/console/trial-models/zod.gen.ts @@ -0,0 +1,15 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import * as z from 'zod' + +/** + * TrialModelsResponse + */ +export const zTrialModelsResponse = z.object({ + trial_models: z.array(z.string()), +}) + +/** + * Success + */ +export const zGetTrialModelsResponse = zTrialModelsResponse diff --git a/packages/contracts/generated/api/web/types.gen.ts b/packages/contracts/generated/api/web/types.gen.ts index 56f8164e91..cc18ffaf59 100644 --- a/packages/contracts/generated/api/web/types.gen.ts +++ b/packages/contracts/generated/api/web/types.gen.ts @@ -237,7 +237,6 @@ export type SystemFeatureModel = { plugin_manager: PluginManagerModel sso_enforced_for_signin: boolean sso_enforced_for_signin_protocol: string - trial_models: Array webapp_auth: WebAppAuthModel } diff --git a/packages/contracts/generated/api/web/zod.gen.ts b/packages/contracts/generated/api/web/zod.gen.ts index 9ca727267d..9f11a0eaeb 100644 --- a/packages/contracts/generated/api/web/zod.gen.ts +++ b/packages/contracts/generated/api/web/zod.gen.ts @@ -383,7 +383,6 @@ export const zSystemFeatureModel = z.object({ plugin_manager: zPluginManagerModel, sso_enforced_for_signin: z.boolean().default(false), sso_enforced_for_signin_protocol: z.string().default(''), - trial_models: z.array(z.string()).default([]), webapp_auth: zWebAppAuthModel, }) diff --git a/web/__tests__/utils/mock-system-features.tsx b/web/__tests__/utils/mock-system-features.tsx index ed4daedd29..e2e65db8d5 100644 --- a/web/__tests__/utils/mock-system-features.tsx +++ b/web/__tests__/utils/mock-system-features.tsx @@ -6,28 +6,39 @@ import { render, renderHook } from '@testing-library/react' import { consoleQuery } from '@/service/client' import { defaultSystemFeatures } from '@/types/feature' -type DeepPartial = T extends Array - ? Array - : T extends object - ? { [K in keyof T]?: DeepPartial } - : T - type QueryKeyProvider = { queryKey: () => readonly unknown[] } +type TrialModelsQueryProvider = { + get?: QueryKeyProvider +} + type AppDslVersionQueryProvider = { get?: QueryKeyProvider } +const fallbackTrialModelsQueryKey = ['console', 'trialModels', 'get'] as const const fallbackAppDslVersionQueryKey = ['console', 'appDslVersion', 'get'] as const +const getTrialModelsQueryKey = () => { + const trialModelsQuery = (consoleQuery as { trialModels?: TrialModelsQueryProvider }).trialModels + + return trialModelsQuery?.get?.queryKey() ?? fallbackTrialModelsQueryKey +} + const getAppDslVersionQueryKey = () => { const appDslVersionQuery = (consoleQuery as { appDslVersion?: AppDslVersionQueryProvider }).appDslVersion return appDslVersionQuery?.get?.queryKey() ?? fallbackAppDslVersionQueryKey } +type DeepPartial = T extends Array + ? Array + : T extends object + ? { [K in keyof T]?: DeepPartial } + : T + const buildSystemFeatures = ( overrides: DeepPartial = {}, ): SystemFeatures => { @@ -86,6 +97,13 @@ export const seedSystemFeatures = ( return data } +const seedTrialModels = ( + queryClient: QueryClient, + trialModels: readonly string[] = [], +) => { + queryClient.setQueryData(getTrialModelsQueryKey(), { trial_models: [...trialModels] }) +} + export const seedAppDslVersion = ( queryClient: QueryClient, appDslVersion = '0.6.0', @@ -101,6 +119,7 @@ type SystemFeaturesTestOptions = { * keep the systemFeatures query in the pending state. */ systemFeatures?: DeepPartial | null + trialModels?: readonly string[] | null /** * Seed the workflow clipboard DSL version query only for tests that need it. * Omit or pass `null` to leave it unseeded. @@ -122,6 +141,8 @@ export const createSystemFeaturesWrapper = ( const systemFeatures = options.systemFeatures === null ? null : seedSystemFeatures(queryClient, options.systemFeatures) + if (options.trialModels !== undefined && options.trialModels !== null) + seedTrialModels(queryClient, options.trialModels) if (options.appDslVersion !== undefined && options.appDslVersion !== null) seedAppDslVersion(queryClient, options.appDslVersion) const wrapper = ({ children }: { children: ReactNode }) => ( @@ -134,9 +155,10 @@ export const renderWithSystemFeatures = ( ui: ReactElement, options: SystemFeaturesTestOptions & Omit = {}, ): RenderResult & { queryClient: QueryClient, systemFeatures: SystemFeatures | null } => { - const { systemFeatures: sf, appDslVersion, queryClient: qc, ...renderOptions } = options + const { systemFeatures: sf, trialModels, appDslVersion, queryClient: qc, ...renderOptions } = options const { wrapper, queryClient, systemFeatures } = createSystemFeaturesWrapper({ systemFeatures: sf, + trialModels, appDslVersion, queryClient: qc, }) @@ -148,9 +170,10 @@ export const renderHookWithSystemFeatures = ( callback: (props: Props) => Result, options: SystemFeaturesTestOptions & Omit, 'wrapper'> = {}, ): RenderHookResult & { queryClient: QueryClient, systemFeatures: SystemFeatures | null } => { - const { systemFeatures: sf, appDslVersion, queryClient: qc, ...hookOptions } = options + const { systemFeatures: sf, trialModels, appDslVersion, queryClient: qc, ...hookOptions } = options const { wrapper, queryClient, systemFeatures } = createSystemFeaturesWrapper({ systemFeatures: sf, + trialModels, appDslVersion, queryClient: qc, }) diff --git a/web/app/components/header/account-setting/model-provider-page/model-selector/__tests__/popup.spec.tsx b/web/app/components/header/account-setting/model-provider-page/model-selector/__tests__/popup.spec.tsx index a4166c1b74..45218923d8 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-selector/__tests__/popup.spec.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-selector/__tests__/popup.spec.tsx @@ -1,7 +1,6 @@ import type { ReactElement } from 'react' import type { Model, ModelItem, ModelProvider } from '../../declarations' import type { PopupProps } from '../popup' -import type { SystemFeatures } from '@/types/feature' import { Combobox } from '@langgenius/dify-ui/combobox' import { fireEvent, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' @@ -105,7 +104,7 @@ function PopupHarness(props: PopupTestProps) { } const renderPopup = (ui: ReactElement) => renderWithSystemFeatures(ui, { - systemFeatures: { trial_models: mockTrialModels.current as unknown as SystemFeatures['trial_models'] }, + trialModels: mockTrialModels.current, }) const mockTrialCredits = vi.hoisted(() => ({ diff --git a/web/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx b/web/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx index 16153a199b..7b5854d363 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx @@ -3,17 +3,18 @@ import type { ModelSelectorPreviewPayload } from './popup-item' import type { ModelProviderQuotaGetPaid } from '@/types/model-provider' import { ComboboxList } from '@langgenius/dify-ui/combobox' import { createPreviewCardHandle, PreviewCard, PreviewCardContent } from '@langgenius/dify-ui/preview-card' -import { useSuspenseQuery } from '@tanstack/react-query' +import { useQuery } from '@tanstack/react-query' import { useTheme } from 'next-themes' import { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { ACCOUNT_SETTING_MODAL_ACTION, ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants' import checkTaskStatus from '@/app/components/plugins/install-plugin/base/check-task-status' import useRefreshPluginList from '@/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list' +import { IS_CLOUD_EDITION } from '@/config' import { useModalContext } from '@/context/modal-context' import { useProviderContext } from '@/context/provider-context' import { useSearchParams } from '@/next/navigation' -import { systemFeaturesQueryOptions } from '@/service/system-features' +import { consoleQuery } from '@/service/client' import { useInstallPackageFromMarketPlace } from '@/service/use-plugins' import { CustomConfigurationStatusEnum, ModelFeatureEnum, ModelStatusEnum, ModelTypeEnum } from '../declarations' import { useLanguage, useMarketplaceAllPlugins } from '../hooks' @@ -62,8 +63,10 @@ function Popup({ const { refreshPluginList } = useRefreshPluginList() const [installingProvider, setInstallingProvider] = useState(null) const { isExhausted: isCreditsExhausted } = useTrialCredits() - const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions()) - const trialModels = systemFeatures.trial_models + const { data: trialModels = [] } = useQuery(consoleQuery.trialModels.get.queryOptions({ + enabled: IS_CLOUD_EDITION, + select: data => data.trial_models, + })) const installedProviderMap = useMemo(() => new Map( modelProviders.map(provider => [provider.provider, provider]), ), [modelProviders]) diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/credential-panel.spec.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/credential-panel.spec.tsx index 257b0128ab..0cd7291c8d 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/credential-panel.spec.tsx +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/credential-panel.spec.tsx @@ -111,7 +111,7 @@ const createProvider = (overrides: Partial = {}): ModelProvider = const renderWithQueryClient = (provider: ModelProvider) => { return renderWithSystemFeatures(, { - systemFeatures: { trial_models: ['langgenius/openai/openai'] as never }, + trialModels: ['langgenius/openai/openai'], }) } diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/quota-panel.spec.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/quota-panel.spec.tsx index ed7f0e72d0..01627533a2 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/quota-panel.spec.tsx +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/quota-panel.spec.tsx @@ -47,7 +47,7 @@ vi.mock('../use-trial-credits', () => ({ })) const renderQuotaPanel = (ui: ReactElement) => renderWithSystemFeatures(ui, { - systemFeatures: mockTrialModels === undefined ? null : { trial_models: mockTrialModels as never }, + trialModels: mockTrialModels ?? [], }) vi.mock('../../hooks', () => ({ diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/use-credential-panel-state.spec.ts b/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/use-credential-panel-state.spec.ts index 2052c1eb8d..90be589b36 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/use-credential-panel-state.spec.ts +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/use-credential-panel-state.spec.ts @@ -22,7 +22,7 @@ vi.mock('@/config', async (importOriginal) => { const renderPanelHook = (provider: ModelProvider | undefined) => renderHookWithSystemFeatures(() => useCredentialPanelState(provider), { - systemFeatures: { trial_models: mockTrialModels as never }, + trialModels: mockTrialModels, }) const createProvider = (overrides: Partial = {}): ModelProvider => ({ diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx index 3b72f66429..0b8b928636 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx @@ -4,7 +4,7 @@ import type { Plugin } from '@/app/components/plugins/types' import type { ModelProviderQuotaGetPaid } from '@/types/model-provider' import { cn } from '@langgenius/dify-ui/cn' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' -import { useSuspenseQuery } from '@tanstack/react-query' +import { useQuery } from '@tanstack/react-query' import { useBoolean } from 'ahooks' import * as React from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' @@ -12,8 +12,9 @@ import { useTranslation } from 'react-i18next' import { Infotip } from '@/app/components/base/infotip' import Loading from '@/app/components/base/loading' import InstallFromMarketplace from '@/app/components/plugins/install-plugin/install-from-marketplace' +import { IS_CLOUD_EDITION } from '@/config' import useTimestamp from '@/hooks/use-timestamp' -import { systemFeaturesQueryOptions } from '@/service/system-features' +import { consoleQuery } from '@/service/client' import { formatNumber } from '@/utils/format' import { PreferredProviderTypeEnum } from '../declarations' import { useMarketplaceAllPlugins } from '../hooks' @@ -34,8 +35,10 @@ const QuotaPanel: FC = ({ }) => { const { t } = useTranslation() const { credits, isExhausted, isLoading, nextCreditResetDate } = useTrialCredits() - const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions()) - const trialModels = systemFeatures.trial_models + const { data: trialModels = [] } = useQuery(consoleQuery.trialModels.get.queryOptions({ + enabled: IS_CLOUD_EDITION, + select: data => data.trial_models, + })) const providerMap = useMemo(() => new Map( providers.map(p => [p.provider, p.preferred_provider_type]), ), [providers]) diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/use-credential-panel-state.ts b/web/app/components/header/account-setting/model-provider-page/provider-added-card/use-credential-panel-state.ts index e8a5f0f8a5..63c2d54b13 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/use-credential-panel-state.ts +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/use-credential-panel-state.ts @@ -1,7 +1,8 @@ import type { ModelProvider } from '../declarations' -import { useSuspenseQuery } from '@tanstack/react-query' +import { useQuery } from '@tanstack/react-query' import { useCredentialStatus } from '@/app/components/header/account-setting/model-provider-page/model-auth/hooks' -import { systemFeaturesQueryOptions } from '@/service/system-features' +import { IS_CLOUD_EDITION } from '@/config' +import { consoleQuery } from '@/service/client' import { PreferredProviderTypeEnum, } from '../declarations' @@ -80,8 +81,10 @@ export function useCredentialPanelState(provider: ModelProvider | undefined): Cr current_credential_name, } = useCredentialStatus(provider) - const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions()) - const trialModels = systemFeatures.trial_models + const { data: trialModels = [] } = useQuery(consoleQuery.trialModels.get.queryOptions({ + enabled: IS_CLOUD_EDITION, + select: data => data.trial_models, + })) const preferredType = provider?.preferred_provider_type diff --git a/web/types/feature.ts b/web/types/feature.ts index 8e5ae417c7..cc9b870d69 100644 --- a/web/types/feature.ts +++ b/web/types/feature.ts @@ -1,26 +1,30 @@ -import type { ModelProviderQuotaGetPaid } from './model-provider' +export const SSOProtocol = { + SAML: 'saml', + OIDC: 'oidc', + OAuth2: 'oauth2', +} as const -export enum SSOProtocol { - SAML = 'saml', - OIDC = 'oidc', - OAuth2 = 'oauth2', -} +export type SSOProtocol = typeof SSOProtocol[keyof typeof SSOProtocol] -export enum LicenseStatus { - NONE = 'none', - INACTIVE = 'inactive', - ACTIVE = 'active', - EXPIRING = 'expiring', - EXPIRED = 'expired', - LOST = 'lost', -} +export const LicenseStatus = { + NONE: 'none', + INACTIVE: 'inactive', + ACTIVE: 'active', + EXPIRING: 'expiring', + EXPIRED: 'expired', + LOST: 'lost', +} as const -export enum InstallationScope { - ALL = 'all', - NONE = 'none', - OFFICIAL_ONLY = 'official_only', - OFFICIAL_AND_PARTNER = 'official_and_specific_partners', -} +export type LicenseStatus = typeof LicenseStatus[keyof typeof LicenseStatus] + +export const InstallationScope = { + ALL: 'all', + NONE: 'none', + OFFICIAL_ONLY: 'official_only', + OFFICIAL_AND_PARTNER: 'official_and_specific_partners', +} as const + +export type InstallationScope = typeof InstallationScope[keyof typeof InstallationScope] type License = { status: LicenseStatus @@ -28,7 +32,6 @@ type License = { } export type SystemFeatures = { - trial_models: ModelProviderQuotaGetPaid[] plugin_installation_permission: { plugin_installation_scope: InstallationScope restrict_to_marketplace_only: boolean @@ -69,7 +72,6 @@ export type SystemFeatures = { } export const defaultSystemFeatures: SystemFeatures = { - trial_models: [], plugin_installation_permission: { plugin_installation_scope: InstallationScope.ALL, restrict_to_marketplace_only: false,