create-fullstack-scaffold 0.4.11 → 0.4.13
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/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/template/src/admin/App.tsx +4 -1
- package/template/src/admin/components/NotificationDrawer.tsx +15 -40
- package/template/src/admin/components/ThemeToggle.tsx +2 -2
- package/template/src/admin/layouts/Header.tsx +12 -9
- package/template/src/admin/pages/ContentPage.tsx +8 -10
- package/template/src/admin/pages/DashboardPage.tsx +30 -17
- package/template/src/admin/pages/DisputesPage.tsx +20 -14
- package/template/src/admin/pages/LoginPage.tsx +14 -3
- package/template/src/admin/pages/OrdersPage.tsx +10 -6
- package/template/src/admin/pages/PermissionsPage.tsx +1 -3
- package/template/src/admin/pages/RegisterPage.tsx +6 -4
- package/template/src/admin/pages/RolesPage.tsx +10 -3
- package/template/src/admin/pages/SystemLogsPage.tsx +12 -4
- package/template/src/admin/pages/TicketsPage.tsx +15 -15
- package/template/src/admin/pages/UsersPage.tsx +10 -6
- package/template/src/admin/stores/themeStore.ts +1 -1
- package/template/src/cli/modules/admin/index.ts +28 -30
- package/template/src/cli/modules/content/index.ts +10 -2
- package/template/src/cli/modules/dispute/index.ts +8 -2
- package/template/src/cli/modules/file/index.ts +6 -1
- package/template/src/cli/modules/index.ts +3 -0
- package/template/src/cli/modules/merchant/index.ts +123 -0
- package/template/src/cli/modules/order/index.ts +16 -3
- package/template/src/cli/modules/permission/index.ts +7 -1
- package/template/src/cli/modules/ticket/index.ts +14 -3
- package/template/src/client/index.css +22 -24
- package/template/vite.config.ts +5 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react'
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
Table,
|
|
4
4
|
Card,
|
|
@@ -37,18 +37,20 @@ export const UsersPage: React.FC = () => {
|
|
|
37
37
|
const [form] = Form.useForm<UserFormData>()
|
|
38
38
|
const { roleLabels } = useRoleLabels()
|
|
39
39
|
|
|
40
|
-
const fetchUsers = async () => {
|
|
40
|
+
const fetchUsers = useCallback(async () => {
|
|
41
41
|
try {
|
|
42
|
-
const data = await api(apiClient.api.admin.users.$get())
|
|
42
|
+
const data = await api(apiClient.api.admin.users.$get())
|
|
43
|
+
.withLoading(t('users.loading'))
|
|
44
|
+
.json()
|
|
43
45
|
setUsers(data)
|
|
44
46
|
} catch {
|
|
45
47
|
// handled by api-request
|
|
46
48
|
}
|
|
47
|
-
}
|
|
49
|
+
}, [t])
|
|
48
50
|
|
|
49
51
|
useEffect(() => {
|
|
50
52
|
fetchUsers()
|
|
51
|
-
}, [])
|
|
53
|
+
}, [fetchUsers])
|
|
52
54
|
|
|
53
55
|
const handleCreate = () => {
|
|
54
56
|
setEditingUser(null)
|
|
@@ -271,7 +273,9 @@ export const UsersPage: React.FC = () => {
|
|
|
271
273
|
>
|
|
272
274
|
<Select placeholder={t('users.rolePlaceholder')}>
|
|
273
275
|
<Select.Option value={Role.SUPER_ADMIN}>{t('users.superAdmin')}</Select.Option>
|
|
274
|
-
<Select.Option value={Role.CUSTOMER_SERVICE}>
|
|
276
|
+
<Select.Option value={Role.CUSTOMER_SERVICE}>
|
|
277
|
+
{t('users.customerService')}
|
|
278
|
+
</Select.Option>
|
|
275
279
|
<Select.Option value={Role.USER}>{t('users.normalUser')}</Select.Option>
|
|
276
280
|
</Select>
|
|
277
281
|
</Form.Item>
|
|
@@ -2,6 +2,21 @@ import type { SiteInstance } from '@dyyz1993/xcli-core'
|
|
|
2
2
|
import { ok, fail } from '@dyyz1993/xcli-core'
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
import { getClient } from '@cli/utils/api'
|
|
5
|
+
import type { Role } from '@shared/modules/permission'
|
|
6
|
+
|
|
7
|
+
const createUserParams = z.object({
|
|
8
|
+
username: z.string().min(1).describe('Username'),
|
|
9
|
+
email: z.string().email().describe('Email'),
|
|
10
|
+
password: z.string().min(6).describe('Password'),
|
|
11
|
+
role: z.enum(['super_admin', 'customer_service', 'user']).default('user').describe('Role'),
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const updateUserParams = z.object({
|
|
15
|
+
id: z.string().describe('User ID'),
|
|
16
|
+
username: z.string().optional().describe('New username'),
|
|
17
|
+
email: z.string().email().optional().describe('New email'),
|
|
18
|
+
role: z.enum(['super_admin', 'customer_service', 'user']).optional().describe('New role'),
|
|
19
|
+
})
|
|
5
20
|
|
|
6
21
|
export function registerAdminCommands(site: SiteInstance) {
|
|
7
22
|
site.command('dashboard', {
|
|
@@ -84,29 +99,21 @@ export function registerAdminCommands(site: SiteInstance) {
|
|
|
84
99
|
|
|
85
100
|
site.command('create-user', {
|
|
86
101
|
description: 'Create a new user',
|
|
87
|
-
parameters:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
role: z.enum(['super_admin', 'customer_service', 'user']).default('user').describe('Role'),
|
|
92
|
-
}),
|
|
93
|
-
handler: async (params: unknown) => {
|
|
94
|
-
const p = params as {
|
|
95
|
-
username: string
|
|
96
|
-
email: string
|
|
97
|
-
password: string
|
|
98
|
-
role: 'super_admin' | 'customer_service' | 'user'
|
|
99
|
-
}
|
|
102
|
+
parameters: createUserParams,
|
|
103
|
+
handler: async params => {
|
|
104
|
+
// @ts-expect-error -- auto-command passes unknown, we parse from zod schema
|
|
105
|
+
const p: z.infer<typeof createUserParams> = params
|
|
100
106
|
try {
|
|
101
107
|
const client = getClient()
|
|
102
108
|
const res = await client.api.admin.users.$post({
|
|
103
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
104
109
|
json: {
|
|
105
110
|
username: p.username,
|
|
106
111
|
email: p.email,
|
|
107
112
|
password: p.password,
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
// Role enum values overlap with z.enum string literals — safe cast for RPC compatibility
|
|
114
|
+
// eslint-disable-next-line local-rules/no-type-assertion-on-shared-types
|
|
115
|
+
role: p.role as Role,
|
|
116
|
+
},
|
|
110
117
|
})
|
|
111
118
|
const data = await res.json()
|
|
112
119
|
return ok(data, ['User created'])
|
|
@@ -118,19 +125,10 @@ export function registerAdminCommands(site: SiteInstance) {
|
|
|
118
125
|
|
|
119
126
|
site.command('update-user', {
|
|
120
127
|
description: 'Update a user',
|
|
121
|
-
parameters:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
role: z.enum(['super_admin', 'customer_service', 'user']).optional().describe('New role'),
|
|
126
|
-
}),
|
|
127
|
-
handler: async (params: unknown) => {
|
|
128
|
-
const p = params as {
|
|
129
|
-
id: string
|
|
130
|
-
username?: string
|
|
131
|
-
email?: string
|
|
132
|
-
role?: 'super_admin' | 'customer_service' | 'user'
|
|
133
|
-
}
|
|
128
|
+
parameters: updateUserParams,
|
|
129
|
+
handler: async params => {
|
|
130
|
+
// @ts-expect-error -- auto-command passes unknown, we parse from zod schema
|
|
131
|
+
const p: z.infer<typeof updateUserParams> = params
|
|
134
132
|
const { id, ...rest } = p
|
|
135
133
|
const body: Record<string, string | undefined> = {}
|
|
136
134
|
if (rest.username) body.username = rest.username
|
|
@@ -138,7 +136,7 @@ export function registerAdminCommands(site: SiteInstance) {
|
|
|
138
136
|
if (rest.role) body.role = rest.role
|
|
139
137
|
try {
|
|
140
138
|
const client = getClient()
|
|
141
|
-
const res = await client.api.admin.users[':id'].$put({ param: { id }, json: body
|
|
139
|
+
const res = await client.api.admin.users[':id'].$put({ param: { id }, json: body })
|
|
142
140
|
const data = await res.json()
|
|
143
141
|
return ok(data, ['User updated'])
|
|
144
142
|
} catch (err) {
|
|
@@ -48,7 +48,10 @@ export function registerContentCommands(site: SiteInstance) {
|
|
|
48
48
|
parameters: z.object({
|
|
49
49
|
title: z.string().min(1).describe('Content title'),
|
|
50
50
|
content: z.string().min(1).describe('Content body'),
|
|
51
|
-
category: z
|
|
51
|
+
category: z
|
|
52
|
+
.enum(['article', 'announcement', 'tutorial', 'news', 'policy'])
|
|
53
|
+
.default('article')
|
|
54
|
+
.describe('Category'),
|
|
52
55
|
tags: z.string().optional().describe('Comma-separated tags'),
|
|
53
56
|
}),
|
|
54
57
|
handler: async (params: unknown) => {
|
|
@@ -57,7 +60,12 @@ export function registerContentCommands(site: SiteInstance) {
|
|
|
57
60
|
const client = getClient()
|
|
58
61
|
const tags = p.tags ? p.tags.split(',') : undefined
|
|
59
62
|
const res = await client.api.contents.$post({
|
|
60
|
-
json: {
|
|
63
|
+
json: {
|
|
64
|
+
title: p.title,
|
|
65
|
+
content: p.content,
|
|
66
|
+
category: p.category as 'article' | 'announcement' | 'tutorial' | 'news' | 'policy',
|
|
67
|
+
tags,
|
|
68
|
+
},
|
|
61
69
|
})
|
|
62
70
|
const data = await res.json()
|
|
63
71
|
return ok(data, ['Content created'])
|
|
@@ -50,7 +50,10 @@ export function registerDisputeCommands(site: SiteInstance) {
|
|
|
50
50
|
'order-no': z.string().describe('Order number'),
|
|
51
51
|
'customer-name': z.string().describe('Customer name'),
|
|
52
52
|
'customer-email': z.string().email().describe('Customer email'),
|
|
53
|
-
type: z
|
|
53
|
+
type: z
|
|
54
|
+
.enum(['refund', 'product_quality', 'service_quality', 'delivery', 'other'])
|
|
55
|
+
.default('other')
|
|
56
|
+
.describe('Type'),
|
|
54
57
|
description: z.string().min(1).describe('Description'),
|
|
55
58
|
amount: z.coerce.number().positive().describe('Amount'),
|
|
56
59
|
}),
|
|
@@ -89,7 +92,10 @@ export function registerDisputeCommands(site: SiteInstance) {
|
|
|
89
92
|
description: 'Update a dispute status',
|
|
90
93
|
parameters: z.object({
|
|
91
94
|
id: z.string().describe('Dispute ID'),
|
|
92
|
-
status: z
|
|
95
|
+
status: z
|
|
96
|
+
.enum(['pending', 'resolved', 'investigating', 'rejected'])
|
|
97
|
+
.optional()
|
|
98
|
+
.describe('New status'),
|
|
93
99
|
}),
|
|
94
100
|
handler: async (params: unknown) => {
|
|
95
101
|
const p = params as { id: string; status?: string }
|
|
@@ -13,7 +13,12 @@ export function registerFileCommands(site: SiteInstance) {
|
|
|
13
13
|
'expiry-seconds': z.coerce.number().default(3600).describe('URL expiry in seconds'),
|
|
14
14
|
}),
|
|
15
15
|
handler: async (params: unknown) => {
|
|
16
|
-
const p = params as {
|
|
16
|
+
const p = params as {
|
|
17
|
+
namespace: string
|
|
18
|
+
filename: string
|
|
19
|
+
private: boolean
|
|
20
|
+
'expiry-seconds': number
|
|
21
|
+
}
|
|
17
22
|
try {
|
|
18
23
|
const client = getClient()
|
|
19
24
|
const res = await client.api['generate-url'].$post({
|
|
@@ -14,6 +14,7 @@ import { registerOrderCommands } from './order'
|
|
|
14
14
|
import { registerPermissionCommands } from './permission'
|
|
15
15
|
import { registerTenantCommands } from './tenant'
|
|
16
16
|
import { registerTicketCommands } from './ticket'
|
|
17
|
+
import { registerMerchantCommands } from './merchant'
|
|
17
18
|
|
|
18
19
|
export function registerBuiltinCommands(app: Core) {
|
|
19
20
|
const api = app.loader.getAPI()
|
|
@@ -38,6 +39,7 @@ export function registerBuiltinCommands(app: Core) {
|
|
|
38
39
|
registerPermissionCommands(site)
|
|
39
40
|
registerTenantCommands(site)
|
|
40
41
|
registerTicketCommands(site)
|
|
42
|
+
registerMerchantCommands(site)
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
export {
|
|
@@ -56,4 +58,5 @@ export {
|
|
|
56
58
|
registerPermissionCommands,
|
|
57
59
|
registerTenantCommands,
|
|
58
60
|
registerTicketCommands,
|
|
61
|
+
registerMerchantCommands,
|
|
59
62
|
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { SiteInstance } from '@dyyz1993/xcli-core'
|
|
2
|
+
import { ok, fail } from '@dyyz1993/xcli-core'
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
import { getClient } from '@cli/utils/api'
|
|
5
|
+
|
|
6
|
+
const createProductParams = z.object({
|
|
7
|
+
name: z.string().min(1).describe('Product name'),
|
|
8
|
+
description: z.string().max(1000).describe('Product description'),
|
|
9
|
+
price: z.coerce.number().positive().describe('Product price'),
|
|
10
|
+
stock: z.coerce.number().int().min(0).default(0).describe('Stock quantity'),
|
|
11
|
+
status: z
|
|
12
|
+
.enum(['active', 'inactive', 'out_of_stock'])
|
|
13
|
+
.default('active')
|
|
14
|
+
.describe('Product status'),
|
|
15
|
+
'image-url': z.string().url().nullable().default(null).describe('Image URL'),
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export function registerMerchantCommands(site: SiteInstance) {
|
|
19
|
+
site.command('login', {
|
|
20
|
+
description: 'Login as merchant',
|
|
21
|
+
parameters: z.object({
|
|
22
|
+
username: z.string().min(1).describe('Merchant username'),
|
|
23
|
+
password: z.string().min(6).describe('Merchant password'),
|
|
24
|
+
}),
|
|
25
|
+
handler: async (params: unknown) => {
|
|
26
|
+
const p = params as { username: string; password: string }
|
|
27
|
+
try {
|
|
28
|
+
const client = getClient()
|
|
29
|
+
const res = await client.api.merchant.login.$post({
|
|
30
|
+
json: { username: p.username, password: p.password },
|
|
31
|
+
})
|
|
32
|
+
const data = await res.json()
|
|
33
|
+
return ok(data)
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return fail(err instanceof Error ? err.message : 'Failed to login')
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
site.command('me', {
|
|
41
|
+
description: 'Get current merchant profile',
|
|
42
|
+
parameters: z.object({}),
|
|
43
|
+
handler: async () => {
|
|
44
|
+
try {
|
|
45
|
+
const client = getClient()
|
|
46
|
+
const res = await client.api.merchant.me.$get()
|
|
47
|
+
const data = await res.json()
|
|
48
|
+
return ok(data)
|
|
49
|
+
} catch (err) {
|
|
50
|
+
return fail(err instanceof Error ? err.message : 'Failed to get merchant profile')
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
site.command('stats', {
|
|
56
|
+
description: 'Get merchant statistics',
|
|
57
|
+
parameters: z.object({}),
|
|
58
|
+
handler: async () => {
|
|
59
|
+
try {
|
|
60
|
+
const client = getClient()
|
|
61
|
+
const res = await client.api.merchant.stats.$get()
|
|
62
|
+
const data = await res.json()
|
|
63
|
+
return ok(data)
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return fail(err instanceof Error ? err.message : 'Failed to get merchant stats')
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
site.command('list-products', {
|
|
71
|
+
description: 'List merchant products',
|
|
72
|
+
parameters: z.object({
|
|
73
|
+
page: z.coerce.number().int().positive().default(1).describe('Page number'),
|
|
74
|
+
'page-size': z.coerce.number().int().positive().max(100).default(20).describe('Page size'),
|
|
75
|
+
status: z
|
|
76
|
+
.enum(['active', 'inactive', 'out_of_stock'])
|
|
77
|
+
.optional()
|
|
78
|
+
.describe('Filter by status'),
|
|
79
|
+
}),
|
|
80
|
+
handler: async (params: unknown) => {
|
|
81
|
+
const p = params as { page: number; 'page-size': number; status?: string }
|
|
82
|
+
try {
|
|
83
|
+
const client = getClient()
|
|
84
|
+
const query: Record<string, string> = {
|
|
85
|
+
page: String(p.page),
|
|
86
|
+
pageSize: String(p['page-size']),
|
|
87
|
+
}
|
|
88
|
+
if (p.status) query.status = p.status
|
|
89
|
+
const res = await client.api.merchant.products.$get({ query })
|
|
90
|
+
const data = await res.json()
|
|
91
|
+
return ok(data)
|
|
92
|
+
} catch (err) {
|
|
93
|
+
return fail(err instanceof Error ? err.message : 'Failed to list products')
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
site.command('create-product', {
|
|
99
|
+
description: 'Create a new product',
|
|
100
|
+
parameters: createProductParams,
|
|
101
|
+
handler: async params => {
|
|
102
|
+
// @ts-expect-error -- auto-command passes unknown, we parse from zod schema
|
|
103
|
+
const p: z.infer<typeof createProductParams> = params
|
|
104
|
+
try {
|
|
105
|
+
const client = getClient()
|
|
106
|
+
const res = await client.api.merchant.products.$post({
|
|
107
|
+
json: {
|
|
108
|
+
name: p.name,
|
|
109
|
+
description: p.description,
|
|
110
|
+
price: p.price,
|
|
111
|
+
stock: p.stock,
|
|
112
|
+
status: p.status,
|
|
113
|
+
imageUrl: p['image-url'],
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
const data = await res.json()
|
|
117
|
+
return ok(data, ['Product created'])
|
|
118
|
+
} catch (err) {
|
|
119
|
+
return fail(err instanceof Error ? err.message : 'Failed to create product')
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
}
|
|
@@ -13,7 +13,12 @@ export function registerOrderCommands(site: SiteInstance) {
|
|
|
13
13
|
'customer-name': z.string().optional().describe('Filter by customer name'),
|
|
14
14
|
}),
|
|
15
15
|
handler: async (params: unknown) => {
|
|
16
|
-
const p = params as {
|
|
16
|
+
const p = params as {
|
|
17
|
+
limit: number
|
|
18
|
+
offset: number
|
|
19
|
+
status?: string
|
|
20
|
+
'customer-name'?: string
|
|
21
|
+
}
|
|
17
22
|
try {
|
|
18
23
|
const client = getClient()
|
|
19
24
|
const query: Record<string, string> = {
|
|
@@ -58,7 +63,12 @@ export function registerOrderCommands(site: SiteInstance) {
|
|
|
58
63
|
amount: z.coerce.number().positive().describe('Order amount'),
|
|
59
64
|
}),
|
|
60
65
|
handler: async (params: unknown) => {
|
|
61
|
-
const p = params as {
|
|
66
|
+
const p = params as {
|
|
67
|
+
'customer-name': string
|
|
68
|
+
'customer-email': string
|
|
69
|
+
'product-name': string
|
|
70
|
+
amount: number
|
|
71
|
+
}
|
|
62
72
|
try {
|
|
63
73
|
const client = getClient()
|
|
64
74
|
const res = await client.api.orders.$post({
|
|
@@ -81,7 +91,10 @@ export function registerOrderCommands(site: SiteInstance) {
|
|
|
81
91
|
description: 'Update order status',
|
|
82
92
|
parameters: z.object({
|
|
83
93
|
id: z.string().describe('Order ID'),
|
|
84
|
-
status: z
|
|
94
|
+
status: z
|
|
95
|
+
.enum(['pending', 'processing', 'completed', 'cancelled', 'disputed'])
|
|
96
|
+
.optional()
|
|
97
|
+
.describe('New status'),
|
|
85
98
|
}),
|
|
86
99
|
handler: async (params: unknown) => {
|
|
87
100
|
const p = params as { id: string; status?: string }
|
|
@@ -152,7 +152,13 @@ export function registerPermissionCommands(site: SiteInstance) {
|
|
|
152
152
|
'resource-type': z.string().optional().describe('Filter by resource type'),
|
|
153
153
|
}),
|
|
154
154
|
handler: async (params: unknown) => {
|
|
155
|
-
const p = params as {
|
|
155
|
+
const p = params as {
|
|
156
|
+
limit: number
|
|
157
|
+
offset: number
|
|
158
|
+
'user-id'?: string
|
|
159
|
+
action?: string
|
|
160
|
+
'resource-type'?: string
|
|
161
|
+
}
|
|
156
162
|
try {
|
|
157
163
|
const client = getClient()
|
|
158
164
|
const query: Record<string, string> = {
|
|
@@ -50,7 +50,10 @@ export function registerTicketCommands(site: SiteInstance) {
|
|
|
50
50
|
'customer-email': z.string().email().describe('Customer email'),
|
|
51
51
|
subject: z.string().min(1).describe('Ticket subject'),
|
|
52
52
|
description: z.string().min(1).describe('Ticket description'),
|
|
53
|
-
category: z
|
|
53
|
+
category: z
|
|
54
|
+
.enum(['technical', 'billing', 'feature_request', 'bug_report', 'general'])
|
|
55
|
+
.default('general')
|
|
56
|
+
.describe('Category'),
|
|
54
57
|
priority: z.enum(['low', 'medium', 'high', 'urgent']).default('medium').describe('Priority'),
|
|
55
58
|
}),
|
|
56
59
|
handler: async (params: unknown) => {
|
|
@@ -70,7 +73,12 @@ export function registerTicketCommands(site: SiteInstance) {
|
|
|
70
73
|
customerEmail: p['customer-email'],
|
|
71
74
|
subject: p.subject,
|
|
72
75
|
description: p.description,
|
|
73
|
-
category: p.category as
|
|
76
|
+
category: p.category as
|
|
77
|
+
| 'technical'
|
|
78
|
+
| 'billing'
|
|
79
|
+
| 'feature_request'
|
|
80
|
+
| 'bug_report'
|
|
81
|
+
| 'general',
|
|
74
82
|
priority: p.priority as 'low' | 'medium' | 'high' | 'urgent',
|
|
75
83
|
},
|
|
76
84
|
})
|
|
@@ -86,7 +94,10 @@ export function registerTicketCommands(site: SiteInstance) {
|
|
|
86
94
|
description: 'Update ticket status',
|
|
87
95
|
parameters: z.object({
|
|
88
96
|
id: z.string().describe('Ticket ID'),
|
|
89
|
-
status: z
|
|
97
|
+
status: z
|
|
98
|
+
.enum(['open', 'closed', 'in_progress', 'waiting_customer', 'resolved'])
|
|
99
|
+
.optional()
|
|
100
|
+
.describe('New status'),
|
|
90
101
|
'assigned-to': z.string().optional().describe('Assign to user'),
|
|
91
102
|
}),
|
|
92
103
|
handler: async (params: unknown) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@import
|
|
1
|
+
@import 'tailwindcss';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Global styles
|
|
@@ -10,91 +10,89 @@
|
|
|
10
10
|
|
|
11
11
|
body {
|
|
12
12
|
margin: 0;
|
|
13
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
14
|
-
'
|
|
15
|
-
sans-serif;
|
|
13
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
|
14
|
+
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
16
15
|
-webkit-font-smoothing: antialiased;
|
|
17
16
|
-moz-osx-font-smoothing: grayscale;
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
code {
|
|
21
|
-
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
22
|
-
monospace;
|
|
20
|
+
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
#root {
|
|
26
24
|
min-height: 100vh;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
[data-theme=
|
|
27
|
+
[data-theme='dark'] {
|
|
30
28
|
color-scheme: dark;
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
[data-theme=
|
|
31
|
+
[data-theme='dark'] body {
|
|
34
32
|
background-color: #141414;
|
|
35
33
|
color: rgba(255, 255, 255, 0.85);
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
[data-theme=
|
|
36
|
+
[data-theme='dark'] .bg-white {
|
|
39
37
|
background-color: #1f1f1f !important;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
[data-theme=
|
|
40
|
+
[data-theme='dark'] .bg-gray-50 {
|
|
43
41
|
background-color: #1a1a1a !important;
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
[data-theme=
|
|
44
|
+
[data-theme='dark'] .bg-gray-100 {
|
|
47
45
|
background-color: #1f1f1f !important;
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
[data-theme=
|
|
48
|
+
[data-theme='dark'] .text-gray-900 {
|
|
51
49
|
color: rgba(255, 255, 255, 0.95) !important;
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
[data-theme=
|
|
52
|
+
[data-theme='dark'] .text-gray-800 {
|
|
55
53
|
color: rgba(255, 255, 255, 0.85) !important;
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
[data-theme=
|
|
56
|
+
[data-theme='dark'] .text-gray-700 {
|
|
59
57
|
color: rgba(255, 255, 255, 0.75) !important;
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
[data-theme=
|
|
60
|
+
[data-theme='dark'] .text-gray-600 {
|
|
63
61
|
color: rgba(255, 255, 255, 0.65) !important;
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
[data-theme=
|
|
64
|
+
[data-theme='dark'] .text-gray-500 {
|
|
67
65
|
color: rgba(255, 255, 255, 0.55) !important;
|
|
68
66
|
}
|
|
69
67
|
|
|
70
|
-
[data-theme=
|
|
68
|
+
[data-theme='dark'] .border-gray-200 {
|
|
71
69
|
border-color: #303030 !important;
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
[data-theme=
|
|
72
|
+
[data-theme='dark'] .border-gray-100 {
|
|
75
73
|
border-color: #262626 !important;
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
[data-theme=
|
|
76
|
+
[data-theme='dark'] .hover\:bg-gray-100:hover {
|
|
79
77
|
background-color: rgba(255, 255, 255, 0.08) !important;
|
|
80
78
|
}
|
|
81
79
|
|
|
82
|
-
[data-theme=
|
|
80
|
+
[data-theme='dark'] .hover\:bg-gray-50:hover {
|
|
83
81
|
background-color: rgba(255, 255, 255, 0.06) !important;
|
|
84
82
|
}
|
|
85
83
|
|
|
86
|
-
[data-theme=
|
|
84
|
+
[data-theme='dark'] .text-gray-400 {
|
|
87
85
|
color: #8c8c8c;
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
[data-theme=
|
|
88
|
+
[data-theme='dark'] .text-gray-300 {
|
|
91
89
|
color: #a0a0a0;
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
[data-theme=
|
|
92
|
+
[data-theme='dark'] .bg-blue-50 {
|
|
95
93
|
background-color: rgba(59, 130, 246, 0.1);
|
|
96
94
|
}
|
|
97
95
|
|
|
98
|
-
[data-theme=
|
|
96
|
+
[data-theme='dark'] .border-gray-300 {
|
|
99
97
|
border-color: #434343;
|
|
100
98
|
}
|
package/template/vite.config.ts
CHANGED
|
@@ -85,6 +85,11 @@ export default defineConfig({
|
|
|
85
85
|
}),
|
|
86
86
|
],
|
|
87
87
|
},
|
|
88
|
+
onwarn(warning, defaultHandler) {
|
|
89
|
+
// Suppress antd "use client" directive warnings (React Server Components marker)
|
|
90
|
+
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') return
|
|
91
|
+
defaultHandler(warning)
|
|
92
|
+
},
|
|
88
93
|
},
|
|
89
94
|
},
|
|
90
95
|
resolve: {
|