@locode2/harness 0.1.0-preview.1
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 +27 -0
- package/THIRD_PARTY_LICENSES.txt +32769 -0
- package/THIRD_PARTY_NOTICES.md +13 -0
- package/apps/host/dist/document-parser-worker.js +215 -0
- package/apps/host/dist/frontend-runtime-worker.js +1755 -0
- package/apps/host/dist/index.js +23380 -0
- package/apps/web/dist/assets/LocalMonacoEditor-CXkKwxiP.css +1 -0
- package/apps/web/dist/assets/LocalMonacoEditor-WKAHQmzG.js +940 -0
- package/apps/web/dist/assets/LogsView-BFFFSFB-.js +1 -0
- package/apps/web/dist/assets/PluginsView-DM_ZnENS.js +1 -0
- package/apps/web/dist/assets/SettingsView-Cb5Q4ile.js +1 -0
- package/apps/web/dist/assets/abap-DLDM7-KI.js +1 -0
- package/apps/web/dist/assets/apex-DNDY2TF8.js +1 -0
- package/apps/web/dist/assets/azcli-Y6nb8tq_.js +1 -0
- package/apps/web/dist/assets/bat-BwHxbl9M.js +1 -0
- package/apps/web/dist/assets/bicep-CFznDFnq.js +2 -0
- package/apps/web/dist/assets/cameligo-Bf6VGUru.js +1 -0
- package/apps/web/dist/assets/clojure-Dnu-v4kV.js +1 -0
- package/apps/web/dist/assets/codicon-Brq4_Ui5.ttf +0 -0
- package/apps/web/dist/assets/coffee-Bd8akH9Z.js +1 -0
- package/apps/web/dist/assets/cpp-BbWJElDN.js +1 -0
- package/apps/web/dist/assets/csharp-Co3qMtFm.js +1 -0
- package/apps/web/dist/assets/csp-D-4FJmMZ.js +1 -0
- package/apps/web/dist/assets/css-DdJfP1eB.js +3 -0
- package/apps/web/dist/assets/css.worker-11mhRRLC.js +97 -0
- package/apps/web/dist/assets/cssMode-L5f5LAEn.js +1 -0
- package/apps/web/dist/assets/cypher-cTPe9QuQ.js +1 -0
- package/apps/web/dist/assets/dart-BOtBlQCF.js +1 -0
- package/apps/web/dist/assets/dockerfile-BG73LgW2.js +1 -0
- package/apps/web/dist/assets/ecl-BEgZUVRK.js +1 -0
- package/apps/web/dist/assets/editor.worker-DysRFSaV.js +30 -0
- package/apps/web/dist/assets/elixir-BkW5O-1t.js +1 -0
- package/apps/web/dist/assets/flow9-BeJ5waoc.js +1 -0
- package/apps/web/dist/assets/freemarker2-UOwftS75.js +3 -0
- package/apps/web/dist/assets/fsharp-PahG7c26.js +1 -0
- package/apps/web/dist/assets/go-acbASCJo.js +1 -0
- package/apps/web/dist/assets/graphql-BxJiqAUM.js +1 -0
- package/apps/web/dist/assets/handlebars-C_E41ffr.js +1 -0
- package/apps/web/dist/assets/hcl-DtV1sZF8.js +1 -0
- package/apps/web/dist/assets/html-HsrixH2x.js +1 -0
- package/apps/web/dist/assets/html.worker-C8Tw8ncf.js +474 -0
- package/apps/web/dist/assets/htmlMode-DipGmEOi.js +1 -0
- package/apps/web/dist/assets/index-COUF63cT.js +213 -0
- package/apps/web/dist/assets/index-SNSmF2-c.css +1 -0
- package/apps/web/dist/assets/ini-Kd9XrMLS.js +1 -0
- package/apps/web/dist/assets/java-CXBNlu9o.js +1 -0
- package/apps/web/dist/assets/javascript-D36WEqF9.js +1 -0
- package/apps/web/dist/assets/json.worker-BzkYZgJ7.js +62 -0
- package/apps/web/dist/assets/jsonMode-D9BrIats.js +7 -0
- package/apps/web/dist/assets/julia-cl7-CwDS.js +1 -0
- package/apps/web/dist/assets/kotlin-s7OhZKlX.js +1 -0
- package/apps/web/dist/assets/less-9HpZscsL.js +2 -0
- package/apps/web/dist/assets/lexon-OrD6JF1K.js +1 -0
- package/apps/web/dist/assets/liquid-DES89Tjc.js +1 -0
- package/apps/web/dist/assets/lock-keyhole-jo-FJcGq.js +1 -0
- package/apps/web/dist/assets/lspLanguageFeatures-YKkgcn4q.js +4 -0
- package/apps/web/dist/assets/lua-Cyyb5UIc.js +1 -0
- package/apps/web/dist/assets/m3-B8OfTtLu.js +1 -0
- package/apps/web/dist/assets/markdown-BFxVWTOG.js +1 -0
- package/apps/web/dist/assets/mdx-D1Bfax8e.js +1 -0
- package/apps/web/dist/assets/mips-CiqrrVzr.js +1 -0
- package/apps/web/dist/assets/msdax-DmeGPVcC.js +1 -0
- package/apps/web/dist/assets/mysql-C_tMU-Nz.js +1 -0
- package/apps/web/dist/assets/objective-c-BDtDVThU.js +1 -0
- package/apps/web/dist/assets/pascal-vHIfCaH5.js +1 -0
- package/apps/web/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
- package/apps/web/dist/assets/perl-Ub6l9XKa.js +1 -0
- package/apps/web/dist/assets/pgsql-BlNEE0v7.js +1 -0
- package/apps/web/dist/assets/php-BBUBE1dy.js +1 -0
- package/apps/web/dist/assets/pla-DSh2-awV.js +1 -0
- package/apps/web/dist/assets/postiats-CocnycG-.js +1 -0
- package/apps/web/dist/assets/powerquery-tScXyioY.js +1 -0
- package/apps/web/dist/assets/powershell-COWaemsV.js +1 -0
- package/apps/web/dist/assets/protobuf-Brw8urJB.js +2 -0
- package/apps/web/dist/assets/pug-8SOpv6rk.js +1 -0
- package/apps/web/dist/assets/python-DKhPhY0N.js +1 -0
- package/apps/web/dist/assets/qsharp-Bw9ernYp.js +1 -0
- package/apps/web/dist/assets/r-j7ic8hl3.js +1 -0
- package/apps/web/dist/assets/razor-Cha8qrI6.js +1 -0
- package/apps/web/dist/assets/redis-Bu5POkcn.js +1 -0
- package/apps/web/dist/assets/redshift-Bs9aos_-.js +1 -0
- package/apps/web/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
- package/apps/web/dist/assets/ruby-zBfavPgS.js +1 -0
- package/apps/web/dist/assets/rust-BzKRNQWT.js +1 -0
- package/apps/web/dist/assets/sb-BBc9UKZt.js +1 -0
- package/apps/web/dist/assets/scala-D9hQfWCl.js +1 -0
- package/apps/web/dist/assets/scheme-BPhDTwHR.js +1 -0
- package/apps/web/dist/assets/scss-CBJaRo0y.js +3 -0
- package/apps/web/dist/assets/shell-DiJ1NA_G.js +1 -0
- package/apps/web/dist/assets/solidity-Db0IVjzk.js +1 -0
- package/apps/web/dist/assets/sophia-CnS9iZB_.js +1 -0
- package/apps/web/dist/assets/sparql-CJmd_6j2.js +1 -0
- package/apps/web/dist/assets/sql-ClhHkBeG.js +1 -0
- package/apps/web/dist/assets/st-CHwy0fLd.js +1 -0
- package/apps/web/dist/assets/swift-CnmFD0ga.js +1 -0
- package/apps/web/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
- package/apps/web/dist/assets/tcl-Dm6ycUr_.js +1 -0
- package/apps/web/dist/assets/ts.worker-Bupg6llt.js +67722 -0
- package/apps/web/dist/assets/tsMode-CEhssXv8.js +11 -0
- package/apps/web/dist/assets/twig-Csy3S7wG.js +1 -0
- package/apps/web/dist/assets/typescript-DWqmw58R.js +1 -0
- package/apps/web/dist/assets/typespec-Btyra-wh.js +1 -0
- package/apps/web/dist/assets/vb-Db0cS2oM.js +1 -0
- package/apps/web/dist/assets/wgsl-DumH7NcR.js +298 -0
- package/apps/web/dist/assets/workers-BmZvNFRq.js +1 -0
- package/apps/web/dist/assets/xml-WQTAFV9b.js +1 -0
- package/apps/web/dist/assets/yaml-Ke2Lf79d.js +1 -0
- package/apps/web/dist/index.html +15 -0
- package/bin/launch.mjs +71 -0
- package/bin/locode-mini.mjs +12 -0
- package/bin/options.mjs +49 -0
- package/bin/restore-assets.mjs +40 -0
- package/bundled-plugins/fast-frontend/.gitignore +2 -0
- package/bundled-plugins/fast-frontend/README.md +29 -0
- package/bundled-plugins/fast-frontend/harness.plugin.json +123 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/PUBLIC_CONTRACT.md +139 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/contracts/app.schema.json +24 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/contracts/route.schema.json +52 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/examples/app.json +9 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/examples/route.json +8 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/index.html +17 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/package.json +31 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/scripts/smoke-build.mjs +40 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/inspector/index.ts +612 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/main.tsx +17 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/sdk/index.ts +1028 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/shell/RuntimeApp.tsx +380 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/shell/runtime.css +246 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/tsconfig.json +20 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/types/runtime.consumer-smoke.ts +70 -0
- package/bundled-plugins/fast-frontend/runtimes/antd-admin/types/runtime.d.ts +227 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/.gitignore +9 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/.harness/template.json +10 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/index.html +13 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/package.json +34 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/pnpm-lock.yaml +1451 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/pnpm-workspace.yaml +4 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/public/generated/.gitkeep +1 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/scripts/validate-routes.mjs +153 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/app/App.tsx +27 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/app/NotFoundPage.tsx +15 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/features/.gitkeep +1 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/layouts/MainLayout.tsx +77 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/main.tsx +14 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/mocks/dashboard.ts +48 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/pages/dashboard/page.tsx +151 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/pages/dashboard/route.ts +9 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/routes/definition.ts +21 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/routes/menu.tsx +44 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/routes/registry.ts +48 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/routes/router.tsx +34 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/shared/components/business/.gitkeep +1 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/shared/components/business/BusinessProviders.tsx +9 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/styles/global.css +180 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/src/vite-env.d.ts +1 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/tsconfig.app.json +24 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/tsconfig.json +7 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/tsconfig.node.json +17 -0
- package/bundled-plugins/fast-frontend/templates/antd-admin/vite.config.ts +39 -0
- package/npm-shrinkwrap.json +9737 -0
- package/package.json +80 -0
- package/release-integrity.json +168 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import {
|
|
2
|
+
App as AntApp,
|
|
3
|
+
Avatar,
|
|
4
|
+
Breadcrumb,
|
|
5
|
+
ConfigProvider,
|
|
6
|
+
Empty,
|
|
7
|
+
Layout,
|
|
8
|
+
Menu,
|
|
9
|
+
Result,
|
|
10
|
+
Skeleton,
|
|
11
|
+
Space,
|
|
12
|
+
theme,
|
|
13
|
+
Typography,
|
|
14
|
+
type MenuProps,
|
|
15
|
+
} from "antd";
|
|
16
|
+
import {
|
|
17
|
+
AppstoreOutlined,
|
|
18
|
+
BarChartOutlined,
|
|
19
|
+
DashboardOutlined,
|
|
20
|
+
FileTextOutlined,
|
|
21
|
+
FormOutlined,
|
|
22
|
+
HomeOutlined,
|
|
23
|
+
SettingOutlined,
|
|
24
|
+
TeamOutlined,
|
|
25
|
+
UnorderedListOutlined,
|
|
26
|
+
} from "@ant-design/icons";
|
|
27
|
+
import {
|
|
28
|
+
Component,
|
|
29
|
+
Suspense,
|
|
30
|
+
createElement,
|
|
31
|
+
useCallback,
|
|
32
|
+
useEffect,
|
|
33
|
+
useMemo,
|
|
34
|
+
useRef,
|
|
35
|
+
useState,
|
|
36
|
+
type ErrorInfo,
|
|
37
|
+
type PropsWithChildren,
|
|
38
|
+
type ReactNode,
|
|
39
|
+
} from "react";
|
|
40
|
+
import {
|
|
41
|
+
HashRouter,
|
|
42
|
+
Navigate,
|
|
43
|
+
Route,
|
|
44
|
+
Routes,
|
|
45
|
+
matchPath,
|
|
46
|
+
useLocation,
|
|
47
|
+
useNavigate,
|
|
48
|
+
} from "react-router-dom";
|
|
49
|
+
import {
|
|
50
|
+
appManifest,
|
|
51
|
+
providers,
|
|
52
|
+
routes,
|
|
53
|
+
stylesUrl,
|
|
54
|
+
} from "virtual:harness-business-registry";
|
|
55
|
+
|
|
56
|
+
import {
|
|
57
|
+
FrontendChromeContextProvider,
|
|
58
|
+
FrontendRuntimeContextProvider,
|
|
59
|
+
type FrontendChromeRegistrationApi,
|
|
60
|
+
type FrontendPageOptions,
|
|
61
|
+
type FrontendRouteMetadata,
|
|
62
|
+
type FrontendRuntimeProvider,
|
|
63
|
+
type FrontendShellOptions,
|
|
64
|
+
type FrontendShellUser,
|
|
65
|
+
} from "../sdk/index.js";
|
|
66
|
+
|
|
67
|
+
const { Header, Sider, Content } = Layout;
|
|
68
|
+
|
|
69
|
+
const icons: Record<string, ReactNode> = {
|
|
70
|
+
AppstoreOutlined: <AppstoreOutlined />,
|
|
71
|
+
BarChartOutlined: <BarChartOutlined />,
|
|
72
|
+
DashboardOutlined: <DashboardOutlined />,
|
|
73
|
+
FileTextOutlined: <FileTextOutlined />,
|
|
74
|
+
FormOutlined: <FormOutlined />,
|
|
75
|
+
HomeOutlined: <HomeOutlined />,
|
|
76
|
+
SettingOutlined: <SettingOutlined />,
|
|
77
|
+
TeamOutlined: <TeamOutlined />,
|
|
78
|
+
UnorderedListOutlined: <UnorderedListOutlined />,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
function orderRoutes(left: FrontendRouteMetadata, right: FrontendRouteMetadata): number {
|
|
82
|
+
return (left.order ?? 0) - (right.order ?? 0) || left.title.localeCompare(right.title, "zh-CN");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function buildMenuItems(metadata: readonly FrontendRouteMetadata[]): MenuProps["items"] {
|
|
86
|
+
const visible = metadata.filter((route) => route.hidden !== true);
|
|
87
|
+
const byParent = new Map<string | undefined, FrontendRouteMetadata[]>();
|
|
88
|
+
for (const route of visible) {
|
|
89
|
+
const siblings = byParent.get(route.parentId) ?? [];
|
|
90
|
+
siblings.push(route);
|
|
91
|
+
byParent.set(route.parentId, siblings);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const visit = (parentId: string | undefined): NonNullable<MenuProps["items"]> =>
|
|
95
|
+
(byParent.get(parentId) ?? []).sort(orderRoutes).map((route) => {
|
|
96
|
+
const children = visit(route.id);
|
|
97
|
+
return {
|
|
98
|
+
key: route.path,
|
|
99
|
+
label: route.title,
|
|
100
|
+
icon: route.icon === undefined ? undefined : icons[route.icon],
|
|
101
|
+
...(children.length > 0 ? { children } : {}),
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return visit(undefined);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function buildBreadcrumbs(
|
|
109
|
+
metadata: readonly FrontendRouteMetadata[],
|
|
110
|
+
active: FrontendRouteMetadata | undefined,
|
|
111
|
+
): FrontendRouteMetadata[] {
|
|
112
|
+
if (active === undefined) return [];
|
|
113
|
+
const byId = new Map(metadata.map((route) => [route.id, route]));
|
|
114
|
+
const breadcrumbs: FrontendRouteMetadata[] = [];
|
|
115
|
+
const visited = new Set<string>();
|
|
116
|
+
let current: FrontendRouteMetadata | undefined = active;
|
|
117
|
+
while (current !== undefined && !visited.has(current.id)) {
|
|
118
|
+
visited.add(current.id);
|
|
119
|
+
breadcrumbs.unshift(current);
|
|
120
|
+
current = current.parentId === undefined ? undefined : byId.get(current.parentId);
|
|
121
|
+
}
|
|
122
|
+
return breadcrumbs;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function BusinessProviders({ children }: PropsWithChildren): ReactNode {
|
|
126
|
+
return providers.reduceRight<ReactNode>(
|
|
127
|
+
(content, Provider: FrontendRuntimeProvider) => createElement(Provider, null, content),
|
|
128
|
+
children,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface RuntimeErrorBoundaryState {
|
|
133
|
+
readonly error?: Error;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
class RuntimeErrorBoundary extends Component<PropsWithChildren, RuntimeErrorBoundaryState> {
|
|
137
|
+
state: RuntimeErrorBoundaryState = {};
|
|
138
|
+
|
|
139
|
+
static getDerivedStateFromError(error: Error): RuntimeErrorBoundaryState {
|
|
140
|
+
return { error };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
componentDidCatch(error: Error, info: ErrorInfo): void {
|
|
144
|
+
console.error("Business runtime render failed", error, info.componentStack);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
render(): ReactNode {
|
|
148
|
+
if (this.state.error !== undefined) {
|
|
149
|
+
return (
|
|
150
|
+
<Result
|
|
151
|
+
status="error"
|
|
152
|
+
title="页面渲染失败"
|
|
153
|
+
subTitle={this.state.error.message}
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
return this.props.children;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function RuntimeRoutes(): ReactNode {
|
|
162
|
+
const defaultPath = routes
|
|
163
|
+
.map((route) => route.metadata)
|
|
164
|
+
.filter((route) => route.hidden !== true)
|
|
165
|
+
.sort(orderRoutes)[0]?.path;
|
|
166
|
+
const hasRootRoute = routes.some((route) => route.metadata.path === "/");
|
|
167
|
+
|
|
168
|
+
if (routes.length === 0) {
|
|
169
|
+
return <Empty description="还没有业务页面,请在 src/pages 中创建页面" />;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<Routes>
|
|
174
|
+
{routes.map(({ metadata, Component: Page }) => (
|
|
175
|
+
<Route
|
|
176
|
+
key={metadata.id}
|
|
177
|
+
path={metadata.path}
|
|
178
|
+
element={
|
|
179
|
+
<RuntimeErrorBoundary>
|
|
180
|
+
<Suspense fallback={<Skeleton active paragraph={{ rows: 8 }} />}>
|
|
181
|
+
<Page />
|
|
182
|
+
</Suspense>
|
|
183
|
+
</RuntimeErrorBoundary>
|
|
184
|
+
}
|
|
185
|
+
/>
|
|
186
|
+
))}
|
|
187
|
+
{!hasRootRoute && defaultPath !== undefined && (
|
|
188
|
+
<Route path="/" element={<Navigate replace to={defaultPath} />} />
|
|
189
|
+
)}
|
|
190
|
+
<Route path="*" element={<Result status="404" title="404" subTitle="页面不存在" />} />
|
|
191
|
+
</Routes>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function RuntimeCurrentUser({ user }: { readonly user: FrontendShellUser }): ReactNode {
|
|
196
|
+
const fallback = typeof user.name === "string" && user.name.trim().length > 0
|
|
197
|
+
? user.name.trim().slice(0, 1)
|
|
198
|
+
: "用";
|
|
199
|
+
return (
|
|
200
|
+
<div className="harness-runtime-current-user">
|
|
201
|
+
{user.avatar ?? <Avatar size="small">{fallback}</Avatar>}
|
|
202
|
+
<div className="harness-runtime-current-user-copy">
|
|
203
|
+
<Typography.Text ellipsis>{user.name}</Typography.Text>
|
|
204
|
+
{user.description === undefined
|
|
205
|
+
? null
|
|
206
|
+
: <Typography.Text ellipsis type="secondary" className="harness-runtime-current-user-description">{user.description}</Typography.Text>}
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function RuntimeShell(): ReactNode {
|
|
213
|
+
const location = useLocation();
|
|
214
|
+
const navigate = useNavigate();
|
|
215
|
+
const shellToken = useRef<symbol | undefined>(undefined);
|
|
216
|
+
const pageToken = useRef<symbol | undefined>(undefined);
|
|
217
|
+
const [shellOptions, setShellOptions] = useState<FrontendShellOptions>({});
|
|
218
|
+
const [pageRegistration, setPageRegistration] = useState<{
|
|
219
|
+
readonly routeKey: string;
|
|
220
|
+
readonly options: FrontendPageOptions;
|
|
221
|
+
}>();
|
|
222
|
+
const metadata = useMemo(() => routes.map((route) => route.metadata), []);
|
|
223
|
+
const menuItems = useMemo(() => buildMenuItems(metadata), [metadata]);
|
|
224
|
+
const activeRoute = metadata.find((route) =>
|
|
225
|
+
matchPath({ path: route.path, end: true }, location.pathname),
|
|
226
|
+
);
|
|
227
|
+
const breadcrumbs = useMemo(
|
|
228
|
+
() => buildBreadcrumbs(metadata, activeRoute),
|
|
229
|
+
[activeRoute, metadata],
|
|
230
|
+
);
|
|
231
|
+
const runtimeApi = useMemo(() => ({
|
|
232
|
+
app: appManifest,
|
|
233
|
+
routes: metadata,
|
|
234
|
+
currentPath: location.pathname,
|
|
235
|
+
navigate,
|
|
236
|
+
}), [location.pathname, metadata, navigate]);
|
|
237
|
+
const registerShell = useCallback((options: FrontendShellOptions) => {
|
|
238
|
+
const token = Symbol("frontend-shell");
|
|
239
|
+
shellToken.current = token;
|
|
240
|
+
setShellOptions(options);
|
|
241
|
+
return () => {
|
|
242
|
+
if (shellToken.current !== token) return;
|
|
243
|
+
shellToken.current = undefined;
|
|
244
|
+
setShellOptions({});
|
|
245
|
+
};
|
|
246
|
+
}, []);
|
|
247
|
+
const registerPage = useCallback((routeKey: string, options: FrontendPageOptions) => {
|
|
248
|
+
const token = Symbol("frontend-page");
|
|
249
|
+
pageToken.current = token;
|
|
250
|
+
setPageRegistration({ routeKey, options });
|
|
251
|
+
return () => {
|
|
252
|
+
if (pageToken.current !== token) return;
|
|
253
|
+
pageToken.current = undefined;
|
|
254
|
+
setPageRegistration(undefined);
|
|
255
|
+
};
|
|
256
|
+
}, []);
|
|
257
|
+
const chromeApi = useMemo<FrontendChromeRegistrationApi>(() => ({
|
|
258
|
+
routeKey: location.pathname,
|
|
259
|
+
registerShell,
|
|
260
|
+
registerPage,
|
|
261
|
+
}), [location.pathname, registerPage, registerShell]);
|
|
262
|
+
const pageOptions = pageRegistration?.routeKey === location.pathname
|
|
263
|
+
? pageRegistration.options
|
|
264
|
+
: undefined;
|
|
265
|
+
const pageWidth = pageOptions?.width ?? "full";
|
|
266
|
+
const pageTitle = pageOptions === undefined ? undefined : pageOptions.title ?? activeRoute?.title;
|
|
267
|
+
const hasHeaderExtensions = shellOptions.headerActions !== undefined ||
|
|
268
|
+
shellOptions.currentUser !== undefined || shellOptions.userSwitcher !== undefined;
|
|
269
|
+
const hasPageHeading = pageOptions !== undefined && (
|
|
270
|
+
pageTitle !== undefined || pageOptions.description !== undefined || pageOptions.titleActions !== undefined
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
if (stylesUrl === undefined) return undefined;
|
|
275
|
+
const link = document.createElement("link");
|
|
276
|
+
link.rel = "stylesheet";
|
|
277
|
+
link.href = stylesUrl;
|
|
278
|
+
link.dataset.harnessBusinessStyles = "true";
|
|
279
|
+
document.head.append(link);
|
|
280
|
+
return () => link.remove();
|
|
281
|
+
}, []);
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<FrontendRuntimeContextProvider value={runtimeApi}>
|
|
285
|
+
<FrontendChromeContextProvider value={chromeApi}>
|
|
286
|
+
<BusinessProviders>
|
|
287
|
+
<Layout className="harness-runtime-layout">
|
|
288
|
+
<Sider className="harness-runtime-sider" breakpoint="lg" collapsedWidth="0" width={232}>
|
|
289
|
+
<div className="harness-runtime-brand">
|
|
290
|
+
{appManifest.logo !== undefined && (
|
|
291
|
+
<img alt="" className="harness-runtime-logo" src={appManifest.logo} />
|
|
292
|
+
)}
|
|
293
|
+
<Typography.Title ellipsis level={4}>{appManifest.name ?? "业务管理平台"}</Typography.Title>
|
|
294
|
+
</div>
|
|
295
|
+
<Menu
|
|
296
|
+
items={menuItems}
|
|
297
|
+
mode="inline"
|
|
298
|
+
selectedKeys={activeRoute === undefined ? [] : [activeRoute.path]}
|
|
299
|
+
onClick={({ key }) => navigate(key)}
|
|
300
|
+
/>
|
|
301
|
+
</Sider>
|
|
302
|
+
<Layout className="harness-runtime-main">
|
|
303
|
+
<Header className="harness-runtime-header">
|
|
304
|
+
<div className="harness-runtime-header-inner">
|
|
305
|
+
<Typography.Text strong ellipsis className="harness-runtime-header-brand">
|
|
306
|
+
{appManifest.name ?? "业务管理平台"}
|
|
307
|
+
</Typography.Text>
|
|
308
|
+
{hasHeaderExtensions && (
|
|
309
|
+
<Space className="harness-runtime-header-controls" size="middle">
|
|
310
|
+
{shellOptions.headerActions}
|
|
311
|
+
{shellOptions.userSwitcher}
|
|
312
|
+
{shellOptions.currentUser === undefined
|
|
313
|
+
? null
|
|
314
|
+
: <RuntimeCurrentUser user={shellOptions.currentUser} />}
|
|
315
|
+
</Space>
|
|
316
|
+
)}
|
|
317
|
+
</div>
|
|
318
|
+
</Header>
|
|
319
|
+
<Content className="harness-runtime-content">
|
|
320
|
+
<div className={`harness-runtime-content-inner harness-runtime-content-${pageWidth}`}>
|
|
321
|
+
{breadcrumbs.length > 0 && (
|
|
322
|
+
<Breadcrumb
|
|
323
|
+
className="harness-runtime-breadcrumb"
|
|
324
|
+
items={breadcrumbs.map((route, index) => ({
|
|
325
|
+
title: index === breadcrumbs.length - 1
|
|
326
|
+
? route.title
|
|
327
|
+
: <a href={`#${route.path}`}>{route.title}</a>,
|
|
328
|
+
}))}
|
|
329
|
+
/>
|
|
330
|
+
)}
|
|
331
|
+
{hasPageHeading && (
|
|
332
|
+
<div className="harness-runtime-page-heading">
|
|
333
|
+
<div className="harness-runtime-page-heading-copy">
|
|
334
|
+
{pageTitle === undefined
|
|
335
|
+
? null
|
|
336
|
+
: <Typography.Title level={3} ellipsis className="harness-runtime-page-title">{pageTitle}</Typography.Title>}
|
|
337
|
+
{pageOptions?.description === undefined
|
|
338
|
+
? null
|
|
339
|
+
: <Typography.Paragraph type="secondary" className="harness-runtime-page-description">{pageOptions.description}</Typography.Paragraph>}
|
|
340
|
+
</div>
|
|
341
|
+
{pageOptions?.titleActions === undefined
|
|
342
|
+
? null
|
|
343
|
+
: <div className="harness-runtime-page-title-actions">{pageOptions.titleActions}</div>}
|
|
344
|
+
</div>
|
|
345
|
+
)}
|
|
346
|
+
<RuntimeRoutes />
|
|
347
|
+
</div>
|
|
348
|
+
</Content>
|
|
349
|
+
</Layout>
|
|
350
|
+
</Layout>
|
|
351
|
+
</BusinessProviders>
|
|
352
|
+
</FrontendChromeContextProvider>
|
|
353
|
+
</FrontendRuntimeContextProvider>
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export function RuntimeApp(): ReactNode {
|
|
358
|
+
const compact = appManifest.theme?.compact === true;
|
|
359
|
+
return (
|
|
360
|
+
<ConfigProvider
|
|
361
|
+
theme={{
|
|
362
|
+
algorithm: compact ? theme.compactAlgorithm : theme.defaultAlgorithm,
|
|
363
|
+
token: {
|
|
364
|
+
colorPrimary: appManifest.theme?.colorPrimary ?? "#1677ff",
|
|
365
|
+
borderRadius: appManifest.theme?.borderRadius ?? 8,
|
|
366
|
+
},
|
|
367
|
+
}}
|
|
368
|
+
>
|
|
369
|
+
<AntApp>
|
|
370
|
+
<HashRouter>
|
|
371
|
+
<RuntimeErrorBoundary>
|
|
372
|
+
<Suspense fallback={<Skeleton active paragraph={{ rows: 8 }} />}>
|
|
373
|
+
<RuntimeShell />
|
|
374
|
+
</Suspense>
|
|
375
|
+
</RuntimeErrorBoundary>
|
|
376
|
+
</HashRouter>
|
|
377
|
+
</AntApp>
|
|
378
|
+
</ConfigProvider>
|
|
379
|
+
);
|
|
380
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color: #172033;
|
|
3
|
+
background: #f4f7fb;
|
|
4
|
+
font-family: Inter, "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
|
|
5
|
+
font-synthesis: none;
|
|
6
|
+
text-rendering: optimizeLegibility;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
* {
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
html,
|
|
14
|
+
body,
|
|
15
|
+
#root {
|
|
16
|
+
min-width: 320px;
|
|
17
|
+
height: 100% !important;
|
|
18
|
+
min-height: 0 !important;
|
|
19
|
+
margin: 0;
|
|
20
|
+
overflow: hidden !important;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.harness-runtime-layout {
|
|
24
|
+
height: 100vh !important;
|
|
25
|
+
height: 100dvh !important;
|
|
26
|
+
min-height: 0 !important;
|
|
27
|
+
overflow: hidden !important;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.harness-runtime-main {
|
|
31
|
+
min-width: 0 !important;
|
|
32
|
+
min-height: 0 !important;
|
|
33
|
+
overflow: hidden !important;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.harness-runtime-sider {
|
|
37
|
+
height: 100%;
|
|
38
|
+
border-right: 1px solid #e7ebf2;
|
|
39
|
+
background: #fff !important;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.harness-runtime-sider .ant-layout-sider-children {
|
|
43
|
+
display: flex;
|
|
44
|
+
height: 100%;
|
|
45
|
+
min-height: 0;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.harness-runtime-sider .ant-menu {
|
|
51
|
+
min-height: 0;
|
|
52
|
+
flex: 1;
|
|
53
|
+
overflow-x: hidden;
|
|
54
|
+
overflow-y: auto;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.harness-runtime-brand {
|
|
58
|
+
display: flex;
|
|
59
|
+
min-height: 64px;
|
|
60
|
+
align-items: center;
|
|
61
|
+
gap: 10px;
|
|
62
|
+
padding: 12px 20px;
|
|
63
|
+
border-bottom: 1px solid #eef1f6;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.harness-runtime-brand .ant-typography {
|
|
67
|
+
margin: 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.harness-runtime-logo {
|
|
71
|
+
width: 32px;
|
|
72
|
+
height: 32px;
|
|
73
|
+
border-radius: 8px;
|
|
74
|
+
object-fit: contain;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.harness-runtime-header {
|
|
78
|
+
display: flex;
|
|
79
|
+
flex: 0 0 64px;
|
|
80
|
+
align-items: center;
|
|
81
|
+
height: 64px;
|
|
82
|
+
padding: 0 24px;
|
|
83
|
+
border-bottom: 1px solid #e7ebf2;
|
|
84
|
+
background: rgba(255, 255, 255, 0.92);
|
|
85
|
+
backdrop-filter: blur(10px);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.harness-runtime-header-inner {
|
|
89
|
+
display: flex;
|
|
90
|
+
width: 100%;
|
|
91
|
+
min-width: 0;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: space-between;
|
|
94
|
+
gap: 20px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.harness-runtime-header-brand {
|
|
98
|
+
min-width: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.harness-runtime-header-controls {
|
|
102
|
+
flex: none;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.harness-runtime-current-user {
|
|
106
|
+
display: flex;
|
|
107
|
+
min-width: 0;
|
|
108
|
+
align-items: center;
|
|
109
|
+
gap: 8px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.harness-runtime-current-user-copy {
|
|
113
|
+
display: grid;
|
|
114
|
+
min-width: 0;
|
|
115
|
+
max-width: 168px;
|
|
116
|
+
line-height: 1.25;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.harness-runtime-current-user-description {
|
|
120
|
+
font-size: 12px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.harness-runtime-content {
|
|
124
|
+
min-width: 0 !important;
|
|
125
|
+
min-height: 0 !important;
|
|
126
|
+
padding: 24px;
|
|
127
|
+
overflow: auto !important;
|
|
128
|
+
overscroll-behavior: contain;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.harness-runtime-content-inner {
|
|
132
|
+
width: 100%;
|
|
133
|
+
margin: 0 auto;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.harness-runtime-content-standard {
|
|
137
|
+
max-width: 960px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.harness-runtime-content-wide {
|
|
141
|
+
max-width: 1280px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.harness-runtime-content-full {
|
|
145
|
+
max-width: none;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.harness-runtime-breadcrumb {
|
|
149
|
+
margin-bottom: 16px;
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.harness-runtime-page-heading {
|
|
154
|
+
display: flex;
|
|
155
|
+
min-width: 0;
|
|
156
|
+
align-items: flex-start;
|
|
157
|
+
justify-content: space-between;
|
|
158
|
+
gap: 20px;
|
|
159
|
+
margin-bottom: 20px;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.harness-runtime-page-heading-copy {
|
|
163
|
+
min-width: 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.harness-runtime-page-title.ant-typography,
|
|
167
|
+
.harness-runtime-page-description.ant-typography {
|
|
168
|
+
margin: 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.harness-runtime-page-description.ant-typography {
|
|
172
|
+
max-width: 720px;
|
|
173
|
+
margin-top: 4px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.harness-runtime-page-title-actions {
|
|
177
|
+
flex: none;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.harness-page-container {
|
|
181
|
+
display: grid;
|
|
182
|
+
min-width: 0;
|
|
183
|
+
gap: 16px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.harness-runtime-metric-grid {
|
|
187
|
+
width: 100%;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.harness-runtime-metric-card {
|
|
191
|
+
height: 100%;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.harness-runtime-metric-description {
|
|
195
|
+
display: block;
|
|
196
|
+
margin-top: 8px;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.harness-runtime-data-table-card {
|
|
200
|
+
min-width: 0;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.harness-runtime-data-table-heading {
|
|
204
|
+
display: grid;
|
|
205
|
+
min-width: 0;
|
|
206
|
+
gap: 2px;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.harness-runtime-data-table-heading .ant-typography {
|
|
210
|
+
margin: 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.harness-runtime-crud-drawer-footer {
|
|
214
|
+
display: flex;
|
|
215
|
+
justify-content: flex-end;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@media (max-width: 768px) {
|
|
219
|
+
.harness-runtime-content {
|
|
220
|
+
padding: 16px;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.harness-runtime-breadcrumb {
|
|
224
|
+
margin-bottom: 12px;
|
|
225
|
+
font-size: 12px;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.harness-runtime-header-controls {
|
|
229
|
+
max-width: 72%;
|
|
230
|
+
overflow-x: auto;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.harness-runtime-current-user-copy {
|
|
234
|
+
display: none;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.harness-runtime-page-heading {
|
|
238
|
+
flex-direction: column;
|
|
239
|
+
gap: 12px;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.harness-runtime-page-title-actions {
|
|
243
|
+
width: 100%;
|
|
244
|
+
overflow-x: auto;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"allowJs": false,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"module": "ESNext",
|
|
13
|
+
"moduleResolution": "Bundler",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"jsx": "react-jsx"
|
|
18
|
+
},
|
|
19
|
+
"include": ["src", "types"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CrudDrawer,
|
|
3
|
+
DataTable,
|
|
4
|
+
FrontendShellProvider,
|
|
5
|
+
MetricGrid,
|
|
6
|
+
PageContainer,
|
|
7
|
+
StatusTag,
|
|
8
|
+
createFrontendStore,
|
|
9
|
+
defineFrontendProviders,
|
|
10
|
+
getFrontendStorage,
|
|
11
|
+
usePersistentFrontendState,
|
|
12
|
+
useFrontendRuntime,
|
|
13
|
+
type FrontendStorage,
|
|
14
|
+
type FrontendRouteMetadata,
|
|
15
|
+
type FrontendRuntimeProvider,
|
|
16
|
+
} from "@harness/frontend-runtime";
|
|
17
|
+
import { createElement, type ReactNode } from "react";
|
|
18
|
+
|
|
19
|
+
const provider: FrontendRuntimeProvider = ({ children }) => createElement(
|
|
20
|
+
FrontendShellProvider,
|
|
21
|
+
{
|
|
22
|
+
currentUser: { name: "Runtime user", description: "管理员" },
|
|
23
|
+
headerActions: createElement("span", null, "全局操作"),
|
|
24
|
+
},
|
|
25
|
+
children,
|
|
26
|
+
);
|
|
27
|
+
export const smokeProviders = defineFrontendProviders([provider]);
|
|
28
|
+
export const smokeStorage: FrontendStorage = getFrontendStorage("smoke");
|
|
29
|
+
export const smokeStore = createFrontendStore({ rows: [{ id: "1", title: "Smoke" }] });
|
|
30
|
+
|
|
31
|
+
export const smokeRoute = {
|
|
32
|
+
id: "smoke",
|
|
33
|
+
path: "/smoke",
|
|
34
|
+
title: "Smoke",
|
|
35
|
+
} satisfies FrontendRouteMetadata;
|
|
36
|
+
|
|
37
|
+
export function useRuntimeContractSmoke(): string {
|
|
38
|
+
return useFrontendRuntime().currentPath;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function RuntimePrimitiveSmoke(): ReactNode {
|
|
42
|
+
const [filter] = usePersistentFrontendState("filter", "", { namespace: "smoke" });
|
|
43
|
+
const rows = smokeStore.useStore((state) => state.rows);
|
|
44
|
+
return createElement(
|
|
45
|
+
PageContainer,
|
|
46
|
+
{
|
|
47
|
+
title: "Runtime primitives",
|
|
48
|
+
description: filter,
|
|
49
|
+
titleActions: createElement(StatusTag, { status: "进行中" }),
|
|
50
|
+
width: "standard",
|
|
51
|
+
},
|
|
52
|
+
createElement(MetricGrid, {
|
|
53
|
+
columns: 2,
|
|
54
|
+
items: [{ key: "rows", title: "Rows", value: rows.length }],
|
|
55
|
+
}),
|
|
56
|
+
createElement(DataTable, {
|
|
57
|
+
rowKey: "id",
|
|
58
|
+
dataSource: rows,
|
|
59
|
+
columns: [{ title: "Title", dataIndex: "title" }],
|
|
60
|
+
toolbar: createElement("span", null, "Toolbar"),
|
|
61
|
+
}),
|
|
62
|
+
createElement(CrudDrawer, {
|
|
63
|
+
open: false,
|
|
64
|
+
title: "Edit",
|
|
65
|
+
initialValues: rows[0],
|
|
66
|
+
onClose: () => undefined,
|
|
67
|
+
onSubmit: () => undefined,
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
}
|