akanjs 2.4.2-rc.2 → 3.0.0-alpha.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/base/baseEnv.ts +0 -6
- package/client/cn.ts +52 -0
- package/client/csrTypes.ts +2 -2
- package/client/frameConfig.ts +2 -2
- package/client/index.ts +1 -0
- package/client/types.ts +0 -4
- package/common/fileUpload.ts +1 -1
- package/common/index.ts +1 -0
- package/common/isThenable.ts +12 -0
- package/constant/purify.ts +9 -10
- package/fetch/client/fetchClient.ts +1 -1
- package/fetch/client/httpClient.ts +9 -5
- package/fetch/fetchType/sliceFetch.type.ts +1 -1
- package/package.json +4 -7
- package/server/akanApp.ts +2 -0
- package/server/systemPageDocument.tsx +12 -12
- package/signal/endpointInfo.ts +2 -1
- package/signal/slice.ts +1 -1
- package/signal/sliceInfo.ts +2 -1
- package/store/action.ts +18 -2
- package/store/baseSt.ts +2 -2
- package/store/state.ts +9 -1
- package/store/storeInstance.ts +2 -0
- package/test/sampleOf.ts +3 -3
- package/test/signalTestRuntime.ts +0 -2
- package/types/base/baseEnv.d.ts +0 -2
- package/types/client/cn.d.ts +12 -0
- package/types/client/index.d.ts +1 -0
- package/types/client/types.d.ts +0 -3
- package/types/common/fileUpload.d.ts +1 -1
- package/types/common/index.d.ts +1 -0
- package/types/common/isThenable.d.ts +9 -0
- package/types/constant/purify.d.ts +3 -2
- package/types/fetch/fetchType/sliceFetch.type.d.ts +1 -1
- package/types/signal/endpointInfo.d.ts +2 -2
- package/types/signal/slice.d.ts +1 -1
- package/types/signal/sliceInfo.d.ts +2 -2
- package/types/store/action.d.ts +1 -1
- package/types/store/state.d.ts +4 -2
- package/types/test/sampleOf.d.ts +2 -2
- package/types/ui/Badge.d.ts +6 -0
- package/types/ui/Button.d.ts +26 -6
- package/types/ui/Load/Units.d.ts +3 -1
- package/types/ui/RecentTime.d.ts +1 -1
- package/types/ui/Signal/Collapse.d.ts +12 -0
- package/types/ui/Signal/style.d.ts +5 -6
- package/types/ui/Switch.d.ts +14 -0
- package/types/ui/Tooltip.d.ts +11 -0
- package/types/ui/UiOverride/Provider.d.ts +6 -5
- package/types/ui/UiOverride/context.d.ts +22 -1
- package/types/ui/UiOverride/index.d.ts +2 -1
- package/types/ui/UiOverride/override.d.ts +7 -6
- package/types/ui/UiOverride/useUiRecipe.d.ts +8 -0
- package/types/ui/index.d.ts +5 -1
- package/types/ui/recipe/badgeRecipe.d.ts +13 -0
- package/types/ui/recipe/buttonRecipe.d.ts +15 -0
- package/types/ui/recipe/factory.d.ts +24 -0
- package/types/ui/recipe/index.d.ts +18 -0
- package/types/ui/recipe/inputRecipe.d.ts +13 -0
- package/types/ui/recipe.d.ts +1 -0
- package/ui/Badge.tsx +17 -0
- package/ui/BottomSheet.tsx +8 -10
- package/ui/Button.tsx +158 -48
- package/ui/Clipboard.tsx +3 -3
- package/ui/Constant/Doc.tsx +108 -65
- package/ui/Constant/Mermaid.tsx +9 -9
- package/ui/Data/CardList.tsx +3 -3
- package/ui/Data/Dashboard.tsx +22 -13
- package/ui/Data/Insight.tsx +6 -6
- package/ui/Data/Item.tsx +49 -34
- package/ui/Data/ListContainer.tsx +11 -7
- package/ui/Data/Pagination.tsx +2 -2
- package/ui/DatePicker.tsx +5 -5
- package/ui/Dialog/Content.tsx +2 -2
- package/ui/Dialog/Modal.tsx +12 -8
- package/ui/Dialog/Provider.tsx +2 -2
- package/ui/DragAction.tsx +2 -2
- package/ui/DraggableList.tsx +10 -5
- package/ui/Dropdown.tsx +33 -26
- package/ui/Empty.tsx +5 -5
- package/ui/Field.tsx +82 -70
- package/ui/Image.tsx +2 -2
- package/ui/Input.tsx +62 -60
- package/ui/Layout/BottomInset.tsx +2 -2
- package/ui/Layout/BottomTab.tsx +5 -5
- package/ui/Layout/Header.tsx +3 -3
- package/ui/Layout/LeftSider.tsx +6 -5
- package/ui/Layout/Navbar.tsx +2 -12
- package/ui/Layout/RightSider.tsx +10 -8
- package/ui/Layout/Sider.tsx +5 -4
- package/ui/Layout/Template.tsx +2 -2
- package/ui/Layout/TopInset.tsx +2 -2
- package/ui/Layout/Unit.tsx +2 -2
- package/ui/Layout/View.tsx +2 -2
- package/ui/Layout/Zone.tsx +2 -2
- package/ui/Link/Back.tsx +2 -2
- package/ui/Link/Close.tsx +2 -2
- package/ui/Link/CsrLink.tsx +6 -4
- package/ui/Link/Lang.tsx +2 -2
- package/ui/Link/SsrLink.tsx +6 -5
- package/ui/Load/Page.tsx +1 -1
- package/ui/Load/Pagination.tsx +2 -2
- package/ui/Load/Units.tsx +19 -4
- package/ui/Load/View.tsx +2 -2
- package/ui/Loading/Area.tsx +4 -2
- package/ui/Loading/Button.tsx +2 -2
- package/ui/Loading/Input.tsx +2 -2
- package/ui/Loading/ProgressBar.tsx +2 -2
- package/ui/Loading/Skeleton.tsx +6 -6
- package/ui/Loading/Spin.tsx +2 -2
- package/ui/Menu.tsx +29 -27
- package/ui/Model/Edit.tsx +3 -3
- package/ui/Model/EditModal.tsx +5 -5
- package/ui/Model/EditWrapper.tsx +2 -2
- package/ui/Model/New.tsx +3 -3
- package/ui/Model/NewWrapper_Client.tsx +2 -2
- package/ui/Model/Remove.tsx +5 -4
- package/ui/Model/RemoveWrapper.tsx +2 -2
- package/ui/Model/SureToRemove.tsx +7 -6
- package/ui/Model/View.tsx +2 -2
- package/ui/Model/ViewEditModal.tsx +20 -21
- package/ui/Model/ViewWrapper.tsx +2 -2
- package/ui/More.tsx +2 -2
- package/ui/ObjectId.tsx +9 -3
- package/ui/Pagination.tsx +14 -11
- package/ui/Popconfirm.tsx +20 -11
- package/ui/Radio.tsx +4 -4
- package/ui/RecentTime.tsx +30 -83
- package/ui/Refresh.tsx +1 -1
- package/ui/ScreenNavigator.tsx +2 -2
- package/ui/Select.tsx +21 -23
- package/ui/Signal/Arg.tsx +21 -18
- package/ui/Signal/Collapse.tsx +29 -0
- package/ui/Signal/Doc.tsx +27 -22
- package/ui/Signal/Listener.tsx +3 -3
- package/ui/Signal/Message.tsx +31 -17
- package/ui/Signal/Object.tsx +13 -8
- package/ui/Signal/PubSub.tsx +26 -16
- package/ui/Signal/Request.tsx +3 -2
- package/ui/Signal/Response.tsx +5 -4
- package/ui/Signal/RestApi.tsx +27 -17
- package/ui/Signal/style.ts +16 -16
- package/ui/Switch.tsx +62 -0
- package/ui/System/CSR.tsx +40 -35
- package/ui/System/Client.tsx +2 -2
- package/ui/System/DevModeToggle.tsx +10 -12
- package/ui/System/Messages.tsx +14 -16
- package/ui/System/Reconnect.tsx +7 -7
- package/ui/System/SSR.tsx +25 -21
- package/ui/System/SelectLanguage.tsx +24 -28
- package/ui/System/ThemeToggle.tsx +38 -45
- package/ui/Tab/Menu.tsx +20 -18
- package/ui/Tab/Panel.tsx +3 -3
- package/ui/Tab/Provider.tsx +2 -2
- package/ui/Table.tsx +11 -8
- package/ui/ToggleSelect.tsx +14 -18
- package/ui/Tooltip.tsx +55 -0
- package/ui/UiOverride/Provider.tsx +10 -6
- package/ui/UiOverride/context.ts +22 -2
- package/ui/UiOverride/index.ts +8 -1
- package/ui/UiOverride/override.ts +7 -6
- package/ui/UiOverride/useUiRecipe.ts +15 -0
- package/ui/Unauthorized.tsx +5 -5
- package/ui/index.ts +16 -0
- package/ui/recipe/badgeRecipe.ts +23 -0
- package/ui/recipe/buttonRecipe.ts +32 -0
- package/ui/recipe/factory.ts +32 -0
- package/ui/recipe/index.ts +18 -0
- package/ui/recipe/inputRecipe.ts +13 -0
- package/ui/styles.css +150 -21
package/ui/Constant/Doc.tsx
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { usePage } from "akanjs/client";
|
|
3
|
+
import { cn, usePage } from "akanjs/client";
|
|
4
4
|
import { capitalize } from "akanjs/common";
|
|
5
5
|
import { useMemo, useState } from "react";
|
|
6
6
|
import { AiOutlineInfoCircle, AiOutlineSearch } from "react-icons/ai";
|
|
7
7
|
import { BiNetworkChart, BiTable } from "react-icons/bi";
|
|
8
8
|
|
|
9
|
+
import { badgeRecipe } from "../Badge";
|
|
10
|
+
import { buttonRecipe } from "../Button";
|
|
9
11
|
import { Input } from "../Input";
|
|
10
12
|
import { Modal } from "../Modal";
|
|
11
13
|
import { Mermaid } from "./Mermaid";
|
|
@@ -20,6 +22,9 @@ import {
|
|
|
20
22
|
type ScalarSchema,
|
|
21
23
|
} from "./schemaDoc";
|
|
22
24
|
|
|
25
|
+
const tableClass =
|
|
26
|
+
"w-full text-left text-sm [&_th]:px-3 [&_th]:py-2 [&_th]:font-medium [&_th]:text-foreground/60 [&_td]:px-3 [&_td]:py-2 [&_tbody_tr]:border-border [&_tbody_tr]:border-t";
|
|
27
|
+
|
|
23
28
|
export default function Doc() {
|
|
24
29
|
return <div />;
|
|
25
30
|
}
|
|
@@ -54,7 +59,7 @@ const Zone = ({ models, scalars, enums, openAll }: ZoneProps) => {
|
|
|
54
59
|
<div className="flex break-after-page flex-col gap-4">
|
|
55
60
|
<div>
|
|
56
61
|
<div className="font-bold text-3xl">Constant Schema Docs</div>
|
|
57
|
-
<div className="text-
|
|
62
|
+
<div className="text-foreground/70">
|
|
58
63
|
Database models, scalar models, enums, and relations from ConstantRegistry.
|
|
59
64
|
</div>
|
|
60
65
|
</div>
|
|
@@ -64,7 +69,7 @@ const Zone = ({ models, scalars, enums, openAll }: ZoneProps) => {
|
|
|
64
69
|
<SummaryCard title="Enums" value={filteredEnums.length} />
|
|
65
70
|
<SummaryCard title="Relations" value={schemaDoc.relations.length} />
|
|
66
71
|
</div>
|
|
67
|
-
<div className="flex flex-wrap items-center justify-between gap-2 rounded-xl bg-
|
|
72
|
+
<div className="flex flex-wrap items-center justify-between gap-2 rounded-xl bg-muted p-3">
|
|
68
73
|
<Input
|
|
69
74
|
nullable
|
|
70
75
|
value={query}
|
|
@@ -73,15 +78,21 @@ const Zone = ({ models, scalars, enums, openAll }: ZoneProps) => {
|
|
|
73
78
|
icon={<AiOutlineSearch />}
|
|
74
79
|
placeholder="Search models or enums"
|
|
75
80
|
/>
|
|
76
|
-
<div className="
|
|
81
|
+
<div className="inline-flex w-fit overflow-hidden rounded-field">
|
|
77
82
|
<button
|
|
78
|
-
className={
|
|
83
|
+
className={buttonRecipe(
|
|
84
|
+
{ variant: viewMode === "table" ? "primary" : "outline", size: "sm" },
|
|
85
|
+
"rounded-none",
|
|
86
|
+
)}
|
|
79
87
|
onClick={() => setViewMode("table")}
|
|
80
88
|
>
|
|
81
89
|
<BiTable /> Table
|
|
82
90
|
</button>
|
|
83
91
|
<button
|
|
84
|
-
className={
|
|
92
|
+
className={buttonRecipe(
|
|
93
|
+
{ variant: viewMode === "diagram" ? "primary" : "outline", size: "sm" },
|
|
94
|
+
"rounded-none",
|
|
95
|
+
)}
|
|
85
96
|
onClick={() => setViewMode("diagram")}
|
|
86
97
|
>
|
|
87
98
|
<BiNetworkChart /> Diagram
|
|
@@ -119,10 +130,10 @@ Doc.Zone = Zone;
|
|
|
119
130
|
const Print = ({ models, scalars, enums }: ZoneProps) => {
|
|
120
131
|
const schemaDoc = useMemo(() => getConstantSchemaDoc({ models, scalars, enums }), [models, scalars, enums]);
|
|
121
132
|
return (
|
|
122
|
-
<div className="flex flex-col gap-10 bg-
|
|
133
|
+
<div className="flex flex-col gap-10 bg-background text-foreground print:bg-white print:text-black">
|
|
123
134
|
<div className="break-after-page">
|
|
124
135
|
<div className="font-bold text-4xl">Constant Schema Definition</div>
|
|
125
|
-
<div className="mt-2 text-
|
|
136
|
+
<div className="mt-2 text-foreground/70 print:text-black">
|
|
126
137
|
Database models, scalar models, enums, and relations from ConstantRegistry.
|
|
127
138
|
</div>
|
|
128
139
|
<div className="mt-6 grid grid-cols-2 gap-2 md:grid-cols-4">
|
|
@@ -170,20 +181,20 @@ const Model = ({ refName, database: databaseProp, openAll }: ModelProps) => {
|
|
|
170
181
|
if (!database) return null;
|
|
171
182
|
const activeVariant = database.variants[variant] ?? getDefaultVariant(database);
|
|
172
183
|
return (
|
|
173
|
-
<
|
|
174
|
-
<
|
|
175
|
-
<div className="collapse-title">
|
|
184
|
+
<details className="group rounded-box bg-muted" open={openAll}>
|
|
185
|
+
<summary className="flex cursor-pointer list-none items-center justify-between gap-2 p-4">
|
|
176
186
|
<div className="flex flex-wrap items-center gap-2">
|
|
177
187
|
<div className="font-bold text-xl">{database.modelName}</div>
|
|
178
|
-
<div className="
|
|
179
|
-
<div className="text-
|
|
188
|
+
<div className={badgeRecipe({ variant: "primary" })}>{database.refName}</div>
|
|
189
|
+
<div className="text-foreground/70 text-sm">{l._(`${database.refName}.modelDesc`)}</div>
|
|
180
190
|
</div>
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
<span className="text-foreground/50 transition-transform group-open:rotate-180">▾</span>
|
|
192
|
+
</summary>
|
|
193
|
+
<div className="flex flex-col gap-3 p-4 pt-0">
|
|
183
194
|
<VariantTabs variant={variant} onChange={setVariant} />
|
|
184
195
|
<ModelVariantTable variant={activeVariant} />
|
|
185
196
|
</div>
|
|
186
|
-
</
|
|
197
|
+
</details>
|
|
187
198
|
);
|
|
188
199
|
};
|
|
189
200
|
Doc.Model = Model;
|
|
@@ -202,19 +213,19 @@ const Scalar = ({ refName, scalar: scalarProp, openAll }: ScalarProps) => {
|
|
|
202
213
|
const { l } = usePage();
|
|
203
214
|
if (!scalar) return null;
|
|
204
215
|
return (
|
|
205
|
-
<
|
|
206
|
-
<
|
|
207
|
-
<div className="collapse-title">
|
|
216
|
+
<details className="group rounded-box bg-muted" open={openAll}>
|
|
217
|
+
<summary className="flex cursor-pointer list-none items-center justify-between gap-2 p-4">
|
|
208
218
|
<div className="flex flex-wrap items-center gap-2">
|
|
209
219
|
<div className="font-bold text-xl">{scalar.modelName}</div>
|
|
210
|
-
<div className="
|
|
211
|
-
<div className="text-
|
|
220
|
+
<div className={badgeRecipe({ variant: "secondary" })}>{scalar.refName}</div>
|
|
221
|
+
<div className="text-foreground/70 text-sm">{l._(`${scalar.refName}.modelDesc`)}</div>
|
|
212
222
|
</div>
|
|
213
|
-
|
|
214
|
-
|
|
223
|
+
<span className="text-foreground/50 transition-transform group-open:rotate-180">▾</span>
|
|
224
|
+
</summary>
|
|
225
|
+
<div className="p-4 pt-0">
|
|
215
226
|
<FieldTable refName={scalar.refName} fields={scalar.fields} />
|
|
216
227
|
</div>
|
|
217
|
-
</
|
|
228
|
+
</details>
|
|
218
229
|
);
|
|
219
230
|
};
|
|
220
231
|
Doc.Scalar = Scalar;
|
|
@@ -226,7 +237,7 @@ interface EnumProps {
|
|
|
226
237
|
const EnumList = ({ enums = getConstantSchemaDoc().enums }: EnumProps) => {
|
|
227
238
|
const { l } = usePage();
|
|
228
239
|
return (
|
|
229
|
-
<div className="overflow-x-auto rounded-xl bg-
|
|
240
|
+
<div className="overflow-x-auto rounded-xl bg-muted p-3">
|
|
230
241
|
<table className="table">
|
|
231
242
|
<thead>
|
|
232
243
|
<tr>
|
|
@@ -246,13 +257,13 @@ const EnumList = ({ enums = getConstantSchemaDoc().enums }: EnumProps) => {
|
|
|
246
257
|
<td>
|
|
247
258
|
<div className="flex flex-wrap gap-1">
|
|
248
259
|
{enumSchema.values.map((value) => (
|
|
249
|
-
<
|
|
260
|
+
<button
|
|
250
261
|
key={String(value)}
|
|
251
|
-
className="
|
|
252
|
-
|
|
262
|
+
className={buttonRecipe({ variant: "outline", size: "xs" })}
|
|
263
|
+
title={l._(`${enumSchema.refName}.${value}`)}
|
|
253
264
|
>
|
|
254
|
-
|
|
255
|
-
</
|
|
265
|
+
{String(value)}
|
|
266
|
+
</button>
|
|
256
267
|
))}
|
|
257
268
|
</div>
|
|
258
269
|
</td>
|
|
@@ -262,7 +273,7 @@ const EnumList = ({ enums = getConstantSchemaDoc().enums }: EnumProps) => {
|
|
|
262
273
|
? enumSchema.usedBy.map((usage) => (
|
|
263
274
|
<span
|
|
264
275
|
key={`${usage.refName}-${usage.variant}-${usage.fieldKey}`}
|
|
265
|
-
className="
|
|
276
|
+
className={badgeRecipe({ variant: "outline" })}
|
|
266
277
|
>
|
|
267
278
|
{usage.refName}.{usage.fieldKey}
|
|
268
279
|
</span>
|
|
@@ -286,9 +297,16 @@ const VariantTabs = ({
|
|
|
286
297
|
variant: DatabaseModelVariant;
|
|
287
298
|
onChange: (variant: DatabaseModelVariant) => void;
|
|
288
299
|
}) => (
|
|
289
|
-
<div className="
|
|
300
|
+
<div className="inline-flex w-fit gap-1 rounded-field bg-muted p-1">
|
|
290
301
|
{databaseModelVariants.map((item) => (
|
|
291
|
-
<button
|
|
302
|
+
<button
|
|
303
|
+
key={item}
|
|
304
|
+
className={cn(
|
|
305
|
+
"rounded-[calc(var(--radius-field)-0.25rem)] px-3 py-1 font-medium text-sm transition-colors",
|
|
306
|
+
variant === item ? "bg-background text-foreground shadow-sm" : "text-foreground/60 hover:text-foreground",
|
|
307
|
+
)}
|
|
308
|
+
onClick={() => onChange(item)}
|
|
309
|
+
>
|
|
292
310
|
{getVariantTitle(item)}
|
|
293
311
|
</button>
|
|
294
312
|
))}
|
|
@@ -299,8 +317,8 @@ const ModelVariantTable = ({ variant }: { variant: ReturnType<typeof getDefaultV
|
|
|
299
317
|
<div className="flex flex-col gap-2">
|
|
300
318
|
<div className="flex flex-wrap items-center gap-2">
|
|
301
319
|
<div className="font-extrabold text-lg">{variant.modelName}</div>
|
|
302
|
-
<div className="
|
|
303
|
-
<div className="text-
|
|
320
|
+
<div className={badgeRecipe({ variant: "outline" })}>{getVariantTitle(variant.variant)}</div>
|
|
321
|
+
<div className="text-foreground/60 text-sm">{variant.fields.length} fields</div>
|
|
304
322
|
</div>
|
|
305
323
|
<FieldTable refName={variant.refName} fields={variant.fields} />
|
|
306
324
|
</div>
|
|
@@ -313,11 +331,16 @@ const PrintDatabase = ({ database }: { database: DatabaseSchema }) => {
|
|
|
313
331
|
<div>
|
|
314
332
|
<div className="flex flex-wrap items-center gap-2">
|
|
315
333
|
<div className="font-bold text-3xl">{database.modelName}</div>
|
|
316
|
-
<div
|
|
334
|
+
<div
|
|
335
|
+
className={badgeRecipe(
|
|
336
|
+
{ variant: "primary" },
|
|
337
|
+
"print:border print:border-black print:bg-white print:text-black",
|
|
338
|
+
)}
|
|
339
|
+
>
|
|
317
340
|
{database.refName}
|
|
318
341
|
</div>
|
|
319
342
|
</div>
|
|
320
|
-
<div className="mt-2 text-
|
|
343
|
+
<div className="mt-2 text-foreground/70 print:text-black">{l._(`${database.refName}.modelDesc`)}</div>
|
|
321
344
|
</div>
|
|
322
345
|
{databaseModelVariants.map((variantKey) => {
|
|
323
346
|
const variant = database.variants[variantKey];
|
|
@@ -343,11 +366,16 @@ const PrintScalar = ({ scalar }: { scalar: ScalarSchema }) => {
|
|
|
343
366
|
<div>
|
|
344
367
|
<div className="flex flex-wrap items-center gap-2">
|
|
345
368
|
<div className="font-bold text-2xl">{scalar.modelName}</div>
|
|
346
|
-
<div
|
|
369
|
+
<div
|
|
370
|
+
className={badgeRecipe(
|
|
371
|
+
{ variant: "secondary" },
|
|
372
|
+
"print:border print:border-black print:bg-white print:text-black",
|
|
373
|
+
)}
|
|
374
|
+
>
|
|
347
375
|
{scalar.refName}
|
|
348
376
|
</div>
|
|
349
377
|
</div>
|
|
350
|
-
<div className="mt-1 text-
|
|
378
|
+
<div className="mt-1 text-foreground/70 print:text-black">{l._(`${scalar.refName}.modelDesc`)}</div>
|
|
351
379
|
</div>
|
|
352
380
|
<PrintFieldTable refName={scalar.refName} fields={scalar.fields} />
|
|
353
381
|
</section>
|
|
@@ -359,8 +387,8 @@ const PrintSectionTitle = ({ title }: { title: string }) => <div className="font
|
|
|
359
387
|
const PrintVariantHeader = ({ title, badge, fields }: { title: string; badge: string; fields: number }) => (
|
|
360
388
|
<div className="flex flex-wrap items-center gap-2">
|
|
361
389
|
<div className="font-extrabold text-xl">{title}</div>
|
|
362
|
-
<div className="
|
|
363
|
-
<div className="text-
|
|
390
|
+
<div className={badgeRecipe({ variant: "outline" }, "print:border print:border-black")}>{badge}</div>
|
|
391
|
+
<div className="text-foreground/60 text-sm print:text-black">{fields} fields</div>
|
|
364
392
|
</div>
|
|
365
393
|
);
|
|
366
394
|
|
|
@@ -369,8 +397,8 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
|
|
|
369
397
|
const [selectedField, setSelectedField] = useState<FieldSchema | null>(null);
|
|
370
398
|
return (
|
|
371
399
|
<>
|
|
372
|
-
<div className="overflow-x-auto rounded-xl bg-
|
|
373
|
-
<table className=
|
|
400
|
+
<div className="overflow-x-auto rounded-xl bg-background p-3">
|
|
401
|
+
<table className={tableClass}>
|
|
374
402
|
<thead>
|
|
375
403
|
<tr>
|
|
376
404
|
<th>Key</th>
|
|
@@ -390,33 +418,45 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
|
|
|
390
418
|
<tr key={field.key}>
|
|
391
419
|
<td>
|
|
392
420
|
<div className="font-bold">{field.key}</div>
|
|
393
|
-
<div className="text-
|
|
421
|
+
<div className="text-foreground/60 text-xs">{l._(`${refName}.${field.key}`)}</div>
|
|
394
422
|
</td>
|
|
395
423
|
<td>
|
|
396
|
-
<span
|
|
424
|
+
<span
|
|
425
|
+
className={
|
|
426
|
+
field.typeKind === "primitive"
|
|
427
|
+
? ""
|
|
428
|
+
: badgeRecipe({ variant: "outline" }, "border-primary text-primary")
|
|
429
|
+
}
|
|
430
|
+
>
|
|
397
431
|
{field.typeLabel}
|
|
398
432
|
</span>
|
|
399
433
|
</td>
|
|
400
434
|
<td>
|
|
401
435
|
{field.required ? (
|
|
402
|
-
<span className="
|
|
436
|
+
<span className={badgeRecipe({ variant: "error" })}>Required</span>
|
|
403
437
|
) : (
|
|
404
|
-
<span className=
|
|
438
|
+
<span className={badgeRecipe()}>Optional</span>
|
|
405
439
|
)}
|
|
406
440
|
</td>
|
|
407
441
|
<td>
|
|
408
|
-
<span className="
|
|
409
|
-
{!field.select ?
|
|
442
|
+
<span className={badgeRecipe({ variant: "outline" })}>{field.fieldType}</span>
|
|
443
|
+
{!field.select ? (
|
|
444
|
+
<span className={badgeRecipe({ variant: "warning" }, "ml-1")}>select:false</span>
|
|
445
|
+
) : null}
|
|
410
446
|
</td>
|
|
411
447
|
<td>
|
|
412
|
-
{field.relationLabel ?
|
|
448
|
+
{field.relationLabel ? (
|
|
449
|
+
<span className={badgeRecipe({ variant: "secondary" })}>{field.relationLabel}</span>
|
|
450
|
+
) : (
|
|
451
|
+
"-"
|
|
452
|
+
)}
|
|
413
453
|
</td>
|
|
414
454
|
<td className="max-w-48 truncate">{field.defaultLabel ?? "-"}</td>
|
|
415
455
|
<td>
|
|
416
456
|
<div className="flex flex-wrap gap-1">
|
|
417
457
|
{field.constraints.length
|
|
418
458
|
? field.constraints.map((constraint) => (
|
|
419
|
-
<span key={constraint} className="
|
|
459
|
+
<span key={constraint} className={badgeRecipe({ variant: "outline" })}>
|
|
420
460
|
{constraint}
|
|
421
461
|
</span>
|
|
422
462
|
))
|
|
@@ -427,7 +467,7 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
|
|
|
427
467
|
{field.enumValues ? (
|
|
428
468
|
<div className="flex flex-wrap gap-1">
|
|
429
469
|
{field.enumValues.map((value) => (
|
|
430
|
-
<span key={String(value)} className=
|
|
470
|
+
<span key={String(value)} className={badgeRecipe()}>
|
|
431
471
|
{String(value)}
|
|
432
472
|
</span>
|
|
433
473
|
))}
|
|
@@ -438,7 +478,10 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
|
|
|
438
478
|
</td>
|
|
439
479
|
<td className="min-w-52">{l._(`${refName}.${field.key}.desc`)}</td>
|
|
440
480
|
<td>
|
|
441
|
-
<button
|
|
481
|
+
<button
|
|
482
|
+
className={buttonRecipe({ variant: "ghost", size: "xs" })}
|
|
483
|
+
onClick={() => setSelectedField(field)}
|
|
484
|
+
>
|
|
442
485
|
<AiOutlineInfoCircle /> Detail
|
|
443
486
|
</button>
|
|
444
487
|
</td>
|
|
@@ -455,8 +498,8 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
|
|
|
455
498
|
const PrintFieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[] }) => {
|
|
456
499
|
const { l } = usePage();
|
|
457
500
|
return (
|
|
458
|
-
<div className="overflow-x-auto rounded-xl bg-
|
|
459
|
-
<table className=
|
|
501
|
+
<div className="overflow-x-auto rounded-xl bg-background p-3 print:overflow-visible print:rounded-none print:p-0">
|
|
502
|
+
<table className={tableClass}>
|
|
460
503
|
<thead>
|
|
461
504
|
<tr>
|
|
462
505
|
<th>Key</th>
|
|
@@ -476,7 +519,7 @@ const PrintFieldTable = ({ refName, fields }: { refName: string; fields: FieldSc
|
|
|
476
519
|
<tr key={field.key} className="break-inside-avoid">
|
|
477
520
|
<td>
|
|
478
521
|
<div className="font-bold">{field.key}</div>
|
|
479
|
-
<div className="text-
|
|
522
|
+
<div className="text-foreground/60 text-xs print:text-black">{l._(`${refName}.${field.key}`)}</div>
|
|
480
523
|
</td>
|
|
481
524
|
<td>{field.typeLabel}</td>
|
|
482
525
|
<td>{field.required ? "Required" : "Optional"}</td>
|
|
@@ -515,8 +558,8 @@ const PrintFieldDetail = ({ field }: { field: FieldSchema }) => {
|
|
|
515
558
|
const PrintEnumTable = ({ enums }: { enums: ReturnType<typeof getConstantSchemaDoc>["enums"] }) => {
|
|
516
559
|
const { l } = usePage();
|
|
517
560
|
return (
|
|
518
|
-
<div className="overflow-x-auto rounded-xl bg-
|
|
519
|
-
<table className=
|
|
561
|
+
<div className="overflow-x-auto rounded-xl bg-background p-3 print:overflow-visible print:rounded-none print:p-0">
|
|
562
|
+
<table className={tableClass}>
|
|
520
563
|
<thead>
|
|
521
564
|
<tr>
|
|
522
565
|
<th>Key</th>
|
|
@@ -593,9 +636,9 @@ const FieldDetailModal = ({
|
|
|
593
636
|
>
|
|
594
637
|
<div>
|
|
595
638
|
<div className="font-bold text-lg">{l._(`${refName}.${field.key}`)}</div>
|
|
596
|
-
<div className="text-
|
|
639
|
+
<div className="text-foreground/70">{l._(`${refName}.${field.key}.desc`)}</div>
|
|
597
640
|
</div>
|
|
598
|
-
<pre className="max-h-[60vh] overflow-auto rounded-xl bg-
|
|
641
|
+
<pre className="max-h-[60vh] overflow-auto rounded-xl bg-muted p-4 text-sm">
|
|
599
642
|
{JSON.stringify(detail, null, 2)}
|
|
600
643
|
</pre>
|
|
601
644
|
</Modal>
|
|
@@ -613,8 +656,8 @@ const getPrintRelation = (field: FieldSchema) => {
|
|
|
613
656
|
};
|
|
614
657
|
|
|
615
658
|
const SummaryCard = ({ title, value }: { title: string; value: number }) => (
|
|
616
|
-
<div className="rounded-xl bg-
|
|
617
|
-
<div className="text-
|
|
659
|
+
<div className="rounded-xl bg-muted p-4">
|
|
660
|
+
<div className="text-foreground/60 text-sm">{title}</div>
|
|
618
661
|
<div className="font-bold text-2xl">{value}</div>
|
|
619
662
|
</div>
|
|
620
663
|
);
|
|
@@ -637,7 +680,7 @@ const Diagram = ({ databases, scalars }: { databases: DatabaseSchema[]; scalars:
|
|
|
637
680
|
highlightNodes={selectedNode ? [selectedNode] : []}
|
|
638
681
|
onSelectNode={setSelectedNode}
|
|
639
682
|
/>
|
|
640
|
-
<div className="rounded-xl bg-
|
|
683
|
+
<div className="rounded-xl bg-muted p-4">
|
|
641
684
|
<div className="font-bold text-xl">Selected Model</div>
|
|
642
685
|
{selectedDatabase ? (
|
|
643
686
|
<Model database={selectedDatabase} openAll />
|
|
@@ -645,11 +688,11 @@ const Diagram = ({ databases, scalars }: { databases: DatabaseSchema[]; scalars:
|
|
|
645
688
|
<Scalar scalar={selectedScalar} openAll />
|
|
646
689
|
) : selectedRefName ? (
|
|
647
690
|
<div className="mt-4">
|
|
648
|
-
<div className="
|
|
691
|
+
<div className={badgeRecipe({ variant: "outline" })}>External</div>
|
|
649
692
|
<div className="mt-2 font-bold">{selectedRefName}</div>
|
|
650
693
|
</div>
|
|
651
694
|
) : (
|
|
652
|
-
<div className="mt-4 text-
|
|
695
|
+
<div className="mt-4 text-foreground/60">Select a node in the diagram.</div>
|
|
653
696
|
)}
|
|
654
697
|
</div>
|
|
655
698
|
</div>
|
package/ui/Constant/Mermaid.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { cn } from "akanjs/client";
|
|
4
4
|
import { useEffect, useId, useRef, useState } from "react";
|
|
5
5
|
|
|
6
6
|
export interface MermaidProps {
|
|
@@ -80,15 +80,15 @@ export const Mermaid = ({ chart, title, className, highlightNodes = [], onSelect
|
|
|
80
80
|
}, [chart, highlightNodes, onSelectNode, reactId]);
|
|
81
81
|
|
|
82
82
|
return (
|
|
83
|
-
<div className={
|
|
83
|
+
<div className={cn("my-4 overflow-hidden rounded-xl border border-border bg-muted/40", className)}>
|
|
84
84
|
{title ? (
|
|
85
|
-
<div className="border-
|
|
85
|
+
<div className="border-border border-b px-4 py-2 font-bold text-foreground/70 text-sm">{title}</div>
|
|
86
86
|
) : null}
|
|
87
87
|
<div className="overflow-x-auto p-4">
|
|
88
88
|
{error ? (
|
|
89
|
-
<pre className="whitespace-pre-wrap text-
|
|
89
|
+
<pre className="whitespace-pre-wrap text-destructive text-sm">{error}</pre>
|
|
90
90
|
) : (
|
|
91
|
-
<div ref={containerRef} className="min-w-fit text-
|
|
91
|
+
<div ref={containerRef} className="min-w-fit text-foreground" />
|
|
92
92
|
)}
|
|
93
93
|
</div>
|
|
94
94
|
</div>
|
|
@@ -101,10 +101,10 @@ function getThemeColors() {
|
|
|
101
101
|
const fallback = isDarkTheme(root) ? darkThemeFallback : lightThemeFallback;
|
|
102
102
|
|
|
103
103
|
return {
|
|
104
|
-
base100: getMermaidColor(style, "--color-
|
|
105
|
-
base200: getMermaidColor(style, "--color-
|
|
106
|
-
base300: getMermaidColor(style, "--color-
|
|
107
|
-
baseContent: getMermaidColor(style, "--color-
|
|
104
|
+
base100: getMermaidColor(style, "--color-background", fallback.base100),
|
|
105
|
+
base200: getMermaidColor(style, "--color-muted", fallback.base200),
|
|
106
|
+
base300: getMermaidColor(style, "--color-border", fallback.base300),
|
|
107
|
+
baseContent: getMermaidColor(style, "--color-foreground", fallback.baseContent),
|
|
108
108
|
primary: getMermaidColor(style, "--color-primary", fallback.primary),
|
|
109
109
|
};
|
|
110
110
|
}
|
package/ui/Data/CardList.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import type { DataList } from "akanjs/base";
|
|
3
|
-
import {
|
|
3
|
+
import { cn, type DataAction, type DataColumn } from "akanjs/client";
|
|
4
4
|
import { capitalize } from "akanjs/common";
|
|
5
5
|
import type { FilterInstance } from "akanjs/document";
|
|
6
6
|
import type { FetchInitForm, SliceMeta } from "akanjs/fetch";
|
|
@@ -86,14 +86,14 @@ export default function CardList<
|
|
|
86
86
|
return (
|
|
87
87
|
<div className={className}>
|
|
88
88
|
{modelListLoading ? (
|
|
89
|
-
<div className={
|
|
89
|
+
<div className={cn("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5", cardListClassName)}>
|
|
90
90
|
{new Array(limitOfModel || 20)
|
|
91
91
|
.fill(0)
|
|
92
92
|
.map((_, idx) => `skeleton-${idx}`)
|
|
93
93
|
.map((key) => (renderLoading ? renderLoading() : <Loading.Skeleton key={key} active />))}
|
|
94
94
|
</div>
|
|
95
95
|
) : (
|
|
96
|
-
<div className={
|
|
96
|
+
<div className={cn("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5", cardListClassName)}>
|
|
97
97
|
{modelList.map((model, idx) => {
|
|
98
98
|
return (
|
|
99
99
|
<DataItem
|
package/ui/Data/Dashboard.tsx
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn, usePage } from "akanjs/client";
|
|
3
3
|
import { capitalize } from "akanjs/common";
|
|
4
4
|
import type { SliceMeta } from "akanjs/fetch";
|
|
5
5
|
import { st } from "akanjs/store";
|
|
6
6
|
|
|
7
|
+
import { buttonRecipe } from "../Button";
|
|
7
8
|
import { Link } from "../Link";
|
|
8
9
|
|
|
9
10
|
export interface DashboardProps<T extends string, State> {
|
|
@@ -33,21 +34,26 @@ export default function Dashboard<T extends string, State>({
|
|
|
33
34
|
const formatSummaryValue = (value: unknown) =>
|
|
34
35
|
typeof value === "number" || typeof value === "string" ? value.toLocaleString() : "";
|
|
35
36
|
return (
|
|
36
|
-
<div className={
|
|
37
|
-
<div className="
|
|
37
|
+
<div className={cn("my-2 flex w-full flex-wrap justify-center py-0 shadow-sm", className)}>
|
|
38
|
+
<div className="flex flex-wrap">
|
|
38
39
|
{columns?.map(
|
|
39
40
|
(column) =>
|
|
40
41
|
summary[column] !== undefined &&
|
|
41
42
|
queryMap[column] !== undefined && (
|
|
42
43
|
<button
|
|
43
44
|
key={column}
|
|
44
|
-
className={
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
className={buttonRecipe({ variant: "ghost" }, [
|
|
46
|
+
"mx-1 h-32 w-48 rounded-none pt-3 hover:border",
|
|
47
|
+
filter === column ? "border" : "border-0",
|
|
48
|
+
])}
|
|
47
49
|
>
|
|
48
|
-
<Link
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
<Link
|
|
51
|
+
key={column}
|
|
52
|
+
className="flex flex-col gap-1"
|
|
53
|
+
href={`/admin?topMenu=data&subMenu=${modelName}&filter=${column}`}
|
|
54
|
+
>
|
|
55
|
+
<div className="text-foreground/60 text-xs">{l(`summary.${column}` as "base.new")}</div>
|
|
56
|
+
<div className="font-semibold text-2xl text-primary">{formatSummaryValue(summary[column])}</div>
|
|
51
57
|
</Link>
|
|
52
58
|
</button>
|
|
53
59
|
),
|
|
@@ -57,10 +63,13 @@ export default function Dashboard<T extends string, State>({
|
|
|
57
63
|
(column) =>
|
|
58
64
|
summary[column] !== undefined &&
|
|
59
65
|
queryMap[column] !== undefined && (
|
|
60
|
-
<button
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
<button
|
|
67
|
+
key={column}
|
|
68
|
+
className={buttonRecipe({ variant: "ghost" }, "mx-1 h-32 w-48 rounded-none border-none pt-3")}
|
|
69
|
+
>
|
|
70
|
+
<div className="flex flex-col gap-1">
|
|
71
|
+
<div className="text-foreground/60 text-xs">{l(`summary.${column}` as "base.new")}</div>
|
|
72
|
+
<div className="font-semibold text-2xl text-primary">{formatSummaryValue(summary[column])}</div>
|
|
64
73
|
</div>
|
|
65
74
|
</button>
|
|
66
75
|
),
|
package/ui/Data/Insight.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn, usePage } from "akanjs/client";
|
|
3
3
|
import type { SliceMeta } from "akanjs/fetch";
|
|
4
4
|
|
|
5
5
|
interface InsightProps<T extends string, Insight> {
|
|
@@ -18,14 +18,14 @@ export default function Insight<T extends string, Insight>({
|
|
|
18
18
|
const { l } = usePage();
|
|
19
19
|
const { refName } = slice;
|
|
20
20
|
return (
|
|
21
|
-
<div className={
|
|
22
|
-
<div className="
|
|
21
|
+
<div className={cn("my-2 flex w-full flex-wrap justify-center py-2 shadow-sm", className)}>
|
|
22
|
+
<div className="flex flex-wrap">
|
|
23
23
|
{columns?.map(
|
|
24
24
|
(column: keyof Insight, idx) =>
|
|
25
25
|
insight[column] !== undefined && (
|
|
26
|
-
<div key={column.toString()} className="
|
|
27
|
-
<div className="
|
|
28
|
-
<div className="
|
|
26
|
+
<div key={column.toString()} className="mx-1 flex items-center gap-2 rounded-none px-6 py-4">
|
|
27
|
+
<div className="text-foreground/60 text-xs">{l._(`${refName}.insight.${column as string}`)}</div>
|
|
28
|
+
<div className="font-semibold text-xl">{(insight[column] as string).toLocaleString()}</div>
|
|
29
29
|
</div>
|
|
30
30
|
),
|
|
31
31
|
)}
|