@nocobase/portal-template-default 1.0.4 → 1.0.6
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/README.MD +77 -0
- package/package.json +23 -17
- package/registry/nocobase-acl/demo/prompt-generator.tsx +6 -39
- package/registry/nocobase-acl/demo/role-switcher-prompt-generator.tsx +6 -42
- package/registry/nocobase-ai/demo/page-context-prompt-generator.tsx +1 -1
- package/registry/nocobase-ai/demo/prompt-card.tsx +7 -28
- package/registry/nocobase-ai/demo/prompt-generator.tsx +9 -30
- package/registry/nocobase-ai/demo/shortcut.tsx +1 -1
- package/registry/nocobase-ai/demo/tool-cards.tsx +10 -30
- package/registry/nocobase-auth-cas/README.md +6 -0
- package/registry/nocobase-auth-cas/cas-sign-in-button.tsx +41 -0
- package/registry/nocobase-auth-cas/demo.tsx +20 -0
- package/registry/nocobase-auth-cas/extension.tsx +46 -0
- package/registry/nocobase-auth-cas/index.ts +1 -0
- package/registry/nocobase-auth-cas/use-cas-sign-in.ts +29 -0
- package/registry/nocobase-auth-dingtalk/README.md +7 -0
- package/registry/nocobase-auth-dingtalk/auto-login-provider.tsx +154 -0
- package/registry/nocobase-auth-dingtalk/demo.tsx +23 -0
- package/registry/nocobase-auth-dingtalk/dingtalk-sign-in-button.tsx +45 -0
- package/registry/nocobase-auth-dingtalk/extension.tsx +55 -0
- package/registry/nocobase-auth-dingtalk/index.ts +4 -0
- package/registry/nocobase-auth-dingtalk/use-dingtalk-sign-in.ts +64 -0
- package/registry/nocobase-auth-ldap/README.md +6 -0
- package/registry/nocobase-auth-ldap/demo.tsx +21 -0
- package/registry/nocobase-auth-ldap/extension.tsx +46 -0
- package/registry/nocobase-auth-ldap/index.ts +1 -0
- package/registry/nocobase-auth-ldap/ldap-sign-in-form.tsx +69 -0
- package/registry/nocobase-auth-ldap/use-ldap-sign-in.ts +5 -0
- package/registry/nocobase-auth-oidc/README.md +11 -0
- package/registry/nocobase-auth-oidc/auto-redirect-provider.tsx +13 -0
- package/registry/nocobase-auth-oidc/demo.tsx +20 -0
- package/registry/nocobase-auth-oidc/extension.tsx +51 -0
- package/registry/nocobase-auth-oidc/index.ts +1 -0
- package/registry/nocobase-auth-oidc/oidc-sign-in-button.tsx +44 -0
- package/registry/nocobase-auth-oidc/use-oidc-sign-in.ts +58 -0
- package/registry/nocobase-auth-saml/README.md +6 -0
- package/registry/nocobase-auth-saml/auto-redirect-provider.tsx +13 -0
- package/registry/nocobase-auth-saml/demo.tsx +20 -0
- package/registry/nocobase-auth-saml/extension.tsx +51 -0
- package/registry/nocobase-auth-saml/index.ts +1 -0
- package/registry/nocobase-auth-saml/saml-sign-in-button.tsx +43 -0
- package/registry/nocobase-auth-saml/use-saml-sign-in.ts +51 -0
- package/registry/nocobase-auth-sms/README.md +7 -0
- package/registry/nocobase-auth-sms/demo.tsx +25 -0
- package/registry/nocobase-auth-sms/extension.tsx +46 -0
- package/registry/nocobase-auth-sms/index.ts +1 -0
- package/registry/nocobase-auth-sms/sms-sign-in-form.tsx +107 -0
- package/registry/nocobase-auth-sms/use-sms-sign-in.ts +88 -0
- package/registry/nocobase-auth-wecom/README.md +6 -0
- package/registry/nocobase-auth-wecom/auto-login-provider.tsx +21 -0
- package/registry/nocobase-auth-wecom/demo.tsx +23 -0
- package/registry/nocobase-auth-wecom/extension.tsx +49 -0
- package/registry/nocobase-auth-wecom/index.ts +1 -0
- package/registry/nocobase-auth-wecom/use-wecom-sign-in.ts +62 -0
- package/registry/nocobase-auth-wecom/wecom-sign-in-button.tsx +70 -0
- package/registry/nocobase-i18n/demo/prompt-generator.tsx +30 -54
- package/registry/nocobase-route-surfaces/demo/prompt-generator.tsx +18 -21
- package/registry.config.json +112 -0
- package/scripts/build-html.mjs +106 -0
- package/src/App.tsx +34 -8
- package/src/app/extension.ts +4 -0
- package/src/app/extensions.tsx +24 -1
- package/src/components/auth/authenticator-adapters.ts +20 -0
- package/src/components/auth/auto-redirect-provider.tsx +84 -0
- package/src/components/auth/basic-sign-in-form.tsx +101 -0
- package/src/components/auth/default-sign-in-page.tsx +20 -0
- package/src/components/auth/demo/auth-demo-page.tsx +236 -0
- package/src/components/auth/demo/auth-demo-prompt-generator.tsx +93 -0
- package/src/components/auth/demo/auth-demo-route.tsx +11 -0
- package/src/components/auth/demo/auth-method-demo.tsx +48 -0
- package/src/components/auth/demo/index.ts +4 -0
- package/src/components/auth/dynamic-sign-in.tsx +191 -0
- package/src/components/auth/forgot-password-form.tsx +13 -5
- package/src/components/auth/index.ts +13 -0
- package/src/components/auth/sign-in-form.tsx +1 -111
- package/src/components/auth/sign-up-form.tsx +14 -37
- package/src/components/auth/types.ts +38 -0
- package/src/components/auth/use-authenticator-sign-in.ts +14 -0
- package/src/components/auth/use-public-authenticators.ts +26 -0
- package/src/components/data-table/data-table-filter.tsx +107 -153
- package/src/components/demo/prompt-output.tsx +71 -0
- package/src/components/ui/alert-dialog.tsx +2 -0
- package/src/components/ui/attachment.tsx +207 -0
- package/src/components/ui/bubble.tsx +128 -0
- package/src/components/ui/button-group.tsx +87 -0
- package/src/components/ui/button.tsx +6 -6
- package/src/components/ui/calendar.tsx +0 -2
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/carousel.tsx +2 -0
- package/src/components/ui/combobox.tsx +297 -0
- package/src/components/ui/command.tsx +43 -41
- package/src/components/ui/dialog.tsx +0 -2
- package/src/components/ui/direction.tsx +4 -0
- package/src/components/ui/drawer.tsx +2 -0
- package/src/components/ui/dropdown-menu.tsx +0 -2
- package/src/components/ui/empty.tsx +104 -0
- package/src/components/ui/field.tsx +238 -0
- package/src/components/ui/hover-card.tsx +2 -0
- package/src/components/ui/input-group.tsx +0 -2
- package/src/components/ui/input-otp.tsx +0 -2
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/item.tsx +201 -0
- package/src/components/ui/kbd.tsx +26 -0
- package/src/components/ui/label.tsx +2 -0
- package/src/components/ui/marker.tsx +71 -0
- package/src/components/ui/message-scroller.tsx +131 -0
- package/src/components/ui/message.tsx +92 -0
- package/src/components/ui/native-select.tsx +61 -0
- package/src/components/ui/popover.tsx +0 -2
- package/src/components/ui/progress.tsx +2 -0
- package/src/components/ui/radio-group.tsx +0 -2
- package/src/components/ui/resizable.tsx +2 -0
- package/src/components/ui/scroll-area.tsx +0 -2
- package/src/components/ui/select.tsx +6 -4
- package/src/components/ui/separator.tsx +0 -2
- package/src/components/ui/sheet.tsx +21 -22
- package/src/components/ui/sidebar.tsx +1 -3
- package/src/components/ui/sonner.tsx +2 -0
- package/src/components/ui/spinner.tsx +10 -0
- package/src/components/ui/switch.tsx +0 -2
- package/src/components/ui/table.tsx +4 -2
- package/src/components/ui/tabs.tsx +0 -2
- package/src/components/ui/textarea.tsx +1 -1
- package/src/components/ui/toggle-group.tsx +2 -0
- package/src/components/ui/toggle.tsx +2 -0
- package/src/components/ui/tooltip.tsx +0 -2
- package/src/index.tsx +3 -0
- package/src/lib/nocobase/client.ts +32 -2
- package/src/lib/utils.ts +2 -1
- package/src/locales/en-US.ts +4 -2
- package/src/locales/zh-CN.ts +4 -2
- package/src/pages/login/index.tsx +2 -2
- package/src/pages/users/list.tsx +144 -16
- package/src/providers/auth-callback.ts +21 -0
- package/src/providers/auth.ts +108 -22
- package/src/providers/constants.ts +4 -1
- package/src/providers/runtime-config.ts +19 -0
- package/src/vite-env.d.ts +5 -0
- package/vite.config.ts +55 -2
package/README.MD
CHANGED
|
@@ -24,6 +24,83 @@ namespace for shared controls. Feature-specific Registry translations remain
|
|
|
24
24
|
inside their own extension namespace and are not mixed into application locale
|
|
25
25
|
files.
|
|
26
26
|
|
|
27
|
+
### Authentication UI
|
|
28
|
+
|
|
29
|
+
The default login page calls `authenticators:publicList` and renders every
|
|
30
|
+
enabled NocoBase authenticator that has a frontend adapter installed. Basic
|
|
31
|
+
username/password authentication is built into the Starter. Optional methods
|
|
32
|
+
are installed independently:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pnpm exec shadcn add @nocobase/auth-sms
|
|
36
|
+
pnpm exec shadcn add @nocobase/auth-ldap
|
|
37
|
+
pnpm exec shadcn add @nocobase/auth-oidc
|
|
38
|
+
pnpm exec shadcn add @nocobase/auth-saml
|
|
39
|
+
pnpm exec shadcn add @nocobase/auth-cas
|
|
40
|
+
pnpm exec shadcn add @nocobase/auth-wecom
|
|
41
|
+
pnpm exec shadcn add @nocobase/auth-dingtalk
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The Starter includes an Authentication Demo for the three customization
|
|
45
|
+
boundaries below. Each optional authentication Registry adds its own component
|
|
46
|
+
Demo under the same Authentication menu when installed.
|
|
47
|
+
|
|
48
|
+
The application login page remains the customization boundary. Keep the
|
|
49
|
+
default dynamic page with:
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { DefaultSignInPage } from "@/components/auth/default-sign-in-page"
|
|
53
|
+
|
|
54
|
+
export const Login = () => <DefaultSignInPage />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
To replace only one authenticator UI, use `renderAuthenticator` and return the
|
|
58
|
+
default element for everything else:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { DefaultSignInPage } from "@/components/auth/default-sign-in-page"
|
|
62
|
+
import { useOidcSignIn } from "@/extensions/nocobase-auth-oidc"
|
|
63
|
+
import { Button } from "@/components/ui/button"
|
|
64
|
+
|
|
65
|
+
function CompanyOidcButton({ authenticator }) {
|
|
66
|
+
const oidc = useOidcSignIn(authenticator)
|
|
67
|
+
return <Button onClick={oidc.signIn}>Company SSO</Button>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const Login = () => (
|
|
71
|
+
<DefaultSignInPage
|
|
72
|
+
renderAuthenticator={({ authenticator, defaultElement }) =>
|
|
73
|
+
authenticator.name === "company-oidc" ? (
|
|
74
|
+
<CompanyOidcButton authenticator={authenticator} />
|
|
75
|
+
) : (
|
|
76
|
+
defaultElement
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
/>
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Replace `src/pages/login/index.tsx` completely when the application needs a
|
|
84
|
+
fully custom login page. Token callback capture, current authenticator storage,
|
|
85
|
+
request headers, and logout behavior remain provided by the Starter runtime and
|
|
86
|
+
do not depend on `DefaultSignInPage`.
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { AuthLayout } from "@/components/auth/auth-layout"
|
|
90
|
+
import { BasicSignInForm } from "@/components/auth"
|
|
91
|
+
|
|
92
|
+
export const Login = () => (
|
|
93
|
+
<AuthLayout title="Sign in" description="Continue to your workspace.">
|
|
94
|
+
<BasicSignInForm
|
|
95
|
+
authenticator={{
|
|
96
|
+
name: "basic",
|
|
97
|
+
authType: "Email/Password",
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
</AuthLayout>
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
27
104
|
## Available Scripts
|
|
28
105
|
|
|
29
106
|
### Running the development server.
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/portal-template-default",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"devDependencies": {
|
|
6
6
|
"@ai-sdk/react": "2.0.0",
|
|
7
7
|
"@base-ui/react": "^1.6.0",
|
|
8
8
|
"@dicebear/core": "^9.4.3",
|
|
9
|
+
"@eslint/js": "^9.25.0",
|
|
9
10
|
"@fontsource-variable/geist": "^5.3.0",
|
|
10
11
|
"@hookform/resolvers": "^5.0.1",
|
|
11
12
|
"@nocobase/ai-employee-avatars": "^1.0.2",
|
|
@@ -17,18 +18,31 @@
|
|
|
17
18
|
"@refinedev/react-table": "^6.0.0",
|
|
18
19
|
"@refinedev/rest": "^2.1.0",
|
|
19
20
|
"@refinedev/simple-rest": "^6.0.0",
|
|
21
|
+
"@tailwindcss/postcss": "^4.1.4",
|
|
20
22
|
"@tailwindcss/vite": "^4.1.8",
|
|
21
23
|
"@tanstack/react-query": "^5.81.5",
|
|
22
24
|
"@tanstack/react-table": "^8.2.6",
|
|
25
|
+
"@types/node": "^20",
|
|
26
|
+
"@types/react": "^19.1.0",
|
|
27
|
+
"@types/react-dom": "^19.1.0",
|
|
28
|
+
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
|
29
|
+
"@typescript-eslint/parser": "^5.57.1",
|
|
30
|
+
"@vitejs/plugin-react": "^4.4.1",
|
|
23
31
|
"ai": "5.0.0",
|
|
24
32
|
"class-variance-authority": "^0.7.1",
|
|
25
33
|
"clsx": "^2.1.1",
|
|
26
34
|
"date-fns": "^4.1.0",
|
|
27
35
|
"dayjs": "^1.10.7",
|
|
36
|
+
"dingtalk-jsapi": "3.1.1",
|
|
28
37
|
"echarts": "^5.5.0",
|
|
29
38
|
"echarts-for-react": "3.0.2",
|
|
30
39
|
"embla-carousel-react": "^8.6.0",
|
|
40
|
+
"eslint": "^9.25.0",
|
|
41
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
42
|
+
"eslint-plugin-react-refresh": "^0.4.19",
|
|
31
43
|
"eventsource-parser": "3.1.0",
|
|
44
|
+
"globals": "^16.0.0",
|
|
45
|
+
"i18next": "^25.3.2",
|
|
32
46
|
"ignore": "^7.0.6",
|
|
33
47
|
"input-otp": "^1.4.2",
|
|
34
48
|
"lucide-react": "^0.487.0",
|
|
@@ -46,25 +60,12 @@
|
|
|
46
60
|
"shadcn": "^4.13.1",
|
|
47
61
|
"sonner": "^2.0.3",
|
|
48
62
|
"tailwind-merge": "^3.2.0",
|
|
49
|
-
"tw-animate-css": "^1.2.5",
|
|
50
|
-
"zod": "^3.24.3",
|
|
51
|
-
"@eslint/js": "^9.25.0",
|
|
52
|
-
"@tailwindcss/postcss": "^4.1.4",
|
|
53
|
-
"@types/node": "^20",
|
|
54
|
-
"@types/react": "^19.1.0",
|
|
55
|
-
"@types/react-dom": "^19.1.0",
|
|
56
|
-
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
|
57
|
-
"@typescript-eslint/parser": "^5.57.1",
|
|
58
|
-
"@vitejs/plugin-react": "^4.4.1",
|
|
59
|
-
"eslint": "^9.25.0",
|
|
60
|
-
"eslint-plugin-react-hooks": "^5.2.0",
|
|
61
|
-
"eslint-plugin-react-refresh": "^0.4.19",
|
|
62
|
-
"globals": "^16.0.0",
|
|
63
|
-
"i18next": "^25.3.2",
|
|
64
63
|
"tailwindcss": "^4.1.4",
|
|
64
|
+
"tw-animate-css": "^1.2.5",
|
|
65
65
|
"typescript": "^5.8.3",
|
|
66
66
|
"typescript-eslint": "^8.30.1",
|
|
67
|
-
"vite": "^6.3.5"
|
|
67
|
+
"vite": "^6.3.5",
|
|
68
|
+
"zod": "^3.25.76"
|
|
68
69
|
},
|
|
69
70
|
"publishConfig": {
|
|
70
71
|
"access": "public"
|
|
@@ -77,6 +78,7 @@
|
|
|
77
78
|
"postinstall": "node ./scripts/registry.mjs install-missing",
|
|
78
79
|
"dev": "vite",
|
|
79
80
|
"build": "tsc && refine build",
|
|
81
|
+
"build:html": "node ./scripts/build-html.mjs",
|
|
80
82
|
"registry:install": "node ./scripts/registry.mjs install-missing",
|
|
81
83
|
"registry:preview": "node ./scripts/registry.mjs preview",
|
|
82
84
|
"registry:build": "node ./scripts/registry.mjs build && shadcn build ./registry.json -o ./public/r",
|
|
@@ -96,5 +98,9 @@
|
|
|
96
98
|
"last 1 firefox version",
|
|
97
99
|
"last 1 safari version"
|
|
98
100
|
]
|
|
101
|
+
},
|
|
102
|
+
"dependencies": {
|
|
103
|
+
"@shadcn/react": "^0.2.1",
|
|
104
|
+
"cmdk": "^1.1.1"
|
|
99
105
|
}
|
|
100
106
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChevronDown, Sparkles } from "lucide-react";
|
|
2
2
|
import { useMemo, useState } from "react";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { PromptOutput } from "@/components/demo/prompt-output";
|
|
5
5
|
import {
|
|
6
6
|
Card,
|
|
7
7
|
CardContent,
|
|
@@ -28,8 +28,6 @@ export function AclScenarioPromptGenerator({
|
|
|
28
28
|
}) {
|
|
29
29
|
const [scene, setScene] = useState(config.defaultScene);
|
|
30
30
|
const [target, setTarget] = useState(config.defaultTarget);
|
|
31
|
-
const [copied, setCopied] = useState(false);
|
|
32
|
-
const [copyError, setCopyError] = useState(false);
|
|
33
31
|
|
|
34
32
|
const prompt = useMemo(
|
|
35
33
|
() => `Build a complete NocoBase ACL scene in the NocoBase Admin Starter.
|
|
@@ -93,41 +91,10 @@ Implementation contract
|
|
|
93
91
|
</div>
|
|
94
92
|
</CardContent>
|
|
95
93
|
</Card>
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<div className="text-xs text-muted-foreground">
|
|
101
|
-
Updates as you change the business scene and permission target.
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
<Button
|
|
105
|
-
size="sm"
|
|
106
|
-
onClick={async () => {
|
|
107
|
-
try {
|
|
108
|
-
await navigator.clipboard.writeText(prompt);
|
|
109
|
-
setCopyError(false);
|
|
110
|
-
setCopied(true);
|
|
111
|
-
window.setTimeout(() => setCopied(false), 1500);
|
|
112
|
-
} catch {
|
|
113
|
-
setCopyError(true);
|
|
114
|
-
}
|
|
115
|
-
}}
|
|
116
|
-
>
|
|
117
|
-
{copied ? <Check /> : <Copy />}
|
|
118
|
-
{copied ? "Copied" : "Copy prompt"}
|
|
119
|
-
</Button>
|
|
120
|
-
</div>
|
|
121
|
-
{copyError ? (
|
|
122
|
-
<p className="border-b px-4 py-2 text-xs text-destructive">
|
|
123
|
-
Clipboard access failed. Select the prompt text and copy it
|
|
124
|
-
manually.
|
|
125
|
-
</p>
|
|
126
|
-
) : null}
|
|
127
|
-
<pre className="max-h-[520px] overflow-auto whitespace-pre-wrap bg-muted/25 p-5 font-mono text-xs leading-5 text-muted-foreground">
|
|
128
|
-
{prompt}
|
|
129
|
-
</pre>
|
|
130
|
-
</Card>
|
|
94
|
+
<PromptOutput
|
|
95
|
+
description="Updates as you change the business scene and permission target."
|
|
96
|
+
prompt={prompt}
|
|
97
|
+
/>
|
|
131
98
|
</div>
|
|
132
99
|
</details>
|
|
133
100
|
);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Check, Copy } from "lucide-react";
|
|
2
1
|
import { useMemo, useState } from "react";
|
|
3
2
|
|
|
4
|
-
import {
|
|
3
|
+
import { PromptOutput } from "@/components/demo/prompt-output";
|
|
5
4
|
import {
|
|
6
5
|
Card,
|
|
7
6
|
CardContent,
|
|
@@ -54,8 +53,6 @@ export function RoleSwitcherPromptGenerator() {
|
|
|
54
53
|
const [surface, setSurface] = useState(
|
|
55
54
|
"Use the Starter's existing account controls and visual language. Do not create a separate demo page."
|
|
56
55
|
);
|
|
57
|
-
const [copied, setCopied] = useState(false);
|
|
58
|
-
const [copyError, setCopyError] = useState(false);
|
|
59
56
|
|
|
60
57
|
const prompt = useMemo(
|
|
61
58
|
() => `Integrate the RoleSwitcher into the existing NocoBase Admin Starter.
|
|
@@ -155,44 +152,11 @@ Integration requirements
|
|
|
155
152
|
</CardContent>
|
|
156
153
|
</Card>
|
|
157
154
|
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
</div>
|
|
164
|
-
<div className="text-xs text-muted-foreground">
|
|
165
|
-
Updates as you change placement and presentation settings.
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
<Button
|
|
169
|
-
size="sm"
|
|
170
|
-
onClick={async () => {
|
|
171
|
-
try {
|
|
172
|
-
await navigator.clipboard.writeText(prompt);
|
|
173
|
-
setCopyError(false);
|
|
174
|
-
setCopied(true);
|
|
175
|
-
window.setTimeout(() => setCopied(false), 1500);
|
|
176
|
-
} catch {
|
|
177
|
-
setCopyError(true);
|
|
178
|
-
}
|
|
179
|
-
}}
|
|
180
|
-
>
|
|
181
|
-
{copied ? <Check /> : <Copy />}
|
|
182
|
-
{copied ? "Copied" : "Copy prompt"}
|
|
183
|
-
</Button>
|
|
184
|
-
</div>
|
|
185
|
-
{copyError ? (
|
|
186
|
-
<p className="border-b px-4 py-2 text-xs text-destructive">
|
|
187
|
-
Clipboard access failed. Select the prompt and copy it manually.
|
|
188
|
-
</p>
|
|
189
|
-
) : null}
|
|
190
|
-
<CardContent className="p-0">
|
|
191
|
-
<pre className="max-h-[560px] overflow-auto whitespace-pre-wrap bg-muted/25 p-5 font-mono text-xs leading-5 text-muted-foreground">
|
|
192
|
-
{prompt}
|
|
193
|
-
</pre>
|
|
194
|
-
</CardContent>
|
|
195
|
-
</Card>
|
|
155
|
+
<PromptOutput
|
|
156
|
+
title="Generated integration prompt"
|
|
157
|
+
description="Updates as you change placement and presentation settings."
|
|
158
|
+
prompt={prompt}
|
|
159
|
+
/>
|
|
196
160
|
</div>
|
|
197
161
|
);
|
|
198
162
|
}
|
|
@@ -155,7 +155,7 @@ Implementation requirements
|
|
|
155
155
|
]);
|
|
156
156
|
|
|
157
157
|
return (
|
|
158
|
-
<div className="grid items-start gap-5 xl:grid-cols-[
|
|
158
|
+
<div className="grid items-start gap-5 xl:grid-cols-[360px_minmax(0,1fr)]">
|
|
159
159
|
<Card className="gap-0 py-0">
|
|
160
160
|
<CardHeader className="border-b py-4">
|
|
161
161
|
<CardTitle>Scene settings</CardTitle>
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Card } from "@/components/ui/card";
|
|
3
|
-
import { Check, Copy } from "lucide-react";
|
|
4
|
-
import { useState } from "react";
|
|
1
|
+
import { PromptOutput } from "@/components/demo/prompt-output";
|
|
5
2
|
|
|
6
3
|
export function PromptCard({
|
|
7
4
|
title,
|
|
@@ -12,30 +9,12 @@ export function PromptCard({
|
|
|
12
9
|
description: string;
|
|
13
10
|
prompt: string;
|
|
14
11
|
}) {
|
|
15
|
-
const [copied, setCopied] = useState(false);
|
|
16
|
-
|
|
17
12
|
return (
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<Button
|
|
25
|
-
size="sm"
|
|
26
|
-
onClick={async () => {
|
|
27
|
-
await navigator.clipboard.writeText(prompt);
|
|
28
|
-
setCopied(true);
|
|
29
|
-
window.setTimeout(() => setCopied(false), 1500);
|
|
30
|
-
}}
|
|
31
|
-
>
|
|
32
|
-
{copied ? <Check /> : <Copy />}
|
|
33
|
-
{copied ? "Copied" : "Copy prompt"}
|
|
34
|
-
</Button>
|
|
35
|
-
</div>
|
|
36
|
-
<pre className="max-h-[620px] overflow-auto whitespace-pre-wrap bg-muted/25 p-5 font-mono text-xs leading-5 text-muted-foreground">
|
|
37
|
-
{prompt}
|
|
38
|
-
</pre>
|
|
39
|
-
</Card>
|
|
13
|
+
<PromptOutput
|
|
14
|
+
title={title}
|
|
15
|
+
description={description}
|
|
16
|
+
prompt={prompt}
|
|
17
|
+
promptClassName="max-h-[620px]"
|
|
18
|
+
/>
|
|
40
19
|
);
|
|
41
20
|
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
useAIPageElementPicker,
|
|
7
7
|
type AIChatComposerAction,
|
|
8
8
|
} from "../components";
|
|
9
|
-
import {
|
|
9
|
+
import { PromptOutput } from "@/components/demo/prompt-output";
|
|
10
10
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
11
11
|
import { Input } from "@/components/ui/input";
|
|
12
12
|
import {
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "@/components/ui/select";
|
|
19
19
|
import { Switch } from "@/components/ui/switch";
|
|
20
20
|
import { AIChatProvider, useAIChatBase } from "../providers";
|
|
21
|
-
import {
|
|
21
|
+
import { Globe2, MousePointer2 } from "lucide-react";
|
|
22
22
|
import { useMemo, useState } from "react";
|
|
23
23
|
import type { ChatContainer } from "./container-showcase";
|
|
24
24
|
|
|
@@ -95,7 +95,6 @@ function PromptGeneratorContent() {
|
|
|
95
95
|
const [messagePresentation, setMessagePresentation] =
|
|
96
96
|
useState<MessagePresentation>("transcript");
|
|
97
97
|
const [capabilities, setCapabilities] = useState(DEFAULT_CAPABILITIES);
|
|
98
|
-
const [copied, setCopied] = useState(false);
|
|
99
98
|
|
|
100
99
|
const previewActions = useMemo<AIChatComposerAction[]>(() => {
|
|
101
100
|
const actions: AIChatComposerAction[] = [];
|
|
@@ -275,7 +274,7 @@ Implementation requirements:
|
|
|
275
274
|
})();
|
|
276
275
|
|
|
277
276
|
return (
|
|
278
|
-
<div className="grid items-start gap-5 xl:grid-cols-[
|
|
277
|
+
<div className="grid items-start gap-5 xl:grid-cols-[360px_minmax(0,1fr)]">
|
|
279
278
|
<Card className="gap-0 py-0">
|
|
280
279
|
<CardHeader className="border-b py-4">
|
|
281
280
|
<CardTitle className="text-base">Describe the integration</CardTitle>
|
|
@@ -405,32 +404,12 @@ Implementation requirements:
|
|
|
405
404
|
</div>
|
|
406
405
|
</Card>
|
|
407
406
|
|
|
408
|
-
<
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
<div className="text-xs text-muted-foreground">
|
|
415
|
-
Updates from the selected page, placement, and capabilities.
|
|
416
|
-
</div>
|
|
417
|
-
</div>
|
|
418
|
-
<Button
|
|
419
|
-
size="sm"
|
|
420
|
-
onClick={async () => {
|
|
421
|
-
await navigator.clipboard.writeText(prompt);
|
|
422
|
-
setCopied(true);
|
|
423
|
-
window.setTimeout(() => setCopied(false), 1500);
|
|
424
|
-
}}
|
|
425
|
-
>
|
|
426
|
-
{copied ? <Check /> : <Copy />}
|
|
427
|
-
{copied ? "Copied" : "Copy prompt"}
|
|
428
|
-
</Button>
|
|
429
|
-
</div>
|
|
430
|
-
<pre className="max-h-[760px] min-h-[520px] overflow-auto whitespace-pre-wrap bg-muted/25 p-5 font-mono text-xs leading-5 text-muted-foreground">
|
|
431
|
-
{prompt}
|
|
432
|
-
</pre>
|
|
433
|
-
</Card>
|
|
407
|
+
<PromptOutput
|
|
408
|
+
title="Generated implementation prompt"
|
|
409
|
+
description="Updates from the selected page, placement, and capabilities."
|
|
410
|
+
prompt={prompt}
|
|
411
|
+
promptClassName="max-h-[760px] min-h-[520px]"
|
|
412
|
+
/>
|
|
434
413
|
</div>
|
|
435
414
|
</div>
|
|
436
415
|
);
|
|
@@ -678,7 +678,7 @@ Implementation requirements:
|
|
|
678
678
|
task, model, Web search, Skills, and Tools configuration.
|
|
679
679
|
</p>
|
|
680
680
|
</div>
|
|
681
|
-
<div className="grid items-start gap-5 xl:grid-cols-[
|
|
681
|
+
<div className="grid items-start gap-5 xl:grid-cols-[360px_minmax(0,1fr)]">
|
|
682
682
|
<Card className="gap-0 py-0">
|
|
683
683
|
<CardHeader className="py-4">
|
|
684
684
|
<CardTitle className="text-base">
|
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
ToolCallCard,
|
|
3
3
|
type ToolCallPart,
|
|
4
4
|
} from "../components/chat/tool-call-card";
|
|
5
|
+
import { PromptOutput } from "@/components/demo/prompt-output";
|
|
5
6
|
import { Badge } from "@/components/ui/badge";
|
|
6
|
-
import { Button } from "@/components/ui/button";
|
|
7
7
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
8
8
|
import { Input } from "@/components/ui/input";
|
|
9
9
|
import {
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
} from "@/components/ui/select";
|
|
16
16
|
import { Switch } from "@/components/ui/switch";
|
|
17
17
|
import { Textarea } from "@/components/ui/textarea";
|
|
18
|
-
import { Check, Copy } from "lucide-react";
|
|
19
18
|
import { useState } from "react";
|
|
20
19
|
|
|
21
20
|
const tools = {
|
|
@@ -217,8 +216,8 @@ export function ToolCardsPage() {
|
|
|
217
216
|
Tool Cards
|
|
218
217
|
</h1>
|
|
219
218
|
<p className="mt-3 max-w-3xl text-sm leading-6 text-muted-foreground">
|
|
220
|
-
Specialized tools render their complete business interaction.
|
|
221
|
-
|
|
219
|
+
Specialized tools render their complete business interaction. Tools
|
|
220
|
+
without a registered renderer fall back to the shared status,
|
|
222
221
|
approval, error, and input disclosure card.
|
|
223
222
|
</p>
|
|
224
223
|
</div>
|
|
@@ -371,7 +370,6 @@ function ToolCardCodePrompt() {
|
|
|
371
370
|
"Show the affected support records, summarize the proposed changes, and let the user approve, request a revision, or reject the operation."
|
|
372
371
|
);
|
|
373
372
|
const [handlesApproval, setHandlesApproval] = useState(true);
|
|
374
|
-
const [copied, setCopied] = useState(false);
|
|
375
373
|
const referenceDefinition = referenceRenderers[reference];
|
|
376
374
|
const prompt = `Implement a specialized NocoBase AI Tool Card for the tool "${
|
|
377
375
|
toolName || "customTool"
|
|
@@ -410,7 +408,7 @@ Verification:
|
|
|
410
408
|
- Verify the card in light and dark themes, narrow chat panels, expanded dialogs, pending approval, completed, and error states.`;
|
|
411
409
|
|
|
412
410
|
return (
|
|
413
|
-
<div className="grid items-start gap-5 xl:grid-cols-[
|
|
411
|
+
<div className="grid items-start gap-5 xl:grid-cols-[360px_minmax(0,1fr)]">
|
|
414
412
|
<Card className="gap-0 py-0">
|
|
415
413
|
<CardHeader className="border-b py-4">
|
|
416
414
|
<CardTitle className="text-base">Describe the Tool Card</CardTitle>
|
|
@@ -479,30 +477,12 @@ Verification:
|
|
|
479
477
|
</label>
|
|
480
478
|
</CardContent>
|
|
481
479
|
</Card>
|
|
482
|
-
<
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
</div>
|
|
489
|
-
</div>
|
|
490
|
-
<Button
|
|
491
|
-
size="sm"
|
|
492
|
-
onClick={async () => {
|
|
493
|
-
await navigator.clipboard.writeText(prompt);
|
|
494
|
-
setCopied(true);
|
|
495
|
-
window.setTimeout(() => setCopied(false), 1500);
|
|
496
|
-
}}
|
|
497
|
-
>
|
|
498
|
-
{copied ? <Check /> : <Copy />}
|
|
499
|
-
{copied ? "Copied" : "Copy prompt"}
|
|
500
|
-
</Button>
|
|
501
|
-
</div>
|
|
502
|
-
<pre className="max-h-[720px] min-h-[560px] overflow-auto whitespace-pre-wrap bg-muted/25 p-5 font-mono text-xs leading-5 text-muted-foreground">
|
|
503
|
-
{prompt}
|
|
504
|
-
</pre>
|
|
505
|
-
</Card>
|
|
480
|
+
<PromptOutput
|
|
481
|
+
title="Coding prompt"
|
|
482
|
+
description="Ready to paste into an implementation task."
|
|
483
|
+
prompt={prompt}
|
|
484
|
+
promptClassName="max-h-[720px] min-h-[560px]"
|
|
485
|
+
/>
|
|
506
486
|
</div>
|
|
507
487
|
);
|
|
508
488
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { LogIn } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
import type { AuthenticatorComponentProps } from "@/components/auth/types";
|
|
4
|
+
import {
|
|
5
|
+
Alert,
|
|
6
|
+
AlertDescription,
|
|
7
|
+
AlertTitle,
|
|
8
|
+
} from "@/components/ui/alert";
|
|
9
|
+
import { Button } from "@/components/ui/button";
|
|
10
|
+
import { resolveTranslatableText } from "@/lib/i18n";
|
|
11
|
+
|
|
12
|
+
import { useCasSignIn } from "./use-cas-sign-in";
|
|
13
|
+
|
|
14
|
+
export default function CasSignInButton({
|
|
15
|
+
authenticator,
|
|
16
|
+
onSignIn,
|
|
17
|
+
}: AuthenticatorComponentProps & { onSignIn?: () => void }) {
|
|
18
|
+
const { signIn, error } = useCasSignIn(authenticator);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className="space-y-3">
|
|
22
|
+
{error && (
|
|
23
|
+
<Alert variant="destructive">
|
|
24
|
+
<AlertTitle>CAS sign-in failed</AlertTitle>
|
|
25
|
+
<AlertDescription>{error.message}</AlertDescription>
|
|
26
|
+
</Alert>
|
|
27
|
+
)}
|
|
28
|
+
<Button
|
|
29
|
+
type="button"
|
|
30
|
+
variant="outline"
|
|
31
|
+
className="w-full"
|
|
32
|
+
onClick={onSignIn ?? signIn}
|
|
33
|
+
>
|
|
34
|
+
<LogIn />
|
|
35
|
+
{resolveTranslatableText(
|
|
36
|
+
authenticator.title || authenticator.authTypeTitle || "CAS"
|
|
37
|
+
)}
|
|
38
|
+
</Button>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AuthMethodDemo } from "@/components/auth/demo";
|
|
2
|
+
import CasSignInButton from "./cas-sign-in-button";
|
|
3
|
+
|
|
4
|
+
const authenticator = {
|
|
5
|
+
name: "company-cas",
|
|
6
|
+
authType: "CAS",
|
|
7
|
+
title: "Company CAS",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function CasAuthDemoPage() {
|
|
11
|
+
return (
|
|
12
|
+
<AuthMethodDemo
|
|
13
|
+
authType="CAS"
|
|
14
|
+
methodName="Central Authentication Service"
|
|
15
|
+
description="Redirect users to a CAS server and capture the returned NocoBase token without coupling the page UI to CAS."
|
|
16
|
+
>
|
|
17
|
+
<CasSignInButton authenticator={authenticator} onSignIn={() => {}} />
|
|
18
|
+
</AuthMethodDemo>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { lazy } from "react";
|
|
2
|
+
import { KeyRound } from "lucide-react";
|
|
3
|
+
import { Route } from "react-router";
|
|
4
|
+
|
|
5
|
+
import type { AppExtension } from "@/app/extension";
|
|
6
|
+
import { AuthDemoRoute } from "@/components/auth/demo";
|
|
7
|
+
|
|
8
|
+
const CasSignInButton = lazy(() => import("./cas-sign-in-button"));
|
|
9
|
+
const CasAuthDemoPage = lazy(() =>
|
|
10
|
+
import("./demo").then((module) => ({ default: module.CasAuthDemoPage }))
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const casAuthExtension: AppExtension = {
|
|
14
|
+
id: "nocobase-auth-cas",
|
|
15
|
+
resources: [
|
|
16
|
+
{
|
|
17
|
+
name: "auth-cas-demo",
|
|
18
|
+
list: "/auth/cas",
|
|
19
|
+
meta: {
|
|
20
|
+
parent: "auth-components",
|
|
21
|
+
label: "CAS",
|
|
22
|
+
icon: <KeyRound />,
|
|
23
|
+
acl: { type: "authenticated" },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
routes: (
|
|
28
|
+
<Route
|
|
29
|
+
path="/auth/cas"
|
|
30
|
+
element={
|
|
31
|
+
<AuthDemoRoute>
|
|
32
|
+
<CasAuthDemoPage />
|
|
33
|
+
</AuthDemoRoute>
|
|
34
|
+
}
|
|
35
|
+
/>
|
|
36
|
+
),
|
|
37
|
+
authAdapters: [
|
|
38
|
+
{
|
|
39
|
+
authType: "CAS",
|
|
40
|
+
placement: "button",
|
|
41
|
+
Component: CasSignInButton,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default casAuthExtension;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useCasSignIn } from "./use-cas-sign-in";
|