@fougere/admin 0.9.2-alpha.0 → 0.10.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/dist/{extensions.d.ts → AdminExtension.d.ts} +5 -14
- package/dist/AdminExtension.d.ts.map +1 -0
- package/dist/{extensions.js → AdminExtension.js} +3 -3
- package/dist/AdminExtension.js.map +1 -0
- package/dist/AdminFacetRegistry.d.ts +9 -0
- package/dist/AdminFacetRegistry.d.ts.map +1 -0
- package/dist/AdminFacetRegistry.js +2 -0
- package/dist/AdminFacetRegistry.js.map +1 -0
- package/dist/AdminFacets.d.ts +6 -0
- package/dist/AdminFacets.d.ts.map +1 -0
- package/dist/{facets.js → AdminFacets.js} +1 -1
- package/dist/AdminFacets.js.map +1 -0
- package/dist/AdminFieldExtension.d.ts +7 -0
- package/dist/AdminFieldExtension.d.ts.map +1 -0
- package/dist/AdminFieldExtension.js +2 -0
- package/dist/AdminFieldExtension.js.map +1 -0
- package/dist/AdminOperation.d.ts +9 -0
- package/dist/AdminOperation.d.ts.map +1 -0
- package/dist/AdminOperation.js +2 -0
- package/dist/AdminOperation.js.map +1 -0
- package/dist/AdminOperationExtension.d.ts +6 -0
- package/dist/AdminOperationExtension.d.ts.map +1 -0
- package/dist/AdminOperationExtension.js +2 -0
- package/dist/AdminOperationExtension.js.map +1 -0
- package/dist/{resources.d.ts → AdminResource.d.ts} +11 -17
- package/dist/AdminResource.d.ts.map +1 -0
- package/dist/{resources.js → AdminResource.js} +13 -14
- package/dist/AdminResource.js.map +1 -0
- package/dist/AdminRuntime.d.ts +11 -0
- package/dist/AdminRuntime.d.ts.map +1 -0
- package/dist/{runtime.js → AdminRuntime.js} +5 -6
- package/dist/AdminRuntime.js.map +1 -0
- package/dist/AdminRuntimeOptions.d.ts +8 -0
- package/dist/AdminRuntimeOptions.d.ts.map +1 -0
- package/dist/AdminRuntimeOptions.js +2 -0
- package/dist/AdminRuntimeOptions.js.map +1 -0
- package/dist/Drawing.d.ts +39 -0
- package/dist/Drawing.d.ts.map +1 -0
- package/dist/Drawing.js +212 -0
- package/dist/Drawing.js.map +1 -0
- package/dist/EditorialFacet.d.ts +13 -0
- package/dist/EditorialFacet.d.ts.map +1 -0
- package/dist/EditorialFacet.js +2 -0
- package/dist/EditorialFacet.js.map +1 -0
- package/dist/FougereAdminProps.d.ts +17 -0
- package/dist/FougereAdminProps.d.ts.map +1 -0
- package/dist/FougereAdminProps.js +2 -0
- package/dist/FougereAdminProps.js.map +1 -0
- package/dist/FougereDashboardContextValue.d.ts +11 -0
- package/dist/FougereDashboardContextValue.d.ts.map +1 -0
- package/dist/FougereDashboardContextValue.js +2 -0
- package/dist/FougereDashboardContextValue.js.map +1 -0
- package/dist/FougereDashboardExtension.d.ts +13 -0
- package/dist/FougereDashboardExtension.d.ts.map +1 -0
- package/dist/FougereDashboardExtension.js +2 -0
- package/dist/FougereDashboardExtension.js.map +1 -0
- package/dist/FougereDashboardMetrics.d.ts +7 -0
- package/dist/FougereDashboardMetrics.d.ts.map +1 -0
- package/dist/FougereDashboardMetrics.js +2 -0
- package/dist/FougereDashboardMetrics.js.map +1 -0
- package/dist/FougereDashboardResource.d.ts +14 -0
- package/dist/FougereDashboardResource.d.ts.map +1 -0
- package/dist/FougereDashboardResource.js +2 -0
- package/dist/FougereDashboardResource.js.map +1 -0
- package/dist/FougereDashboardWidget.d.ts +11 -0
- package/dist/FougereDashboardWidget.d.ts.map +1 -0
- package/dist/FougereDashboardWidget.js +2 -0
- package/dist/FougereDashboardWidget.js.map +1 -0
- package/dist/FougereDashboardZone.d.ts +2 -0
- package/dist/FougereDashboardZone.d.ts.map +1 -0
- package/dist/FougereDashboardZone.js +2 -0
- package/dist/FougereDashboardZone.js.map +1 -0
- package/dist/{provider.d.ts → FougereDataProvider.d.ts} +2 -17
- package/dist/FougereDataProvider.d.ts.map +1 -0
- package/dist/{provider.js → FougereDataProvider.js} +2 -3
- package/dist/FougereDataProvider.js.map +1 -0
- package/dist/FougereResourceOptions.d.ts +16 -0
- package/dist/FougereResourceOptions.d.ts.map +1 -0
- package/dist/FougereResourceOptions.js +2 -0
- package/dist/FougereResourceOptions.js.map +1 -0
- package/dist/LoadedAdmin.d.ts +7 -0
- package/dist/LoadedAdmin.d.ts.map +1 -0
- package/dist/LoadedAdmin.js +2 -0
- package/dist/LoadedAdmin.js.map +1 -0
- package/dist/PlacedEdge.d.ts +17 -0
- package/dist/PlacedEdge.d.ts.map +1 -0
- package/dist/PlacedEdge.js +2 -0
- package/dist/PlacedEdge.js.map +1 -0
- package/dist/PlacedNode.d.ts +10 -0
- package/dist/PlacedNode.d.ts.map +1 -0
- package/dist/PlacedNode.js +2 -0
- package/dist/PlacedNode.js.map +1 -0
- package/dist/Point.d.ts +5 -0
- package/dist/Point.d.ts.map +1 -0
- package/dist/Point.js +2 -0
- package/dist/Point.js.map +1 -0
- package/dist/ProviderOptions.d.ts +10 -0
- package/dist/ProviderOptions.d.ts.map +1 -0
- package/dist/ProviderOptions.js +2 -0
- package/dist/ProviderOptions.js.map +1 -0
- package/dist/ReactAdminFieldContext.d.ts +10 -0
- package/dist/ReactAdminFieldContext.d.ts.map +1 -0
- package/dist/ReactAdminFieldContext.js +2 -0
- package/dist/ReactAdminFieldContext.js.map +1 -0
- package/dist/ReactAdminFieldRenderer.d.ts +4 -0
- package/dist/ReactAdminFieldRenderer.d.ts.map +1 -0
- package/dist/ReactAdminFieldRenderer.js +2 -0
- package/dist/ReactAdminFieldRenderer.js.map +1 -0
- package/dist/ReactAdminInputContext.d.ts +9 -0
- package/dist/ReactAdminInputContext.d.ts.map +1 -0
- package/dist/ReactAdminInputContext.js +2 -0
- package/dist/ReactAdminInputContext.js.map +1 -0
- package/dist/ReactAdminInputRenderer.d.ts +4 -0
- package/dist/ReactAdminInputRenderer.d.ts.map +1 -0
- package/dist/ReactAdminInputRenderer.js +2 -0
- package/dist/ReactAdminInputRenderer.js.map +1 -0
- package/dist/ReactAdminRenderers.d.ts +8 -0
- package/dist/ReactAdminRenderers.d.ts.map +1 -0
- package/dist/ReactAdminRenderers.js +2 -0
- package/dist/ReactAdminRenderers.js.map +1 -0
- package/dist/ReactAdminResourceComponents.d.ts +9 -0
- package/dist/ReactAdminResourceComponents.d.ts.map +1 -0
- package/dist/ReactAdminResourceComponents.js +2 -0
- package/dist/ReactAdminResourceComponents.js.map +1 -0
- package/dist/ResourceKey.d.ts +8 -0
- package/dist/ResourceKey.d.ts.map +1 -0
- package/dist/ResourceKey.js +2 -0
- package/dist/ResourceKey.js.map +1 -0
- package/dist/ResourceRenderOptions.d.ts +7 -0
- package/dist/ResourceRenderOptions.d.ts.map +1 -0
- package/dist/ResourceRenderOptions.js +2 -0
- package/dist/ResourceRenderOptions.js.map +1 -0
- package/dist/TopologyNode.d.ts +18 -0
- package/dist/TopologyNode.d.ts.map +1 -0
- package/dist/TopologyNode.js +2 -0
- package/dist/TopologyNode.js.map +1 -0
- package/dist/UsersFacet.d.ts +13 -0
- package/dist/UsersFacet.d.ts.map +1 -0
- package/dist/UsersFacet.js +2 -0
- package/dist/UsersFacet.js.map +1 -0
- package/dist/dashboard.d.ts +4 -61
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/dashboard.js +9 -9
- package/dist/dashboard.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +21 -65
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -7
- package/dist/react.js.map +1 -1
- package/dist/theme.js +1 -1
- package/dist/topology-page.d.ts.map +1 -1
- package/dist/topology-page.js +105 -11
- package/dist/topology-page.js.map +1 -1
- package/package.json +7 -5
- package/src/{extensions.ts → AdminExtension.ts} +5 -16
- package/src/AdminFacetRegistry.ts +9 -0
- package/src/AdminFacets.ts +22 -0
- package/src/AdminFieldExtension.ts +6 -0
- package/src/AdminOperation.ts +9 -0
- package/src/AdminOperationExtension.ts +5 -0
- package/src/{resources.ts → AdminResource.ts} +18 -26
- package/src/{runtime.ts → AdminRuntime.ts} +6 -24
- package/src/AdminRuntimeOptions.ts +8 -0
- package/src/Drawing.ts +261 -0
- package/src/EditorialFacet.ts +12 -0
- package/src/FougereAdminProps.ts +17 -0
- package/src/FougereDashboardContextValue.ts +11 -0
- package/src/FougereDashboardExtension.ts +13 -0
- package/src/FougereDashboardMetrics.ts +6 -0
- package/src/FougereDashboardResource.ts +14 -0
- package/src/FougereDashboardWidget.ts +11 -0
- package/src/FougereDashboardZone.ts +1 -0
- package/src/{provider.ts → FougereDataProvider.ts} +3 -26
- package/src/FougereResourceOptions.ts +13 -0
- package/src/LoadedAdmin.ts +7 -0
- package/src/PlacedEdge.ts +17 -0
- package/src/PlacedNode.ts +10 -0
- package/src/Point.ts +4 -0
- package/src/ProviderOptions.ts +10 -0
- package/src/ReactAdminFieldContext.ts +10 -0
- package/src/ReactAdminFieldRenderer.ts +4 -0
- package/src/ReactAdminInputContext.ts +9 -0
- package/src/ReactAdminInputRenderer.ts +4 -0
- package/src/ReactAdminRenderers.ts +8 -0
- package/src/ReactAdminResourceComponents.ts +9 -0
- package/src/ResourceKey.ts +7 -0
- package/src/ResourceRenderOptions.ts +7 -0
- package/src/TopologyNode.ts +18 -0
- package/src/UsersFacet.ts +12 -0
- package/src/dashboard.tsx +19 -88
- package/src/index.ts +3 -9
- package/src/react.tsx +37 -80
- package/src/theme.tsx +1 -1
- package/src/topology-page.tsx +202 -16
- package/template/index.html +5 -0
- package/template/package.json +22 -0
- package/template/src/main.tsx +27 -0
- package/template/tsconfig.json +12 -0
- package/template/vite.config.ts +16 -0
- package/dist/extensions.d.ts.map +0 -1
- package/dist/extensions.js.map +0 -1
- package/dist/facets.d.ts +0 -36
- package/dist/facets.d.ts.map +0 -1
- package/dist/facets.js.map +0 -1
- package/dist/provider.d.ts.map +0 -1
- package/dist/provider.js.map +0 -1
- package/dist/resources.d.ts.map +0 -1
- package/dist/resources.js.map +0 -1
- package/dist/runtime.d.ts +0 -22
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js.map +0 -1
- package/dist/topology.d.ts +0 -18
- package/dist/topology.d.ts.map +0 -1
- package/dist/topology.js +0 -30
- package/dist/topology.js.map +0 -1
- package/src/facets.ts +0 -55
- package/src/topology.ts +0 -59
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { type AdminResource } from './
|
|
2
|
-
import { type AdminFacets } from './
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
label?: string;
|
|
6
|
-
/** Removes the field from derived tables, shows and forms. */
|
|
7
|
-
hidden?: boolean;
|
|
8
|
-
}
|
|
9
|
-
export interface AdminOperationExtension {
|
|
10
|
-
label?: string;
|
|
11
|
-
/** `false` explicitly removes a confirmation added by an earlier extension. */
|
|
12
|
-
confirm?: string | false;
|
|
13
|
-
}
|
|
1
|
+
import { type AdminResource } from './AdminResource.js';
|
|
2
|
+
import { type AdminFacets } from './AdminFacets.js';
|
|
3
|
+
import type { AdminFieldExtension } from './AdminFieldExtension.js';
|
|
4
|
+
import type { AdminOperationExtension } from './AdminOperationExtension.js';
|
|
14
5
|
export interface AdminExtension {
|
|
15
6
|
/** Registration key from the card (`post`, not `Post`). */
|
|
16
7
|
resource: string;
|
|
@@ -24,4 +15,4 @@ export interface AdminExtension {
|
|
|
24
15
|
export declare function defineAdminExtension<const T extends AdminExtension>(extension: T): T;
|
|
25
16
|
/** Apply deltas to the latest derived model. Unmentioned and future resources pass through. */
|
|
26
17
|
export declare function applyAdminExtensions(resources: readonly AdminResource[], extensions?: readonly AdminExtension[]): AdminResource[];
|
|
27
|
-
//# sourceMappingURL=
|
|
18
|
+
//# sourceMappingURL=AdminExtension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminExtension.d.ts","sourceRoot":"","sources":["../src/AdminExtension.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAE5E,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;CACtD;AAED,qEAAqE;AACrE,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,CAAC,SAAS,cAAc,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,CAEpF;AAsDD,+FAA+F;AAC/F,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,SAAS,aAAa,EAAE,EACnC,UAAU,GAAE,SAAS,cAAc,EAAO,GACzC,aAAa,EAAE,CAqBjB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { capabilitiesOf } from './
|
|
2
|
-
import { mergeAdminFacets } from './
|
|
1
|
+
import { capabilitiesOf } from './AdminResource.js';
|
|
2
|
+
import { mergeAdminFacets } from './AdminFacets.js';
|
|
3
3
|
/** Typed identity helper for extensions kept in their own module. */
|
|
4
4
|
export function defineAdminExtension(extension) {
|
|
5
5
|
return extension;
|
|
@@ -71,4 +71,4 @@ export function applyAdminExtensions(resources, extensions = []) {
|
|
|
71
71
|
};
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
|
-
//# sourceMappingURL=
|
|
74
|
+
//# sourceMappingURL=AdminExtension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminExtension.js","sourceRoot":"","sources":["../src/AdminExtension.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { EditorialFacet } from './EditorialFacet.js';
|
|
2
|
+
import type { UsersFacet } from './UsersFacet.js';
|
|
3
|
+
/** Open registry of the semantic projections renderers understand. */
|
|
4
|
+
export interface AdminFacetRegistry {
|
|
5
|
+
editorial: EditorialFacet;
|
|
6
|
+
users: UsersFacet;
|
|
7
|
+
[facet: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=AdminFacetRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminFacetRegistry.d.ts","sourceRoot":"","sources":["../src/AdminFacetRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,UAAU,CAAC;IAClB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminFacetRegistry.js","sourceRoot":"","sources":["../src/AdminFacetRegistry.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AdminFacetRegistry } from './AdminFacetRegistry.js';
|
|
2
|
+
export type AdminFacets = Partial<AdminFacetRegistry>;
|
|
3
|
+
export declare function defineAdminFacet<const Name extends string, const Value>(name: Name, value: Value): Record<Name, Value>;
|
|
4
|
+
/** Arrays replace; semantic objects merge recursively so small project deltas stay small. */
|
|
5
|
+
export declare function mergeAdminFacets(base: AdminFacets, patch: AdminFacets): AdminFacets;
|
|
6
|
+
//# sourceMappingURL=AdminFacets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminFacets.d.ts","sourceRoot":"","sources":["../src/AdminFacets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEtD,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,EAAE,KAAK,CAAC,KAAK,EACrE,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,GACX,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAErB;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,WAAW,CAQnF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminFacets.js","sourceRoot":"","sources":["../src/AdminFacets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAK3C,MAAM,UAAU,gBAAgB,CAC9B,IAAU,EACV,KAAY;IAEZ,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAyB,CAAC;AAClD,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,gBAAgB,CAAC,IAAiB,EAAE,KAAkB;IACpE,MAAM,KAAK,GAAG,CAAC,IAAa,EAAE,KAAc,EAAW,EAAE;QACvD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACtD,MAAM,GAAG,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QACpF,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,EAAE,KAAK,CAAgB,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminFieldExtension.d.ts","sourceRoot":"","sources":["../src/AdminFieldExtension.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminFieldExtension.js","sourceRoot":"","sources":["../src/AdminFieldExtension.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CardOp } from '@fougere/core/contract';
|
|
2
|
+
/** One operation as the admin meets it, before a renderer decides its widget. */
|
|
3
|
+
export interface AdminOperation extends CardOp {
|
|
4
|
+
/** Display fallback. An extension may replace it without renaming the call. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Optional confirmation sentence, interpreted by renderers that support actions. */
|
|
7
|
+
confirm?: string;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=AdminOperation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminOperation.d.ts","sourceRoot":"","sources":["../src/AdminOperation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,iFAAiF;AACjF,MAAM,WAAW,cAAe,SAAQ,MAAM;IAC5C,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminOperation.js","sourceRoot":"","sources":["../src/AdminOperation.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminOperationExtension.d.ts","sourceRoot":"","sources":["../src/AdminOperationExtension.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminOperationExtension.js","sourceRoot":"","sources":["../src/AdminOperationExtension.ts"],"names":[],"mappings":""}
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import { type Fetcher, type FormField, type TableColumn } from '@fougere/app/client';
|
|
2
|
-
import { type
|
|
3
|
-
import type { ResourceKey } from './
|
|
4
|
-
import type { AdminFacets } from './
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/** Display fallback. An extension may replace it without renaming the call. */
|
|
8
|
-
label: string;
|
|
9
|
-
/** Optional confirmation sentence, interpreted by renderers that support actions. */
|
|
10
|
-
confirm?: string;
|
|
11
|
-
}
|
|
12
|
-
/** One door, everything the UI needs to render it. */
|
|
2
|
+
import { type IdentityCard } from '@fougere/core/contract';
|
|
3
|
+
import type { ResourceKey } from './ResourceKey.js';
|
|
4
|
+
import type { AdminFacets } from './AdminFacets.js';
|
|
5
|
+
import type { AdminOperation } from './AdminOperation.js';
|
|
6
|
+
/** One facade, everything the UI needs to render it. */
|
|
13
7
|
export interface AdminResource extends ResourceKey {
|
|
14
8
|
/** The frond it belongs to — the menu groups by it, as the card does. */
|
|
15
9
|
frond: string;
|
|
@@ -27,7 +21,7 @@ export interface AdminResource extends ResourceKey {
|
|
|
27
21
|
/** Every callable operation, including the five CRUD verbs. */
|
|
28
22
|
operations: AdminOperation[];
|
|
29
23
|
/**
|
|
30
|
-
* Which of the five the
|
|
24
|
+
* Which of the five the facade actually serves. A facade answering only `list` gets a
|
|
31
25
|
* list and no buttons — the card says so, so the UI never offers what would 404.
|
|
32
26
|
*/
|
|
33
27
|
can: {
|
|
@@ -39,18 +33,18 @@ export interface AdminResource extends ResourceKey {
|
|
|
39
33
|
};
|
|
40
34
|
}
|
|
41
35
|
/**
|
|
42
|
-
* The five verbs react-admin already has pages for. Everything else a
|
|
36
|
+
* The five verbs react-admin already has pages for. Everything else a facade serves is a
|
|
43
37
|
* business operation, and gets a button rather than a page.
|
|
44
38
|
*/
|
|
45
39
|
export declare const CRUD_OPS: readonly ['list', 'findById', 'create', 'update', 'delete'];
|
|
46
|
-
/** What a
|
|
40
|
+
/** What a facade serves beyond CRUD — the only thing this panel has that a generic one has not. */
|
|
47
41
|
export declare function actionsOf(operations: readonly AdminOperation[]): AdminOperation[];
|
|
48
42
|
/** Capabilities are a reading of the visible operations, never a second list to maintain. */
|
|
49
43
|
export declare function capabilitiesOf(operations: readonly Pick<AdminOperation, 'name'>[]): AdminResource['can'];
|
|
50
|
-
/** A
|
|
44
|
+
/** A facade with no schema is not a resource. */
|
|
51
45
|
export declare function resourcesOf(card: IdentityCard): AdminResource[];
|
|
52
|
-
/** The provider's index — the half of a resource it needs, keyed by
|
|
46
|
+
/** The provider's index — the half of a resource it needs, keyed by facade name. */
|
|
53
47
|
export declare function keysOf(resources: AdminResource[]): Record<string, ResourceKey>;
|
|
54
48
|
/** Ask the running app what it hosts. */
|
|
55
49
|
export declare function fetchCard(endpoint?: string, fetcher?: Fetcher): Promise<IdentityCard>;
|
|
56
|
-
//# sourceMappingURL=
|
|
50
|
+
//# sourceMappingURL=AdminResource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminResource.d.ts","sourceRoot":"","sources":["../src/AdminResource.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,YAAY,EAAc,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,wDAAwD;AACxD,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,EAAE,WAAW,CAAC;IACpB,kEAAkE;IAClE,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,4EAA4E;IAC5E,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,+DAA+D;IAC/D,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B;;;OAGG;IACH,GAAG,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;CACxF;AAOD;;;GAGG;AACH,eAAO,MAAM,QAAQ,YAAI,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAEpF,mGAAmG;AACnG,wBAAgB,SAAS,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,GAAG,cAAc,EAAE,CAEjF;AAED,6FAA6F;AAC7F,wBAAgB,cAAc,CAAC,UAAU,EAAE,SAAS,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,CASxG;AAED,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,EAAE,CA4B/D;AAED,oFAAoF;AACpF,wBAAgB,MAAM,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAE9E;AAED,yCAAyC;AACzC,wBAAsB,SAAS,CAC7B,QAAQ,SAAgB,EACxB,OAAO,GAAE,OAAwB,GAChC,OAAO,CAAC,YAAY,CAAC,CAOvB"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** What the app hosts, read as a back-office. */
|
|
2
1
|
import { Card, FieldSet } from '@fougere/schema';
|
|
3
2
|
import { CALL_ENDPOINT, fetcher as browserFetcher, formFieldsOf, sendCall, tableColumnsOf, } from '@fougere/app/client';
|
|
4
3
|
import { Invocation } from '@fougere/core/contract';
|
|
@@ -7,11 +6,11 @@ function labelOf(name) {
|
|
|
7
6
|
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
8
7
|
}
|
|
9
8
|
/**
|
|
10
|
-
* The five verbs react-admin already has pages for. Everything else a
|
|
9
|
+
* The five verbs react-admin already has pages for. Everything else a facade serves is a
|
|
11
10
|
* business operation, and gets a button rather than a page.
|
|
12
11
|
*/
|
|
13
12
|
export const CRUD_OPS = ['list', 'findById', 'create', 'update', 'delete'];
|
|
14
|
-
/** What a
|
|
13
|
+
/** What a facade serves beyond CRUD — the only thing this panel has that a generic one has not. */
|
|
15
14
|
export function actionsOf(operations) {
|
|
16
15
|
return operations.filter((op) => !CRUD_OPS.includes(op.name));
|
|
17
16
|
}
|
|
@@ -26,27 +25,27 @@ export function capabilitiesOf(operations) {
|
|
|
26
25
|
delete: serves.has('delete'),
|
|
27
26
|
};
|
|
28
27
|
}
|
|
29
|
-
/** A
|
|
28
|
+
/** A facade with no schema is not a resource. */
|
|
30
29
|
export function resourcesOf(card) {
|
|
31
30
|
const out = [];
|
|
32
31
|
for (const frond of card.fronds) {
|
|
33
|
-
for (const
|
|
34
|
-
if (!
|
|
32
|
+
for (const facade of frond.facades) {
|
|
33
|
+
if (!facade.schema)
|
|
35
34
|
continue;
|
|
36
|
-
const entity = Card.fromDescriptor(
|
|
35
|
+
const entity = Card.fromDescriptor(facade.schema).toSchema();
|
|
37
36
|
const primary = FieldSet.of(entity.getFields()).primary;
|
|
38
37
|
// No primary means no row identity — a list could be drawn, but nothing could be
|
|
39
38
|
// opened, edited or deleted. Refusing here is the same answer `FieldSet.primary`
|
|
40
39
|
// gives by not defaulting to 'id': the caller decides, and this caller declines.
|
|
41
40
|
if (!primary)
|
|
42
41
|
continue;
|
|
43
|
-
const operations =
|
|
44
|
-
const columns = tableColumnsOf(entity,
|
|
45
|
-
const fields = formFieldsOf(entity,
|
|
42
|
+
const operations = facade.ops.map((op) => ({ ...op, label: labelOf(op.name) }));
|
|
43
|
+
const columns = tableColumnsOf(entity, facade.name);
|
|
44
|
+
const fields = formFieldsOf(entity, facade.name);
|
|
46
45
|
out.push({
|
|
47
|
-
name:
|
|
46
|
+
name: facade.name,
|
|
48
47
|
frond: frond.name,
|
|
49
|
-
label: labelOf(
|
|
48
|
+
label: labelOf(facade.name),
|
|
50
49
|
facets: {},
|
|
51
50
|
primary,
|
|
52
51
|
columns,
|
|
@@ -58,7 +57,7 @@ export function resourcesOf(card) {
|
|
|
58
57
|
}
|
|
59
58
|
return out;
|
|
60
59
|
}
|
|
61
|
-
/** The provider's index — the half of a resource it needs, keyed by
|
|
60
|
+
/** The provider's index — the half of a resource it needs, keyed by facade name. */
|
|
62
61
|
export function keysOf(resources) {
|
|
63
62
|
return Object.fromEntries(resources.map((r) => [r.name, { name: r.name, primary: r.primary }]));
|
|
64
63
|
}
|
|
@@ -66,4 +65,4 @@ export function keysOf(resources) {
|
|
|
66
65
|
export async function fetchCard(endpoint = CALL_ENDPOINT, fetcher = browserFetcher) {
|
|
67
66
|
return await sendCall(fetcher, { entity: 'rpc', op: 'discover' }, Invocation.empty, endpoint);
|
|
68
67
|
}
|
|
69
|
-
//# sourceMappingURL=
|
|
68
|
+
//# sourceMappingURL=AdminResource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminResource.js","sourceRoot":"","sources":["../src/AdminResource.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type FougereDataProvider } from './FougereDataProvider.js';
|
|
2
|
+
import type { AdminRuntimeOptions } from './AdminRuntimeOptions.js';
|
|
3
|
+
import type { LoadedAdmin } from './LoadedAdmin.js';
|
|
4
|
+
export interface AdminRuntime {
|
|
5
|
+
/** Loads and caches the card-derived model. */
|
|
6
|
+
load(): Promise<LoadedAdmin>;
|
|
7
|
+
/** Synchronous shell required by react-admin; delegates after `load()` resolves. */
|
|
8
|
+
dataProvider: FougereDataProvider;
|
|
9
|
+
}
|
|
10
|
+
export declare function createAdminRuntime(options?: AdminRuntimeOptions): AdminRuntime;
|
|
11
|
+
//# sourceMappingURL=AdminRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminRuntime.d.ts","sourceRoot":"","sources":["../src/AdminRuntime.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8C,KAAK,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEhH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7B,oFAAoF;IACpF,YAAY,EAAE,mBAAmB,CAAC;CACnC;AAED,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CA0BlF"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { fetchCard, keysOf, resourcesOf } from './resources.js';
|
|
1
|
+
import { CALL_ENDPOINT, fetcher as browserFetcher } from '@fougere/app/client';
|
|
2
|
+
import { applyAdminExtensions } from './AdminExtension.js';
|
|
3
|
+
import { createDataProvider, createLazyDataProvider } from './FougereDataProvider.js';
|
|
4
|
+
import { fetchCard, keysOf, resourcesOf } from './AdminResource.js';
|
|
6
5
|
export function createAdminRuntime(options = {}) {
|
|
7
6
|
const { endpoint = CALL_ENDPOINT, fetcher = browserFetcher, extensions = [], } = options;
|
|
8
7
|
let loading;
|
|
@@ -24,4 +23,4 @@ export function createAdminRuntime(options = {}) {
|
|
|
24
23
|
dataProvider: createLazyDataProvider(async () => (await load()).provider),
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
|
-
//# sourceMappingURL=
|
|
26
|
+
//# sourceMappingURL=AdminRuntime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminRuntime.js","sourceRoot":"","sources":["../src/AdminRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAA4B,MAAM,0BAA0B,CAAC;AAChH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAWpE,MAAM,UAAU,kBAAkB,CAAC,OAAO,GAAwB,EAAE;IAClE,MAAM,EACJ,QAAQ,GAAG,aAAa,EACxB,OAAO,GAAG,cAAc,EACxB,UAAU,GAAG,EAAE,GAChB,GAAG,OAAO,CAAC;IACZ,IAAI,OAAyC,CAAC;IAE9C,iEAAiE;IACjE,MAAM,IAAI,GAAG,GAAyB,EAAE,CAAC,OAAO,KAAK,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC;SAC9E,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACb,MAAM,SAAS,GAAG,oBAAoB,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC;QACtE,OAAO;YACL,SAAS;YACT,QAAQ,EAAE,kBAAkB,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;SAClF,CAAC;IACJ,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxB,OAAO,GAAG,SAAS,CAAC;QACpB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEL,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,sBAAsB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC;KAC1E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Fetcher } from '@fougere/app/client';
|
|
2
|
+
import { type AdminExtension } from './AdminExtension.js';
|
|
3
|
+
export interface AdminRuntimeOptions {
|
|
4
|
+
endpoint?: string;
|
|
5
|
+
fetcher?: Fetcher;
|
|
6
|
+
extensions?: readonly AdminExtension[];
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=AdminRuntimeOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminRuntimeOptions.d.ts","sourceRoot":"","sources":["../src/AdminRuntimeOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CACxC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminRuntimeOptions.js","sourceRoot":"","sources":["../src/AdminRuntimeOptions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type Fetcher } from '@fougere/app/client';
|
|
2
|
+
import { type FrondPlacement, type TopologyReport } from '@fougere/core/contract';
|
|
3
|
+
import type { TopologyNode } from './TopologyNode.js';
|
|
4
|
+
import type { PlacedNode } from './PlacedNode.js';
|
|
5
|
+
import type { PlacedEdge } from './PlacedEdge.js';
|
|
6
|
+
/** The report, or `undefined` when the app serves no topology at all. */
|
|
7
|
+
export declare function fetchTopology(endpoint?: string, fetcher?: Fetcher): Promise<TopologyReport | undefined>;
|
|
8
|
+
/** The report read as a graph — what runs here first, then what answered, then what never did. */
|
|
9
|
+
export declare function nodesOf(report: TopologyReport): TopologyNode[];
|
|
10
|
+
export interface Drawing {
|
|
11
|
+
nodes: PlacedNode[];
|
|
12
|
+
edges: PlacedEdge[];
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Where each frond sits, and the line between two of them.
|
|
18
|
+
*
|
|
19
|
+
* The placement is `@dagrejs/dagre`'s — ranks by depth, order within a rank chosen to cross as
|
|
20
|
+
* little as possible, and a polyline per edge that goes around the nodes between its ends. Two
|
|
21
|
+
* hand-written columns could not do the second or the third: a chain of three fronds put two of
|
|
22
|
+
* them in one column, and the curve between them had to bulge around whatever sat in the way.
|
|
23
|
+
*
|
|
24
|
+
* Rendering stays ours, which is why only the layout is bought: the drawing reads `error.main`
|
|
25
|
+
* and the rest of the MUI palette off the theme, and a library that painted its own canvas
|
|
26
|
+
* would have to be told the theme again on every switch. Kiali left Cytoscape for this in 2.0.0,
|
|
27
|
+
* and every service map whose source can be read — Grafana, Jaeger, Linkerd — buys the same half.
|
|
28
|
+
*/
|
|
29
|
+
export declare function layoutOf(nodes: readonly TopologyNode[]): Drawing;
|
|
30
|
+
/** A count as an operator reads it at a glance — `2.1k`, never `2140`. */
|
|
31
|
+
export declare function short(count: number): string;
|
|
32
|
+
/** What a link says of itself, and the only figure the drawing carries. */
|
|
33
|
+
export declare function figureOf(link: Pick<PlacedEdge, 'count' | 'errors'>): string;
|
|
34
|
+
/**
|
|
35
|
+
* A frond this process called that publishes nothing of its own shape. Read AFTER `silent`:
|
|
36
|
+
* a frond that never answered has the same two zeroes and a different reason for them.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isOpaque(node: FrondPlacement): boolean;
|
|
39
|
+
//# sourceMappingURL=Drawing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Drawing.d.ts","sourceRoot":"","sources":["../src/Drawing.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,OAAO,EACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAa,KAAK,cAAc,EAAE,KAAK,cAAc,EAAc,MAAM,wBAAwB,CAAC;AACzG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,yEAAyE;AACzE,wBAAsB,aAAa,CACjC,QAAQ,SAAgB,EACxB,OAAO,GAAE,OAAwB,GAChC,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAYrC;AAED,kGAAkG;AAClG,wBAAgB,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,YAAY,EAAE,CAqC9D;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CA6ChE;AAED,0EAA0E;AAC1E,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3C;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAC,GAAG,MAAM,CAI3E;AAsGD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAEtD"}
|
package/dist/Drawing.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import dagre from '@dagrejs/dagre';
|
|
2
|
+
import { CALL_ENDPOINT, fetcher as browserFetcher, sendCall, } from '@fougere/app/client';
|
|
3
|
+
import { ErrorCode, Invocation } from '@fougere/core/contract';
|
|
4
|
+
/** The report, or `undefined` when the app serves no topology at all. */
|
|
5
|
+
export async function fetchTopology(endpoint = CALL_ENDPOINT, fetcher = browserFetcher) {
|
|
6
|
+
try {
|
|
7
|
+
return await sendCall(fetcher, { entity: 'rpc', op: 'topology' }, Invocation.empty, endpoint);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (error?.code === ErrorCode.NOT_FOUND)
|
|
11
|
+
return undefined;
|
|
12
|
+
throw error;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** The report read as a graph — what runs here first, then what answered, then what never did. */
|
|
16
|
+
export function nodesOf(report) {
|
|
17
|
+
const order = { local: 0, remote: 1 };
|
|
18
|
+
const stated = new Map(report.declared.fronds.map((one) => [one.frond, one]));
|
|
19
|
+
const answered = new Set(report.fronds.map((frond) => frond.frond));
|
|
20
|
+
const around = (frond) => ({
|
|
21
|
+
calls: report.edges.filter((edge) => edge.from === frond),
|
|
22
|
+
calledBy: report.edges.filter((edge) => edge.to === frond),
|
|
23
|
+
declaredCalls: report.declared.edges.filter((edge) => edge.from === frond),
|
|
24
|
+
});
|
|
25
|
+
const heard = [...report.fronds]
|
|
26
|
+
.sort((a, b) => order[a.placement] - order[b.placement] || a.frond.localeCompare(b.frond))
|
|
27
|
+
.map((frond) => ({
|
|
28
|
+
...frond,
|
|
29
|
+
...around(frond.frond),
|
|
30
|
+
...(stated.get(frond.frond)?.at ? { at: stated.get(frond.frond).at } : {}),
|
|
31
|
+
silent: false,
|
|
32
|
+
}));
|
|
33
|
+
// The whole reason the declared half travels: a frond that never answered is absent from
|
|
34
|
+
// the observed one, so without this the node the operator most needs to see is the one
|
|
35
|
+
// that disappears.
|
|
36
|
+
const silent = report.declared.fronds
|
|
37
|
+
.filter((one) => one.placement === 'remote' && !answered.has(one.frond))
|
|
38
|
+
.sort((a, b) => a.frond.localeCompare(b.frond))
|
|
39
|
+
.map((one) => ({
|
|
40
|
+
frond: one.frond,
|
|
41
|
+
placement: 'remote',
|
|
42
|
+
entities: 0,
|
|
43
|
+
facades: 0,
|
|
44
|
+
...around(one.frond),
|
|
45
|
+
...(one.at ? { at: one.at } : {}),
|
|
46
|
+
silent: true,
|
|
47
|
+
}));
|
|
48
|
+
return [...heard, ...silent];
|
|
49
|
+
}
|
|
50
|
+
const NODE = { width: 176, height: 54 };
|
|
51
|
+
/**
|
|
52
|
+
* Where each frond sits, and the line between two of them.
|
|
53
|
+
*
|
|
54
|
+
* The placement is `@dagrejs/dagre`'s — ranks by depth, order within a rank chosen to cross as
|
|
55
|
+
* little as possible, and a polyline per edge that goes around the nodes between its ends. Two
|
|
56
|
+
* hand-written columns could not do the second or the third: a chain of three fronds put two of
|
|
57
|
+
* them in one column, and the curve between them had to bulge around whatever sat in the way.
|
|
58
|
+
*
|
|
59
|
+
* Rendering stays ours, which is why only the layout is bought: the drawing reads `error.main`
|
|
60
|
+
* and the rest of the MUI palette off the theme, and a library that painted its own canvas
|
|
61
|
+
* would have to be told the theme again on every switch. Kiali left Cytoscape for this in 2.0.0,
|
|
62
|
+
* and every service map whose source can be read — Grafana, Jaeger, Linkerd — buys the same half.
|
|
63
|
+
*/
|
|
64
|
+
export function layoutOf(nodes) {
|
|
65
|
+
const graph = new dagre.graphlib.Graph();
|
|
66
|
+
// Left to right: the reader is the process being asked, and what it depends on goes outward.
|
|
67
|
+
graph.setGraph({ rankdir: 'LR', nodesep: 26, ranksep: 92, marginx: 22, marginy: 22 });
|
|
68
|
+
graph.setDefaultEdgeLabel(() => ({}));
|
|
69
|
+
for (const node of nodes)
|
|
70
|
+
graph.setNode(node.frond, { ...NODE });
|
|
71
|
+
const links = linksBetween(nodes);
|
|
72
|
+
for (const link of links) {
|
|
73
|
+
if (graph.hasNode(link.from) && graph.hasNode(link.to))
|
|
74
|
+
graph.setEdge(link.from, link.to);
|
|
75
|
+
}
|
|
76
|
+
dagre.layout(graph);
|
|
77
|
+
const travelled = links.map((link) => link.count).filter((count) => count !== undefined);
|
|
78
|
+
const shape = graph.graph();
|
|
79
|
+
const placed = nodes
|
|
80
|
+
.filter((node) => graph.hasNode(node.frond))
|
|
81
|
+
.map((node) => {
|
|
82
|
+
const { x, y, width, height } = graph.node(node.frond);
|
|
83
|
+
return { node, x, y, width, height };
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
nodes: placed,
|
|
87
|
+
edges: links.flatMap((link) => {
|
|
88
|
+
const drawn = graph.hasNode(link.from) && graph.hasNode(link.to) ? graph.edge(link.from, link.to) : undefined;
|
|
89
|
+
if (!drawn)
|
|
90
|
+
return [];
|
|
91
|
+
const points = drawn.points;
|
|
92
|
+
const at = labelAt(points, placed, figureOf(link).length * 3.4 + 8);
|
|
93
|
+
return [{
|
|
94
|
+
...link,
|
|
95
|
+
path: through(points),
|
|
96
|
+
...(at ? { at } : {}),
|
|
97
|
+
...(link.count === undefined ? {} : { weight: weightOf(link.count, travelled) }),
|
|
98
|
+
}];
|
|
99
|
+
}),
|
|
100
|
+
width: shape.width ?? 0,
|
|
101
|
+
height: shape.height ?? 0,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** A count as an operator reads it at a glance — `2.1k`, never `2140`. */
|
|
105
|
+
export function short(count) {
|
|
106
|
+
if (count < 1000)
|
|
107
|
+
return String(count);
|
|
108
|
+
return `${(count / 1000).toFixed(count < 10_000 ? 1 : 0)}k`;
|
|
109
|
+
}
|
|
110
|
+
/** What a link says of itself, and the only figure the drawing carries. */
|
|
111
|
+
export function figureOf(link) {
|
|
112
|
+
if (link.count === undefined)
|
|
113
|
+
return '—';
|
|
114
|
+
return link.errors > 0 ? `${short(link.count)} · ${short(link.errors)} ✕` : short(link.count);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Where a volume sits among the others, on a SQUARE ROOT scale. Linear makes every link but the
|
|
118
|
+
* busiest a hairline; a log flattens them the other way, and flattening is wrong at this spread —
|
|
119
|
+
* 40 to 2140 is under two orders of magnitude, and the busiest link deserves to look it.
|
|
120
|
+
*/
|
|
121
|
+
function weightOf(count, travelled) {
|
|
122
|
+
const high = Math.max(...travelled);
|
|
123
|
+
if (high <= 0)
|
|
124
|
+
return 1;
|
|
125
|
+
return Math.sqrt(count / high);
|
|
126
|
+
}
|
|
127
|
+
/** Every link, observed or merely declared, each named once. */
|
|
128
|
+
function linksBetween(nodes) {
|
|
129
|
+
const observed = nodes.flatMap((one) => one.calls);
|
|
130
|
+
const travelled = new Set(observed.map((edge) => `${edge.from} ${edge.to}`));
|
|
131
|
+
return [
|
|
132
|
+
...observed.map((edge) => ({ from: edge.from, to: edge.to, count: edge.count, errors: edge.errors })),
|
|
133
|
+
...nodes
|
|
134
|
+
.flatMap((one) => one.declaredCalls)
|
|
135
|
+
.filter((edge) => !travelled.has(`${edge.from} ${edge.to}`))
|
|
136
|
+
.map((edge) => ({ from: edge.from, to: edge.to, errors: 0 })),
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* A B-spline over the waypoints — what dagre-d3 and Grafana draw their edges with.
|
|
141
|
+
*
|
|
142
|
+
* It deliberately does NOT pass through them. A curve pinned to the points takes its character
|
|
143
|
+
* from their COUNT, and a router hands back two for a short hop and five for one that goes around
|
|
144
|
+
* something — so every edge came out with a bearing of its own and the drawing read as noise.
|
|
145
|
+
*
|
|
146
|
+
* The ends are TRIPLED rather than joined by a straight segment: a clamped spline reaches its
|
|
147
|
+
* endpoint on its own tangent, where an anchor line meets the curve at whatever angle it happens
|
|
148
|
+
* to, which is a visible corner exactly where the arrow is.
|
|
149
|
+
*/
|
|
150
|
+
function through(points) {
|
|
151
|
+
const first = points[0];
|
|
152
|
+
const last = points.at(-1);
|
|
153
|
+
if (!first || !last)
|
|
154
|
+
return '';
|
|
155
|
+
if (points.length === 1)
|
|
156
|
+
return `M ${first.x} ${first.y}`;
|
|
157
|
+
const held = [first, first, ...points, last, last];
|
|
158
|
+
const steps = held.slice(2).map((point, nth) => {
|
|
159
|
+
const back = held[nth];
|
|
160
|
+
const near = held[nth + 1];
|
|
161
|
+
return `C ${(2 * back.x + near.x) / 3} ${(2 * back.y + near.y) / 3},`
|
|
162
|
+
+ ` ${(back.x + 2 * near.x) / 3} ${(back.y + 2 * near.y) / 3},`
|
|
163
|
+
+ ` ${(back.x + 4 * near.x + point.x) / 6} ${(back.y + 4 * near.y + point.y) / 6}`;
|
|
164
|
+
});
|
|
165
|
+
return `M ${first.x} ${first.y} ${steps.join(' ')}`;
|
|
166
|
+
}
|
|
167
|
+
/** A point at a fraction of a route's length. */
|
|
168
|
+
function alongOf(points, fraction) {
|
|
169
|
+
if (fraction <= 0 || fraction >= 1)
|
|
170
|
+
return undefined;
|
|
171
|
+
const spans = points.slice(1).map((point, nth) => Math.hypot(point.x - points[nth].x, point.y - points[nth].y));
|
|
172
|
+
const target = spans.reduce((sum, span) => sum + span, 0) * fraction;
|
|
173
|
+
let walked = 0;
|
|
174
|
+
for (let nth = 0; nth < spans.length; nth++) {
|
|
175
|
+
if (walked + spans[nth] >= target) {
|
|
176
|
+
const into = spans[nth] === 0 ? 0 : (target - walked) / spans[nth];
|
|
177
|
+
return {
|
|
178
|
+
x: points[nth].x + (points[nth + 1].x - points[nth].x) * into,
|
|
179
|
+
y: points[nth].y + (points[nth + 1].y - points[nth].y) * into,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
walked += spans[nth];
|
|
183
|
+
}
|
|
184
|
+
return points.at(-1);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Where a link's figure sits: halfway ALONG the route, then moved along it until it sits inside no
|
|
188
|
+
* node. The middle waypoint is not the middle of the line — a routed edge bunches its points near
|
|
189
|
+
* the ends — and a figure drawn over a card cannot be read at all.
|
|
190
|
+
*/
|
|
191
|
+
function labelAt(points, boxes, half) {
|
|
192
|
+
const inside = (point) => boxes.some((box) => Math.abs(point.x - box.x) < box.width / 2 + half && Math.abs(point.y - box.y) < box.height / 2 + 13);
|
|
193
|
+
const middle = alongOf(points, 0.5);
|
|
194
|
+
if (!middle || !inside(middle))
|
|
195
|
+
return middle;
|
|
196
|
+
for (let step = 1; step <= 12; step++) {
|
|
197
|
+
for (const side of [-1, 1]) {
|
|
198
|
+
const moved = alongOf(points, 0.5 + side * step * 0.035);
|
|
199
|
+
if (moved && !inside(moved))
|
|
200
|
+
return moved;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return middle;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* A frond this process called that publishes nothing of its own shape. Read AFTER `silent`:
|
|
207
|
+
* a frond that never answered has the same two zeroes and a different reason for them.
|
|
208
|
+
*/
|
|
209
|
+
export function isOpaque(node) {
|
|
210
|
+
return node.placement === 'remote' && node.entities === 0 && node.facades === 0;
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=Drawing.js.map
|