@gadmin2n/schematics 0.0.83 → 0.0.85

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.
Files changed (20) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +1 -1
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/lib/page-helpers.ts +1 -1
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/{syncDataMngtPages.ts → sync-data-mngt-pages.ts} +25 -2
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/App.tsx +1 -0
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/inspectorActions.ts +1 -2
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/header.tsx +2 -2
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/sider.tsx +14 -6
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +8 -6
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/DevShell.tsx +2 -3
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +25 -2
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useUserPageAccess.ts +13 -3
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/index.tsx +9 -0
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/list.tsx +3 -1
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/list.tsx +13 -2
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/list.tsx +13 -3
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/list.tsx +13 -3
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/index.tsx +12 -1
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/index.tsx +2 -2
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/list.tsx +3 -1
  20. package/package.json +1 -1
@@ -26,7 +26,7 @@
26
26
  "migrate:status": "dotenv -e .env.local -e .env -- prisma migrate status",
27
27
  "generate": "dotenv -e .env.local -e .env -- npx prisma generate",
28
28
  "generate:dev": "npm run migrate:dev && dotenv -e .env.local -e .env -- npx prisma generate",
29
- "postgenerate:dev": "dotenv -e .env.local -e .env -- ts-node scripts/syncDataMngtPages.ts && dotenv -e .env.local -e .env -- ts-node scripts/sync-resources.ts",
29
+ "postgenerate:dev": "dotenv -e .env.local -e .env -- ts-node scripts/sync-data-mngt-pages.ts && dotenv -e .env.local -e .env -- ts-node scripts/sync-resources.ts",
30
30
  "generate:web": "dotenv -e .env.local -e .env -- npx prisma generate --generator react",
31
31
  "generate:server": "dotenv -e .env.local -e .env -- npx prisma generate --generator client --generator nestjs",
32
32
  "push:db": "dotenv -e .env.local -e .env -- prisma db push --skip-generate",
@@ -2,7 +2,7 @@
2
2
  * page-helpers.ts — 页面与权限管理的共享 DB 操作原语
3
3
  *
4
4
  * 接受 PrismaClient 作为参数,可被 CLI 脚本(page-manage.ts / permission-manage.ts)
5
- * 和 seed 函数(syncDataMngtPages.ts / seed/permissions.ts)共同调用。
5
+ * 和 ../sync-data-mngt-pages.ts / seed/permissions.ts)共同调用。
6
6
  */
7
7
 
8
8
  import { PrismaClient } from '@prisma/client';
@@ -7,6 +7,22 @@ import {
7
7
  } from './lib/page-helpers';
8
8
  import { readPrismaModels } from './prismaModels';
9
9
 
10
+ /**
11
+ * Models whose Page record should be marked `isVirtual = true`,
12
+ * i.e. routes / resources / role grants are still seeded so that the page
13
+ * remains reachable by URL and protected by RBAC, but the page is hidden
14
+ * from the auto-generated 「系统管理 / 数据管理」 menu.
15
+ *
16
+ * Use this when a model's CRUD page is exposed elsewhere (e.g. embedded
17
+ * inside another custom admin page) instead of as its own menu entry.
18
+ */
19
+ const HIDDEN_FROM_DATA_MNGT_MENU = new Set<string>([
20
+ // Surfaced via a button in /admin/agenda-jobs (Cron Jobs page).
21
+ 'agendaJob',
22
+ // Surfaced via a button in /admin/workflow (Workflow list page).
23
+ 'workflowEventOutbox',
24
+ ]);
25
+
10
26
  // ─── Main Seed Function ───────────────────────────────────────────────────────
11
27
 
12
28
  /**
@@ -64,6 +80,7 @@ export async function seedDataMngtPages(prisma: PrismaClient): Promise<void> {
64
80
  console.log(`[seedDataMngtPages] ── ${model.name} ──`);
65
81
 
66
82
  const pagePath = `/admin/data-mngt/${model.slug}`;
83
+ const hideFromMenu = HIDDEN_FROM_DATA_MNGT_MENU.has(model.code);
67
84
 
68
85
  // 1 + 2 + 3: Upsert page, resource, and PageResource link
69
86
  const page = await upsertPage(
@@ -74,11 +91,17 @@ export async function seedDataMngtPages(prisma: PrismaClient): Promise<void> {
74
91
  sortOrder: 2000 + index * 10,
75
92
  parentId: dataMngtPage.id,
76
93
  path: pagePath,
94
+ isVirtual: hideFromMenu,
77
95
  },
78
- { path: pagePath }, // keep path in sync with model name on update
96
+ // keep path in sync with model name on update;
97
+ // also force isVirtual when in the hide-from-menu list so existing
98
+ // rows get reconciled (otherwise the default upsertPage update is {}).
99
+ { path: pagePath, ...(hideFromMenu && { isVirtual: true }) },
79
100
  );
80
101
  console.log(
81
- `[seedDataMngtPages] Page upserted: ${page.code} → ${pagePath} (id=${page.id})`,
102
+ `[seedDataMngtPages] Page upserted: ${page.code} → ${pagePath} (id=${
103
+ page.id
104
+ })${hideFromMenu ? ' [hidden from menu]' : ''}`,
82
105
  );
83
106
 
84
107
  const resource = await bindResourceToPage(
@@ -76,6 +76,7 @@ function App() {
76
76
  options={{
77
77
  syncWithLocation: true,
78
78
  warnWhenUnsavedChanges: true,
79
+ breadcrumb: null,
79
80
  }}
80
81
  >
81
82
  {resources.length === 0 ? (
@@ -552,8 +552,7 @@ export function getInspectorActions(
552
552
  promptTemplate: `为 ${r} 搜索栏添加 Checkbox 多选过滤`,
553
553
  promptPrefix: '要添加的字段:',
554
554
  requiresInput: true,
555
- inputPlaceholder:
556
- '请填写字段名及选项,例如:字段 category',
555
+ inputPlaceholder: '请填写字段名及选项,例如:字段 category',
557
556
  promptSuffix:
558
557
  '\n你先理解下这个需求,然后找我澄清需求(非技术方案),我确认后再行动',
559
558
  },
@@ -63,7 +63,7 @@ export const Header: React.FC = () => {
63
63
 
64
64
  return (
65
65
  <Layout.Header style={headerStyles} {...agentAttrs({ type: 'app-header' })}>
66
- <Select
66
+ {/* <Select
67
67
  showSearch
68
68
  defaultValue={business.gameId}
69
69
  style={{ width: 160 }}
@@ -87,7 +87,7 @@ export const Header: React.FC = () => {
87
87
  setBusiness(gameInfo);
88
88
  window.location.reload();
89
89
  }}
90
- />
90
+ /> */}
91
91
  <Dropdown menu={langMenu}>
92
92
  <Button type="link">
93
93
  <Space>
@@ -16,6 +16,7 @@ import {
16
16
  useGo,
17
17
  } from '@refinedev/core';
18
18
  import { useTranslation } from 'react-i18next';
19
+ import { useLocation } from 'react-router-dom';
19
20
 
20
21
  import {
21
22
  BarsOutlined,
@@ -87,6 +88,7 @@ const getMenuLabel = (
87
88
  export const Sider: React.FC = () => {
88
89
  const { token } = useToken();
89
90
  const { menuItems, selectedKey, defaultOpenKeys } = useMenu();
91
+ const { pathname: currentPathname } = useLocation();
90
92
  const { t, i18n } = useTranslation();
91
93
  const currentLocale = i18n.language;
92
94
 
@@ -205,12 +207,18 @@ export const Sider: React.FC = () => {
205
207
  }
206
208
 
207
209
  // Skip auto-redirect for CRUD detail pages (edit/show/create)
208
- // These pages are not in the menu but are valid navigation targets
210
+ // These pages are not in the menu but are valid navigation targets.
211
+ // Also skip auto-generated /admin/data-mngt/* CRUD list pages —
212
+ // some of them are intentionally hidden from the sidebar via
213
+ // meta.hide but remain reachable through buttons on other pages.
214
+ // Use the live router pathname (not Refine's selectedKey, which
215
+ // collapses to an ancestor when the resource is hidden).
209
216
  if (
210
- selectedKey &&
211
- (selectedKey.includes('/edit/') ||
212
- selectedKey.includes('/show/') ||
213
- selectedKey.endsWith('/create'))
217
+ currentPathname &&
218
+ (currentPathname.includes('/edit/') ||
219
+ currentPathname.includes('/show/') ||
220
+ currentPathname.endsWith('/create') ||
221
+ currentPathname.includes('/data-mngt/'))
214
222
  ) {
215
223
  return;
216
224
  }
@@ -248,7 +256,7 @@ export const Sider: React.FC = () => {
248
256
  }, 300);
249
257
 
250
258
  return () => clearTimeout(timer);
251
- }, [items, selectedKey, go]);
259
+ }, [items, selectedKey, currentPathname, go]);
252
260
 
253
261
  const handleOpenChange = useCallback(
254
262
  (keys: string[]) => {
@@ -162,10 +162,12 @@ const S = ({ children }: { children: React.ReactNode }) => (
162
162
  // ─── Route Registry ──────────────────────────────────────────────────────────
163
163
  //
164
164
  // 路由路径命名规则:
165
- // Sider 组件会对不在菜单中的路径执行 auto-redirect。只有路径中包含
166
- // `/edit/`、`/show/` 或以 `/create` 结尾的页面才会被豁免。
167
- // 因此,所有不在侧边栏菜单中的子页面(详情、编辑、创建等),
168
- // 路径必须包含上述关键词,例如:
165
+ // Sider 组件会对不在菜单中的路径执行 auto-redirect。豁免规则(见
166
+ // components/layout/sider.tsx 中的 useEffect):
167
+ // 路径含 `/edit/` 或 `/show/`,或以 `/create` 结尾(CRUD 详情页)
168
+ // 路径含 `/data-mngt/`(数据管理 CRUD 列表,部分通过 meta.hide 隐藏)
169
+ // ❌ 其它不在菜单的列表路径会被自动重定向到第一个菜单项
170
+ // 因此,新加的不在侧边栏的子页面,路径必须命中上述某条豁免规则,例如:
169
171
  // ✅ instance/show/:id
170
172
  // ✅ node-instances/edit/:id
171
173
  // ❌ instance/:id ← 会被 auto-redirect 导致 404
@@ -256,7 +258,7 @@ export const routeRegistry: Record<string, RouteEntry> = {
256
258
  path: 'p/:slug',
257
259
  component: lazy(() => import('routes/canvas-page')),
258
260
  },
259
- game: {
261
+ /*game: {
260
262
  path: 'game-list',
261
263
  children: {
262
264
  list: {
@@ -285,7 +287,7 @@ export const routeRegistry: Record<string, RouteEntry> = {
285
287
  ),
286
288
  },
287
289
  },
288
- },
290
+ },*/
289
291
  // Agenda Jobs — sortOrder 1080, code: admin.agenda
290
292
  agenda: {
291
293
  path: 'agenda-jobs',
@@ -219,9 +219,8 @@ export default function DevShell() {
219
219
  });
220
220
  } else {
221
221
  setTimeout(() => {
222
- startNewConversationAndSend(sdk, data.payload).catch(
223
- (err: any) =>
224
- console.error('[DevShell] sendUserPrompt failed:', err),
222
+ startNewConversationAndSend(sdk, data.payload).catch((err: any) =>
223
+ console.error('[DevShell] sendUserPrompt failed:', err),
225
224
  );
226
225
  }, 300);
227
226
  }
@@ -130,8 +130,12 @@ export const useDynamicResources = (): IResourceItem[] => {
130
130
  sortedAccessiblePages.forEach((page) => {
131
131
  if (!page) return;
132
132
 
133
- // Skip virtual pages
134
- if (page.isVirtual) return;
133
+ // NOTE: isVirtual pages are NOT skipped here — keeping them in the
134
+ // resources array lets Refine hooks (useResource, useNavigation, etc.)
135
+ // resolve the page's metadata, and React Router routes for these
136
+ // pages are registered independently via routeRegistry. The menu
137
+ // entry is hidden below by setting `meta.hide = true`, which
138
+ // Refine's useMenu honours.
135
139
 
136
140
  // Skip children of pages that use tabs
137
141
  if (page.parentId) {
@@ -191,6 +195,11 @@ export const useDynamicResources = (): IResourceItem[] => {
191
195
  parentPageCode: page.parentId
192
196
  ? pageMap.get(page.parentId)?.code
193
197
  : undefined,
198
+ // Refine's useMenu skips items whose meta.hide === true.
199
+ // This lets us hide a CRUD page from the auto-generated
200
+ // 「数据管理」menu (e.g. AgendaJob is surfaced from the Cron
201
+ // Jobs custom page instead) while keeping the route reachable.
202
+ ...(page.isVirtual && { hide: true }),
194
203
  },
195
204
  };
196
205
 
@@ -202,6 +211,20 @@ export const useDynamicResources = (): IResourceItem[] => {
202
211
  const dynamicResources = resultResources;
203
212
  const allResources = dynamicResources;
204
213
 
214
+ // 防御性保护:用户已有角色但算出来 0 个资源,说明 rolePagesData
215
+ // 还没到位(isLoading 误报为 false 时进了这条分支),不要把空结果
216
+ // 永久写入 cachedResources,否则后续真正加载完成后无法重算
217
+ if (allResources.length === 0 && roleNames.length > 0) {
218
+ isComputing = false;
219
+ if (import.meta.env.DEV) {
220
+ console.warn(
221
+ '[useDynamicResources] ⚠️ Skip caching: 0 resources but roles present',
222
+ { roleNames },
223
+ );
224
+ }
225
+ return [];
226
+ }
227
+
205
228
  // Cache the result - will be used for all subsequent calls
206
229
  cachedResources = allResources;
207
230
  isComputing = false;
@@ -333,10 +333,20 @@ export const useUserPageAccess = (): UseUserPageAccessResult => {
333
333
  if (hasCache && pagesData && rolePagesData) return false;
334
334
  if (isRoleLoading) return true;
335
335
  if (!pagesData) return true;
336
- if (roleNames.length > 0 && roleIds.length > 0 && !rolePagesData)
337
- return true;
336
+ // 等待 /role/findMany 返回(roleNames 已拿到但 rolesData 还在路上)
337
+ if (roleNames.length > 0 && !rolesData) return true;
338
+ // 等待 /rolePages/findMany 返回
339
+ if (roleIds.length > 0 && !rolePagesData) return true;
338
340
  return false;
339
- }, [isRoleLoading, pagesData, roleNames, roleIds, rolePagesData, hasCache]);
341
+ }, [
342
+ isRoleLoading,
343
+ pagesData,
344
+ roleNames,
345
+ rolesData,
346
+ roleIds,
347
+ rolePagesData,
348
+ hasCache,
349
+ ]);
340
350
 
341
351
  return {
342
352
  accessiblePageIds,
@@ -19,6 +19,7 @@ import {
19
19
  message,
20
20
  } from 'antd';
21
21
  import {
22
+ DatabaseOutlined,
22
23
  DeleteOutlined,
23
24
  PlayCircleOutlined,
24
25
  PlusOutlined,
@@ -445,6 +446,14 @@ export default function AgendaJobsPage() {
445
446
  Cron Jobs
446
447
  </Title>
447
448
  <Space>
449
+ <Tooltip title="查看 AgendaJob 表原始数据">
450
+ <Button
451
+ icon={<DatabaseOutlined />}
452
+ onClick={() => navigate('/admin/data-mngt/agenda-job')}
453
+ >
454
+ AgendaJob 表
455
+ </Button>
456
+ </Tooltip>
448
457
  <Button
449
458
  type="primary"
450
459
  icon={<PlusOutlined />}
@@ -22,7 +22,7 @@ import {
22
22
  useTranslate,
23
23
  useApiUrl,
24
24
  } from '@refinedev/core';
25
- import { useLocation } from 'react-router-dom';
25
+ import { useLocation, useNavigate } from 'react-router-dom';
26
26
  import {
27
27
  getColumns,
28
28
  ModelType,
@@ -61,6 +61,7 @@ export const AgendaJobList: React.FC<IResourceComponentsProps> = () => {
61
61
  const resourceName = 'agendaJob';
62
62
  const t = useTranslate();
63
63
  const apiUrl = useApiUrl();
64
+ const navigate = useNavigate();
64
65
  const { search } = useLocation();
65
66
  const { parsedSorter, parsedFilters } = parseTableParams(search);
66
67
 
@@ -163,6 +164,7 @@ export const AgendaJobList: React.FC<IResourceComponentsProps> = () => {
163
164
  return (
164
165
  <List
165
166
  headerProps={{
167
+ onBack: () => navigate('/admin/agenda-jobs'),
166
168
  subTitle: (
167
169
  <BulkActions
168
170
  selectedRowKeys={batchOps.selectedRowKeys}
@@ -17,6 +17,7 @@ import {
17
17
  Modal,
18
18
  message,
19
19
  Tabs,
20
+ Typography,
20
21
  } from 'antd';
21
22
  import {
22
23
  SaveOutlined,
@@ -1280,7 +1281,17 @@ export const PageManagementListPage: React.FC = () => {
1280
1281
 
1281
1282
  return (
1282
1283
  <div>
1283
- <Space style={{ marginBottom: 16 }}>
1284
+ <div
1285
+ style={{
1286
+ display: 'flex',
1287
+ justifyContent: 'space-between',
1288
+ alignItems: 'center',
1289
+ marginBottom: 16,
1290
+ }}
1291
+ >
1292
+ <Typography.Title level={4} style={{ margin: 0 }}>
1293
+ Page mgnts
1294
+ </Typography.Title>
1284
1295
  <Button
1285
1296
  type="primary"
1286
1297
  onClick={() =>
@@ -1292,7 +1303,7 @@ export const PageManagementListPage: React.FC = () => {
1292
1303
  >
1293
1304
  Create Page
1294
1305
  </Button>
1295
- </Space>
1306
+ </div>
1296
1307
 
1297
1308
  <Tabs
1298
1309
  activeKey={activeTab}
@@ -1,6 +1,6 @@
1
1
  import React, { useState, useMemo } from 'react';
2
2
  import { useTable, FilterDropdown } from '@refinedev/antd';
3
- import { Table, Button, Space, Tooltip, Input } from 'antd';
3
+ import { Table, Button, Space, Tooltip, Input, Typography } from 'antd';
4
4
  import {
5
5
  EditOutlined,
6
6
  EyeOutlined,
@@ -117,7 +117,17 @@ export const ResourceManagementListPage: React.FC = () => {
117
117
 
118
118
  return (
119
119
  <div>
120
- <Space style={{ marginBottom: 16 }}>
120
+ <div
121
+ style={{
122
+ display: 'flex',
123
+ justifyContent: 'space-between',
124
+ alignItems: 'center',
125
+ marginBottom: 16,
126
+ }}
127
+ >
128
+ <Typography.Title level={4} style={{ margin: 0 }}>
129
+ Resource mgnts
130
+ </Typography.Title>
121
131
  <Button
122
132
  type="primary"
123
133
  onClick={() =>
@@ -129,7 +139,7 @@ export const ResourceManagementListPage: React.FC = () => {
129
139
  >
130
140
  Create Resource
131
141
  </Button>
132
- </Space>
142
+ </div>
133
143
  <Table {...tableProps} rowKey="id">
134
144
  <Table.Column
135
145
  dataIndex="code"
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback, useMemo, useState } from 'react';
2
2
  import { useTable } from '@refinedev/antd';
3
3
  import { useGetLocale, useGetIdentity } from '@refinedev/core';
4
- import { Table, Button, Space, Tooltip, message } from 'antd';
4
+ import { Table, Button, Space, Tooltip, message, Typography } from 'antd';
5
5
 
6
6
  import { EditModal } from './Components/EditModal';
7
7
  import { CreateModal } from './Components/CreateModal';
@@ -321,7 +321,17 @@ export const RoleManagementListPage: React.FC = () => {
321
321
 
322
322
  return (
323
323
  <div>
324
- <Space style={{ marginBottom: 16 }}>
324
+ <div
325
+ style={{
326
+ display: 'flex',
327
+ justifyContent: 'space-between',
328
+ alignItems: 'center',
329
+ marginBottom: 16,
330
+ }}
331
+ >
332
+ <Typography.Title level={4} style={{ margin: 0 }}>
333
+ Role mgnts
334
+ </Typography.Title>
325
335
  <Button
326
336
  type="primary"
327
337
  onClick={() =>
@@ -333,7 +343,7 @@ export const RoleManagementListPage: React.FC = () => {
333
343
  >
334
344
  Create Role
335
345
  </Button>
336
- </Space>
346
+ </div>
337
347
  <Table {...tableProps} rowKey="id">
338
348
  <Table.Column dataIndex="name" title="Name" />
339
349
  <Table.Column dataIndex="description" title="Description" />
@@ -15,6 +15,7 @@ import {
15
15
  message,
16
16
  } from 'antd';
17
17
  import {
18
+ DatabaseOutlined,
18
19
  DeleteOutlined,
19
20
  EditOutlined,
20
21
  ExportOutlined,
@@ -412,7 +413,16 @@ export default function WorkflowListPage() {
412
413
  Workflows
413
414
  </Title>
414
415
  <Space>
415
- <Button icon={<ReloadOutlined />} onClick={fetchData} />
416
+ <Tooltip title="查看 WorkflowEventOutbox 表原始数据">
417
+ <Button
418
+ icon={<DatabaseOutlined />}
419
+ onClick={() =>
420
+ navigate('/admin/data-mngt/workflow-event-outbox')
421
+ }
422
+ >
423
+ EventOutbox 表
424
+ </Button>
425
+ </Tooltip>
416
426
  <Button
417
427
  icon={<ImportOutlined />}
418
428
  onClick={() => setImportModalOpen(true)}
@@ -426,6 +436,7 @@ export default function WorkflowListPage() {
426
436
  >
427
437
  New Workflow
428
438
  </Button>
439
+ <Button icon={<ReloadOutlined />} onClick={fetchData} />
429
440
  </Space>
430
441
  </div>
431
442
  </Card>
@@ -236,10 +236,9 @@ export default function NodeInstanceListPage() {
236
236
  }}
237
237
  >
238
238
  <Title level={4} style={{ margin: 0 }}>
239
- Node Instance Mgnt
239
+ Node instance mgnts
240
240
  </Title>
241
241
  <Space>
242
- <Button icon={<ReloadOutlined />} onClick={fetchData} />
243
242
  <Button
244
243
  type="primary"
245
244
  icon={<PlusOutlined />}
@@ -247,6 +246,7 @@ export default function NodeInstanceListPage() {
247
246
  >
248
247
  New Instance
249
248
  </Button>
249
+ <Button icon={<ReloadOutlined />} onClick={fetchData} />
250
250
  </Space>
251
251
  </div>
252
252
  </Card>
@@ -22,7 +22,7 @@ import {
22
22
  useTranslate,
23
23
  useApiUrl,
24
24
  } from '@refinedev/core';
25
- import { useLocation } from 'react-router-dom';
25
+ import { useLocation, useNavigate } from 'react-router-dom';
26
26
  import {
27
27
  getColumns,
28
28
  ModelType,
@@ -66,6 +66,7 @@ export const WorkflowEventOutboxList: React.FC<
66
66
  const resourceName = 'workflowEventOutbox';
67
67
  const t = useTranslate();
68
68
  const apiUrl = useApiUrl();
69
+ const navigate = useNavigate();
69
70
  const { search } = useLocation();
70
71
  const { parsedSorter, parsedFilters } = parseTableParams(search);
71
72
 
@@ -172,6 +173,7 @@ export const WorkflowEventOutboxList: React.FC<
172
173
  return (
173
174
  <List
174
175
  headerProps={{
176
+ onBack: () => navigate('/admin/workflow'),
175
177
  subTitle: (
176
178
  <BulkActions
177
179
  selectedRowKeys={batchOps.selectedRowKeys}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gadmin2n/schematics",
3
- "version": "0.0.83",
3
+ "version": "0.0.85",
4
4
  "description": "Gadmin - modern, fast, powerful node.js web framework (@schematics)",
5
5
  "main": "dist/index.js",
6
6
  "files": [