@manta-eu/react 0.8.1 → 0.10.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/components/chart/ForecastLegend.d.ts.map +1 -1
- package/dist/components/chart/ForecastLegend.js +10 -2
- package/dist/components/chart/ForecastLegend.js.map +1 -1
- package/dist/components/chart/forecast-model.d.ts.map +1 -1
- package/dist/components/chart/forecast-model.js.map +1 -1
- package/dist/components/chat-view/Chat.js +2 -2
- package/dist/components/file-dropzone/index.d.ts +25 -0
- package/dist/components/file-dropzone/index.d.ts.map +1 -0
- package/dist/components/file-dropzone/index.js +70 -0
- package/dist/components/file-dropzone/index.js.map +1 -0
- package/dist/components/planning/plan-detail-utils.d.ts.map +1 -1
- package/dist/components/planning/plan-detail-utils.js +2 -0
- package/dist/components/planning/plan-detail-utils.js.map +1 -1
- package/dist/components/toast/index.d.ts +1 -0
- package/dist/components/toast/index.d.ts.map +1 -1
- package/dist/components/toast/index.js +1 -0
- package/dist/components/toast/index.js.map +1 -1
- package/dist/globals.css +27 -0
- package/dist/graph/NodeDetailPanel/TypeSummaryPanel.d.ts.map +1 -1
- package/dist/graph/NodeDetailPanel/TypeSummaryPanel.js.map +1 -1
- package/dist/hooks/use-sparql-construct.d.ts +2 -0
- package/dist/hooks/use-sparql-construct.d.ts.map +1 -1
- package/dist/hooks/use-sparql-construct.js +2 -1
- package/dist/hooks/use-sparql-construct.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/datastore-route-table.d.ts +3 -0
- package/dist/lib/datastore-route-table.d.ts.map +1 -1
- package/dist/lib/datastore-route-table.js +3 -0
- package/dist/lib/datastore-route-table.js.map +1 -1
- package/dist/lib/hooks/{useChatUpload.d.ts → useFileUpload.d.ts} +3 -3
- package/dist/lib/hooks/{useChatUpload.d.ts.map → useFileUpload.d.ts.map} +1 -1
- package/dist/lib/hooks/{useChatUpload.js → useFileUpload.js} +2 -2
- package/dist/lib/hooks/{useChatUpload.js.map → useFileUpload.js.map} +1 -1
- package/dist/routes/data-collection/index.d.ts +3 -0
- package/dist/routes/data-collection/index.d.ts.map +1 -0
- package/dist/routes/data-collection/index.js +43 -0
- package/dist/routes/data-collection/index.js.map +1 -0
- package/dist/routes/data-explorer/components/DataExplorerLayout.d.ts.map +1 -1
- package/dist/routes/data-explorer/components/DataExplorerLayout.js +5 -2
- package/dist/routes/data-explorer/components/DataExplorerLayout.js.map +1 -1
- package/dist/routes/data-explorer/components/Rail.d.ts.map +1 -1
- package/dist/routes/data-explorer/components/Rail.js +3 -3
- package/dist/routes/data-explorer/components/Rail.js.map +1 -1
- package/dist/routes/data-explorer/components/uploads/IngestRunsList.d.ts +8 -0
- package/dist/routes/data-explorer/components/uploads/IngestRunsList.d.ts.map +1 -0
- package/dist/routes/data-explorer/components/uploads/IngestRunsList.js +18 -0
- package/dist/routes/data-explorer/components/uploads/IngestRunsList.js.map +1 -0
- package/dist/routes/data-explorer/components/uploads/IngestStateStatus.d.ts +14 -0
- package/dist/routes/data-explorer/components/uploads/IngestStateStatus.d.ts.map +1 -0
- package/dist/routes/data-explorer/components/uploads/IngestStateStatus.js +33 -0
- package/dist/routes/data-explorer/components/uploads/IngestStateStatus.js.map +1 -0
- package/dist/routes/data-explorer/components/uploads/UploadedFilesList.d.ts +8 -0
- package/dist/routes/data-explorer/components/uploads/UploadedFilesList.d.ts.map +1 -0
- package/dist/routes/data-explorer/components/uploads/UploadedFilesList.js +34 -0
- package/dist/routes/data-explorer/components/uploads/UploadedFilesList.js.map +1 -0
- package/dist/routes/data-explorer/components/uploads/UploadsPages.d.ts +7 -0
- package/dist/routes/data-explorer/components/uploads/UploadsPages.d.ts.map +1 -0
- package/dist/routes/data-explorer/components/uploads/UploadsPages.js +35 -0
- package/dist/routes/data-explorer/components/uploads/UploadsPages.js.map +1 -0
- package/dist/routes/data-explorer/index.d.ts +1 -0
- package/dist/routes/data-explorer/index.d.ts.map +1 -1
- package/dist/routes/data-explorer/index.js +1 -0
- package/dist/routes/data-explorer/index.js.map +1 -1
- package/dist/routes/data-explorer/namespaces.d.ts +4 -0
- package/dist/routes/data-explorer/namespaces.d.ts.map +1 -1
- package/dist/routes/data-explorer/namespaces.js +6 -1
- package/dist/routes/data-explorer/namespaces.js.map +1 -1
- package/dist/routes/data-explorer/uploads.d.ts +56 -0
- package/dist/routes/data-explorer/uploads.d.ts.map +1 -0
- package/dist/routes/data-explorer/uploads.js +140 -0
- package/dist/routes/data-explorer/uploads.js.map +1 -0
- package/dist/routes/datastores/components/LinkUnlinkedDatastoreDialog.d.ts +1 -0
- package/dist/routes/datastores/components/LinkUnlinkedDatastoreDialog.d.ts.map +1 -1
- package/dist/routes/datastores/components/LinkUnlinkedDatastoreDialog.js +16 -9
- package/dist/routes/datastores/components/LinkUnlinkedDatastoreDialog.js.map +1 -1
- package/dist/routes/datastores/components/StatusBadge.d.ts +7 -8
- package/dist/routes/datastores/components/StatusBadge.d.ts.map +1 -1
- package/dist/routes/datastores/components/StatusBadge.js +17 -1
- package/dist/routes/datastores/components/StatusBadge.js.map +1 -1
- package/dist/routes/datastores/flatten.d.ts +6 -1
- package/dist/routes/datastores/flatten.d.ts.map +1 -1
- package/dist/routes/datastores/flatten.js +37 -2
- package/dist/routes/datastores/flatten.js.map +1 -1
- package/dist/routes/datastores/hooks/useDatastoreColumns.d.ts +2 -0
- package/dist/routes/datastores/hooks/useDatastoreColumns.d.ts.map +1 -1
- package/dist/routes/datastores/hooks/useDatastoreColumns.js +8 -4
- package/dist/routes/datastores/hooks/useDatastoreColumns.js.map +1 -1
- package/dist/routes/datastores/index.d.ts.map +1 -1
- package/dist/routes/datastores/index.js +53 -18
- package/dist/routes/datastores/index.js.map +1 -1
- package/dist/routes/integrations/components/connect-forms/GoogleMerchantCenterConnectForm.d.ts +3 -0
- package/dist/routes/integrations/components/connect-forms/GoogleMerchantCenterConnectForm.d.ts.map +1 -0
- package/dist/routes/integrations/components/connect-forms/GoogleMerchantCenterConnectForm.js +38 -0
- package/dist/routes/integrations/components/connect-forms/GoogleMerchantCenterConnectForm.js.map +1 -0
- package/dist/routes/integrations/components/connect-forms/google-merchant-center-account-tree.d.ts +4 -0
- package/dist/routes/integrations/components/connect-forms/google-merchant-center-account-tree.d.ts.map +1 -0
- package/dist/routes/integrations/components/connect-forms/google-merchant-center-account-tree.js +32 -0
- package/dist/routes/integrations/components/connect-forms/google-merchant-center-account-tree.js.map +1 -0
- package/dist/routes/integrations/components/connect-forms/setup-account-unavailable-reason.d.ts.map +1 -1
- package/dist/routes/integrations/components/connect-forms/setup-account-unavailable-reason.js +1 -0
- package/dist/routes/integrations/components/connect-forms/setup-account-unavailable-reason.js.map +1 -1
- package/dist/routes/integrations/connect-forms.d.ts +1 -0
- package/dist/routes/integrations/connect-forms.d.ts.map +1 -1
- package/dist/routes/integrations/connect-forms.js +1 -0
- package/dist/routes/integrations/connect-forms.js.map +1 -1
- package/dist/routes/integrations/connection-view.d.ts.map +1 -1
- package/dist/routes/integrations/connection-view.js +1 -0
- package/dist/routes/integrations/connection-view.js.map +1 -1
- package/dist/shared/graph-derived-queries.d.ts.map +1 -1
- package/dist/shared/graph-derived-queries.js +2 -1
- package/dist/shared/graph-derived-queries.js.map +1 -1
- package/package.json +21 -9
- package/src/app-subpaths.json +1 -0
- package/src/components/chart/ForecastLegend.tsx +15 -13
- package/src/components/chart/forecast-model.ts +6 -8
- package/src/components/chat-view/Chat.tsx +2 -2
- package/src/components/file-dropzone/index.tsx +165 -0
- package/src/components/planning/plan-detail-utils.tsx +2 -0
- package/src/components/toast/index.tsx +1 -0
- package/src/graph/NodeDetailPanel/TypeSummaryPanel.tsx +12 -14
- package/src/hooks/use-sparql-construct.ts +4 -2
- package/src/index.ts +1 -0
- package/src/lib/datastore-route-table.ts +6 -0
- package/src/lib/hooks/{useChatUpload.ts → useFileUpload.ts} +2 -2
- package/src/routes/data-collection/index.tsx +82 -0
- package/src/routes/data-explorer/components/DataExplorerLayout.tsx +5 -2
- package/src/routes/data-explorer/components/Rail.tsx +13 -2
- package/src/routes/data-explorer/components/uploads/IngestRunsList.tsx +63 -0
- package/src/routes/data-explorer/components/uploads/IngestStateStatus.tsx +45 -0
- package/src/routes/data-explorer/components/uploads/UploadedFilesList.tsx +93 -0
- package/src/routes/data-explorer/components/uploads/UploadsPages.tsx +80 -0
- package/src/routes/data-explorer/index.tsx +6 -0
- package/src/routes/data-explorer/namespaces.ts +7 -1
- package/src/routes/data-explorer/uploads.ts +205 -0
- package/src/routes/datastores/components/LinkUnlinkedDatastoreDialog.tsx +49 -10
- package/src/routes/datastores/components/StatusBadge.tsx +22 -7
- package/src/routes/datastores/flatten.ts +50 -2
- package/src/routes/datastores/hooks/useDatastoreColumns.tsx +21 -1
- package/src/routes/datastores/index.tsx +64 -13
- package/src/routes/integrations/components/connect-forms/GoogleMerchantCenterConnectForm.tsx +61 -0
- package/src/routes/integrations/components/connect-forms/google-merchant-center-account-tree.ts +38 -0
- package/src/routes/integrations/components/connect-forms/setup-account-unavailable-reason.ts +1 -0
- package/src/routes/integrations/connect-forms.ts +1 -0
- package/src/routes/integrations/connection-view.ts +1 -0
- package/src/shared/graph-derived-queries.ts +2 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useActionPlanByIriQuery, useActionPlanDiffQuery, useActionPlanRulesQuery, useActionPlanRunHistoryQuery, useActionPlanSamplesQuery, useActionPlansQuery, useConversationStartersQuery, useCoverageRulesQuery, useCurrentFactValueQuery, useExplainFactQuery, useGetActionPlansSummaryQuery, useMemoriesQuery, useMemorySchemasQuery, useNodePropertiesQuery, useNodeRelationshipsQuery, useRulesQuery, useShaclShapesQuery, useSparqlQueryQuery, useUserPreferencesQuery, useValidateActionPlanQuery, } from "@manta-eu/client";
|
|
1
|
+
import { useActionPlanByIriQuery, useActionPlanDiffQuery, useActionPlanRulesQuery, useActionPlanRunHistoryQuery, useActionPlanSamplesQuery, useActionPlansQuery, useConversationStartersQuery, useCoverageRulesQuery, useCurrentFactValueQuery, useExplainFactQuery, useGetActionPlansSummaryQuery, useManualActionProgressQuery, useMemoriesQuery, useMemorySchemasQuery, useNodePropertiesQuery, useNodeRelationshipsQuery, useRulesQuery, useShaclShapesQuery, useSparqlQueryQuery, useUserPreferencesQuery, useValidateActionPlanQuery, } from "@manta-eu/client";
|
|
2
2
|
import { invalidateQueries } from "#lib/tanstack-query";
|
|
3
3
|
// Queries whose resolver reads the active datastore's knowledge graph, so any graph write can change them.
|
|
4
4
|
export const graphDerivedQueries = [
|
|
@@ -13,6 +13,7 @@ export const graphDerivedQueries = [
|
|
|
13
13
|
useCurrentFactValueQuery,
|
|
14
14
|
useExplainFactQuery,
|
|
15
15
|
useGetActionPlansSummaryQuery,
|
|
16
|
+
useManualActionProgressQuery,
|
|
16
17
|
useMemoriesQuery,
|
|
17
18
|
useMemorySchemasQuery,
|
|
18
19
|
useNodePropertiesQuery,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-derived-queries.js","sourceRoot":"","sources":["../../src/shared/graph-derived-queries.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,EACzB,mBAAmB,EACnB,4BAA4B,EAC5B,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,EACnB,6BAA6B,EAC7B,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAwB,MAAM,qBAAqB,CAAC;AAE9E,2GAA2G;AAC3G,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,uBAAuB;IACvB,sBAAsB;IACtB,uBAAuB;IACvB,4BAA4B;IAC5B,yBAAyB;IACzB,mBAAmB;IACnB,4BAA4B;IAC5B,qBAAqB;IACrB,wBAAwB;IACxB,mBAAmB;IACnB,6BAA6B;IAC7B,gBAAgB;IAChB,qBAAqB;IACrB,sBAAsB;IACtB,yBAAyB;IACzB,aAAa;IACb,mBAAmB;IACnB,mBAAmB;IACnB,uBAAuB;IACvB,0BAA0B;CAC3B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,6BAA6B,CAAC,WAAwB;IAC1E,MAAM,iBAAiB,CAAC,WAAW,EAAE,CAAC,GAAG,mBAAmB,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC"}
|
|
1
|
+
{"version":3,"file":"graph-derived-queries.js","sourceRoot":"","sources":["../../src/shared/graph-derived-queries.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,EACzB,mBAAmB,EACnB,4BAA4B,EAC5B,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,EACnB,6BAA6B,EAC7B,4BAA4B,EAC5B,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAwB,MAAM,qBAAqB,CAAC;AAE9E,2GAA2G;AAC3G,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,uBAAuB;IACvB,sBAAsB;IACtB,uBAAuB;IACvB,4BAA4B;IAC5B,yBAAyB;IACzB,mBAAmB;IACnB,4BAA4B;IAC5B,qBAAqB;IACrB,wBAAwB;IACxB,mBAAmB;IACnB,6BAA6B;IAC7B,4BAA4B;IAC5B,gBAAgB;IAChB,qBAAqB;IACrB,sBAAsB;IACtB,yBAAyB;IACzB,aAAa;IACb,mBAAmB;IACnB,mBAAmB;IACnB,uBAAuB;IACvB,0BAA0B;CAC3B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,6BAA6B,CAAC,WAAwB;IAC1E,MAAM,iBAAiB,CAAC,WAAW,EAAE,CAAC,GAAG,mBAAmB,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manta-eu/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The Manta design system, knowledge-graph UI and agent components",
|
|
5
5
|
"homepage": "https://developers.manta.eu",
|
|
6
6
|
"keywords": [
|
|
@@ -310,6 +310,11 @@
|
|
|
310
310
|
"types": "./dist/engine.d.ts",
|
|
311
311
|
"import": "./dist/engine.js"
|
|
312
312
|
},
|
|
313
|
+
"./file-dropzone": {
|
|
314
|
+
"manta-source": "./src/components/file-dropzone/index.tsx",
|
|
315
|
+
"types": "./dist/components/file-dropzone/index.d.ts",
|
|
316
|
+
"import": "./dist/components/file-dropzone/index.js"
|
|
317
|
+
},
|
|
313
318
|
"./filter-sheet": {
|
|
314
319
|
"manta-source": "./src/components/filter-sheet/index.tsx",
|
|
315
320
|
"types": "./dist/components/filter-sheet/index.d.ts",
|
|
@@ -721,6 +726,11 @@
|
|
|
721
726
|
"types": "./dist/routes/activity/format.d.ts",
|
|
722
727
|
"import": "./dist/routes/activity/format.js"
|
|
723
728
|
},
|
|
729
|
+
"./routes/data-collection": {
|
|
730
|
+
"manta-source": "./src/routes/data-collection/index.tsx",
|
|
731
|
+
"types": "./dist/routes/data-collection/index.d.ts",
|
|
732
|
+
"import": "./dist/routes/data-collection/index.js"
|
|
733
|
+
},
|
|
724
734
|
"./routes/data-explorer": {
|
|
725
735
|
"manta-source": "./src/routes/data-explorer/index.tsx",
|
|
726
736
|
"types": "./dist/routes/data-explorer/index.d.ts",
|
|
@@ -1137,14 +1147,14 @@
|
|
|
1137
1147
|
"tailwindcss-animate": "^1.0.7",
|
|
1138
1148
|
"ts-pattern": "^5.9.0",
|
|
1139
1149
|
"usehooks-ts": "^3.1.1",
|
|
1140
|
-
"zod": "^4.
|
|
1150
|
+
"zod": "^4.6.7",
|
|
1141
1151
|
"zustand": "^5.0.2",
|
|
1142
|
-
"@manta-eu/auth": "0.
|
|
1143
|
-
"@manta-eu/
|
|
1144
|
-
"@manta-eu/
|
|
1145
|
-
"@manta-eu/
|
|
1146
|
-
"@manta-eu/
|
|
1147
|
-
"@manta-eu/
|
|
1152
|
+
"@manta-eu/auth": "0.10.0",
|
|
1153
|
+
"@manta-eu/lib": "0.10.0",
|
|
1154
|
+
"@manta-eu/ldo": "0.10.0",
|
|
1155
|
+
"@manta-eu/client": "0.10.0",
|
|
1156
|
+
"@manta-eu/rdf-lib": "0.10.0",
|
|
1157
|
+
"@manta-eu/datalog-parser": "0.10.0"
|
|
1148
1158
|
},
|
|
1149
1159
|
"peerDependencies": {
|
|
1150
1160
|
"@ulb-darmstadt/shacl-form": "^2.1.1-rc1",
|
|
@@ -1177,10 +1187,11 @@
|
|
|
1177
1187
|
"storybook": "^10.6.4",
|
|
1178
1188
|
"tailwindcss": "^4.3.3",
|
|
1179
1189
|
"tsc-alias": "^1.9.5",
|
|
1190
|
+
"tsx": "^4.21.0",
|
|
1180
1191
|
"typescript": "^7.0.2",
|
|
1181
1192
|
"uuid": "^13.0.0",
|
|
1182
1193
|
"vite": "^8.3.5",
|
|
1183
|
-
"vitest": "
|
|
1194
|
+
"vitest": "~5.0.5",
|
|
1184
1195
|
"@manta-eu/oxlint-config": "0.1.0"
|
|
1185
1196
|
},
|
|
1186
1197
|
"imports": {
|
|
@@ -1202,6 +1213,7 @@
|
|
|
1202
1213
|
"scripts": {
|
|
1203
1214
|
"build": "rimraf dist && postcss src/globals.css -o dist/globals.css && tsc --project tsconfig.build.json && tsc-alias --project tsconfig.build.json --resolve-full-paths",
|
|
1204
1215
|
"build-storybook": "NODE_OPTIONS=\"$NODE_OPTIONS --max-old-space-size=6144\" storybook build",
|
|
1216
|
+
"build-storybook:public": "NODE_OPTIONS=\"$NODE_OPTIONS --max-old-space-size=6144\" storybook build -c .storybook-public -o storybook-public",
|
|
1205
1217
|
"lint": "oxlint --type-aware --report-unused-disable-directives-severity=warn .",
|
|
1206
1218
|
"storybook": "storybook dev -p 6007",
|
|
1207
1219
|
"test": "vitest --run",
|
package/src/app-subpaths.json
CHANGED
|
@@ -32,20 +32,22 @@ export function forecastLegendItems(source: LegendSource): ForecastLegendItem[]
|
|
|
32
32
|
hasProjection,
|
|
33
33
|
legendLabels,
|
|
34
34
|
} = source;
|
|
35
|
-
const withoutItems = [...new Set(withoutLabels)].map(
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
const withoutItems = [...new Set(withoutLabels)].map((label): ForecastLegendItem => ({
|
|
36
|
+
label,
|
|
37
|
+
color: withoutColor,
|
|
38
|
+
kind: "thin-line",
|
|
39
|
+
}));
|
|
38
40
|
const oneGainColor = new Set(gains.map((gain) => gain.color)).size === 1;
|
|
39
|
-
const gainItems = (oneGainColor ? gains.slice(0, 1) : gains).map(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
41
|
+
const gainItems = (oneGainColor ? gains.slice(0, 1) : gains).map((gain): ForecastLegendItem => ({
|
|
42
|
+
label: oneGainColor ? gainLabel : `${gainLabel} · ${gain.metric}`,
|
|
43
|
+
color: gain.color,
|
|
44
|
+
kind: "fill",
|
|
45
|
+
}));
|
|
46
|
+
const betweenItems = betweenLabels.map((label): ForecastLegendItem => ({
|
|
47
|
+
label,
|
|
48
|
+
color: firstColor,
|
|
49
|
+
kind: "faint-fill",
|
|
50
|
+
}));
|
|
49
51
|
if (metrics.length > 1) {
|
|
50
52
|
return [
|
|
51
53
|
...metrics.map((metric): ForecastLegendItem => ({ label: metric.label, color: metric.color, kind: "line" })),
|
|
@@ -104,14 +104,12 @@ export function buildForecastModel(input: ModelInput) {
|
|
|
104
104
|
config: Object.fromEntries(
|
|
105
105
|
[...metrics, ...withPlans.map((entry) => entry.without)].map((line) => [line.key, { label: line.label }]),
|
|
106
106
|
) satisfies ChartConfig,
|
|
107
|
-
hoverMetrics: metrics.map(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}),
|
|
114
|
-
),
|
|
107
|
+
hoverMetrics: metrics.map((metric): ForecastHoverMetric => ({
|
|
108
|
+
key: metric.key,
|
|
109
|
+
label: metric.label,
|
|
110
|
+
lowerIsBetter: metric.lowerIsBetter === true,
|
|
111
|
+
...(isPresent(metric.withoutPlans) ? { withoutKey: metric.withoutPlans.key } : {}),
|
|
112
|
+
})),
|
|
115
113
|
legendItems: forecastLegendItems({
|
|
116
114
|
metrics: metrics.map((metric, index) => ({ label: metric.label, color: metricColor(metric, index) })),
|
|
117
115
|
withoutLabels: withPlans.map((entry) => entry.without.label),
|
|
@@ -50,7 +50,7 @@ import { useSelectedModel } from "#hooks/useSelectedModel";
|
|
|
50
50
|
import { isDevBuild } from "#lib/build-config";
|
|
51
51
|
import type { ChatDraft, CopilotMenuDefaults, Datastore, PageContext, User } from "#lib/chat-types";
|
|
52
52
|
import { findLatestShowcase } from "#lib/find-latest-showcase";
|
|
53
|
-
import {
|
|
53
|
+
import { useFileUpload } from "#lib/hooks/useFileUpload";
|
|
54
54
|
import { planStatusLabel } from "#lib/plan-status-label";
|
|
55
55
|
import { cn } from "#lib/utils";
|
|
56
56
|
import { ActiveChatProvider, useActiveChatConnection } from "#providers/ActiveChatProvider";
|
|
@@ -360,7 +360,7 @@ function ChatContent(props: ChatContentProps) {
|
|
|
360
360
|
|
|
361
361
|
const toolsUsedInSession = useRef(new Set<string>());
|
|
362
362
|
|
|
363
|
-
const { uploadFiles, isUploading, progress: uploadProgress } =
|
|
363
|
+
const { uploadFiles, isUploading, progress: uploadProgress } = useFileUpload();
|
|
364
364
|
|
|
365
365
|
const beginAssistantTurn = useCallback(() => {
|
|
366
366
|
turnKeyRef.current += 1;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { maxUploadBytes } from "@manta-eu/client/shared/upload";
|
|
2
|
+
import { fileIdentityKey } from "@manta-eu/lib/file";
|
|
3
|
+
import { humanBytes } from "@manta-eu/lib/humanize";
|
|
4
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
5
|
+
import { FileText, UploadCloud } from "lucide-react";
|
|
6
|
+
import { useRef, useState, type ChangeEvent, type DragEvent } from "react";
|
|
7
|
+
import { Progress } from "#components/progress/index";
|
|
8
|
+
import { cn } from "#style";
|
|
9
|
+
|
|
10
|
+
export type RejectedDrop = {
|
|
11
|
+
file: File;
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function partitionDroppedFiles(files: readonly File[], maxFileSize: number) {
|
|
16
|
+
const accepted: File[] = [];
|
|
17
|
+
const rejected: RejectedDrop[] = [];
|
|
18
|
+
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
if (file.size === 0) rejected.push({ file, reason: "File is empty" });
|
|
21
|
+
else if (file.size > maxFileSize) rejected.push({ file, reason: `File exceeds ${humanBytes(maxFileSize)}` });
|
|
22
|
+
else accepted.push(file);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { accepted, rejected };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function hasFiles(dataTransfer: DataTransfer | null) {
|
|
29
|
+
return dataTransfer?.types.includes("Files") ?? false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type FileDropzoneProps = {
|
|
33
|
+
onFiles: (files: File[]) => void;
|
|
34
|
+
onRejected?: (rejected: RejectedDrop[]) => void;
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
maxFileSize?: number;
|
|
37
|
+
title?: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
className?: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function FileDropzone(props: FileDropzoneProps) {
|
|
43
|
+
const {
|
|
44
|
+
onFiles,
|
|
45
|
+
onRejected,
|
|
46
|
+
disabled = false,
|
|
47
|
+
maxFileSize = maxUploadBytes,
|
|
48
|
+
title = "Drop files here",
|
|
49
|
+
description,
|
|
50
|
+
className,
|
|
51
|
+
} = props;
|
|
52
|
+
|
|
53
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
54
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
55
|
+
|
|
56
|
+
function handleFiles(files: File[]) {
|
|
57
|
+
const { accepted, rejected } = partitionDroppedFiles(files, maxFileSize);
|
|
58
|
+
|
|
59
|
+
if (isPresent(rejected)) onRejected?.(rejected);
|
|
60
|
+
if (isPresent(accepted)) onFiles(accepted);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function handleDragOver(event: DragEvent<HTMLButtonElement>) {
|
|
64
|
+
if (disabled || !hasFiles(event.dataTransfer)) return;
|
|
65
|
+
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
setIsDragging(true);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function handleDragLeave(event: DragEvent<HTMLButtonElement>) {
|
|
71
|
+
if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget)) return;
|
|
72
|
+
|
|
73
|
+
setIsDragging(false);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function handleDrop(event: DragEvent<HTMLButtonElement>) {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
setIsDragging(false);
|
|
79
|
+
|
|
80
|
+
if (disabled) return;
|
|
81
|
+
|
|
82
|
+
handleFiles(Array.from(event.dataTransfer.files));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function handleChange(event: ChangeEvent<HTMLInputElement>) {
|
|
86
|
+
handleFiles(Array.from(event.target.files ?? []));
|
|
87
|
+
event.target.value = "";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<>
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
disabled={disabled}
|
|
95
|
+
onClick={() => inputRef.current?.click()}
|
|
96
|
+
onDragEnter={handleDragOver}
|
|
97
|
+
onDragOver={handleDragOver}
|
|
98
|
+
onDragLeave={handleDragLeave}
|
|
99
|
+
onDrop={handleDrop}
|
|
100
|
+
data-dragging={isDragging}
|
|
101
|
+
className={cn(
|
|
102
|
+
"flex min-h-56 w-full flex-col items-center justify-center gap-3 rounded-3xl border-2 border-dashed px-6 py-10",
|
|
103
|
+
"border-muted-border bg-faint text-center outline-none transition-colors",
|
|
104
|
+
"hover:border-accent-foreground/60 focus-visible:ring-2 focus-visible:ring-active-border/50",
|
|
105
|
+
"disabled:cursor-not-allowed disabled:opacity-60",
|
|
106
|
+
isDragging && "border-accent-foreground/80 bg-accent-foreground/[0.04]",
|
|
107
|
+
className,
|
|
108
|
+
)}
|
|
109
|
+
>
|
|
110
|
+
<UploadCloud className="size-8 text-accent-foreground" />
|
|
111
|
+
<span className="typography-body-medium text-default-foreground">{title}</span>
|
|
112
|
+
<span className="typography-small text-muted-foreground">
|
|
113
|
+
or <span className="text-primary underline underline-offset-2">browse your computer</span>
|
|
114
|
+
</span>
|
|
115
|
+
<span className="typography-caption text-muted-foreground">
|
|
116
|
+
{description ?? `Any file type, up to ${humanBytes(maxFileSize)} each`}
|
|
117
|
+
</span>
|
|
118
|
+
</button>
|
|
119
|
+
|
|
120
|
+
<input
|
|
121
|
+
ref={inputRef}
|
|
122
|
+
type="file"
|
|
123
|
+
multiple
|
|
124
|
+
hidden
|
|
125
|
+
disabled={disabled}
|
|
126
|
+
onChange={handleChange}
|
|
127
|
+
data-testid="file-dropzone-input"
|
|
128
|
+
/>
|
|
129
|
+
</>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export type UploadProgressListProps = {
|
|
134
|
+
files: readonly File[];
|
|
135
|
+
progress: Record<string, number>;
|
|
136
|
+
className?: string;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export function UploadProgressList(props: UploadProgressListProps) {
|
|
140
|
+
const { files, progress, className } = props;
|
|
141
|
+
|
|
142
|
+
if (!isPresent(files)) return null;
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<ul className={cn("flex flex-col gap-2", className)} aria-label="Uploads in progress">
|
|
146
|
+
{files.map((file) => {
|
|
147
|
+
const percent = progress[fileIdentityKey(file)] ?? 0;
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<li
|
|
151
|
+
key={fileIdentityKey(file)}
|
|
152
|
+
className="flex items-center gap-3 rounded-lg border border-muted-border px-3 py-2"
|
|
153
|
+
>
|
|
154
|
+
<FileText className="size-4 shrink-0 text-muted-foreground" />
|
|
155
|
+
<span className="typography-small min-w-0 flex-1 truncate text-default-foreground">{file.name}</span>
|
|
156
|
+
<Progress value={percent} size="sm" className="w-24 shrink-0 sm:w-40" aria-label={`${file.name} upload`} />
|
|
157
|
+
<span className="typography-caption w-10 shrink-0 text-right tabular-nums text-muted-foreground">
|
|
158
|
+
{percent}%
|
|
159
|
+
</span>
|
|
160
|
+
</li>
|
|
161
|
+
);
|
|
162
|
+
})}
|
|
163
|
+
</ul>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
@@ -109,6 +109,7 @@ export function formatIntegration(integration: GQLIntegration | null): string {
|
|
|
109
109
|
.with(GQLIntegration.Meta, () => "Meta")
|
|
110
110
|
.with(GQLIntegration.Google, () => "Google")
|
|
111
111
|
.with(GQLIntegration.GoogleAnalytics, () => "Google Analytics")
|
|
112
|
+
.with(GQLIntegration.GoogleMerchantCenter, () => "Merchant Center")
|
|
112
113
|
.with(GQLIntegration.Linkedin, () => "LinkedIn")
|
|
113
114
|
.with(GQLIntegration.MicrosoftAds, () => "Microsoft Ads")
|
|
114
115
|
.with(GQLIntegration.Shopify, () => "Shopify")
|
|
@@ -126,6 +127,7 @@ export function integrationToChannel(integration: GQLIntegration): Channel | nul
|
|
|
126
127
|
[GQLIntegration.Meta]: "META",
|
|
127
128
|
[GQLIntegration.Google]: "GOOGLE_ADS",
|
|
128
129
|
[GQLIntegration.GoogleAnalytics]: null,
|
|
130
|
+
[GQLIntegration.GoogleMerchantCenter]: null,
|
|
129
131
|
[GQLIntegration.Linkedin]: null,
|
|
130
132
|
[GQLIntegration.MicrosoftAds]: null,
|
|
131
133
|
[GQLIntegration.Shopify]: "SHOPIFY",
|
|
@@ -107,20 +107,18 @@ function buildInstanceColumns(args: BuildInstanceColumnsArgs): ColumnDef<SampleI
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
columns.push(
|
|
110
|
-
...previewKeys.map(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}),
|
|
123
|
-
),
|
|
110
|
+
...previewKeys.map((key): ColumnDef<SampleInstance> => ({
|
|
111
|
+
id: `preview:${key}`,
|
|
112
|
+
header: titleCase(key),
|
|
113
|
+
meta: denseCellMeta,
|
|
114
|
+
cell: ({ row }) => {
|
|
115
|
+
const value = propertyValue(row.original, key);
|
|
116
|
+
if (!isPresent(value)) return null;
|
|
117
|
+
return (
|
|
118
|
+
<span className="typography-tiny block truncate text-muted-foreground">{formatDisplayValue(value)}</span>
|
|
119
|
+
);
|
|
120
|
+
},
|
|
121
|
+
})),
|
|
124
122
|
);
|
|
125
123
|
|
|
126
124
|
return columns;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
|
1
|
+
import { keepPreviousData, useQuery, type Query } from "@tanstack/react-query";
|
|
2
2
|
import type { QueryContext } from "ldkit";
|
|
3
3
|
import type { RDF } from "ldkit/rdf";
|
|
4
4
|
import { withAbortSignal } from "../engine";
|
|
@@ -39,10 +39,11 @@ export type UseSparqlSelectOptions = {
|
|
|
39
39
|
queryKey: readonly unknown[];
|
|
40
40
|
enabled?: boolean;
|
|
41
41
|
staleTime?: number;
|
|
42
|
+
refetchInterval?: number | false | ((query: Query<RDF.Bindings[]>) => number | false | undefined);
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
export function useSparqlSelect(config: UseSparqlSelectOptions) {
|
|
45
|
-
const { query, queryKey, enabled = true, staleTime } = config;
|
|
46
|
+
const { query, queryKey, enabled = true, staleTime, refetchInterval } = config;
|
|
46
47
|
const engine = useSparqlEngine();
|
|
47
48
|
const options = useSparqlOptions();
|
|
48
49
|
|
|
@@ -54,5 +55,6 @@ export function useSparqlSelect(config: UseSparqlSelectOptions) {
|
|
|
54
55
|
},
|
|
55
56
|
enabled: enabled && !!query,
|
|
56
57
|
staleTime,
|
|
58
|
+
refetchInterval,
|
|
57
59
|
});
|
|
58
60
|
}
|
package/src/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ export * from "./components/disabled-action-tooltip";
|
|
|
23
23
|
export * from "./components/dropdown";
|
|
24
24
|
export * from "./components/editable-text";
|
|
25
25
|
export * from "./components/empty-state";
|
|
26
|
+
export * from "./components/file-dropzone";
|
|
26
27
|
export * from "./components/filter-sheet";
|
|
27
28
|
export * from "./components/hover-media";
|
|
28
29
|
export * from "./components/input";
|
|
@@ -24,6 +24,9 @@ export type RouteElements = {
|
|
|
24
24
|
DataExplorerIndex?: ReactNode;
|
|
25
25
|
DataExplorerRecent?: ReactNode;
|
|
26
26
|
DataExplorerCoverage?: ReactNode;
|
|
27
|
+
DataExplorerFiles?: ReactNode;
|
|
28
|
+
DataExplorerIngest?: ReactNode;
|
|
29
|
+
DataCollection?: ReactNode;
|
|
27
30
|
DataExplorerPrefix?: ReactNode;
|
|
28
31
|
DataExplorerType?: ReactNode;
|
|
29
32
|
DataEntity?: ReactNode;
|
|
@@ -72,12 +75,15 @@ export const datastoreRoutes: RouteDefinition[] = [
|
|
|
72
75
|
{ path: "/data", render: (e) => e.DataExplorerIndex || notFoundElement(e) },
|
|
73
76
|
{ path: "/data/recent", render: (e) => e.DataExplorerRecent || notFoundElement(e) },
|
|
74
77
|
{ path: "/data/coverage", render: (e) => e.DataExplorerCoverage || notFoundElement(e) },
|
|
78
|
+
{ path: "/data/files", render: (e) => e.DataExplorerFiles || notFoundElement(e) },
|
|
79
|
+
{ path: "/data/ingest-runs", render: (e) => e.DataExplorerIngest || notFoundElement(e) },
|
|
75
80
|
{ path: "/data/entity/:iri", render: (e) => e.DataEntity || notFoundElement(e) },
|
|
76
81
|
{ path: "/data/:prefix", render: (e) => e.DataExplorerPrefix || notFoundElement(e) },
|
|
77
82
|
{ path: "/data/:prefix/:type", render: (e) => e.DataExplorerType || notFoundElement(e) },
|
|
78
83
|
{ path: "/data/:prefix/:type/:id", render: (e) => e.DataDetail || notFoundElement(e) },
|
|
79
84
|
],
|
|
80
85
|
},
|
|
86
|
+
{ path: "/data-collection", render: (e) => e.DataCollection || notFoundElement(e) },
|
|
81
87
|
{ path: newChatPath, render: (e) => e.Chat },
|
|
82
88
|
{ path: "/chat/:chatId", render: (e) => e.Chat },
|
|
83
89
|
{ path: notFoundRoutePath, render: notFoundElement },
|
|
@@ -21,13 +21,13 @@ export type UploadProgress = Record<string, number>;
|
|
|
21
21
|
|
|
22
22
|
const uploadConcurrency = 6;
|
|
23
23
|
|
|
24
|
-
export type
|
|
24
|
+
export type UseFileUploadResult = {
|
|
25
25
|
uploadFiles: (files: File[]) => Promise<UploadFilesResult>;
|
|
26
26
|
isUploading: boolean;
|
|
27
27
|
progress: UploadProgress;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
export function
|
|
30
|
+
export function useFileUpload(): UseFileUploadResult {
|
|
31
31
|
const { mantaClient, uploadRelay } = useMantaClient();
|
|
32
32
|
|
|
33
33
|
const { mutateAsync: initiateUpload } = useInitiateUploadMutation(mantaClient);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { fileIdentityKey } from "@manta-eu/lib/file";
|
|
2
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
3
|
+
import { FolderUp } from "lucide-react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { toast } from "sonner";
|
|
6
|
+
import { FileDropzone, UploadProgressList, type RejectedDrop } from "#components/file-dropzone/index";
|
|
7
|
+
import { PageBody, PageHeader } from "#components/layouts/page/index";
|
|
8
|
+
import { RouteLayout } from "#components/layouts/RouteLayout";
|
|
9
|
+
import { useFileUpload } from "#lib/hooks/useFileUpload";
|
|
10
|
+
import { useAuthContext } from "#providers/AuthContext";
|
|
11
|
+
import { UploadedFilesSection } from "#routes/data-explorer/components/uploads/UploadsPages";
|
|
12
|
+
import { useInvalidateUploads } from "#routes/data-explorer/uploads";
|
|
13
|
+
|
|
14
|
+
function showRejected(rejected: RejectedDrop[]) {
|
|
15
|
+
for (const { file, reason } of rejected) toast.error(`${file.name}: ${reason}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function DataCollectionUploader() {
|
|
19
|
+
const { uploadFiles, progress } = useFileUpload();
|
|
20
|
+
const invalidateUploads = useInvalidateUploads();
|
|
21
|
+
const [inFlight, setInFlight] = useState<File[]>([]);
|
|
22
|
+
|
|
23
|
+
async function handleFiles(files: File[]) {
|
|
24
|
+
setInFlight((current) => [...current, ...files]);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const { uploaded, failed } = await uploadFiles(files);
|
|
28
|
+
|
|
29
|
+
for (const { file } of failed) toast.error(`${file.name} could not be uploaded. Try again.`);
|
|
30
|
+
if (isPresent(uploaded)) toast.success(`Uploaded ${uploaded.length} of ${files.length} files`);
|
|
31
|
+
} finally {
|
|
32
|
+
const done = new Set(files.map(fileIdentityKey));
|
|
33
|
+
|
|
34
|
+
setInFlight((current) => current.filter((file) => !done.has(fileIdentityKey(file))));
|
|
35
|
+
await invalidateUploads();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className="flex flex-col gap-3">
|
|
41
|
+
<FileDropzone onFiles={(files) => void handleFiles(files)} onRejected={showRejected} />
|
|
42
|
+
<UploadProgressList files={inFlight} progress={progress} />
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function DataCollectionRoute() {
|
|
48
|
+
const { datastore, datastores, user, logout, isOperator, canSwitchDatastore } = useAuthContext();
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<RouteLayout
|
|
52
|
+
user={user}
|
|
53
|
+
datastore={datastore}
|
|
54
|
+
datastores={datastores}
|
|
55
|
+
isOperator={isOperator}
|
|
56
|
+
canSwitchDatastore={canSwitchDatastore}
|
|
57
|
+
logout={logout}
|
|
58
|
+
>
|
|
59
|
+
<PageHeader title="Data collection" icon={FolderUp} />
|
|
60
|
+
<PageBody className="px-4 py-6 sm:px-6">
|
|
61
|
+
<div className="mx-auto flex max-w-4xl flex-col gap-8">
|
|
62
|
+
<div className="flex flex-col gap-2">
|
|
63
|
+
<h2 className="typography-header text-default-foreground">Upload your sample data</h2>
|
|
64
|
+
<p className="typography-small max-w-prose text-muted-foreground">
|
|
65
|
+
Add the sample files you want to share with us. They are stored in this datastore only. Remove personal
|
|
66
|
+
data before you upload.
|
|
67
|
+
</p>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<DataCollectionUploader />
|
|
71
|
+
|
|
72
|
+
<section className="flex flex-col gap-3" aria-labelledby="data-collection-files">
|
|
73
|
+
<h3 id="data-collection-files" className="typography-body-medium text-default-foreground">
|
|
74
|
+
Uploaded files
|
|
75
|
+
</h3>
|
|
76
|
+
<UploadedFilesSection emptyText="Nothing uploaded yet. Files you add appear here with their status." />
|
|
77
|
+
</section>
|
|
78
|
+
</div>
|
|
79
|
+
</PageBody>
|
|
80
|
+
</RouteLayout>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -4,7 +4,7 @@ import { useEffect } from "react";
|
|
|
4
4
|
import { Outlet, useMatch } from "react-router";
|
|
5
5
|
import { useDeclaredNamespaces } from "../declared-namespaces";
|
|
6
6
|
import { useRailState } from "../hooks/useRailState";
|
|
7
|
-
import { coveragePath, explorerPath } from "../namespaces";
|
|
7
|
+
import { coveragePath, explorerPath, filesPath, ingestRunsPath } from "../namespaces";
|
|
8
8
|
import { Rail } from "./Rail";
|
|
9
9
|
import { RailSheet } from "./RailSheet";
|
|
10
10
|
import { LoadingRows } from "./RawTriples";
|
|
@@ -31,7 +31,10 @@ export function DataExplorerLayout() {
|
|
|
31
31
|
const { datastore, datastores, user, logout, isOperator, canSwitchDatastore } = useAuthContext();
|
|
32
32
|
|
|
33
33
|
const isIndex = Boolean(useMatch(explorerPath));
|
|
34
|
-
const
|
|
34
|
+
const isCoverage = Boolean(useMatch(coveragePath));
|
|
35
|
+
const isFiles = Boolean(useMatch(filesPath));
|
|
36
|
+
const isIngest = Boolean(useMatch(ingestRunsPath));
|
|
37
|
+
const isFullPage = isCoverage || isFiles || isIngest;
|
|
35
38
|
const railState = useRailState();
|
|
36
39
|
const { isLoading: isLoadingNamespaces } = useDeclaredNamespaces();
|
|
37
40
|
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import { isPresent } from "@manta-eu/lib/present";
|
|
2
|
-
import { Clock, Gauge } from "lucide-react";
|
|
2
|
+
import { Clock, FileUp, Gauge, Workflow } from "lucide-react";
|
|
3
3
|
import { useEffect, useMemo, useRef } from "react";
|
|
4
4
|
import { useMatch } from "react-router";
|
|
5
5
|
import { buildClassGroups, useExplorerClasses, useInstanceCounts, useSubclassEdges } from "../classes";
|
|
6
6
|
import { type RailState } from "../hooks/useRailState";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
coveragePath,
|
|
9
|
+
explorerPath,
|
|
10
|
+
filesPath,
|
|
11
|
+
groupKeyFor,
|
|
12
|
+
ingestRunsPath,
|
|
13
|
+
isNamespaceSegment,
|
|
14
|
+
prefixForIri,
|
|
15
|
+
recentPath,
|
|
16
|
+
} from "../namespaces";
|
|
8
17
|
import { ClassTreeNodes } from "./ClassTreeNodes";
|
|
9
18
|
import { NamespaceGroupRow } from "./NamespaceGroupRow";
|
|
10
19
|
import { RailLink } from "./RailLink";
|
|
@@ -63,6 +72,8 @@ export function Rail(props: RailProps) {
|
|
|
63
72
|
<SearchInput placeholder="Filter types…" value={filter} onChange={(e) => setFilter(e.target.value)} />
|
|
64
73
|
<RailLink to={recentPath} icon={Clock} label="Recently modified" />
|
|
65
74
|
<RailLink to={coveragePath} icon={Gauge} label="Ontology coverage" />
|
|
75
|
+
<RailLink to={filesPath} icon={FileUp} label="Files" />
|
|
76
|
+
<RailLink to={ingestRunsPath} icon={Workflow} label="Ingest runs" />
|
|
66
77
|
</div>
|
|
67
78
|
|
|
68
79
|
<div ref={listRef} className="min-h-0 flex-1 overflow-y-auto px-2 pb-4">
|