@protobase/ui 0.12.1 → 0.12.3
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/app/app.d.ts +2 -0
- package/dist/app/app.js +6 -2
- package/dist/app/current-address.js +5 -4
- package/dist/app/displays/cards-display.js +1 -1
- package/dist/app/displays/display-controls.js +1 -1
- package/dist/app/displays/list-displays.js +11 -1
- package/dist/app/list-page.js +1 -1
- package/dist/app/meta-gate.js +47 -6
- package/dist/app/nav-from-meta.js +20 -1
- package/dist/app/pages/project-ui.d.ts +5 -1
- package/dist/app/pages/use-run-action.js +3 -2
- package/dist/app/source-notice.js +47 -0
- package/dist/app/use-app-address.js +7 -1
- package/dist/app-shell/sidebar-item.js +7 -1
- package/dist/data/api-provider.d.ts +46 -3
- package/dist/data/api-provider.js +57 -3
- package/dist/data/meta-context.js +6 -0
- package/dist/data/meta-data.d.ts +15 -1
- package/dist/data/query-keys.js +8 -0
- package/dist/data/use-meta.d.ts +4 -2
- package/dist/data/use-meta.js +15 -3
- package/dist/data/use-source-metas.js +61 -0
- package/dist/data/with-sources.js +38 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lib/use-media-query.js +3 -1
- package/dist/package.js +1 -1
- package/dist/shell/assets/app-Cqr5Ze7R.js +65 -0
- package/dist/shell/assets/{index-Bro4QDEX.js → index-ntYv19kQ.js} +1 -1
- package/dist/shell/assets/shared-protobase-ui-eH-UjL47.js +1 -0
- package/dist/shell/index.html +3 -3
- package/dist/shell/protobase.shell.json +1 -1
- package/package.json +4 -4
- package/dist/shell/assets/app-BKdW5nhg.js +0 -65
- package/dist/shell/assets/shared-protobase-ui-PjtR6P4n.js +0 -1
package/dist/data/use-meta.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { keys } from "./query-keys.js";
|
|
2
2
|
import { useClient } from "./api-provider.js";
|
|
3
|
+
import { MetaContext } from "./meta-context.js";
|
|
4
|
+
import { useContext, useMemo } from "react";
|
|
3
5
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
6
|
//#region src/data/use-meta.ts
|
|
5
7
|
/**
|
|
6
8
|
* The resource and view models. Refetches on window focus with `If-None-Match`, so an unchanged
|
|
7
|
-
* `/meta` costs a 304, and the cached object keeps its identity.
|
|
9
|
+
* `/meta` costs a 304, and the cached object keeps its identity. Below the app's `MetaGate`, `data` holds the resources
|
|
10
|
+
* of its sources too, as every page of the app reads them.
|
|
8
11
|
*/
|
|
9
12
|
const useMeta = () => {
|
|
10
13
|
const client = useClient();
|
|
11
14
|
const queryClient = useQueryClient();
|
|
12
|
-
|
|
15
|
+
const merged = useContext(MetaContext);
|
|
16
|
+
const query = useQuery({
|
|
13
17
|
queryKey: keys.meta,
|
|
14
18
|
staleTime: 0,
|
|
15
19
|
refetchOnWindowFocus: "always",
|
|
@@ -30,10 +34,18 @@ const useMeta = () => {
|
|
|
30
34
|
...result.meta.bottomBar && { bottomBar: result.meta.bottomBar },
|
|
31
35
|
...result.meta.assistant && { assistant: result.meta.assistant },
|
|
32
36
|
...result.meta.runtime && { runtime: result.meta.runtime },
|
|
33
|
-
...result.meta.plugins && { plugins: result.meta.plugins }
|
|
37
|
+
...result.meta.plugins && { plugins: result.meta.plugins },
|
|
38
|
+
...result.meta.sources && { sources: result.meta.sources.map((source) => ({
|
|
39
|
+
source,
|
|
40
|
+
state: "loading"
|
|
41
|
+
})) }
|
|
34
42
|
};
|
|
35
43
|
}
|
|
36
44
|
});
|
|
45
|
+
return useMemo(() => merged && query.data ? {
|
|
46
|
+
...query,
|
|
47
|
+
data: merged
|
|
48
|
+
} : query, [merged, query]);
|
|
37
49
|
};
|
|
38
50
|
//#endregion
|
|
39
51
|
export { useMeta };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { keys } from "./query-keys.js";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { sourceMeta } from "@protobase/client";
|
|
4
|
+
import { useQueries, useQueryClient } from "@tanstack/react-query";
|
|
5
|
+
//#region src/data/use-source-metas.ts
|
|
6
|
+
/** How long the app waits for a source's `/meta` before it shows the source's resources as unavailable. */
|
|
7
|
+
const sourceTimeoutMs = 1e4;
|
|
8
|
+
const combine = (results) => results.map((result) => ({
|
|
9
|
+
data: result.data?.meta,
|
|
10
|
+
error: result.error
|
|
11
|
+
}));
|
|
12
|
+
/**
|
|
13
|
+
* Each source's `/meta`, read with the user's token from that API and scoped to the resources the app draws from it
|
|
14
|
+
* (`sourceMeta`). Like the app's own, it is read again on window focus with `If-None-Match`, and a source that cannot be
|
|
15
|
+
* read is an `error` without holding up the others or the app.
|
|
16
|
+
*/
|
|
17
|
+
const useSourceMetas = (sources, clientOf) => {
|
|
18
|
+
const queryClient = useQueryClient();
|
|
19
|
+
const results = useQueries({
|
|
20
|
+
queries: sources.map((source) => {
|
|
21
|
+
const queryKey = keys.sourceMeta(source.url, source.resources);
|
|
22
|
+
return {
|
|
23
|
+
queryKey,
|
|
24
|
+
staleTime: 0,
|
|
25
|
+
refetchOnWindowFocus: "always",
|
|
26
|
+
queryFn: async () => {
|
|
27
|
+
const previous = queryClient.getQueryData(queryKey);
|
|
28
|
+
const result = await clientOf(source).meta(previous?.etag, { signal: AbortSignal.timeout(sourceTimeoutMs) });
|
|
29
|
+
if (result.status === "unchanged") {
|
|
30
|
+
if (!previous) throw new Error(`${source.label} answered 304 to a request without If-None-Match`);
|
|
31
|
+
return previous;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
etag: result.etag,
|
|
35
|
+
meta: sourceMeta(result.meta, source)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}),
|
|
40
|
+
combine
|
|
41
|
+
});
|
|
42
|
+
return useMemo(() => sources.map((source, index) => {
|
|
43
|
+
const { data, error } = results[index];
|
|
44
|
+
if (data) return {
|
|
45
|
+
source,
|
|
46
|
+
state: "ready",
|
|
47
|
+
meta: data
|
|
48
|
+
};
|
|
49
|
+
if (error) return {
|
|
50
|
+
source,
|
|
51
|
+
state: "error",
|
|
52
|
+
error
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
source,
|
|
56
|
+
state: "loading"
|
|
57
|
+
};
|
|
58
|
+
}), [sources, results]);
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { sourceTimeoutMs, useSourceMetas };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//#region src/data/with-sources.ts
|
|
2
|
+
/**
|
|
3
|
+
* The app's `/meta` with the resources it draws from its sources: those of every source that is ready, with their views
|
|
4
|
+
* and permissions, as if they were the app's own, and how far each source has loaded in `sources`. A source that is
|
|
5
|
+
* loading or cannot be read adds no resources; the app shows its resources as unavailable (see `sourceStatusOf`).
|
|
6
|
+
*/
|
|
7
|
+
const withSources = (meta, results) => {
|
|
8
|
+
if (results.length === 0) return meta;
|
|
9
|
+
const ready = results.flatMap((result) => result.state === "ready" ? [result.meta] : []);
|
|
10
|
+
const sources = results.map((result) => result.state === "error" ? {
|
|
11
|
+
source: result.source,
|
|
12
|
+
state: "error",
|
|
13
|
+
error: result.error
|
|
14
|
+
} : {
|
|
15
|
+
source: result.source,
|
|
16
|
+
state: result.state
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
...meta,
|
|
20
|
+
resources: {
|
|
21
|
+
...meta.resources,
|
|
22
|
+
...Object.fromEntries(ready.flatMap((part) => part.resources.map((model) => [model.name, model])))
|
|
23
|
+
},
|
|
24
|
+
views: {
|
|
25
|
+
...meta.views,
|
|
26
|
+
...Object.fromEntries(ready.flatMap((part) => part.views.map((view) => [view.resource, view])))
|
|
27
|
+
},
|
|
28
|
+
permissions: {
|
|
29
|
+
...meta.permissions,
|
|
30
|
+
...Object.assign({}, ...ready.map((part) => part.permissions))
|
|
31
|
+
},
|
|
32
|
+
sources
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** The source the app draws `resource` from, with how far it has loaded; `undefined` for a resource of the app's own. */
|
|
36
|
+
const sourceStatusOf = (meta, resource) => meta.sources?.find((status) => status.source.resources.includes(resource));
|
|
37
|
+
//#endregion
|
|
38
|
+
export { sourceStatusOf, withSources };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ActionContext, ActionHandler, ProjectUi, definePlugin, defineUi } from
|
|
|
3
3
|
import { PluginInfo, usePlugin } from "./plugins/plugin-context.js";
|
|
4
4
|
import { App, AppProps } from "./app/app.js";
|
|
5
5
|
import "./app/index.js";
|
|
6
|
-
import { ApiProvider, ApiProviderProps, useClient } from "./data/api-provider.js";
|
|
6
|
+
import { ApiProvider, ApiProviderProps, useClient, useResourceClient } from "./data/api-provider.js";
|
|
7
7
|
import { MetaData } from "./data/meta-data.js";
|
|
8
8
|
import { useMeta } from "./data/use-meta.js";
|
|
9
9
|
import { useList } from "./data/use-list.js";
|
|
@@ -39,4 +39,4 @@ import { Step, StepList, StepState } from "./step-list/step-list.js";
|
|
|
39
39
|
import { DiffView, DiffViewProps } from "./diff-view/diff-view.js";
|
|
40
40
|
import { DiffLine, diffStats, parseDiff } from "./diff-view/diff.js";
|
|
41
41
|
import { CompactTable, CompactTableProps } from "./compact-table/compact-table.js";
|
|
42
|
-
export { ActionCard, type ActionCardProps, type ActionContext, type ActionHandler, ApiProvider, type ApiProviderProps, App, AppLink, type AppProps, AssistantDock, type AssistantDockProps, type BackendData, type BackendRefresh, type CardAction, type CardTone, ChatMessage, ChatThread, type ChatThreadProps, CompactTable, type CompactTableProps, Composer, type ComposerProps, type CurrentAddress, type DiffLine, DiffView, type DiffViewProps, FieldList, type FieldWidget, type FieldWidgetEditorProps, type FieldWidgetProps, type LayoutRecord, type ListAddress, type ListChange, type ListDisplay, type ListDisplayRow, type MetaData, PartView, type PluginInfo, type ProjectUi, type RecordCardProps, RecordLink, SidePanel, type SidePanelProps, type Step, StepList, type StepState, definePlugin, defineUi, diffStats, isConflict, mergeUi, parseDiff, pluginApi, protobaseVersion, uiFromModule, useApiToken, useAppAddress, useAssistant, useAssistantClient, useBackendData, useClient, useFacets, useHistogram, useLayoutRecord, useList, useListDisplay, useMeta, usePlugin, useRecord, useSeries, useUpdateRecord };
|
|
42
|
+
export { ActionCard, type ActionCardProps, type ActionContext, type ActionHandler, ApiProvider, type ApiProviderProps, App, AppLink, type AppProps, AssistantDock, type AssistantDockProps, type BackendData, type BackendRefresh, type CardAction, type CardTone, ChatMessage, ChatThread, type ChatThreadProps, CompactTable, type CompactTableProps, Composer, type ComposerProps, type CurrentAddress, type DiffLine, DiffView, type DiffViewProps, FieldList, type FieldWidget, type FieldWidgetEditorProps, type FieldWidgetProps, type LayoutRecord, type ListAddress, type ListChange, type ListDisplay, type ListDisplayRow, type MetaData, PartView, type PluginInfo, type ProjectUi, type RecordCardProps, RecordLink, SidePanel, type SidePanelProps, type Step, StepList, type StepState, definePlugin, defineUi, diffStats, isConflict, mergeUi, parseDiff, pluginApi, protobaseVersion, uiFromModule, useApiToken, useAppAddress, useAssistant, useAssistantClient, useBackendData, useClient, useFacets, useHistogram, useLayoutRecord, useList, useListDisplay, useMeta, usePlugin, useRecord, useResourceClient, useSeries, useUpdateRecord };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApiProvider, useClient } from "./data/api-provider.js";
|
|
1
|
+
import { ApiProvider, useClient, useResourceClient } from "./data/api-provider.js";
|
|
2
2
|
import { useApiToken } from "./auth/use-api-token.js";
|
|
3
3
|
import { useRecord } from "./data/use-record.js";
|
|
4
4
|
import { ChatMessage } from "./chat/chat-message.js";
|
|
@@ -30,4 +30,4 @@ import { useList } from "./data/use-list.js";
|
|
|
30
30
|
import { isConflict, useUpdateRecord } from "./data/use-update-record.js";
|
|
31
31
|
import { App } from "./app/app.js";
|
|
32
32
|
import { RecordLink } from "./app/displays/record-link.js";
|
|
33
|
-
export { ActionCard, ApiProvider, App, AppLink, AssistantDock, ChatMessage, ChatThread, CompactTable, Composer, DiffView, FieldList, PartView, RecordLink, SidePanel, StepList, definePlugin, defineUi, diffStats, isConflict, mergeUi, parseDiff, pluginApi, protobaseVersion, uiFromModule, useApiToken, useAppAddress, useAssistant, useAssistantClient, useBackendData, useClient, useFacets, useHistogram, useLayoutRecord, useList, useListDisplay, useMeta, usePlugin, useRecord, useSeries, useUpdateRecord };
|
|
33
|
+
export { ActionCard, ApiProvider, App, AppLink, AssistantDock, ChatMessage, ChatThread, CompactTable, Composer, DiffView, FieldList, PartView, RecordLink, SidePanel, StepList, definePlugin, defineUi, diffStats, isConflict, mergeUi, parseDiff, pluginApi, protobaseVersion, uiFromModule, useApiToken, useAppAddress, useAssistant, useAssistantClient, useBackendData, useClient, useFacets, useHistogram, useLayoutRecord, useList, useListDisplay, useMeta, usePlugin, useRecord, useResourceClient, useSeries, useUpdateRecord };
|
|
@@ -8,5 +8,7 @@ const useMediaQuery = (query) => useSyncExternalStore((onChange) => {
|
|
|
8
8
|
}, () => window.matchMedia(query).matches, () => false);
|
|
9
9
|
/** The `md` breakpoint: where the sidebar stops being a drawer and tables stop squeezing. */
|
|
10
10
|
const useIsDesktop = () => useMediaQuery("(min-width: 768px)");
|
|
11
|
+
/** Below the `sm` breakpoint: a phone, where a list opens in its cards display. */
|
|
12
|
+
const useIsXs = () => useMediaQuery("not all and (min-width: 640px)");
|
|
11
13
|
//#endregion
|
|
12
|
-
export { useIsDesktop, useMediaQuery };
|
|
14
|
+
export { useIsDesktop, useIsXs, useMediaQuery };
|
package/dist/package.js
CHANGED