diff --git a/api/controllers/console/explore/recommended_app.py b/api/controllers/console/explore/recommended_app.py index 5821b914890acf..4e91a870616a30 100644 --- a/api/controllers/console/explore/recommended_app.py +++ b/api/controllers/console/explore/recommended_app.py @@ -64,15 +64,28 @@ class RecommendedAppListResponse(ResponseModel): categories: list[str] +class LearnDifyAppListResponse(ResponseModel): + recommended_apps: list[RecommendedAppResponse] + + register_schema_models( console_ns, RecommendedAppsQuery, RecommendedAppInfoResponse, RecommendedAppResponse, RecommendedAppListResponse, + LearnDifyAppListResponse, ) +def _resolve_language(language: str | None) -> str: + if language and language in languages: + return language + if current_user and current_user.interface_language: + return current_user.interface_language + return languages[0] + + @console_ns.route("/explore/apps") class RecommendedAppListApi(Resource): @console_ns.doc(params=query_params_from_model(RecommendedAppsQuery)) @@ -82,13 +95,7 @@ class RecommendedAppListApi(Resource): def get(self): # language args args = RecommendedAppsQuery.model_validate(request.args.to_dict(flat=True)) - language = args.language - if language and language in languages: - language_prefix = language - elif current_user and current_user.interface_language: - language_prefix = current_user.interface_language - else: - language_prefix = languages[0] + language_prefix = _resolve_language(args.language) return RecommendedAppListResponse.model_validate( RecommendedAppService.get_recommended_apps_and_categories(language_prefix), @@ -96,6 +103,22 @@ def get(self): ).model_dump(mode="json") +@console_ns.route("/explore/apps/learn-dify") +class LearnDifyAppListApi(Resource): + @console_ns.doc(params=query_params_from_model(RecommendedAppsQuery)) + @console_ns.response(200, "Success", console_ns.models[LearnDifyAppListResponse.__name__]) + @login_required + @account_initialization_required + def get(self): + args = RecommendedAppsQuery.model_validate(request.args.to_dict(flat=True)) + language_prefix = _resolve_language(args.language) + + return LearnDifyAppListResponse.model_validate( + RecommendedAppService.get_learn_dify_apps(language_prefix), + from_attributes=True, + ).model_dump(mode="json") + + @console_ns.route("/explore/apps/") class RecommendedAppApi(Resource): @login_required diff --git a/api/migrations/versions/2026_05_18_1500-f5e8a9c0d2b3_add_learn_dify_flag_to_recommended_apps.py b/api/migrations/versions/2026_05_18_1500-f5e8a9c0d2b3_add_learn_dify_flag_to_recommended_apps.py new file mode 100644 index 00000000000000..a1efc8fe8fce8f --- /dev/null +++ b/api/migrations/versions/2026_05_18_1500-f5e8a9c0d2b3_add_learn_dify_flag_to_recommended_apps.py @@ -0,0 +1,26 @@ +"""add learn dify flag to recommended apps + +Revision ID: f5e8a9c0d2b3 +Revises: a4f2d8c9b731 +Create Date: 2026-05-18 15:00:00.000000 + +""" + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = "f5e8a9c0d2b3" +down_revision = "a4f2d8c9b731" +branch_labels = None +depends_on = None + + +def upgrade(): + with op.batch_alter_table("recommended_apps", schema=None) as batch_op: + batch_op.add_column(sa.Column("is_learn_dify", sa.Boolean(), server_default=sa.text("false"), nullable=False)) + + +def downgrade(): + with op.batch_alter_table("recommended_apps", schema=None) as batch_op: + batch_op.drop_column("is_learn_dify") diff --git a/api/models/model.py b/api/models/model.py index f7f90465cf61fa..1327b2fbb93209 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -882,6 +882,9 @@ class RecommendedApp(TypeBase): custom_disclaimer: Mapped[str] = mapped_column(LongText, default="") position: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=0) is_listed: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=True) + is_learn_dify: Mapped[bool] = mapped_column( + sa.Boolean, nullable=False, server_default=sa.text("false"), default=False + ) install_count: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=0) language: Mapped[str] = mapped_column( String(255), diff --git a/api/openapi/markdown/console-swagger.md b/api/openapi/markdown/console-swagger.md index dc055c58239d91..0c38b3c298d858 100644 --- a/api/openapi/markdown/console-swagger.md +++ b/api/openapi/markdown/console-swagger.md @@ -5400,6 +5400,21 @@ Delete an API key for a dataset | ---- | ----------- | ------ | | 200 | Success | [RecommendedAppListResponse](#recommendedapplistresponse) | +### /explore/apps/learn-dify + +#### GET +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| language | query | Language code for recommended app localization | No | string | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [LearnDifyAppListResponse](#learndifyapplistresponse) | + ### /explore/apps/{app_id} #### GET @@ -12234,6 +12249,12 @@ Enum class for large language model mode. | ---- | ---- | ----------- | -------- | | LLMMode | string | Enum class for large language model mode. | | +#### LearnDifyAppListResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| recommended_apps | [ [RecommendedAppResponse](#recommendedappresponse) ] | | Yes | + #### LegacyEndpointUpdatePayload | Name | Type | Description | Required | diff --git a/api/services/app_service.py b/api/services/app_service.py index 6716833f6c6e90..996f19006b598b 100644 --- a/api/services/app_service.py +++ b/api/services/app_service.py @@ -91,7 +91,7 @@ def get_paginate_apps(self, user_id: str, tenant_id: str, params: AppListParams) return None app_models = db.paginate( - sa.select(App).where(*filters).order_by(App.created_at.desc()), + sa.select(App).where(*filters).order_by(App.updated_at.desc()), page=params.page, per_page=params.limit, error_out=False, diff --git a/api/services/recommend_app/database/database_retrieval.py b/api/services/recommend_app/database/database_retrieval.py index ac870f07001b30..0a92827f14ba10 100644 --- a/api/services/recommend_app/database/database_retrieval.py +++ b/api/services/recommend_app/database/database_retrieval.py @@ -1,4 +1,4 @@ -from typing import Any, TypedDict +from typing import Any, NotRequired, TypedDict from sqlalchemy import select @@ -22,6 +22,7 @@ class RecommendedAppItemDict(TypedDict): categories: list[str] position: int is_listed: bool + can_trial: NotRequired[bool] class RecommendedAppsResultDict(TypedDict): @@ -61,14 +62,47 @@ def fetch_recommended_apps_from_db(cls, language: str) -> RecommendedAppsResultD :param language: language :return: """ - recommended_apps = db.session.scalars( - select(RecommendedApp).where(RecommendedApp.is_listed == True, RecommendedApp.language == language) - ).all() + recommended_apps = cls._fetch_listed_recommended_apps(language) if len(recommended_apps) == 0: - recommended_apps = db.session.scalars( - select(RecommendedApp).where(RecommendedApp.is_listed == True, RecommendedApp.language == languages[0]) - ).all() + recommended_apps = cls._fetch_listed_recommended_apps(languages[0]) + + return cls._format_recommended_apps(recommended_apps, language) + + @classmethod + def fetch_learn_dify_apps_from_db(cls, language: str) -> RecommendedAppsResultDict: + """ + Fetch listed recommended apps explicitly marked for the Learn Dify section. + :param language: language + :return: + """ + recommended_apps = cls._fetch_listed_recommended_apps(language, is_learn_dify=True) + + if len(recommended_apps) == 0 and language != languages[0]: + recommended_apps = cls._fetch_listed_recommended_apps(languages[0], is_learn_dify=True) + + return cls._format_recommended_apps(recommended_apps, language) + + @classmethod + def _fetch_listed_recommended_apps( + cls, language: str, *, is_learn_dify: bool | None = None + ) -> list[RecommendedApp]: + filters = [RecommendedApp.is_listed.is_(True), RecommendedApp.language == language] + if is_learn_dify is not None: + filters.append(RecommendedApp.is_learn_dify.is_(is_learn_dify)) + + return db.session.scalars(select(RecommendedApp).where(*filters)).all() + + @classmethod + def _format_recommended_apps( + cls, recommended_apps: list[RecommendedApp], language: str + ) -> RecommendedAppsResultDict: + """ + Serialize DB recommended app rows into the Explore list response shape. + :param recommended_apps: recommended app rows + :param language: language used for category ordering + :return: + """ categories = set() recommended_apps_result: list[RecommendedAppItemDict] = [] diff --git a/api/services/recommended_app_service.py b/api/services/recommended_app_service.py index 4e189e6e7c9016..f4276e7fc331d9 100644 --- a/api/services/recommended_app_service.py +++ b/api/services/recommended_app_service.py @@ -6,6 +6,7 @@ from extensions.ext_database import db from models.model import AccountTrialAppRecord, TrialApp from services.feature_service import FeatureService +from services.recommend_app.database.database_retrieval import DatabaseRecommendAppRetrieval from services.recommend_app.recommend_app_factory import RecommendAppRetrievalFactory @@ -31,13 +32,24 @@ def get_recommended_apps_and_categories(cls, language: str): apps = result["recommended_apps"] for app in apps: app_id = app["app_id"] - trial_app_model = db.session.scalar(select(TrialApp).where(TrialApp.app_id == app_id).limit(1)) - if trial_app_model: - app["can_trial"] = True - else: - app["can_trial"] = False + app["can_trial"] = cls._can_trial_app(app_id) return result + @classmethod + def get_learn_dify_apps(cls, language: str) -> dict[str, Any]: + """ + Get database-backed recommended apps marked as Learn Dify. + :param language: language + :return: + """ + result = DatabaseRecommendAppRetrieval.fetch_learn_dify_apps_from_db(language) + + if FeatureService.get_system_features().enable_trial_app: + for app in result["recommended_apps"]: + app["can_trial"] = cls._can_trial_app(app["app_id"]) + + return {"recommended_apps": result["recommended_apps"]} + @classmethod def get_recommend_app_detail(cls, app_id: str) -> dict[str, Any] | None: """ @@ -52,11 +64,7 @@ def get_recommend_app_detail(cls, app_id: str) -> dict[str, Any] | None: return None if FeatureService.get_system_features().enable_trial_app: app_id = result["id"] - trial_app_model = db.session.scalar(select(TrialApp).where(TrialApp.app_id == app_id).limit(1)) - if trial_app_model: - result["can_trial"] = True - else: - result["can_trial"] = False + result["can_trial"] = cls._can_trial_app(app_id) return result @classmethod @@ -77,3 +85,8 @@ def add_trial_app_record(cls, app_id: str, account_id: str): else: db.session.add(AccountTrialAppRecord(app_id=app_id, count=1, account_id=account_id)) db.session.commit() + + @staticmethod + def _can_trial_app(app_id: str) -> bool: + trial_app_model = db.session.scalar(select(TrialApp).where(TrialApp.app_id == app_id).limit(1)) + return trial_app_model is not None diff --git a/api/tests/test_containers_integration_tests/services/recommend_app/test_database_retrieval.py b/api/tests/test_containers_integration_tests/services/recommend_app/test_database_retrieval.py index 11e864176ad9c0..d5dd53291fffcb 100644 --- a/api/tests/test_containers_integration_tests/services/recommend_app/test_database_retrieval.py +++ b/api/tests/test_containers_integration_tests/services/recommend_app/test_database_retrieval.py @@ -50,6 +50,7 @@ def _create_recommended_app( categories: list[str] | None = None, language: str = "en-US", is_listed: bool = True, + is_learn_dify: bool = False, position: int = 1, ) -> RecommendedApp: rec = RecommendedApp( @@ -61,6 +62,7 @@ def _create_recommended_app( categories=[category] if categories is None else categories, language=language, is_listed=is_listed, + is_learn_dify=is_learn_dify, position=position, ) rec.id = str(uuid4()) @@ -202,6 +204,65 @@ def test_skips_apps_without_site(self, flask_app_with_containers, db_session_wit app_ids = {r["app_id"] for r in result["recommended_apps"]} assert app1.id not in app_ids + def test_fetch_learn_dify_apps_uses_flag_not_categories( + self, + flask_app_with_containers, + db_session_with_containers: Session, + ): + tenant_id = str(uuid4()) + learn_dify_app = _create_app(db_session_with_containers, tenant_id=tenant_id) + _create_site(db_session_with_containers, app_id=learn_dify_app.id) + _create_recommended_app( + db_session_with_containers, + app_id=learn_dify_app.id, + category="workflow", + categories=["Workflow"], + is_learn_dify=True, + ) + + category_only_app = _create_app(db_session_with_containers, tenant_id=tenant_id) + _create_site(db_session_with_containers, app_id=category_only_app.id) + _create_recommended_app( + db_session_with_containers, + app_id=category_only_app.id, + category="Learn Dify", + categories=["Learn Dify"], + is_learn_dify=False, + ) + + db_session_with_containers.expire_all() + + result = DatabaseRecommendAppRetrieval.fetch_learn_dify_apps_from_db("en-US") + + app_ids = {r["app_id"] for r in result["recommended_apps"]} + assert learn_dify_app.id in app_ids + assert category_only_app.id not in app_ids + recommended_app = next(item for item in result["recommended_apps"] if item["app_id"] == learn_dify_app.id) + assert recommended_app["categories"] == ["Workflow"] + + def test_fetch_learn_dify_apps_falls_back_to_default_language( + self, + flask_app_with_containers, + db_session_with_containers: Session, + ): + tenant_id = str(uuid4()) + learn_dify_app = _create_app(db_session_with_containers, tenant_id=tenant_id) + _create_site(db_session_with_containers, app_id=learn_dify_app.id) + _create_recommended_app( + db_session_with_containers, + app_id=learn_dify_app.id, + categories=["Workflow"], + is_learn_dify=True, + language="en-US", + ) + + db_session_with_containers.expire_all() + + result = DatabaseRecommendAppRetrieval.fetch_learn_dify_apps_from_db("fr-FR") + + app_ids = {r["app_id"] for r in result["recommended_apps"]} + assert learn_dify_app.id in app_ids + class TestFetchRecommendedAppDetailFromDb: def test_returns_none_when_not_listed(self, flask_app_with_containers, db_session_with_containers: Session): diff --git a/api/tests/unit_tests/controllers/console/explore/test_recommended_app.py b/api/tests/unit_tests/controllers/console/explore/test_recommended_app.py index 89cbea5ddc6afc..131221ec5047d5 100644 --- a/api/tests/unit_tests/controllers/console/explore/test_recommended_app.py +++ b/api/tests/unit_tests/controllers/console/explore/test_recommended_app.py @@ -74,6 +74,48 @@ def test_get_fallback_to_default_language(self, app: Flask): assert result == result_data +class TestLearnDifyAppListApi: + def test_get_with_language_param(self, app: Flask): + api = module.LearnDifyAppListApi() + method = unwrap(api.get) + + result_data = {"recommended_apps": []} + + with ( + app.test_request_context("/", query_string={"language": "en-US"}), + patch.object(module, "current_user", MagicMock(interface_language="fr-FR")), + patch.object( + module.RecommendedAppService, + "get_learn_dify_apps", + return_value=result_data, + ) as service_mock, + ): + result = method(api) + + service_mock.assert_called_once_with("en-US") + assert result == result_data + + def test_get_fallback_to_user_language(self, app: Flask): + api = module.LearnDifyAppListApi() + method = unwrap(api.get) + + result_data = {"recommended_apps": []} + + with ( + app.test_request_context("/", query_string={"language": "invalid"}), + patch.object(module, "current_user", MagicMock(interface_language="fr-FR")), + patch.object( + module.RecommendedAppService, + "get_learn_dify_apps", + return_value=result_data, + ) as service_mock, + ): + result = method(api) + + service_mock.assert_called_once_with("fr-FR") + assert result == result_data + + class TestRecommendedAppApi: def test_get_success(self, app: Flask): api = module.RecommendedAppApi() @@ -139,3 +181,29 @@ def test_recommended_app_list_response_serialization(self): assert response["recommended_apps"][0]["app_id"] == "app-1" assert response["recommended_apps"][0]["categories"] == ["cat", "other"] assert response["categories"] == ["cat"] + + def test_learn_dify_app_list_response_serialization(self): + response = module.LearnDifyAppListResponse.model_validate( + { + "recommended_apps": [ + { + "app": { + "id": "app-1", + "name": "App", + "mode": "chat", + "icon": "icon.png", + "icon_type": "emoji", + "icon_background": "#fff", + }, + "app_id": "app-1", + "description": "desc", + "categories": ["Workflow"], + "position": 1, + "is_listed": True, + } + ], + } + ).model_dump(mode="json") + + assert response["recommended_apps"][0]["app_id"] == "app-1" + assert response["recommended_apps"][0]["categories"] == ["Workflow"] diff --git a/api/tests/unit_tests/services/test_recommended_app_service.py b/api/tests/unit_tests/services/test_recommended_app_service.py index 030d0d73fec818..31647f26b542fd 100644 --- a/api/tests/unit_tests/services/test_recommended_app_service.py +++ b/api/tests/unit_tests/services/test_recommended_app_service.py @@ -7,6 +7,7 @@ from types import SimpleNamespace from unittest.mock import MagicMock, patch +from services import recommended_app_service as service_module from services.recommended_app_service import RecommendedAppService @@ -44,3 +45,40 @@ def test_returns_none_when_retrieval_returns_none_and_trial_enabled( assert result is None mock_instance.get_recommend_app_detail.assert_called_once_with("nonexistent") + + +class TestGetLearnDifyApps: + @patch("services.recommended_app_service.FeatureService", autospec=True) + @patch("services.recommended_app_service.DatabaseRecommendAppRetrieval", autospec=True) + def test_returns_database_learn_dify_apps_without_remote_factory( + self, mock_database_retrieval, mock_feature_service + ): + expected_app = {"app_id": "app-1", "categories": ["Workflow"]} + mock_database_retrieval.fetch_learn_dify_apps_from_db.return_value = { + "recommended_apps": [expected_app], + "categories": ["Workflow"], + } + mock_feature_service.get_system_features.return_value = SimpleNamespace(enable_trial_app=False) + + with patch.object(service_module.RecommendAppRetrievalFactory, "get_recommend_app_factory") as factory_mock: + result = RecommendedAppService.get_learn_dify_apps("en-US") + + assert result == {"recommended_apps": [expected_app]} + mock_database_retrieval.fetch_learn_dify_apps_from_db.assert_called_once_with("en-US") + factory_mock.assert_not_called() + + @patch("services.recommended_app_service.FeatureService", autospec=True) + @patch("services.recommended_app_service.DatabaseRecommendAppRetrieval", autospec=True) + def test_sets_can_trial_when_trial_feature_enabled(self, mock_database_retrieval, mock_feature_service): + app = {"app_id": "app-1", "categories": ["Workflow"]} + mock_database_retrieval.fetch_learn_dify_apps_from_db.return_value = { + "recommended_apps": [app], + "categories": ["Workflow"], + } + mock_feature_service.get_system_features.return_value = SimpleNamespace(enable_trial_app=True) + + with patch.object(RecommendedAppService, "_can_trial_app", return_value=True) as can_trial_mock: + result = RecommendedAppService.get_learn_dify_apps("en-US") + + assert result["recommended_apps"][0]["can_trial"] is True + can_trial_mock.assert_called_once_with("app-1") diff --git a/packages/contracts/README.md b/packages/contracts/README.md index ae682faa539388..e31aa9d2ffe1c8 100644 --- a/packages/contracts/README.md +++ b/packages/contracts/README.md @@ -8,14 +8,14 @@ Snapshot generated from `packages/contracts/generated/api/readiness.json` after running `pnpm -C packages/contracts gen-api-contract-from-openapi`. -Are we OpenAPI ready? **No.** Current generated API contracts are **16.6% ready**. +Are we OpenAPI ready? **No.** Current generated API contracts are **16.9% ready**. | Surface | Ready | Not ready | Total | Ready % | | --------- | ------: | --------: | ------: | --------: | -| console | 95 | 475 | 570 | 16.7% | +| console | 97 | 474 | 571 | 17.0% | | service | 16 | 72 | 88 | 18.2% | | web | 5 | 36 | 41 | 12.2% | -| **total** | **116** | **583** | **699** | **16.6%** | +| **total** | **118** | **582** | **700** | **16.9%** | Readiness here means the generated contract operation is not marked with: diff --git a/packages/contracts/generated/api/console/apps/orpc.gen.ts b/packages/contracts/generated/api/console/apps/orpc.gen.ts index 2eea4f13c496ab..a1a0faaefd1ac8 100644 --- a/packages/contracts/generated/api/console/apps/orpc.gen.ts +++ b/packages/contracts/generated/api/console/apps/orpc.gen.ts @@ -426,16 +426,10 @@ export const imports = { /** * Get workflow online users - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post3 = oc .route({ - deprecated: true, - description: - 'Get workflow online users\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Get workflow online users', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsWorkflowsOnlineUsers', diff --git a/packages/contracts/generated/api/console/explore/orpc.gen.ts b/packages/contracts/generated/api/console/explore/orpc.gen.ts index 4933c1ec12d664..1529b36ed85135 100644 --- a/packages/contracts/generated/api/console/explore/orpc.gen.ts +++ b/packages/contracts/generated/api/console/explore/orpc.gen.ts @@ -6,17 +6,34 @@ import * as z from 'zod' import { zGetExploreAppsByAppIdPath, zGetExploreAppsByAppIdResponse, + zGetExploreAppsLearnDifyQuery, + zGetExploreAppsLearnDifyResponse, zGetExploreAppsQuery, zGetExploreAppsResponse, zGetExploreBannersResponse, } from './zod.gen' +export const get = oc + .route({ + inputStructure: 'detailed', + method: 'GET', + operationId: 'getExploreAppsLearnDify', + path: '/explore/apps/learn-dify', + tags: ['console'], + }) + .input(z.object({ query: zGetExploreAppsLearnDifyQuery.optional() })) + .output(zGetExploreAppsLearnDifyResponse) + +export const learnDify = { + get, +} + /** * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. * * @deprecated */ -export const get = oc +export const get2 = oc .route({ deprecated: true, description: @@ -31,10 +48,10 @@ export const get = oc .output(zGetExploreAppsByAppIdResponse) export const byAppId = { - get, + get: get2, } -export const get2 = oc +export const get3 = oc .route({ inputStructure: 'detailed', method: 'GET', @@ -46,7 +63,8 @@ export const get2 = oc .output(zGetExploreAppsResponse) export const apps = { - get: get2, + get: get3, + learnDify, byAppId, } @@ -57,7 +75,7 @@ export const apps = { * * @deprecated */ -export const get3 = oc +export const get4 = oc .route({ deprecated: true, description: @@ -72,7 +90,7 @@ export const get3 = oc .output(zGetExploreBannersResponse) export const banners = { - get: get3, + get: get4, } export const explore = { diff --git a/packages/contracts/generated/api/console/explore/types.gen.ts b/packages/contracts/generated/api/console/explore/types.gen.ts index 329c1f7722c43e..b9e3c4dcce06fc 100644 --- a/packages/contracts/generated/api/console/explore/types.gen.ts +++ b/packages/contracts/generated/api/console/explore/types.gen.ts @@ -9,6 +9,10 @@ export type RecommendedAppListResponse = { recommended_apps: Array } +export type LearnDifyAppListResponse = { + recommended_apps: Array +} + export type RecommendedAppResponse = { app?: RecommendedAppInfoResponse app_id: string @@ -46,6 +50,22 @@ export type GetExploreAppsResponses = { export type GetExploreAppsResponse = GetExploreAppsResponses[keyof GetExploreAppsResponses] +export type GetExploreAppsLearnDifyData = { + body?: never + path?: never + query?: { + language?: string + } + url: '/explore/apps/learn-dify' +} + +export type GetExploreAppsLearnDifyResponses = { + 200: LearnDifyAppListResponse +} + +export type GetExploreAppsLearnDifyResponse + = GetExploreAppsLearnDifyResponses[keyof GetExploreAppsLearnDifyResponses] + export type GetExploreAppsByAppIdData = { body?: never path: { diff --git a/packages/contracts/generated/api/console/explore/zod.gen.ts b/packages/contracts/generated/api/console/explore/zod.gen.ts index c65c47be918bcb..66d431204ee178 100644 --- a/packages/contracts/generated/api/console/explore/zod.gen.ts +++ b/packages/contracts/generated/api/console/explore/zod.gen.ts @@ -38,6 +38,13 @@ export const zRecommendedAppListResponse = z.object({ recommended_apps: z.array(zRecommendedAppResponse), }) +/** + * LearnDifyAppListResponse + */ +export const zLearnDifyAppListResponse = z.object({ + recommended_apps: z.array(zRecommendedAppResponse), +}) + export const zGetExploreAppsQuery = z.object({ language: z.string().optional(), }) @@ -47,6 +54,15 @@ export const zGetExploreAppsQuery = z.object({ */ export const zGetExploreAppsResponse = zRecommendedAppListResponse +export const zGetExploreAppsLearnDifyQuery = z.object({ + language: z.string().optional(), +}) + +/** + * Success + */ +export const zGetExploreAppsLearnDifyResponse = zLearnDifyAppListResponse + export const zGetExploreAppsByAppIdPath = z.object({ app_id: z.string(), }) diff --git a/packages/contracts/generated/api/readiness.json b/packages/contracts/generated/api/readiness.json index af86c7646e3a3b..2a64600633105d 100644 --- a/packages/contracts/generated/api/readiness.json +++ b/packages/contracts/generated/api/readiness.json @@ -1,8 +1,8 @@ { "surfaces": { "console": { - "notReady": 475, - "total": 570 + "notReady": 474, + "total": 571 }, "service": { "notReady": 72,