lemma-sdk 0.2.30 → 0.2.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +211 -51
- package/dist/react/index.d.ts +20 -0
- package/dist/react/index.js +10 -0
- package/dist/react/useAgentInputSchema.d.ts +19 -0
- package/dist/react/useAgentInputSchema.js +73 -0
- package/dist/react/useAgentRun.js +18 -20
- package/dist/react/useAgentRuns.d.ts +33 -0
- package/dist/react/useAgentRuns.js +149 -0
- package/dist/react/useAssistantRun.js +10 -9
- package/dist/react/useAssistantSession.js +21 -25
- package/dist/react/useBulkRecords.js +9 -16
- package/dist/react/useConversation.js +24 -8
- package/dist/react/useConversations.d.ts +4 -0
- package/dist/react/useConversations.js +49 -3
- package/dist/react/useCreateRecord.js +9 -16
- package/dist/react/useCurrentUser.d.ts +14 -0
- package/dist/react/useCurrentUser.js +68 -0
- package/dist/react/useDeleteRecord.js +9 -16
- package/dist/react/useFlowRunHistory.js +1 -5
- package/dist/react/useFlowSession.js +41 -33
- package/dist/react/useForeignKeyOptions.js +26 -15
- package/dist/react/useFunctionRun.d.ts +19 -0
- package/dist/react/useFunctionRun.js +30 -0
- package/dist/react/useFunctionRuns.d.ts +33 -0
- package/dist/react/useFunctionRuns.js +149 -0
- package/dist/react/useFunctionSession.js +37 -29
- package/dist/react/useJoinedRecords.js +24 -23
- package/dist/react/useMembers.d.ts +4 -0
- package/dist/react/useMembers.js +55 -16
- package/dist/react/useOrganizationMembers.d.ts +26 -0
- package/dist/react/useOrganizationMembers.js +113 -0
- package/dist/react/usePodAccess.d.ts +22 -0
- package/dist/react/usePodAccess.js +128 -0
- package/dist/react/useRecord.js +24 -13
- package/dist/react/useRecordForm.js +1 -18
- package/dist/react/useRecords.d.ts +2 -0
- package/dist/react/useRecords.js +62 -22
- package/dist/react/useRelatedRecords.js +28 -21
- package/dist/react/useReverseRelatedRecords.js +30 -21
- package/dist/react/useSchemaForm.js +1 -13
- package/dist/react/useTable.js +24 -13
- package/dist/react/useTables.d.ts +4 -0
- package/dist/react/useTables.js +57 -15
- package/dist/react/useTaskSession.js +11 -22
- package/dist/react/useUpdateRecord.js +9 -16
- package/dist/react/useWorkflowResume.d.ts +18 -0
- package/dist/react/useWorkflowResume.js +45 -0
- package/dist/react/useWorkflowRun.d.ts +21 -0
- package/dist/react/useWorkflowRun.js +49 -0
- package/dist/react/useWorkflowRuns.d.ts +33 -0
- package/dist/react/useWorkflowRuns.js +149 -0
- package/dist/react/useWorkflowStart.js +20 -27
- package/dist/react/utils.d.ts +5 -0
- package/dist/react/utils.js +25 -0
- package/dist/types.d.ts +1 -0
- package/package.json +2 -4
- package/dist/react/components/AssistantChrome.d.ts +0 -86
- package/dist/react/components/AssistantChrome.js +0 -48
- package/dist/react/components/AssistantEmbedded.d.ts +0 -10
- package/dist/react/components/AssistantEmbedded.js +0 -15
- package/dist/react/components/AssistantExperience.d.ts +0 -96
- package/dist/react/components/AssistantExperience.js +0 -1294
- package/dist/react/components/assistant-types.d.ts +0 -80
- package/dist/react/components/assistant-types.js +0 -1
package/dist/react/useRecord.js
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
-
|
|
3
|
-
if (!podId || podId === client.podId)
|
|
4
|
-
return client;
|
|
5
|
-
return client.withPod(podId);
|
|
6
|
-
}
|
|
7
|
-
function normalizeError(error, fallback) {
|
|
8
|
-
if (error instanceof Error)
|
|
9
|
-
return error;
|
|
10
|
-
return new Error(fallback);
|
|
11
|
-
}
|
|
2
|
+
import { normalizeError, resolvePodClient } from "./utils.js";
|
|
12
3
|
export function useRecord({ client, podId, tableName, recordId = null, enabled = true, autoLoad = true, }) {
|
|
13
4
|
const [record, setRecord] = useState(null);
|
|
14
5
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -16,7 +7,7 @@ export function useRecord({ client, podId, tableName, recordId = null, enabled =
|
|
|
16
7
|
const trimmedTableName = tableName.trim();
|
|
17
8
|
const trimmedRecordId = typeof recordId === "string" ? recordId.trim() : "";
|
|
18
9
|
const isEnabled = enabled && trimmedTableName.length > 0 && trimmedRecordId.length > 0;
|
|
19
|
-
const refresh = useCallback(async (overrides = {}) => {
|
|
10
|
+
const refresh = useCallback(async (overrides = {}, signal) => {
|
|
20
11
|
const nextRecordId = typeof overrides.recordId === "string"
|
|
21
12
|
? overrides.recordId.trim()
|
|
22
13
|
: trimmedRecordId;
|
|
@@ -31,17 +22,22 @@ export function useRecord({ client, podId, tableName, recordId = null, enabled =
|
|
|
31
22
|
try {
|
|
32
23
|
const scopedClient = resolvePodClient(client, podId);
|
|
33
24
|
const response = await scopedClient.records.get(trimmedTableName, nextRecordId);
|
|
25
|
+
if (signal?.aborted)
|
|
26
|
+
return null;
|
|
34
27
|
const nextRecord = (response.data ?? null);
|
|
35
28
|
setRecord(nextRecord);
|
|
36
29
|
return nextRecord;
|
|
37
30
|
}
|
|
38
31
|
catch (refreshError) {
|
|
32
|
+
if (signal?.aborted)
|
|
33
|
+
return null;
|
|
39
34
|
const normalized = normalizeError(refreshError, "Failed to load record.");
|
|
40
35
|
setError(normalized);
|
|
41
36
|
return null;
|
|
42
37
|
}
|
|
43
38
|
finally {
|
|
44
|
-
|
|
39
|
+
if (!signal?.aborted)
|
|
40
|
+
setIsLoading(false);
|
|
45
41
|
}
|
|
46
42
|
}, [client, enabled, podId, trimmedRecordId, trimmedTableName]);
|
|
47
43
|
useEffect(() => {
|
|
@@ -53,7 +49,22 @@ export function useRecord({ client, podId, tableName, recordId = null, enabled =
|
|
|
53
49
|
}
|
|
54
50
|
if (!autoLoad)
|
|
55
51
|
return;
|
|
56
|
-
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
let cancelled = false;
|
|
54
|
+
(async () => {
|
|
55
|
+
try {
|
|
56
|
+
await refresh({}, controller.signal);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
if (!cancelled) {
|
|
60
|
+
setError(normalizeError(new Error("Failed to load record."), "Failed to load record."));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})();
|
|
64
|
+
return () => {
|
|
65
|
+
cancelled = true;
|
|
66
|
+
controller.abort();
|
|
67
|
+
};
|
|
57
68
|
}, [autoLoad, isEnabled, refresh]);
|
|
58
69
|
return useMemo(() => ({
|
|
59
70
|
record,
|
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { buildRecordFormValues, buildRecordPayload, } from "../record-form.js";
|
|
3
|
+
import { normalizeError, resolvePodClient, stringifyComparable } from "./utils.js";
|
|
3
4
|
import { useRecordSchema, } from "./useRecordSchema.js";
|
|
4
5
|
const EMPTY_VALUES = {};
|
|
5
|
-
function normalizeError(error, fallback) {
|
|
6
|
-
if (error instanceof Error)
|
|
7
|
-
return error;
|
|
8
|
-
return new Error(fallback);
|
|
9
|
-
}
|
|
10
|
-
function resolvePodClient(client, podId) {
|
|
11
|
-
if (!podId || podId === client.podId)
|
|
12
|
-
return client;
|
|
13
|
-
return client.withPod(podId);
|
|
14
|
-
}
|
|
15
|
-
function stringifyComparable(value) {
|
|
16
|
-
try {
|
|
17
|
-
return JSON.stringify(value);
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
return String(value);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
6
|
export function useRecordForm({ client, podId, tableName, recordId = null, initialValues = EMPTY_VALUES, mode = "auto", enabled = true, autoLoad = true, onSubmitSuccess, onError, }) {
|
|
24
7
|
const schema = useRecordSchema({
|
|
25
8
|
client,
|
|
@@ -12,7 +12,9 @@ export interface UseRecordsResult<TRecord extends Record<string, unknown> = Reco
|
|
|
12
12
|
total: number;
|
|
13
13
|
nextPageToken: string | null;
|
|
14
14
|
isLoading: boolean;
|
|
15
|
+
isLoadingMore: boolean;
|
|
15
16
|
error: Error | null;
|
|
16
17
|
refresh: (overrides?: Partial<ListRecordsOptions>) => Promise<TRecord[]>;
|
|
18
|
+
loadMore: (overrides?: Partial<ListRecordsOptions>) => Promise<TRecord[]>;
|
|
17
19
|
}
|
|
18
20
|
export declare function useRecords<TRecord extends Record<string, unknown> = Record<string, unknown>>({ client, podId, tableName, filters, sort, limit, pageToken, offset, sortBy, order, params, enabled, autoLoad, }: UseRecordsOptions): UseRecordsResult<TRecord>;
|
package/dist/react/useRecords.js
CHANGED
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
-
|
|
3
|
-
if (!podId || podId === client.podId)
|
|
4
|
-
return client;
|
|
5
|
-
return client.withPod(podId);
|
|
6
|
-
}
|
|
7
|
-
function normalizeError(error, fallback) {
|
|
8
|
-
if (error instanceof Error)
|
|
9
|
-
return error;
|
|
10
|
-
return new Error(fallback);
|
|
11
|
-
}
|
|
12
|
-
function stringifyComparable(value) {
|
|
13
|
-
try {
|
|
14
|
-
return JSON.stringify(value);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
return String(value);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
2
|
+
import { normalizeError, resolvePodClient, stringifyComparable } from "./utils.js";
|
|
20
3
|
export function useRecords({ client, podId, tableName, filters, sort, limit = 20, pageToken, offset, sortBy, order, params, enabled = true, autoLoad = true, }) {
|
|
21
4
|
const [records, setRecords] = useState([]);
|
|
22
5
|
const [total, setTotal] = useState(0);
|
|
23
6
|
const [nextPageToken, setNextPageToken] = useState(null);
|
|
24
7
|
const [isLoading, setIsLoading] = useState(false);
|
|
8
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
25
9
|
const [error, setError] = useState(null);
|
|
26
10
|
const trimmedTableName = tableName.trim();
|
|
27
11
|
const isEnabled = enabled && trimmedTableName.length > 0;
|
|
@@ -31,7 +15,7 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
31
15
|
const stableFilters = useMemo(() => filters, [filtersKey]);
|
|
32
16
|
const stableSort = useMemo(() => sort, [sortKey]);
|
|
33
17
|
const stableParams = useMemo(() => params, [paramsKey]);
|
|
34
|
-
const refresh = useCallback(async (overrides = {}) => {
|
|
18
|
+
const refresh = useCallback(async (overrides = {}, signal) => {
|
|
35
19
|
if (!isEnabled) {
|
|
36
20
|
setRecords([]);
|
|
37
21
|
setTotal(0);
|
|
@@ -54,6 +38,8 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
54
38
|
order: overrides.order ?? order,
|
|
55
39
|
params: overrides.params ?? stableParams,
|
|
56
40
|
});
|
|
41
|
+
if (signal?.aborted)
|
|
42
|
+
return [];
|
|
57
43
|
const nextRecords = (response.items ?? []);
|
|
58
44
|
setRecords(nextRecords);
|
|
59
45
|
setTotal(response.total ?? nextRecords.length);
|
|
@@ -61,12 +47,15 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
61
47
|
return nextRecords;
|
|
62
48
|
}
|
|
63
49
|
catch (refreshError) {
|
|
50
|
+
if (signal?.aborted)
|
|
51
|
+
return [];
|
|
64
52
|
const normalized = normalizeError(refreshError, "Failed to load records.");
|
|
65
53
|
setError(normalized);
|
|
66
54
|
return [];
|
|
67
55
|
}
|
|
68
56
|
finally {
|
|
69
|
-
|
|
57
|
+
if (!signal?.aborted)
|
|
58
|
+
setIsLoading(false);
|
|
70
59
|
}
|
|
71
60
|
}, [
|
|
72
61
|
client,
|
|
@@ -82,6 +71,39 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
82
71
|
stableSort,
|
|
83
72
|
trimmedTableName,
|
|
84
73
|
]);
|
|
74
|
+
const loadMore = useCallback(async (overrides = {}) => {
|
|
75
|
+
if (!isEnabled || !nextPageToken || isLoading || isLoadingMore) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
setIsLoadingMore(true);
|
|
79
|
+
setError(null);
|
|
80
|
+
try {
|
|
81
|
+
const scopedClient = resolvePodClient(client, podId);
|
|
82
|
+
const response = await scopedClient.records.list(trimmedTableName, {
|
|
83
|
+
filters: stableFilters,
|
|
84
|
+
sort: stableSort,
|
|
85
|
+
limit: overrides.limit ?? limit,
|
|
86
|
+
pageToken: nextPageToken,
|
|
87
|
+
offset: overrides.offset,
|
|
88
|
+
sortBy: overrides.sortBy ?? sortBy,
|
|
89
|
+
order: overrides.order ?? order,
|
|
90
|
+
params: overrides.params ?? stableParams,
|
|
91
|
+
});
|
|
92
|
+
const moreRecords = (response.items ?? []);
|
|
93
|
+
setRecords((previous) => [...previous, ...moreRecords]);
|
|
94
|
+
setTotal(response.total ?? records.length + moreRecords.length);
|
|
95
|
+
setNextPageToken(response.next_page_token ?? null);
|
|
96
|
+
return moreRecords;
|
|
97
|
+
}
|
|
98
|
+
catch (loadError) {
|
|
99
|
+
const normalized = normalizeError(loadError, "Failed to load more records.");
|
|
100
|
+
setError(normalized);
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
setIsLoadingMore(false);
|
|
105
|
+
}
|
|
106
|
+
}, [client, isEnabled, isLoading, isLoadingMore, limit, nextPageToken, offset, order, podId, records.length, sortBy, stableFilters, stableParams, stableSort, trimmedTableName]);
|
|
85
107
|
useEffect(() => {
|
|
86
108
|
if (!isEnabled) {
|
|
87
109
|
setRecords([]);
|
|
@@ -89,18 +111,36 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
89
111
|
setNextPageToken(null);
|
|
90
112
|
setError(null);
|
|
91
113
|
setIsLoading(false);
|
|
114
|
+
setIsLoadingMore(false);
|
|
92
115
|
return;
|
|
93
116
|
}
|
|
94
117
|
if (!autoLoad)
|
|
95
118
|
return;
|
|
96
|
-
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
let cancelled = false;
|
|
121
|
+
(async () => {
|
|
122
|
+
try {
|
|
123
|
+
await refresh({}, controller.signal);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
if (!cancelled) {
|
|
127
|
+
setError(normalizeError(new Error("Failed to load records."), "Failed to load records."));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
})();
|
|
131
|
+
return () => {
|
|
132
|
+
cancelled = true;
|
|
133
|
+
controller.abort();
|
|
134
|
+
};
|
|
97
135
|
}, [autoLoad, isEnabled, refresh]);
|
|
98
136
|
return useMemo(() => ({
|
|
99
137
|
records,
|
|
100
138
|
total,
|
|
101
139
|
nextPageToken,
|
|
102
140
|
isLoading,
|
|
141
|
+
isLoadingMore,
|
|
103
142
|
error,
|
|
104
143
|
refresh,
|
|
105
|
-
|
|
144
|
+
loadMore,
|
|
145
|
+
}), [error, isLoading, isLoadingMore, loadMore, nextPageToken, records, refresh, total]);
|
|
106
146
|
}
|
|
@@ -1,23 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { buildJoinedRecordsQuery, parseForeignKeyReference } from "../datastore-query.js";
|
|
3
|
-
|
|
4
|
-
if (!podId || podId === client.podId)
|
|
5
|
-
return client;
|
|
6
|
-
return client.withPod(podId);
|
|
7
|
-
}
|
|
8
|
-
function normalizeError(error, fallback) {
|
|
9
|
-
if (error instanceof Error)
|
|
10
|
-
return error;
|
|
11
|
-
return new Error(fallback);
|
|
12
|
-
}
|
|
13
|
-
function stringifyComparable(value) {
|
|
14
|
-
try {
|
|
15
|
-
return JSON.stringify(value);
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return String(value);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
3
|
+
import { normalizeError, resolvePodClient, stringifyComparable } from "./utils.js";
|
|
21
4
|
function sentenceCase(value) {
|
|
22
5
|
return value
|
|
23
6
|
.replace(/[_\.]/g, " ")
|
|
@@ -82,7 +65,7 @@ export function useRelatedRecords({ client, podId, tableName, baseFields, includ
|
|
|
82
65
|
const stableInclude = useMemo(() => include, [includeKey]);
|
|
83
66
|
const stableBaseFields = useMemo(() => baseFields, [baseFieldsKey]);
|
|
84
67
|
const isEnabled = enabled && trimmedTableName.length > 0 && stableInclude.length > 0;
|
|
85
|
-
const refresh = useCallback(async () => {
|
|
68
|
+
const refresh = useCallback(async (signal) => {
|
|
86
69
|
if (!isEnabled) {
|
|
87
70
|
setRecords([]);
|
|
88
71
|
setColumns([]);
|
|
@@ -98,6 +81,8 @@ export function useRelatedRecords({ client, podId, tableName, baseFields, includ
|
|
|
98
81
|
try {
|
|
99
82
|
const scopedClient = resolvePodClient(client, podId);
|
|
100
83
|
const nextBaseTable = await scopedClient.tables.get(trimmedTableName);
|
|
84
|
+
if (signal?.aborted)
|
|
85
|
+
return [];
|
|
101
86
|
if (nextBaseTable.enable_rls) {
|
|
102
87
|
throw new Error(`Related record queries are not supported for RLS-enabled table "${trimmedTableName}". Use table-scoped record APIs instead.`);
|
|
103
88
|
}
|
|
@@ -105,6 +90,8 @@ export function useRelatedRecords({ client, podId, tableName, baseFields, includ
|
|
|
105
90
|
const resolvedBaseFields = (stableBaseFields?.length ? stableBaseFields : pickDefaultBaseFields(nextBaseTable))
|
|
106
91
|
.filter((field, index, allFields) => field.trim().length > 0 && allFields.indexOf(field) === index);
|
|
107
92
|
const resolvedIncludes = await Promise.all(stableInclude.map(async (entry, index) => {
|
|
93
|
+
if (signal?.aborted)
|
|
94
|
+
throw new Error("Aborted");
|
|
108
95
|
const baseColumn = nextBaseTable.columns.find((column) => column.name === entry.foreignKey) ?? null;
|
|
109
96
|
const reference = baseColumn?.foreign_key?.references
|
|
110
97
|
? parseForeignKeyReference(baseColumn.foreign_key.references)
|
|
@@ -163,6 +150,8 @@ export function useRelatedRecords({ client, podId, tableName, baseFields, includ
|
|
|
163
150
|
setSql(nextSql);
|
|
164
151
|
setIncludes(resolvedIncludes.map(({ alias: _alias, ...rest }) => rest));
|
|
165
152
|
const response = await scopedClient.datastore.query(nextSql);
|
|
153
|
+
if (signal?.aborted)
|
|
154
|
+
return [];
|
|
166
155
|
const nextColumns = [
|
|
167
156
|
...resolvedBaseFields.map((field) => ({
|
|
168
157
|
key: field,
|
|
@@ -196,12 +185,15 @@ export function useRelatedRecords({ client, podId, tableName, baseFields, includ
|
|
|
196
185
|
return nextRecords;
|
|
197
186
|
}
|
|
198
187
|
catch (refreshError) {
|
|
188
|
+
if (signal?.aborted)
|
|
189
|
+
return [];
|
|
199
190
|
const normalized = normalizeError(refreshError, "Failed to load related records.");
|
|
200
191
|
setError(normalized);
|
|
201
192
|
return [];
|
|
202
193
|
}
|
|
203
194
|
finally {
|
|
204
|
-
|
|
195
|
+
if (!signal?.aborted)
|
|
196
|
+
setIsLoading(false);
|
|
205
197
|
}
|
|
206
198
|
}, [client, isEnabled, limit, offset, podId, stableBaseFields, stableInclude, trimmedTableName]);
|
|
207
199
|
useEffect(() => {
|
|
@@ -217,7 +209,22 @@ export function useRelatedRecords({ client, podId, tableName, baseFields, includ
|
|
|
217
209
|
}
|
|
218
210
|
if (!autoLoad)
|
|
219
211
|
return;
|
|
220
|
-
|
|
212
|
+
const controller = new AbortController();
|
|
213
|
+
let cancelled = false;
|
|
214
|
+
(async () => {
|
|
215
|
+
try {
|
|
216
|
+
await refresh(controller.signal);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
if (!cancelled) {
|
|
220
|
+
setError(normalizeError(new Error("Failed to load related records."), "Failed to load related records."));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
})();
|
|
224
|
+
return () => {
|
|
225
|
+
cancelled = true;
|
|
226
|
+
controller.abort();
|
|
227
|
+
};
|
|
221
228
|
}, [autoLoad, isEnabled, refresh]);
|
|
222
229
|
return useMemo(() => ({
|
|
223
230
|
records,
|
|
@@ -1,23 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { parseForeignKeyReference } from "../datastore-query.js";
|
|
3
|
-
|
|
4
|
-
if (!podId || podId === client.podId)
|
|
5
|
-
return client;
|
|
6
|
-
return client.withPod(podId);
|
|
7
|
-
}
|
|
8
|
-
function normalizeError(error, fallback) {
|
|
9
|
-
if (error instanceof Error)
|
|
10
|
-
return error;
|
|
11
|
-
return new Error(fallback);
|
|
12
|
-
}
|
|
13
|
-
function stringifyComparable(value) {
|
|
14
|
-
try {
|
|
15
|
-
return JSON.stringify(value);
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return String(value);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
3
|
+
import { normalizeError, resolvePodClient, stringifyComparable } from "./utils.js";
|
|
21
4
|
function sentenceCase(value) {
|
|
22
5
|
return value
|
|
23
6
|
.replace(/[_\.]/g, " ")
|
|
@@ -62,7 +45,7 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
62
45
|
const stableRelation = useMemo(() => relation, [relationKey]);
|
|
63
46
|
const stableFields = useMemo(() => fields, [fieldsKey]);
|
|
64
47
|
const isEnabled = enabled && trimmedTableName.length > 0 && trimmedRecordId.length > 0;
|
|
65
|
-
const refresh = useCallback(async () => {
|
|
48
|
+
const refresh = useCallback(async (signal) => {
|
|
66
49
|
if (!isEnabled) {
|
|
67
50
|
setParentTable(null);
|
|
68
51
|
setRelatedTable(null);
|
|
@@ -85,10 +68,14 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
85
68
|
scopedClient.tables.list({ limit: tablesLimit }),
|
|
86
69
|
scopedClient.records.get(trimmedTableName, trimmedRecordId),
|
|
87
70
|
]);
|
|
71
|
+
if (signal?.aborted)
|
|
72
|
+
return [];
|
|
88
73
|
const listedTables = tablesResponse.items ?? [];
|
|
89
74
|
const nextParentTable = listedTables.find((tableEntry) => tableEntry.name === trimmedTableName)
|
|
90
75
|
?? await scopedClient.tables.get(trimmedTableName);
|
|
91
76
|
const nextParentRecord = parentRecordResponse.data ?? null;
|
|
77
|
+
if (signal?.aborted)
|
|
78
|
+
return [];
|
|
92
79
|
setParentTable(nextParentTable);
|
|
93
80
|
setParentRecord(nextParentRecord);
|
|
94
81
|
const nextRelations = listedTables.flatMap((candidateTable) => candidateTable.columns.flatMap((column) => {
|
|
@@ -123,6 +110,8 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
123
110
|
?? await scopedClient.tables.get(nextSelectedRelation.tableName);
|
|
124
111
|
const referenceValue = nextParentRecord?.[nextSelectedRelation.referencedColumn]
|
|
125
112
|
?? (nextSelectedRelation.referencedColumn === "id" ? trimmedRecordId : undefined);
|
|
113
|
+
if (signal?.aborted)
|
|
114
|
+
return [];
|
|
126
115
|
setRelatedTable(nextRelatedTable);
|
|
127
116
|
if (typeof referenceValue === "undefined" || referenceValue === null) {
|
|
128
117
|
setColumns([]);
|
|
@@ -144,6 +133,8 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
144
133
|
sortBy,
|
|
145
134
|
order,
|
|
146
135
|
});
|
|
136
|
+
if (signal?.aborted)
|
|
137
|
+
return [];
|
|
147
138
|
const nextRecords = (response.items ?? []);
|
|
148
139
|
setColumns(resolvedFields.map((field) => ({
|
|
149
140
|
key: field,
|
|
@@ -156,12 +147,15 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
156
147
|
return nextRecords;
|
|
157
148
|
}
|
|
158
149
|
catch (refreshError) {
|
|
150
|
+
if (signal?.aborted)
|
|
151
|
+
return [];
|
|
159
152
|
const normalized = normalizeError(refreshError, "Failed to load reverse-related records.");
|
|
160
153
|
setError(normalized);
|
|
161
154
|
return [];
|
|
162
155
|
}
|
|
163
156
|
finally {
|
|
164
|
-
|
|
157
|
+
if (!signal?.aborted)
|
|
158
|
+
setIsLoading(false);
|
|
165
159
|
}
|
|
166
160
|
}, [
|
|
167
161
|
client,
|
|
@@ -194,7 +188,22 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
194
188
|
}
|
|
195
189
|
if (!autoLoad)
|
|
196
190
|
return;
|
|
197
|
-
|
|
191
|
+
const controller = new AbortController();
|
|
192
|
+
let cancelled = false;
|
|
193
|
+
(async () => {
|
|
194
|
+
try {
|
|
195
|
+
await refresh(controller.signal);
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
if (!cancelled) {
|
|
199
|
+
setError(normalizeError(new Error("Failed to load reverse-related records."), "Failed to load reverse-related records."));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
})();
|
|
203
|
+
return () => {
|
|
204
|
+
cancelled = true;
|
|
205
|
+
controller.abort();
|
|
206
|
+
};
|
|
198
207
|
}, [autoLoad, isEnabled, refresh]);
|
|
199
208
|
return useMemo(() => ({
|
|
200
209
|
parentTable,
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { buildSchemaFormFields, buildSchemaFormPayload, buildSchemaFormValues, } from "../schema-form.js";
|
|
3
|
-
|
|
4
|
-
if (error instanceof Error)
|
|
5
|
-
return error;
|
|
6
|
-
return new Error(fallback);
|
|
7
|
-
}
|
|
8
|
-
function stringifyComparable(value) {
|
|
9
|
-
try {
|
|
10
|
-
return JSON.stringify(value);
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
return String(value);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
3
|
+
import { normalizeError, stringifyComparable } from "./utils.js";
|
|
16
4
|
const EMPTY_VALUES = {};
|
|
17
5
|
export function useSchemaForm({ schema = null, uiSchema = null, initialValues = EMPTY_VALUES, enabled = true, onSubmit, onError, }) {
|
|
18
6
|
const [values, setValuesState] = useState({});
|
package/dist/react/useTable.js
CHANGED
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
-
|
|
3
|
-
if (!podId || podId === client.podId)
|
|
4
|
-
return client;
|
|
5
|
-
return client.withPod(podId);
|
|
6
|
-
}
|
|
7
|
-
function normalizeError(error, fallback) {
|
|
8
|
-
if (error instanceof Error)
|
|
9
|
-
return error;
|
|
10
|
-
return new Error(fallback);
|
|
11
|
-
}
|
|
2
|
+
import { normalizeError, resolvePodClient } from "./utils.js";
|
|
12
3
|
export function useTable({ client, podId, tableName, enabled = true, autoLoad = true, }) {
|
|
13
4
|
const [table, setTable] = useState(null);
|
|
14
5
|
const [isLoading, setIsLoading] = useState(false);
|
|
15
6
|
const [error, setError] = useState(null);
|
|
16
7
|
const trimmedTableName = tableName.trim();
|
|
17
8
|
const isEnabled = enabled && trimmedTableName.length > 0;
|
|
18
|
-
const refresh = useCallback(async () => {
|
|
9
|
+
const refresh = useCallback(async (signal) => {
|
|
19
10
|
if (!isEnabled) {
|
|
20
11
|
setTable(null);
|
|
21
12
|
setError(null);
|
|
@@ -27,16 +18,21 @@ export function useTable({ client, podId, tableName, enabled = true, autoLoad =
|
|
|
27
18
|
try {
|
|
28
19
|
const scopedClient = resolvePodClient(client, podId);
|
|
29
20
|
const nextTable = await scopedClient.tables.get(trimmedTableName);
|
|
21
|
+
if (signal?.aborted)
|
|
22
|
+
return null;
|
|
30
23
|
setTable(nextTable);
|
|
31
24
|
return nextTable;
|
|
32
25
|
}
|
|
33
26
|
catch (refreshError) {
|
|
27
|
+
if (signal?.aborted)
|
|
28
|
+
return null;
|
|
34
29
|
const normalized = normalizeError(refreshError, "Failed to load table.");
|
|
35
30
|
setError(normalized);
|
|
36
31
|
return null;
|
|
37
32
|
}
|
|
38
33
|
finally {
|
|
39
|
-
|
|
34
|
+
if (!signal?.aborted)
|
|
35
|
+
setIsLoading(false);
|
|
40
36
|
}
|
|
41
37
|
}, [client, isEnabled, podId, trimmedTableName]);
|
|
42
38
|
useEffect(() => {
|
|
@@ -48,7 +44,22 @@ export function useTable({ client, podId, tableName, enabled = true, autoLoad =
|
|
|
48
44
|
}
|
|
49
45
|
if (!autoLoad)
|
|
50
46
|
return;
|
|
51
|
-
|
|
47
|
+
const controller = new AbortController();
|
|
48
|
+
let cancelled = false;
|
|
49
|
+
(async () => {
|
|
50
|
+
try {
|
|
51
|
+
await refresh(controller.signal);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
if (!cancelled) {
|
|
55
|
+
setError(normalizeError(new Error("Failed to load table."), "Failed to load table."));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
})();
|
|
59
|
+
return () => {
|
|
60
|
+
cancelled = true;
|
|
61
|
+
controller.abort();
|
|
62
|
+
};
|
|
52
63
|
}, [autoLoad, isEnabled, refresh]);
|
|
53
64
|
return useMemo(() => ({
|
|
54
65
|
table,
|
|
@@ -13,10 +13,14 @@ export interface UseTablesResult {
|
|
|
13
13
|
total: number;
|
|
14
14
|
nextPageToken: string | null;
|
|
15
15
|
isLoading: boolean;
|
|
16
|
+
isLoadingMore: boolean;
|
|
16
17
|
error: Error | null;
|
|
17
18
|
refresh: (overrides?: {
|
|
18
19
|
limit?: number;
|
|
19
20
|
pageToken?: string;
|
|
20
21
|
}) => Promise<Table[]>;
|
|
22
|
+
loadMore: (overrides?: {
|
|
23
|
+
limit?: number;
|
|
24
|
+
}) => Promise<Table[]>;
|
|
21
25
|
}
|
|
22
26
|
export declare function useTables({ client, podId, enabled, autoLoad, limit, pageToken, }: UseTablesOptions): UseTablesResult;
|
package/dist/react/useTables.js
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
-
|
|
3
|
-
if (!podId || podId === client.podId)
|
|
4
|
-
return client;
|
|
5
|
-
return client.withPod(podId);
|
|
6
|
-
}
|
|
7
|
-
function normalizeError(error, fallback) {
|
|
8
|
-
if (error instanceof Error)
|
|
9
|
-
return error;
|
|
10
|
-
return new Error(fallback);
|
|
11
|
-
}
|
|
2
|
+
import { normalizeError, resolvePodClient } from "./utils.js";
|
|
12
3
|
export function useTables({ client, podId, enabled = true, autoLoad = true, limit = 100, pageToken, }) {
|
|
13
4
|
const [tables, setTables] = useState([]);
|
|
14
5
|
const [total, setTotal] = useState(0);
|
|
15
6
|
const [nextPageToken, setNextPageToken] = useState(null);
|
|
16
7
|
const [isLoading, setIsLoading] = useState(false);
|
|
8
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
17
9
|
const [error, setError] = useState(null);
|
|
18
|
-
const refresh = useCallback(async (overrides = {}) => {
|
|
10
|
+
const refresh = useCallback(async (overrides = {}, signal) => {
|
|
19
11
|
if (!enabled) {
|
|
20
12
|
setTables([]);
|
|
21
13
|
setTotal(0);
|
|
@@ -32,21 +24,53 @@ export function useTables({ client, podId, enabled = true, autoLoad = true, limi
|
|
|
32
24
|
limit: overrides.limit ?? limit,
|
|
33
25
|
pageToken: overrides.pageToken ?? pageToken,
|
|
34
26
|
});
|
|
27
|
+
if (signal?.aborted)
|
|
28
|
+
return [];
|
|
35
29
|
const nextTables = response.items ?? [];
|
|
36
30
|
setTables(nextTables);
|
|
37
|
-
setTotal(nextTables.length);
|
|
31
|
+
setTotal(response.total ?? nextTables.length);
|
|
38
32
|
setNextPageToken(response.next_page_token ?? null);
|
|
39
33
|
return nextTables;
|
|
40
34
|
}
|
|
41
35
|
catch (refreshError) {
|
|
36
|
+
if (signal?.aborted)
|
|
37
|
+
return [];
|
|
42
38
|
const normalized = normalizeError(refreshError, "Failed to load tables.");
|
|
43
39
|
setError(normalized);
|
|
44
40
|
return [];
|
|
45
41
|
}
|
|
46
42
|
finally {
|
|
47
|
-
|
|
43
|
+
if (!signal?.aborted)
|
|
44
|
+
setIsLoading(false);
|
|
48
45
|
}
|
|
49
46
|
}, [client, enabled, limit, pageToken, podId]);
|
|
47
|
+
const loadMore = useCallback(async (overrides = {}) => {
|
|
48
|
+
if (!enabled || !nextPageToken || isLoading || isLoadingMore) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
setIsLoadingMore(true);
|
|
52
|
+
setError(null);
|
|
53
|
+
try {
|
|
54
|
+
const scopedClient = resolvePodClient(client, podId);
|
|
55
|
+
const response = await scopedClient.tables.list({
|
|
56
|
+
limit: overrides.limit ?? limit,
|
|
57
|
+
pageToken: nextPageToken,
|
|
58
|
+
});
|
|
59
|
+
const moreTables = response.items ?? [];
|
|
60
|
+
setTables((previous) => [...previous, ...moreTables]);
|
|
61
|
+
setTotal(response.total ?? tables.length + moreTables.length);
|
|
62
|
+
setNextPageToken(response.next_page_token ?? null);
|
|
63
|
+
return moreTables;
|
|
64
|
+
}
|
|
65
|
+
catch (loadError) {
|
|
66
|
+
const normalized = normalizeError(loadError, "Failed to load more tables.");
|
|
67
|
+
setError(normalized);
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
setIsLoadingMore(false);
|
|
72
|
+
}
|
|
73
|
+
}, [client, enabled, isLoading, isLoadingMore, limit, nextPageToken, podId, tables.length]);
|
|
50
74
|
useEffect(() => {
|
|
51
75
|
if (!enabled) {
|
|
52
76
|
setTables([]);
|
|
@@ -54,18 +78,36 @@ export function useTables({ client, podId, enabled = true, autoLoad = true, limi
|
|
|
54
78
|
setNextPageToken(null);
|
|
55
79
|
setError(null);
|
|
56
80
|
setIsLoading(false);
|
|
81
|
+
setIsLoadingMore(false);
|
|
57
82
|
return;
|
|
58
83
|
}
|
|
59
84
|
if (!autoLoad)
|
|
60
85
|
return;
|
|
61
|
-
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
let cancelled = false;
|
|
88
|
+
(async () => {
|
|
89
|
+
try {
|
|
90
|
+
await refresh({}, controller.signal);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
if (!cancelled) {
|
|
94
|
+
setError(normalizeError(new Error("Failed to load tables."), "Failed to load tables."));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
})();
|
|
98
|
+
return () => {
|
|
99
|
+
cancelled = true;
|
|
100
|
+
controller.abort();
|
|
101
|
+
};
|
|
62
102
|
}, [autoLoad, enabled, refresh]);
|
|
63
103
|
return useMemo(() => ({
|
|
64
104
|
tables,
|
|
65
105
|
total,
|
|
66
106
|
nextPageToken,
|
|
67
107
|
isLoading,
|
|
108
|
+
isLoadingMore,
|
|
68
109
|
error,
|
|
69
110
|
refresh,
|
|
70
|
-
|
|
111
|
+
loadMore,
|
|
112
|
+
}), [error, isLoading, isLoadingMore, loadMore, nextPageToken, refresh, tables, total]);
|
|
71
113
|
}
|