@nocobase/app-template-default 0.0.0-stage → 1.0.0-beta.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/mcp.json +8 -0
- package/.mcp.json +8 -0
- package/.prettierignore +20 -0
- package/.vscode/mcp.json +8 -0
- package/AGENTS.md +432 -0
- package/CLAUDE.md +9 -0
- package/Dockerfile +132 -0
- package/Dockerfile.dockerignore +45 -0
- package/README.MD +481 -0
- package/cli/plugins.ts +14 -0
- package/client/agent-annotations-host.ts +19 -0
- package/client/app.ts +38 -0
- package/client/components/back-button.tsx +49 -0
- package/client/components/breadcrumbs.tsx +167 -0
- package/client/components/inbox-badge.ts +49 -0
- package/client/components/inbox-button.tsx +132 -0
- package/client/components/inbox-header-button.tsx +25 -0
- package/client/components/loading.tsx +35 -0
- package/client/components/page-container.tsx +24 -0
- package/client/components/page-header.tsx +33 -0
- package/client/components/route-child-page.tsx +121 -0
- package/client/components/route-dialog.tsx +10 -0
- package/client/components/route-drawer.tsx +10 -0
- package/client/components/route-overlay.tsx +190 -0
- package/client/components/ui/alert.tsx +75 -0
- package/client/components/ui/badge.tsx +51 -0
- package/client/components/ui/breadcrumb.tsx +121 -0
- package/client/components/ui/button.tsx +58 -0
- package/client/components/ui/collapsible.tsx +19 -0
- package/client/components/ui/context-menu.tsx +271 -0
- package/client/components/ui/dialog.tsx +160 -0
- package/client/components/ui/dropdown-menu.tsx +270 -0
- package/client/components/ui/empty.tsx +103 -0
- package/client/components/ui/field.tsx +236 -0
- package/client/components/ui/input-group.tsx +158 -0
- package/client/components/ui/input.tsx +20 -0
- package/client/components/ui/kbd.tsx +26 -0
- package/client/components/ui/label.tsx +18 -0
- package/client/components/ui/popover.tsx +89 -0
- package/client/components/ui/select.tsx +200 -0
- package/client/components/ui/separator.tsx +22 -0
- package/client/components/ui/sheet.tsx +137 -0
- package/client/components/ui/sidebar.tsx +723 -0
- package/client/components/ui/skeleton.tsx +13 -0
- package/client/components/ui/spinner.tsx +20 -0
- package/client/components/ui/tabs.tsx +79 -0
- package/client/components/ui/textarea.tsx +17 -0
- package/client/components/ui/toast.tsx +231 -0
- package/client/components/ui/tooltip.tsx +63 -0
- package/client/components/use-route-overlay.ts +26 -0
- package/client/config/api.ts +13 -0
- package/client/config/app.ts +8 -0
- package/client/config/auth.ts +18 -0
- package/client/config/index.ts +17 -0
- package/client/extensions/nocobase-auth-forms/field-props.ts +13 -0
- package/client/extensions/nocobase-auth-forms/form-parts.tsx +101 -0
- package/client/extensions/nocobase-auth-forms/password-input.tsx +41 -0
- package/client/extensions/nocobase-auth-forms/password-login-form.tsx +123 -0
- package/client/extensions/nocobase-auth-forms/password-registration-form.tsx +193 -0
- package/client/extensions/nocobase-auth-forms/password-reset-form.tsx +132 -0
- package/client/extensions/nocobase-auth-forms/password-reset-request-form.tsx +99 -0
- package/client/extensions/nocobase-auth-methods/auth-methods.tsx +170 -0
- package/client/extensions/nocobase-auth-split-layout/auth-split-layout.tsx +126 -0
- package/client/extensions/nocobase-device-approval/device-approval.tsx +277 -0
- package/client/extensions/nocobase-device-approval/locales/en-US.ts +55 -0
- package/client/extensions/nocobase-device-approval/locales/zh-CN.ts +27 -0
- package/client/extensions/nocobase-device-approval/use-device-approval.ts +176 -0
- package/client/extensions/nocobase-file-component-ui/README.md +13 -0
- package/client/extensions/nocobase-file-component-ui/components/file-list.tsx +147 -0
- package/client/extensions/nocobase-file-component-ui/components/file-preview-dialog.tsx +263 -0
- package/client/extensions/nocobase-file-component-ui/components/file-preview-field.tsx +68 -0
- package/client/extensions/nocobase-file-component-ui/components/file-thumbnail.tsx +73 -0
- package/client/extensions/nocobase-file-component-ui/components/file-upload-field.tsx +386 -0
- package/client/extensions/nocobase-file-component-ui/components/previewers/file-preview-content.tsx +255 -0
- package/client/extensions/nocobase-file-component-ui/components/previewers/office-open-xml-preview.tsx +226 -0
- package/client/extensions/nocobase-file-component-ui/index.ts +8 -0
- package/client/extensions/nocobase-file-component-ui/lib/file-preview.ts +194 -0
- package/client/extensions/nocobase-file-component-ui/lib/file-url.ts +22 -0
- package/client/extensions/nocobase-file-component-ui/lib/message-key.ts +18 -0
- package/client/extensions/nocobase-file-component-ui/types.ts +69 -0
- package/client/extensions/nocobase-inbox/decision-actions-bar.tsx +140 -0
- package/client/extensions/nocobase-inbox/frame.ts +31 -0
- package/client/extensions/nocobase-inbox/inbox-actions.ts +21 -0
- package/client/extensions/nocobase-inbox/inbox-detail.tsx +386 -0
- package/client/extensions/nocobase-inbox/inbox-item.tsx +274 -0
- package/client/extensions/nocobase-inbox/inbox-list.tsx +433 -0
- package/client/extensions/nocobase-inbox/inbox-page.tsx +545 -0
- package/client/extensions/nocobase-inbox/locales/en-US.ts +111 -0
- package/client/extensions/nocobase-inbox/locales/zh-CN.ts +57 -0
- package/client/extensions/nocobase-inbox/model.ts +428 -0
- package/client/extensions/nocobase-inbox/registry-scope.tsx +49 -0
- package/client/extensions/nocobase-inbox/registry.ts +303 -0
- package/client/extensions/nocobase-inbox/source.ts +117 -0
- package/client/hooks/use-mobile.ts +21 -0
- package/client/index.tsx +60 -0
- package/client/layouts/app-layout.tsx +105 -0
- package/client/layouts/components/app-brand.tsx +49 -0
- package/client/layouts/components/app-sidebar.tsx +196 -0
- package/client/layouts/components/header-actions.tsx +50 -0
- package/client/layouts/components/language-switcher.tsx +95 -0
- package/client/layouts/components/layout-header.tsx +17 -0
- package/client/layouts/components/navigation-menu.tsx +411 -0
- package/client/layouts/components/sidebar-footer.tsx +107 -0
- package/client/layouts/components/surface-empty.tsx +35 -0
- package/client/layouts/components/user-menu.tsx +127 -0
- package/client/layouts/index.ts +2 -0
- package/client/layouts/settings-layout.tsx +172 -0
- package/client/layouts/use-sidebar-preference.ts +57 -0
- package/client/lib/constants.ts +5 -0
- package/client/lib/toaster.ts +56 -0
- package/client/lib/utils.ts +1 -0
- package/client/locales/en-US.ts +178 -0
- package/client/locales/index.ts +9 -0
- package/client/locales/zh-CN.ts +161 -0
- package/client/pages/auth/device.tsx +41 -0
- package/client/pages/auth/forgot-password.tsx +39 -0
- package/client/pages/auth/login.tsx +66 -0
- package/client/pages/auth/register.tsx +46 -0
- package/client/pages/auth/reset-password.tsx +38 -0
- package/client/pages/auth/shared.tsx +111 -0
- package/client/pages/home.tsx +16 -0
- package/client/pages/inbox.tsx +12 -0
- package/client/plugins.ts +41 -0
- package/client/react-providers.ts +27 -0
- package/client/route-overrides.ts +9 -0
- package/client/routes.ts +75 -0
- package/client/routing/app-router.tsx +127 -0
- package/client/routing/client-route.tsx +129 -0
- package/client/routing/route-context.tsx +85 -0
- package/client/routing/route-navigation.ts +153 -0
- package/client/routing/route-tree.tsx +42 -0
- package/client/routing/standalone-page-layout.tsx +15 -0
- package/client/runtime.ts +26 -0
- package/client/service-provider.ts +40 -0
- package/client/source-extensions.ts +19 -0
- package/client/startup.tsx +22 -0
- package/client/styles.css +122 -0
- package/client/theme/index.ts +4 -0
- package/client/theme/theme-context.ts +12 -0
- package/client/theme/theme-preferences.ts +84 -0
- package/client/theme/theme-presets.ts +7 -0
- package/client/theme/theme-provider.tsx +106 -0
- package/client/theme/theme-settings.tsx +176 -0
- package/client/theme/themes/compact.css +140 -0
- package/client/theme/themes/default.css +117 -0
- package/client/vite-env.d.ts +5 -0
- package/components.json +27 -0
- package/config.example.yml +172 -0
- package/database/main/migrations/.gitkeep +0 -0
- package/database/main/migrations/202610060001_create_device_code.ts +37 -0
- package/database/main/seeds/.gitkeep +0 -0
- package/database/tsconfig.json +4 -0
- package/ecosystem.config.js +35 -0
- package/eslint.config.js +24 -0
- package/index.html +100 -0
- package/package.json +200 -3
- package/playwright.config.ts +10 -0
- package/public/assets/favicon.ico +0 -0
- package/public/assets/logo-dark.png +0 -0
- package/public/assets/logo-mark-dark.png +0 -0
- package/public/assets/logo-mark.png +0 -0
- package/public/assets/logo.png +0 -0
- package/server/app.ts +50 -0
- package/server/config/ai.ts +27 -0
- package/server/config/api.ts +8 -0
- package/server/config/app.ts +40 -0
- package/server/config/auth.ts +36 -0
- package/server/config/authorization.ts +18 -0
- package/server/config/caching.ts +21 -0
- package/server/config/database.ts +22 -0
- package/server/config/drive.ts +30 -0
- package/server/config/i18n.ts +17 -0
- package/server/config/index.ts +73 -0
- package/server/config/jobs.ts +27 -0
- package/server/config/logging.ts +23 -0
- package/server/config/notification.ts +11 -0
- package/server/config/queue.ts +28 -0
- package/server/config/scheduler.ts +23 -0
- package/server/config/secrets.ts +10 -0
- package/server/config/server.ts +26 -0
- package/server/config/session.ts +60 -0
- package/server/config/snowflake.ts +21 -0
- package/server/config/spa.ts +24 -0
- package/server/config/users.ts +11 -0
- package/server/config/workflow.ts +24 -0
- package/server/config.ts +24 -0
- package/server/embedded.ts +23 -0
- package/server/locales/en-US.ts +10 -0
- package/server/locales/index.ts +10 -0
- package/server/locales/zh-CN.ts +5 -0
- package/server/plugins.ts +41 -0
- package/server/providers/index.ts +5 -0
- package/server/routes/index.ts +6 -0
- package/server/runtime.ts +24 -0
- package/server/standalone.ts +29 -0
- package/server/tsconfig.json +4 -0
- package/tailwind.config.mjs +59 -0
- package/tests/components/app-layout-routes.test.tsx +132 -0
- package/tests/components/app-title.test.tsx +57 -0
- package/tests/components/auth-i18n.test.tsx +87 -0
- package/tests/components/back-button.test.tsx +80 -0
- package/tests/components/file-preview.test.tsx +101 -0
- package/tests/components/header-hover.test.tsx +87 -0
- package/tests/components/inbox.test.tsx +139 -0
- package/tests/components/language-switcher.test.tsx +298 -0
- package/tests/components/layout-containers.test.tsx +15 -0
- package/tests/components/layout-i18n.test.tsx +187 -0
- package/tests/components/loading.test.tsx +25 -0
- package/tests/components/navigation-menu.test.tsx +355 -0
- package/tests/components/page-harness.test.tsx +318 -0
- package/tests/components/primitive-labels.test.tsx +80 -0
- package/tests/components/sidebar-permissions.test.tsx +110 -0
- package/tests/components/sidebar-preference.test.tsx +42 -0
- package/tests/fixtures/theme-tokens.html +12 -0
- package/tests/fixtures/theme-tokens.tsx +111 -0
- package/tests/logic/account-permissions.test.tsx +204 -0
- package/tests/logic/app-locale-coverage.test.ts +136 -0
- package/tests/logic/app-server.test.ts +1589 -0
- package/tests/logic/asset-url-build.test.ts +106 -0
- package/tests/logic/client-auth.test.tsx +122 -0
- package/tests/logic/client-plugin-registry.test.ts +63 -0
- package/tests/logic/client-route-recovery.test.tsx +80 -0
- package/tests/logic/client-routes.test.ts +126 -0
- package/tests/logic/client-runtime.test.ts +112 -0
- package/tests/logic/client-settings.test.tsx +841 -0
- package/tests/logic/client-shell.test.tsx +466 -0
- package/tests/logic/client-theme.test.tsx +441 -0
- package/tests/logic/config.test.ts +197 -0
- package/tests/logic/dev-client-watch.test.ts +108 -0
- package/tests/logic/dev-routes-production-build.test.ts +168 -0
- package/tests/logic/device-code-migration.test.ts +70 -0
- package/tests/logic/lifecycle.test.ts +221 -0
- package/tests/logic/plugin-commands.test.ts +69 -0
- package/tests/logic/plugin-page-authz.test.ts +76 -0
- package/tests/logic/route-navigation.test.ts +66 -0
- package/tests/logic/route-overlay.test.tsx +353 -0
- package/tests/logic/server-imports.test.ts +88 -0
- package/tests/logic/tailwind-sources.test.ts +151 -0
- package/tests/logic/template-package-name.test.ts +88 -0
- package/tests/logic/theme-preferences.test.ts +86 -0
- package/tests/logic/theme-tokens.test.ts +248 -0
- package/tests/logic/toaster.test.tsx +108 -0
- package/tests/logic/user-menu-sign-out.test.tsx +98 -0
- package/tests/setup/client-config.ts +27 -0
- package/tsconfig.json +11 -0
- package/tsconfig.node.json +12 -0
- package/tsconfig.server.json +19 -0
- package/vite.config.ts +92 -0
- package/vitest.config.ts +37 -0
- package/README.md +0 -3
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
act,
|
|
3
|
+
fireEvent,
|
|
4
|
+
render,
|
|
5
|
+
screen,
|
|
6
|
+
waitFor,
|
|
7
|
+
} from '@testing-library/react';
|
|
8
|
+
import userEvent from '@testing-library/user-event';
|
|
9
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
10
|
+
import {
|
|
11
|
+
TestI18nProvider,
|
|
12
|
+
createTestI18nRuntime,
|
|
13
|
+
} from '@nocobase/i18n/testing';
|
|
14
|
+
import type { ReactNode } from 'react';
|
|
15
|
+
import { UserMenu } from '../../client/layouts/components/user-menu.tsx';
|
|
16
|
+
import enUS from '../../client/locales/en-US.js';
|
|
17
|
+
|
|
18
|
+
const runtime = await createTestI18nRuntime({
|
|
19
|
+
application: { namespace: '@nocobase/app-template-default', resources: enUS },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function I18n({ children }: { readonly children: ReactNode }) {
|
|
23
|
+
return <TestI18nProvider runtime={runtime}>{children}</TestI18nProvider>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { signOut, refresh, showToast } = vi.hoisted(() => ({
|
|
27
|
+
signOut: vi.fn(),
|
|
28
|
+
refresh: vi.fn(),
|
|
29
|
+
showToast: vi.fn(),
|
|
30
|
+
}));
|
|
31
|
+
vi.mock('@nocobase/app-client', () => {
|
|
32
|
+
const toaster = { show: showToast, close: vi.fn() };
|
|
33
|
+
return { useToaster: () => toaster };
|
|
34
|
+
});
|
|
35
|
+
vi.mock('@nocobase/app-plugin-authentication/client', () => ({
|
|
36
|
+
useAuthentication: () => ({
|
|
37
|
+
client: { signOut },
|
|
38
|
+
session: {
|
|
39
|
+
user: { id: 'operator', name: 'Operator', email: 'operator@example.com' },
|
|
40
|
+
},
|
|
41
|
+
isPending: false,
|
|
42
|
+
refresh,
|
|
43
|
+
}),
|
|
44
|
+
}));
|
|
45
|
+
vi.mock('../../client/layouts/components/language-switcher.js', () => ({
|
|
46
|
+
LanguageSwitcher: () => null,
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Opens the account menu from the keyboard. A pointer opens it on hover and again on the press, one frame later, which
|
|
51
|
+
* can reopen the menu after a test has already chosen an item and closed it.
|
|
52
|
+
*/
|
|
53
|
+
async function openAccountMenu(): Promise<void> {
|
|
54
|
+
act(() => screen.getByRole('button', { name: 'Open account menu' }).focus());
|
|
55
|
+
await userEvent.keyboard('{Enter}');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe('account menu sign out', () => {
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
vi.resetAllMocks();
|
|
61
|
+
refresh.mockResolvedValue(undefined);
|
|
62
|
+
});
|
|
63
|
+
async function signOutFromMenu() {
|
|
64
|
+
render(<UserMenu />, { wrapper: I18n });
|
|
65
|
+
await openAccountMenu();
|
|
66
|
+
fireEvent.click(await screen.findByRole('menuitem', { name: 'Sign out' }));
|
|
67
|
+
}
|
|
68
|
+
it('refreshes the server session after successful sign-out', async () => {
|
|
69
|
+
signOut.mockResolvedValue({ data: { success: true }, error: null });
|
|
70
|
+
await signOutFromMenu();
|
|
71
|
+
await waitFor(() => expect(refresh).toHaveBeenCalledTimes(1));
|
|
72
|
+
expect(showToast).not.toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
it('reports a rejected origin without pretending the session ended', async () => {
|
|
75
|
+
signOut.mockResolvedValue({
|
|
76
|
+
data: null,
|
|
77
|
+
error: { status: 403, code: 'INVALID_ORIGIN' },
|
|
78
|
+
});
|
|
79
|
+
await signOutFromMenu();
|
|
80
|
+
await waitFor(() =>
|
|
81
|
+
expect(showToast).toHaveBeenCalledWith({
|
|
82
|
+
type: 'error',
|
|
83
|
+
title: 'Unable to sign out. Please try again.',
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
expect(refresh).not.toHaveBeenCalled();
|
|
87
|
+
await openAccountMenu();
|
|
88
|
+
expect(
|
|
89
|
+
await screen.findByRole('menuitem', { name: 'Sign out' }),
|
|
90
|
+
).not.toHaveAttribute('aria-disabled', 'true');
|
|
91
|
+
});
|
|
92
|
+
it('reports network failures and allows retry', async () => {
|
|
93
|
+
signOut.mockRejectedValue(new Error('Network unavailable'));
|
|
94
|
+
await signOutFromMenu();
|
|
95
|
+
await waitFor(() => expect(showToast).toHaveBeenCalledTimes(1));
|
|
96
|
+
expect(refresh).not.toHaveBeenCalled();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
const RUNTIME_CONFIG_ELEMENT_ID = 'nocobase-runtime-config';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The application server renders the client configuration into every page, and the client reads its mount path and
|
|
7
|
+
* API URL from nowhere else. A test page has no server in front of it, so this puts the same block in place, mounted
|
|
8
|
+
* at `/main`. A test that needs other values removes it and renders its own.
|
|
9
|
+
*/
|
|
10
|
+
function renderClientConfig(): void {
|
|
11
|
+
// Server-side tests run under `@vitest-environment node`, where there is no page to render into.
|
|
12
|
+
if (typeof document === 'undefined') return;
|
|
13
|
+
if (document.getElementById(RUNTIME_CONFIG_ELEMENT_ID)) return;
|
|
14
|
+
const element = document.createElement('script');
|
|
15
|
+
element.id = RUNTIME_CONFIG_ELEMENT_ID;
|
|
16
|
+
element.type = 'application/json';
|
|
17
|
+
element.textContent = JSON.stringify({
|
|
18
|
+
version: 1,
|
|
19
|
+
config: { app: { basePath: '/main' }, api: { baseURL: '/main/api' } },
|
|
20
|
+
});
|
|
21
|
+
document.head.append(element);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Before the test file is imported, as the server renders it before the entry module runs: some modules resolve
|
|
25
|
+
// URLs at the top level.
|
|
26
|
+
renderClientConfig();
|
|
27
|
+
beforeEach(renderClientConfig);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@nocobase/dev-config/tsconfig/client.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo"
|
|
5
|
+
},
|
|
6
|
+
// A workflow package's client form is browser code that the application's
|
|
7
|
+
// Vite build resolves through the workflow plugin's virtual module, so it is
|
|
8
|
+
// typechecked here rather than by the server build.
|
|
9
|
+
"include": ["client", "workflows/*/client"],
|
|
10
|
+
"exclude": ["registry"]
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@nocobase/dev-config/tsconfig/node-tooling.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
|
|
5
|
+
},
|
|
6
|
+
"include": [
|
|
7
|
+
"vite.config.ts",
|
|
8
|
+
"cli/**/*.ts",
|
|
9
|
+
"playwright.config.ts",
|
|
10
|
+
"tests/playwright/**/*.ts"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@nocobase/dev-config/tsconfig/server-library.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// Application configuration factories infer exports during the full TypeScript build.
|
|
5
|
+
"isolatedDeclarations": false,
|
|
6
|
+
// tsc-alias completes relative ESM paths after compilation.
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"rootDir": ".",
|
|
10
|
+
"outDir": "dist"
|
|
11
|
+
},
|
|
12
|
+
"tsc-alias": { "resolveFullPaths": true },
|
|
13
|
+
"include": [
|
|
14
|
+
"server/**/*.ts",
|
|
15
|
+
"database/**/*.ts",
|
|
16
|
+
"cli/**/*.ts",
|
|
17
|
+
"workflows/**/*.ts"
|
|
18
|
+
]
|
|
19
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { createAppViteConfig } from '@nocobase/dev-config/vite/app';
|
|
2
|
+
import { loadAppVitePlugins } from '@nocobase/dev-config/vite/plugins';
|
|
3
|
+
import agentAnnotations from '@gchust/agent-annotations/vite';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import {
|
|
6
|
+
createDevClientConfigPlugin,
|
|
7
|
+
createDevProxy,
|
|
8
|
+
} from '@nocobase/app-cli/dev/proxy';
|
|
9
|
+
|
|
10
|
+
const AGENT_ANNOTATIONS_DISABLED_VALUES = new Set(['false', '0', 'no', 'off']);
|
|
11
|
+
|
|
12
|
+
function isAgentAnnotationsEnabled(value: string | undefined): boolean {
|
|
13
|
+
const normalized = value?.trim().toLowerCase();
|
|
14
|
+
return !normalized || !AGENT_ANNOTATIONS_DISABLED_VALUES.has(normalized);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const numberFromEnv = (value: string | undefined): number | undefined => {
|
|
18
|
+
const parsed = Number(value);
|
|
19
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// https://vite.dev/config/
|
|
23
|
+
export default createAppViteConfig(async (environment) => {
|
|
24
|
+
const command = environment.command;
|
|
25
|
+
// Configuration is loaded by the application runtime. Vite should only
|
|
26
|
+
// consume the environment explicitly supplied by the invoking process;
|
|
27
|
+
// reading .env here would make the client and server use different paths.
|
|
28
|
+
const env = process.env;
|
|
29
|
+
// `pnpm dev` passes the mount path it resolved; the preset serves from it, and a build does not depend on one.
|
|
30
|
+
const appBase = env.APP_BASE_PATH ?? '';
|
|
31
|
+
const devClientConfig =
|
|
32
|
+
command === 'serve'
|
|
33
|
+
? createDevClientConfigPlugin(appBase, env.PROXY_TARGET_URL)
|
|
34
|
+
: undefined;
|
|
35
|
+
const annotationsEnabled = isAgentAnnotationsEnabled(
|
|
36
|
+
env.AGENT_ANNOTATIONS_ENABLED,
|
|
37
|
+
);
|
|
38
|
+
const viteHmrHost = env.APP_VITE_HMR_HOST;
|
|
39
|
+
const viteDevPort = numberFromEnv(env.APP_VITE_DEV_PORT) ?? 5173;
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
root: __dirname,
|
|
43
|
+
...(command === 'build' ? { base: env.CDN_BASE_URL?.trim() || './' } : {}),
|
|
44
|
+
plugins: [
|
|
45
|
+
...(await loadAppVitePlugins({ appRoot: __dirname, environment })),
|
|
46
|
+
...(devClientConfig ? [devClientConfig] : []),
|
|
47
|
+
...(annotationsEnabled
|
|
48
|
+
? [
|
|
49
|
+
agentAnnotations({
|
|
50
|
+
root: __dirname,
|
|
51
|
+
clientExtensions: [
|
|
52
|
+
path.resolve(__dirname, 'client/agent-annotations-host.ts'),
|
|
53
|
+
],
|
|
54
|
+
}),
|
|
55
|
+
]
|
|
56
|
+
: []),
|
|
57
|
+
],
|
|
58
|
+
server: {
|
|
59
|
+
proxy:
|
|
60
|
+
command === 'serve'
|
|
61
|
+
? createDevProxy(appBase, env.PROXY_TARGET_URL)
|
|
62
|
+
: undefined,
|
|
63
|
+
watch: {
|
|
64
|
+
ignored: [
|
|
65
|
+
'**/.agent-annotations/**',
|
|
66
|
+
'**/storage/**',
|
|
67
|
+
// Vite only excludes dist/client automatically. The server build and
|
|
68
|
+
// vendored packages also live in dist and can exhaust file watchers.
|
|
69
|
+
// Scope this to the app so linked dependencies still receive HMR.
|
|
70
|
+
(filePath: string) => {
|
|
71
|
+
const relativePath = path.relative(__dirname, filePath);
|
|
72
|
+
return (
|
|
73
|
+
relativePath === 'dist' ||
|
|
74
|
+
relativePath.startsWith(`dist${path.sep}`)
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
...(command === 'serve'
|
|
80
|
+
? {
|
|
81
|
+
hmr: {
|
|
82
|
+
...(viteHmrHost ? { host: viteHmrHost } : {}),
|
|
83
|
+
clientPort: viteDevPort,
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
: {}),
|
|
87
|
+
},
|
|
88
|
+
resolve: {
|
|
89
|
+
dedupe: ['react', 'react-dom', 'react-router'],
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
});
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
|
|
3
|
+
import { createReactVitestConfig } from '@nocobase/dev-config/vitest/react';
|
|
4
|
+
|
|
5
|
+
const root = fileURLToPath(new URL('.', import.meta.url));
|
|
6
|
+
|
|
7
|
+
export default createReactVitestConfig({
|
|
8
|
+
test: {
|
|
9
|
+
root,
|
|
10
|
+
server: {
|
|
11
|
+
deps: {
|
|
12
|
+
// Transform the public Client surfaces so vi.mock applies, without duplicating the Server packages' identity tokens.
|
|
13
|
+
inline: [
|
|
14
|
+
// The authentication guards read the location, so they share the test's react-router rather than Node's copy,
|
|
15
|
+
// together with every client that resolves the authentication tokens and provider.
|
|
16
|
+
/@nocobase\/app-plugin-(?:authentication|api-keys|users)\/(?:dist\/)?client\//u,
|
|
17
|
+
/@nocobase\/app-plugin-authorization\/(?:dist\/)?client\//u,
|
|
18
|
+
/@nocobase\/app-plugin-notification-in-app\/(?:dist\/)?client\//u,
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
// A glob rather than a list of filenames. The list had to be edited by hand for every test added or removed and
|
|
23
|
+
// silently drifted: it named a file that no longer existed while several real test files were absent from it, so
|
|
24
|
+
// those tests were never run at all.
|
|
25
|
+
include: ['tests/**/*.test.{ts,tsx}'],
|
|
26
|
+
// Playwright runs tests/playwright/ against a built application; its files are named *.test.ts too.
|
|
27
|
+
exclude: ['tests/playwright/**'],
|
|
28
|
+
setupFiles: ['./tests/setup/client-config.ts'],
|
|
29
|
+
// Keep the command usable if an application intentionally removes all scaffold tests before adding its own.
|
|
30
|
+
passWithNoTests: true,
|
|
31
|
+
coverage: {
|
|
32
|
+
provider: 'v8',
|
|
33
|
+
reportsDirectory: './coverage',
|
|
34
|
+
reporter: ['text', 'html'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
package/README.md
DELETED