@postxl/generators 1.12.3 → 1.14.0
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/dist/backend-ai/ai.generator.d.ts +18 -0
- package/dist/backend-ai/ai.generator.js +174 -0
- package/dist/backend-ai/ai.generator.js.map +1 -0
- package/dist/backend-ai/generators/ai-agent-service.generator.d.ts +4 -0
- package/dist/backend-ai/generators/ai-agent-service.generator.js +264 -0
- package/dist/backend-ai/generators/ai-agent-service.generator.js.map +1 -0
- package/dist/backend-ai/generators/ai-cache-service.generator.d.ts +1 -0
- package/dist/backend-ai/generators/ai-cache-service.generator.js +110 -0
- package/dist/backend-ai/generators/ai-cache-service.generator.js.map +1 -0
- package/dist/backend-ai/generators/ai-config.generator.d.ts +1 -0
- package/dist/backend-ai/generators/ai-config.generator.js +27 -0
- package/dist/backend-ai/generators/ai-config.generator.js.map +1 -0
- package/dist/backend-ai/generators/ai-module.generator.d.ts +2 -0
- package/dist/backend-ai/generators/ai-module.generator.js +89 -0
- package/dist/backend-ai/generators/ai-module.generator.js.map +1 -0
- package/dist/backend-ai/generators/ai-route.generator.d.ts +1 -0
- package/dist/backend-ai/generators/ai-route.generator.js +29 -0
- package/dist/backend-ai/generators/ai-route.generator.js.map +1 -0
- package/dist/backend-ai/generators/ai-tools-service.generator.d.ts +4 -0
- package/dist/backend-ai/generators/ai-tools-service.generator.js +222 -0
- package/dist/backend-ai/generators/ai-tools-service.generator.js.map +1 -0
- package/dist/backend-ai/generators/model-provider-interface.generator.d.ts +1 -0
- package/dist/backend-ai/generators/model-provider-interface.generator.js +48 -0
- package/dist/backend-ai/generators/model-provider-interface.generator.js.map +1 -0
- package/dist/backend-ai/generators/openai-model-provider-service.generator.d.ts +1 -0
- package/dist/backend-ai/generators/openai-model-provider-service.generator.js +128 -0
- package/dist/backend-ai/generators/openai-model-provider-service.generator.js.map +1 -0
- package/dist/backend-ai/index.d.ts +4 -0
- package/dist/backend-ai/index.js +40 -0
- package/dist/backend-ai/index.js.map +1 -0
- package/dist/backend-authentication/generators/authentication-service.generator.js +1 -1
- package/dist/backend-core/backend.generator.js +0 -4
- package/dist/backend-core/backend.generator.js.map +1 -1
- package/dist/backend-core/generators/main.generator.js +4 -3
- package/dist/backend-core/generators/main.generator.js.map +1 -1
- package/dist/backend-core/modules/backend-module-xlport.generator.js +1 -1
- package/dist/backend-e2e/backend-e2e.generator.js +4 -4
- package/dist/backend-e2e/backend-e2e.generator.js.map +1 -1
- package/dist/backend-excel-io/excel-io.generator.d.ts +19 -0
- package/dist/backend-excel-io/excel-io.generator.js +106 -0
- package/dist/backend-excel-io/excel-io.generator.js.map +1 -0
- package/dist/backend-excel-io/generators/excel-io-service.generator.d.ts +9 -0
- package/dist/backend-excel-io/generators/excel-io-service.generator.js +680 -0
- package/dist/backend-excel-io/generators/excel-io-service.generator.js.map +1 -0
- package/dist/backend-excel-io/index.d.ts +2 -0
- package/dist/backend-excel-io/index.js +22 -0
- package/dist/backend-excel-io/index.js.map +1 -0
- package/dist/backend-excel-io/template/README.md +24 -0
- package/dist/backend-excel-io/template/excel-io.controller.ts +195 -0
- package/dist/backend-excel-io/template/excel-io.module.ts +17 -0
- package/dist/backend-import/generators/detect-delta/detect-delta-functions.generator.js +149 -14
- package/dist/backend-import/generators/detect-delta/detect-delta-functions.generator.js.map +1 -1
- package/dist/backend-import/generators/filter-error-rows.generator.d.ts +2 -0
- package/dist/backend-import/generators/filter-error-rows.generator.js +28 -0
- package/dist/backend-import/generators/filter-error-rows.generator.js.map +1 -0
- package/dist/backend-import/generators/import-service.generator.js +126 -2
- package/dist/backend-import/generators/import-service.generator.js.map +1 -1
- package/dist/backend-import/import.generator.js +2 -0
- package/dist/backend-import/import.generator.js.map +1 -1
- package/dist/backend-repositories/generators/model-repository.generator.js +17 -2
- package/dist/backend-repositories/generators/model-repository.generator.js.map +1 -1
- package/dist/backend-router-trpc/generators/app-routes.generator.js +8 -1
- package/dist/backend-router-trpc/generators/app-routes.generator.js.map +1 -1
- package/dist/backend-router-trpc/generators/excel-io-route.generator.d.ts +4 -0
- package/dist/backend-router-trpc/generators/excel-io-route.generator.js +35 -0
- package/dist/backend-router-trpc/generators/excel-io-route.generator.js.map +1 -0
- package/dist/backend-router-trpc/generators/trpc-plugin.generator.js +9 -0
- package/dist/backend-router-trpc/generators/trpc-plugin.generator.js.map +1 -1
- package/dist/backend-router-trpc/generators/trpc-router-module.generator.js +9 -1
- package/dist/backend-router-trpc/generators/trpc-router-module.generator.js.map +1 -1
- package/dist/backend-router-trpc/generators/trpc-shared.generator.js +16 -1
- package/dist/backend-router-trpc/generators/trpc-shared.generator.js.map +1 -1
- package/dist/backend-router-trpc/router-trpc.generator.d.ts +3 -1
- package/dist/backend-router-trpc/router-trpc.generator.js +6 -0
- package/dist/backend-router-trpc/router-trpc.generator.js.map +1 -1
- package/dist/backend-seed/seed.generator.js +10 -1
- package/dist/backend-seed/seed.generator.js.map +1 -1
- package/dist/base/base.generator.js +0 -4
- package/dist/base/base.generator.js.map +1 -1
- package/dist/base/template/scripts/setup.sh +9 -4
- package/dist/base/template/sonar-project.properties +9 -1
- package/dist/decoders/datamodel-decoder.generator.js +91 -1
- package/dist/decoders/datamodel-decoder.generator.js.map +1 -1
- package/dist/decoders/decoders.generator.d.ts +9 -0
- package/dist/decoders/decoders.generator.js +15 -0
- package/dist/decoders/decoders.generator.js.map +1 -1
- package/dist/devops/devops.generator.d.ts +5 -1
- package/dist/devops/devops.generator.js +5 -4
- package/dist/devops/devops.generator.js.map +1 -1
- package/dist/devops/generators/bitbucket-pipelines-yml.generator.js +1 -0
- package/dist/devops/generators/bitbucket-pipelines-yml.generator.js.map +1 -1
- package/dist/devops/generators/docker-compose-yml.generator.d.ts +1 -1
- package/dist/devops/generators/docker-compose-yml.generator.js +16 -1
- package/dist/devops/generators/docker-compose-yml.generator.js.map +1 -1
- package/dist/devops/generators/e2e-yml.generator.js +35 -10
- package/dist/devops/generators/e2e-yml.generator.js.map +1 -1
- package/dist/devops/generators/jenkinsfile.generator.js +25 -1
- package/dist/devops/generators/jenkinsfile.generator.js.map +1 -1
- package/dist/e2e/template/e2e/specs/example.spec.ts-snapshots/Navigate-to-homepage-and-take-snapshot-1-chromium-linux.png +0 -0
- package/dist/frontend-actions/actions.generator.d.ts +9 -0
- package/dist/frontend-actions/actions.generator.js +111 -0
- package/dist/frontend-actions/actions.generator.js.map +1 -0
- package/dist/frontend-actions/generators/ai-action-text.utils.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/ai-action-text.utils.generator.js +52 -0
- package/dist/frontend-actions/generators/ai-action-text.utils.generator.js.map +1 -0
- package/dist/frontend-actions/generators/ai-assistant-store.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/ai-assistant-store.generator.js +230 -0
- package/dist/frontend-actions/generators/ai-assistant-store.generator.js.map +1 -0
- package/dist/frontend-actions/generators/ai-sidebar-content.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/ai-sidebar-content.generator.js +139 -0
- package/dist/frontend-actions/generators/ai-sidebar-content.generator.js.map +1 -0
- package/dist/frontend-actions/generators/ai-sidepane.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/ai-sidepane.generator.js +98 -0
- package/dist/frontend-actions/generators/ai-sidepane.generator.js.map +1 -0
- package/dist/frontend-actions/generators/base-global-actions.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/base-global-actions.generator.js +405 -0
- package/dist/frontend-actions/generators/base-global-actions.generator.js.map +1 -0
- package/dist/frontend-actions/generators/command-palette-action.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/command-palette-action.generator.js +87 -0
- package/dist/frontend-actions/generators/command-palette-action.generator.js.map +1 -0
- package/dist/frontend-actions/generators/command-palette-store.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/command-palette-store.generator.js +288 -0
- package/dist/frontend-actions/generators/command-palette-store.generator.js.map +1 -0
- package/dist/frontend-actions/generators/command-palette.generator.d.ts +5 -0
- package/dist/frontend-actions/generators/command-palette.generator.js +332 -0
- package/dist/frontend-actions/generators/command-palette.generator.js.map +1 -0
- package/dist/frontend-actions/generators/filter-utils.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/filter-utils.generator.js +50 -0
- package/dist/frontend-actions/generators/filter-utils.generator.js.map +1 -0
- package/dist/frontend-actions/generators/sidepanel-toggle.generator.d.ts +1 -0
- package/dist/frontend-actions/generators/sidepanel-toggle.generator.js +37 -0
- package/dist/frontend-actions/generators/sidepanel-toggle.generator.js.map +1 -0
- package/dist/frontend-actions/index.d.ts +4 -0
- package/dist/frontend-actions/index.js +40 -0
- package/dist/frontend-actions/index.js.map +1 -0
- package/dist/frontend-admin/admin.generator.d.ts +5 -1
- package/dist/frontend-admin/admin.generator.js +36 -1
- package/dist/frontend-admin/admin.generator.js.map +1 -1
- package/dist/frontend-admin/generators/admin-global-actions.generator.d.ts +4 -0
- package/dist/frontend-admin/generators/admin-global-actions.generator.js +230 -0
- package/dist/frontend-admin/generators/admin-global-actions.generator.js.map +1 -0
- package/dist/frontend-admin/generators/admin-overview-page.generator.js +21 -1
- package/dist/frontend-admin/generators/admin-overview-page.generator.js.map +1 -1
- package/dist/frontend-admin/generators/admin-sidebar.generator.js +20 -0
- package/dist/frontend-admin/generators/admin-sidebar.generator.js.map +1 -1
- package/dist/frontend-admin/generators/detail-sidebar.generator.js +44 -32
- package/dist/frontend-admin/generators/detail-sidebar.generator.js.map +1 -1
- package/dist/frontend-admin/generators/excel-io-page.generator.d.ts +4 -0
- package/dist/frontend-admin/generators/excel-io-page.generator.js +258 -0
- package/dist/frontend-admin/generators/excel-io-page.generator.js.map +1 -0
- package/dist/frontend-admin/generators/import-review-page-result-stage.generator.d.ts +1 -0
- package/dist/frontend-admin/generators/import-review-page-result-stage.generator.js +104 -0
- package/dist/frontend-admin/generators/import-review-page-result-stage.generator.js.map +1 -0
- package/dist/frontend-admin/generators/import-review-page-review-stage.generator.d.ts +1 -0
- package/dist/frontend-admin/generators/import-review-page-review-stage.generator.js +1031 -0
- package/dist/frontend-admin/generators/import-review-page-review-stage.generator.js.map +1 -0
- package/dist/frontend-admin/generators/import-review-page-upload-stage.generator.d.ts +1 -0
- package/dist/frontend-admin/generators/import-review-page-upload-stage.generator.js +77 -0
- package/dist/frontend-admin/generators/import-review-page-upload-stage.generator.js.map +1 -0
- package/dist/frontend-admin/generators/import-review-page.generator.d.ts +7 -0
- package/dist/frontend-admin/generators/import-review-page.generator.js +180 -0
- package/dist/frontend-admin/generators/import-review-page.generator.js.map +1 -0
- package/dist/frontend-admin/generators/model-admin-page.generator.js +198 -60
- package/dist/frontend-admin/generators/model-admin-page.generator.js.map +1 -1
- package/dist/frontend-admin/utils.d.ts +1 -0
- package/dist/frontend-admin/utils.js +26 -33
- package/dist/frontend-admin/utils.js.map +1 -1
- package/dist/frontend-core/frontend.generator.js +1 -2
- package/dist/frontend-core/frontend.generator.js.map +1 -1
- package/dist/frontend-core/generators/tsconfig.generator.js +1 -0
- package/dist/frontend-core/generators/tsconfig.generator.js.map +1 -1
- package/dist/frontend-core/template/.env.example +3 -0
- package/dist/frontend-core/template/src/components/admin/excel-io-actions.tsx +64 -0
- package/dist/frontend-core/template/src/components/admin/table-view-panel.tsx +41 -3
- package/dist/frontend-core/template/src/components/ui/color-mode-toggle/color-mode-toggle.tsx +1 -1
- package/dist/frontend-core/template/src/hooks/use-excel-io.ts +137 -0
- package/dist/frontend-core/template/src/hooks/use-import-review.ts +143 -0
- package/dist/frontend-core/template/src/lib/color.ts +6 -3
- package/dist/frontend-core/template/src/lib/config.ts +3 -1
- package/dist/frontend-core/template/src/lib/excel-download.ts +28 -0
- package/dist/frontend-core/types/hook.d.ts +1 -1
- package/dist/frontend-tables/generators/model-table.generator.js +21 -13
- package/dist/frontend-tables/generators/model-table.generator.js.map +1 -1
- package/dist/generators.js +6 -0
- package/dist/generators.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/seed-data/seed-data.generator.d.ts +3 -0
- package/dist/seed-data/seed-data.generator.js +45 -1
- package/dist/seed-data/seed-data.generator.js.map +1 -1
- package/dist/types/template/ai.types.ts +34 -0
- package/dist/types/types.generator.js +1 -0
- package/dist/types/types.generator.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateAiAssistantStore = generateAiAssistantStore;
|
|
4
|
+
function generateAiAssistantStore() {
|
|
5
|
+
return `import { useSyncExternalStore } from 'react'
|
|
6
|
+
import type { ReactNode } from 'react'
|
|
7
|
+
|
|
8
|
+
export type AiEventKind = 'user' | 'action' | 'assistant' | 'system'
|
|
9
|
+
export type AiEventStatus = 'running' | 'done' | 'error'
|
|
10
|
+
|
|
11
|
+
export type AiAssistantEvent = {
|
|
12
|
+
id: string
|
|
13
|
+
kind: AiEventKind
|
|
14
|
+
text: string
|
|
15
|
+
status?: AiEventStatus
|
|
16
|
+
createdAt: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type AiSidepaneTab = {
|
|
20
|
+
id: string
|
|
21
|
+
label: string
|
|
22
|
+
render: () => ReactNode
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type AiExecutionResult = {
|
|
26
|
+
summary?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type AiExecutor = (
|
|
30
|
+
task: string,
|
|
31
|
+
helpers: {
|
|
32
|
+
signal: AbortSignal
|
|
33
|
+
addEvent: (entry: Omit<AiAssistantEvent, 'id' | 'createdAt'>) => string
|
|
34
|
+
patchEvent: (id: string, patch: Partial<Pick<AiAssistantEvent, 'text' | 'status'>>) => void
|
|
35
|
+
requestUserInput: (question: string) => Promise<string>
|
|
36
|
+
},
|
|
37
|
+
) => Promise<AiExecutionResult>
|
|
38
|
+
|
|
39
|
+
type AiAssistantState = {
|
|
40
|
+
open: boolean
|
|
41
|
+
running: boolean
|
|
42
|
+
pendingQuestion: string | null
|
|
43
|
+
events: AiAssistantEvent[]
|
|
44
|
+
tabs: AiSidepaneTab[]
|
|
45
|
+
activeAdminTab: string
|
|
46
|
+
executor: AiExecutor | null
|
|
47
|
+
controller: AbortController | null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type AiAssistantActions = {
|
|
51
|
+
setOpen: (open: boolean) => void
|
|
52
|
+
clearEvents: () => void
|
|
53
|
+
cancel: () => void
|
|
54
|
+
submit: (task: string) => Promise<void>
|
|
55
|
+
setExecutor: (executor: AiExecutor | null) => void
|
|
56
|
+
registerTabs: (...tabs: AiSidepaneTab[]) => void
|
|
57
|
+
deregisterTabs: (...tabIds: string[]) => void
|
|
58
|
+
setActiveAdminTab: (tabId: string) => void
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type AiAssistantStore = AiAssistantState & { actions: AiAssistantActions }
|
|
62
|
+
|
|
63
|
+
const listeners = new Set<() => void>()
|
|
64
|
+
const subscribe = (listener: () => void) => {
|
|
65
|
+
listeners.add(listener)
|
|
66
|
+
return () => listeners.delete(listener)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const notify = () => {
|
|
70
|
+
for (const listener of listeners) {
|
|
71
|
+
listener()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const setStore = (update: Partial<AiAssistantState>) => {
|
|
76
|
+
store = { ...store, ...update }
|
|
77
|
+
notify()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const newId = () => globalThis.crypto?.randomUUID?.() ?? String(Date.now() + Math.random())
|
|
81
|
+
|
|
82
|
+
const addEvent = (entry: Omit<AiAssistantEvent, 'id' | 'createdAt'>): string => {
|
|
83
|
+
const id = newId()
|
|
84
|
+
const next: AiAssistantEvent = { id, createdAt: Date.now(), ...entry }
|
|
85
|
+
setStore({ events: [...store.events, next] })
|
|
86
|
+
return id
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const patchEvent = (id: string, patch: Partial<Pick<AiAssistantEvent, 'text' | 'status'>>) => {
|
|
90
|
+
setStore({
|
|
91
|
+
events: store.events.map((event) => (event.id === id ? { ...event, ...patch } : event)),
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let pendingAnswerResolve: ((answer: string) => void) | null = null
|
|
96
|
+
let pendingAnswerReject: ((error: Error) => void) | null = null
|
|
97
|
+
let pendingSignalAbortUnsubscribe: (() => void) | null = null
|
|
98
|
+
|
|
99
|
+
const resetPendingInputRequest = () => {
|
|
100
|
+
pendingAnswerResolve = null
|
|
101
|
+
pendingAnswerReject = null
|
|
102
|
+
pendingSignalAbortUnsubscribe?.()
|
|
103
|
+
pendingSignalAbortUnsubscribe = null
|
|
104
|
+
if (store.pendingQuestion) {
|
|
105
|
+
setStore({ pendingQuestion: null })
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const requestUserInput = (question: string, signal: AbortSignal): Promise<string> => {
|
|
110
|
+
resetPendingInputRequest()
|
|
111
|
+
setStore({ pendingQuestion: question })
|
|
112
|
+
|
|
113
|
+
return new Promise<string>((resolve, reject) => {
|
|
114
|
+
pendingAnswerResolve = (answer) => {
|
|
115
|
+
resetPendingInputRequest()
|
|
116
|
+
resolve(answer)
|
|
117
|
+
}
|
|
118
|
+
pendingAnswerReject = (error) => {
|
|
119
|
+
resetPendingInputRequest()
|
|
120
|
+
reject(error)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const onAbort = () => {
|
|
124
|
+
pendingAnswerReject?.(new Error('Execution cancelled'))
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
signal.addEventListener('abort', onAbort, { once: true })
|
|
128
|
+
pendingSignalAbortUnsubscribe = () => signal.removeEventListener('abort', onAbort)
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let store: AiAssistantStore = {
|
|
133
|
+
open: false,
|
|
134
|
+
running: false,
|
|
135
|
+
pendingQuestion: null,
|
|
136
|
+
events: [],
|
|
137
|
+
tabs: [],
|
|
138
|
+
activeAdminTab: 'ai',
|
|
139
|
+
executor: null,
|
|
140
|
+
controller: null,
|
|
141
|
+
actions: {} as AiAssistantActions,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
store.actions = {
|
|
145
|
+
setOpen(open) {
|
|
146
|
+
setStore({ open })
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
clearEvents() {
|
|
150
|
+
setStore({ events: [] })
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
cancel() {
|
|
154
|
+
pendingAnswerReject?.(new Error('Execution cancelled'))
|
|
155
|
+
store.controller?.abort()
|
|
156
|
+
setStore({ running: false, controller: null, pendingQuestion: null })
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
async submit(task) {
|
|
160
|
+
const trimmed = task.trim()
|
|
161
|
+
if (!trimmed) {
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (store.running && store.pendingQuestion) {
|
|
166
|
+
addEvent({ kind: 'user', text: trimmed })
|
|
167
|
+
pendingAnswerResolve?.(trimmed)
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (store.running || !store.executor) {
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const controller = new AbortController()
|
|
176
|
+
setStore({ running: true, open: true, controller })
|
|
177
|
+
|
|
178
|
+
addEvent({ kind: 'user', text: trimmed })
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const result = await store.executor(trimmed, {
|
|
182
|
+
signal: controller.signal,
|
|
183
|
+
addEvent,
|
|
184
|
+
patchEvent,
|
|
185
|
+
requestUserInput: (question) => requestUserInput(question, controller.signal),
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
if (result.summary) {
|
|
189
|
+
addEvent({ kind: 'assistant', text: result.summary, status: 'done' })
|
|
190
|
+
}
|
|
191
|
+
} catch (error) {
|
|
192
|
+
if (controller.signal.aborted) {
|
|
193
|
+
addEvent({ kind: 'system', text: 'Execution cancelled.' })
|
|
194
|
+
} else {
|
|
195
|
+
addEvent({ kind: 'assistant', text: String(error), status: 'error' })
|
|
196
|
+
}
|
|
197
|
+
} finally {
|
|
198
|
+
resetPendingInputRequest()
|
|
199
|
+
setStore({ running: false, controller: null, pendingQuestion: null })
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
setExecutor(executor) {
|
|
204
|
+
setStore({ executor })
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
registerTabs(...tabs) {
|
|
208
|
+
const incoming = new Set(tabs.map((tab) => tab.id))
|
|
209
|
+
const next = [...store.tabs.filter((tab) => !incoming.has(tab.id)), ...tabs]
|
|
210
|
+
setStore({ tabs: next })
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
deregisterTabs(...tabIds) {
|
|
214
|
+
const toRemove = new Set(tabIds)
|
|
215
|
+
setStore({ tabs: store.tabs.filter((tab) => !toRemove.has(tab.id)) })
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
setActiveAdminTab(tabId) {
|
|
219
|
+
setStore({ activeAdminTab: tabId })
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export const useAiAssistantState = <T>(selector: (state: AiAssistantState) => T): T =>
|
|
224
|
+
useSyncExternalStore(subscribe, () => selector(store), () => selector(store))
|
|
225
|
+
|
|
226
|
+
export const useAiAssistantActions = (): AiAssistantActions =>
|
|
227
|
+
useSyncExternalStore(subscribe, () => store.actions, () => store.actions)
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=ai-assistant-store.generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-assistant-store.generator.js","sourceRoot":"","sources":["../../../src/frontend-actions/generators/ai-assistant-store.generator.ts"],"names":[],"mappings":";;AAAA,4DAiOC;AAjOD,SAAgB,wBAAwB;IACtC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+NR,CAAA;AACD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateAiSidebarContent(): string;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateAiSidebarContent = generateAiSidebarContent;
|
|
4
|
+
function generateAiSidebarContent() {
|
|
5
|
+
return `import { BotIcon, SparklesIcon } from 'lucide-react'
|
|
6
|
+
import { useEffect, useRef, useState } from 'react'
|
|
7
|
+
|
|
8
|
+
import { Button, Textarea } from '@postxl/ui-components'
|
|
9
|
+
|
|
10
|
+
import { AiAssistantEvent, useAiAssistantActions, useAiAssistantState } from './ai-assistant-store'
|
|
11
|
+
|
|
12
|
+
const EventBubble = ({ event }: { event: AiAssistantEvent }) => {
|
|
13
|
+
if (event.kind === 'user') {
|
|
14
|
+
return (
|
|
15
|
+
<div className="flex justify-end">
|
|
16
|
+
<div className="max-w-[85%] rounded-lg bg-primary px-3 py-2 text-sm text-primary-foreground">{event.text}</div>
|
|
17
|
+
</div>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (event.kind === 'action') {
|
|
22
|
+
let statusClass = 'border-muted bg-muted/30 text-foreground'
|
|
23
|
+
if (event.status === 'running') {
|
|
24
|
+
statusClass = 'border-blue-300 bg-blue-50 text-blue-800 dark:border-blue-800 dark:bg-blue-950/30 dark:text-blue-200'
|
|
25
|
+
} else if (event.status === 'error') {
|
|
26
|
+
statusClass = 'border-red-300 bg-red-50 text-red-800 dark:border-red-800 dark:bg-red-950/30 dark:text-red-200'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className="flex justify-start">
|
|
31
|
+
<div className={\`max-w-[95%] rounded-lg border px-3 py-2 text-xs \${statusClass}\`}>
|
|
32
|
+
<div className="flex items-center gap-2">
|
|
33
|
+
<SparklesIcon className={event.status === 'running' ? 'size-3 animate-pulse' : 'size-3'} />
|
|
34
|
+
<span className="font-medium">Agent Action</span>
|
|
35
|
+
</div>
|
|
36
|
+
<div className="mt-1">{event.text}</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (event.kind === 'assistant') {
|
|
43
|
+
return (
|
|
44
|
+
<div className="flex justify-start">
|
|
45
|
+
<div className="max-w-[90%] rounded-lg border bg-card px-3 py-2 text-sm">
|
|
46
|
+
<div className="mb-1 flex items-center gap-2 text-xs text-muted-foreground">
|
|
47
|
+
<BotIcon className="size-3" />
|
|
48
|
+
Assistant
|
|
49
|
+
</div>
|
|
50
|
+
<div>{event.text}</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return <div className="text-center text-xs text-muted-foreground">{event.text}</div>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const AiSidebarContent = () => {
|
|
60
|
+
const events = useAiAssistantState((state) => state.events)
|
|
61
|
+
const running = useAiAssistantState((state) => state.running)
|
|
62
|
+
const pendingQuestion = useAiAssistantState((state) => state.pendingQuestion)
|
|
63
|
+
const { cancel, clearEvents, submit } = useAiAssistantActions()
|
|
64
|
+
|
|
65
|
+
const [prompt, setPrompt] = useState('')
|
|
66
|
+
const scrollRef = useRef<HTMLDivElement | null>(null)
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
const el = scrollRef.current
|
|
70
|
+
if (el) {
|
|
71
|
+
el.scrollTop = el.scrollHeight
|
|
72
|
+
}
|
|
73
|
+
}, [events, running])
|
|
74
|
+
|
|
75
|
+
const handleSubmit = () => {
|
|
76
|
+
const trimmed = prompt.trim()
|
|
77
|
+
if (!trimmed) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setPrompt('')
|
|
82
|
+
void submit(trimmed)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<div className="flex h-full min-h-0 flex-col">
|
|
87
|
+
<div className="flex items-center justify-between border-b px-3 py-2">
|
|
88
|
+
<p className="text-xs font-medium text-muted-foreground">AI Assistant</p>
|
|
89
|
+
<Button variant="ghost" size="sm" onClick={clearEvents} disabled={running}>
|
|
90
|
+
Clear
|
|
91
|
+
</Button>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div ref={scrollRef} className="min-h-0 flex-1 space-y-2 overflow-y-auto px-3 py-3">
|
|
95
|
+
{events.length === 0 && (
|
|
96
|
+
<p className="text-sm text-muted-foreground">Ask for navigation, filtering, or data insights.</p>
|
|
97
|
+
)}
|
|
98
|
+
|
|
99
|
+
{events.map((event) => (
|
|
100
|
+
<EventBubble key={event.id} event={event} />
|
|
101
|
+
))}
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div className="space-y-2 border-t p-3">
|
|
105
|
+
<Textarea
|
|
106
|
+
value={prompt}
|
|
107
|
+
onChange={(event) => setPrompt(event.target.value)}
|
|
108
|
+
placeholder={pendingQuestion ?? 'Ask the assistant...'}
|
|
109
|
+
className="min-h-[90px] resize-none"
|
|
110
|
+
onKeyDown={(event) => {
|
|
111
|
+
if (event.key === 'Enter' && !event.metaKey && !event.ctrlKey) {
|
|
112
|
+
event.preventDefault()
|
|
113
|
+
handleSubmit()
|
|
114
|
+
}
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
|
|
118
|
+
<div className="flex items-center justify-between">
|
|
119
|
+
<p className="text-xs text-muted-foreground">
|
|
120
|
+
{pendingQuestion ? 'Assistant is waiting for your answer' : 'Press Enter to send, Ctrl/Cmd + Enter for a new line'}
|
|
121
|
+
</p>
|
|
122
|
+
<div className="flex gap-2">
|
|
123
|
+
{running && (
|
|
124
|
+
<Button variant="outline" size="sm" onClick={cancel}>
|
|
125
|
+
Stop
|
|
126
|
+
</Button>
|
|
127
|
+
)}
|
|
128
|
+
<Button size="sm" onClick={handleSubmit} disabled={(!pendingQuestion && running) || !prompt.trim()}>
|
|
129
|
+
{pendingQuestion ? 'Reply' : 'Send'}
|
|
130
|
+
</Button>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=ai-sidebar-content.generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sidebar-content.generator.js","sourceRoot":"","sources":["../../../src/frontend-actions/generators/ai-sidebar-content.generator.ts"],"names":[],"mappings":";;AAAA,4DAsIC;AAtID,SAAgB,wBAAwB;IACtC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoIR,CAAA;AACD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateAiSidepane(): string;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateAiSidepane = generateAiSidepane;
|
|
4
|
+
function generateAiSidepane() {
|
|
5
|
+
return `import { Component, type ErrorInfo, type PropsWithChildren, useMemo } from 'react'
|
|
6
|
+
import { useLocation } from '@tanstack/react-router'
|
|
7
|
+
|
|
8
|
+
import { Sheet, SheetContent, SheetHeader, SheetTitle, Tabs, TabsContent, TabsList, TabsTrigger } from '@postxl/ui-components'
|
|
9
|
+
|
|
10
|
+
import { APP_CONFIG } from '@lib/config'
|
|
11
|
+
import { useAiAssistantActions, useAiAssistantState } from './ai-assistant-store'
|
|
12
|
+
import { AiSidebarContent } from './ai-sidebar-content'
|
|
13
|
+
|
|
14
|
+
type AiSidepaneErrorBoundaryState = {
|
|
15
|
+
hasError: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class AiSidepaneErrorBoundary extends Component<PropsWithChildren, AiSidepaneErrorBoundaryState> {
|
|
19
|
+
public constructor(props: PropsWithChildren) {
|
|
20
|
+
super(props)
|
|
21
|
+
this.state = { hasError: false }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public static getDerivedStateFromError(): AiSidepaneErrorBoundaryState {
|
|
25
|
+
return { hasError: true }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public componentDidCatch(error: unknown, info: ErrorInfo) {
|
|
29
|
+
console.error('AiSidepane rendering failed:', error, info)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public render() {
|
|
33
|
+
if (this.state.hasError) {
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return this.props.children
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const AiSidepane = () => {
|
|
42
|
+
return (
|
|
43
|
+
<AiSidepaneErrorBoundary>
|
|
44
|
+
<AiSidepaneInner />
|
|
45
|
+
</AiSidepaneErrorBoundary>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const AiSidepaneInner = () => {
|
|
50
|
+
const pathname = useLocation({ select: (location) => location.pathname })
|
|
51
|
+
const open = useAiAssistantState((state) => state.open)
|
|
52
|
+
const tabs = useAiAssistantState((state) => state.tabs)
|
|
53
|
+
const { setOpen } = useAiAssistantActions()
|
|
54
|
+
|
|
55
|
+
const isAdminRoute = pathname.startsWith('/admin')
|
|
56
|
+
const isAdminOverviewRoute = pathname === '/admin' || pathname === '/admin/'
|
|
57
|
+
|
|
58
|
+
const allTabs = useMemo(
|
|
59
|
+
() => [
|
|
60
|
+
{ id: 'ai', label: 'AI', render: () => <AiSidebarContent /> },
|
|
61
|
+
...tabs,
|
|
62
|
+
],
|
|
63
|
+
[tabs],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if (!APP_CONFIG.enableAI || (isAdminRoute && !isAdminOverviewRoute)) {
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Sheet open={open} onOpenChange={setOpen}>
|
|
72
|
+
<SheetContent side="right" className="w-full p-0 sm:max-w-xl">
|
|
73
|
+
<SheetHeader className="border-b px-4 py-3">
|
|
74
|
+
<SheetTitle>Assistant</SheetTitle>
|
|
75
|
+
</SheetHeader>
|
|
76
|
+
|
|
77
|
+
<Tabs defaultValue={allTabs[0]?.id} className="flex h-[calc(100%-56px)] min-h-0 flex-col">
|
|
78
|
+
<TabsList variant="protocol" className="mx-2 mt-2 justify-start">
|
|
79
|
+
{allTabs.map((tab) => (
|
|
80
|
+
<TabsTrigger key={tab.id} value={tab.id} variant="protocol" className="cursor-pointer px-3 h-8">
|
|
81
|
+
{tab.label}
|
|
82
|
+
</TabsTrigger>
|
|
83
|
+
))}
|
|
84
|
+
</TabsList>
|
|
85
|
+
|
|
86
|
+
{allTabs.map((tab) => (
|
|
87
|
+
<TabsContent key={tab.id} value={tab.id} className="mt-0 h-full min-h-0 flex-1">
|
|
88
|
+
{tab.render()}
|
|
89
|
+
</TabsContent>
|
|
90
|
+
))}
|
|
91
|
+
</Tabs>
|
|
92
|
+
</SheetContent>
|
|
93
|
+
</Sheet>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=ai-sidepane.generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sidepane.generator.js","sourceRoot":"","sources":["../../../src/frontend-actions/generators/ai-sidepane.generator.ts"],"names":[],"mappings":";;AAAA,gDA6FC;AA7FD,SAAgB,kBAAkB;IAChC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2FR,CAAA;AACD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateBaseGlobalActions(): string;
|