lemma-sdk 0.2.33 → 0.2.35
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 +71 -98
- package/dist/browser/lemma-client.js +70 -15
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/namespaces/pod-surfaces.js +1 -1
- package/dist/namespaces/workflows.d.ts +1 -1
- package/dist/openapi_client/index.d.ts +50 -12
- package/dist/openapi_client/index.js +10 -2
- package/dist/openapi_client/models/AdminConsentInfoResponse.d.ts +6 -0
- package/dist/openapi_client/models/AssistantSurfaceResponse.d.ts +16 -1
- package/dist/openapi_client/models/AssistantSurfaceStatus.d.ts +5 -0
- package/dist/openapi_client/models/AssistantSurfaceStatus.js +10 -0
- package/dist/openapi_client/models/ConversationMessageResponse.d.ts +4 -0
- package/dist/openapi_client/models/ConversationResponse.d.ts +3 -0
- package/dist/openapi_client/models/ConversationType.d.ts +8 -0
- package/dist/openapi_client/models/ConversationType.js +13 -0
- package/dist/openapi_client/models/CreateSurfaceRequest.d.ts +16 -5
- package/dist/openapi_client/models/{DataStoreFlowStart.d.ts → DataStoreFlowStartInput.d.ts} +1 -1
- package/dist/openapi_client/models/DataStoreFlowStartOutput.d.ts +11 -0
- package/dist/openapi_client/models/DataStoreWorkflowStartInput.d.ts +11 -0
- package/dist/openapi_client/models/DataStoreWorkflowStartOutput.d.ts +11 -0
- package/dist/openapi_client/models/DatastoreDataType.d.ts +2 -0
- package/dist/openapi_client/models/DatastoreDataType.js +2 -0
- package/dist/openapi_client/models/{EventFlowStart.d.ts → EventFlowStartInput.d.ts} +1 -1
- package/dist/openapi_client/models/EventFlowStartOutput.d.ts +19 -0
- package/dist/openapi_client/models/EventWorkflowStartInput.d.ts +11 -0
- package/dist/openapi_client/models/EventWorkflowStartOutput.d.ts +11 -0
- package/dist/openapi_client/models/FlowInstallResponse.d.ts +15 -0
- package/dist/openapi_client/models/FlowResponse.d.ts +5 -2
- package/dist/openapi_client/models/GmailSurfaceConfig.d.ts +7 -0
- package/dist/openapi_client/models/GmailSurfaceConfig.js +1 -0
- package/dist/openapi_client/models/GmailSurfaceConfigInput.d.ts +4 -0
- package/dist/openapi_client/models/GmailSurfaceConfigInput.js +1 -0
- package/dist/openapi_client/models/GrantPermissionRequest.d.ts +6 -0
- package/dist/openapi_client/models/GrantPermissionRequest.js +1 -0
- package/dist/openapi_client/models/ManualWorkflowStartInput.d.ts +10 -0
- package/dist/openapi_client/models/ManualWorkflowStartInput.js +1 -0
- package/dist/openapi_client/models/ManualWorkflowStartOutput.d.ts +10 -0
- package/dist/openapi_client/models/ManualWorkflowStartOutput.js +1 -0
- package/dist/openapi_client/models/OrganizationInvitationRequest.d.ts +2 -0
- package/dist/openapi_client/models/OrganizationInvitationResponse.d.ts +2 -0
- package/dist/openapi_client/models/OutlookSurfaceConfig.d.ts +7 -0
- package/dist/openapi_client/models/OutlookSurfaceConfig.js +1 -0
- package/dist/openapi_client/models/OutlookSurfaceConfigInput.d.ts +4 -0
- package/dist/openapi_client/models/OutlookSurfaceConfigInput.js +1 -0
- package/dist/openapi_client/models/ResourcePermissionListResponse.d.ts +4 -0
- package/dist/openapi_client/models/ResourcePermissionListResponse.js +1 -0
- package/dist/openapi_client/models/ResourcePermissionResponse.d.ts +12 -0
- package/dist/openapi_client/models/ResourcePermissionResponse.js +1 -0
- package/dist/openapi_client/models/{ScheduledFlowStart.d.ts → ScheduledFlowStartInput.d.ts} +1 -1
- package/dist/openapi_client/models/ScheduledFlowStartInput.js +1 -0
- package/dist/openapi_client/models/ScheduledFlowStartOutput.d.ts +7 -0
- package/dist/openapi_client/models/ScheduledFlowStartOutput.js +1 -0
- package/dist/openapi_client/models/ScheduledWorkflowStartInput.d.ts +11 -0
- package/dist/openapi_client/models/ScheduledWorkflowStartInput.js +1 -0
- package/dist/openapi_client/models/ScheduledWorkflowStartOutput.d.ts +11 -0
- package/dist/openapi_client/models/ScheduledWorkflowStartOutput.js +1 -0
- package/dist/openapi_client/models/SetVisibilityRequest.d.ts +3 -0
- package/dist/openapi_client/models/SetVisibilityRequest.js +1 -0
- package/dist/openapi_client/models/SlackCredentialsInput.d.ts +5 -0
- package/dist/openapi_client/models/SlackCredentialsInput.js +1 -0
- package/dist/openapi_client/models/SlackSurfaceConfig.d.ts +10 -0
- package/dist/openapi_client/models/SlackSurfaceConfig.js +1 -0
- package/dist/openapi_client/models/{SlackSurfaceConfigCreate.d.ts → SlackSurfaceConfigInput.d.ts} +1 -1
- package/dist/openapi_client/models/SlackSurfaceConfigInput.js +1 -0
- package/dist/openapi_client/models/SurfaceCredentialMode.d.ts +4 -0
- package/dist/openapi_client/models/SurfaceCredentialMode.js +9 -0
- package/dist/openapi_client/models/SurfaceIntegrationSetupGuide.d.ts +13 -0
- package/dist/openapi_client/models/SurfaceIntegrationSetupGuide.js +1 -0
- package/dist/openapi_client/models/SurfacePlatform.d.ts +8 -0
- package/dist/openapi_client/models/SurfacePlatform.js +13 -0
- package/dist/openapi_client/models/SurfacePlatformSetupGuideResponse.d.ts +9 -0
- package/dist/openapi_client/models/SurfacePlatformSetupGuideResponse.js +1 -0
- package/dist/openapi_client/models/SurfaceRoutingScope.d.ts +4 -0
- package/dist/openapi_client/models/SurfaceRoutingScope.js +9 -0
- package/dist/openapi_client/models/SurfaceSetupField.d.ts +10 -0
- package/dist/openapi_client/models/SurfaceSetupField.js +1 -0
- package/dist/openapi_client/models/SurfaceSetupFieldSource.d.ts +4 -0
- package/dist/openapi_client/models/SurfaceSetupFieldSource.js +9 -0
- package/dist/openapi_client/models/SurfaceSetupMode.d.ts +5 -0
- package/dist/openapi_client/models/SurfaceSetupMode.js +10 -0
- package/dist/openapi_client/models/SurfaceSetupPhase.d.ts +6 -0
- package/dist/openapi_client/models/SurfaceSetupPhase.js +11 -0
- package/dist/openapi_client/models/SurfaceSetupStep.d.ts +6 -0
- package/dist/openapi_client/models/SurfaceSetupStep.js +1 -0
- package/dist/openapi_client/models/SurfaceWebhookMode.d.ts +4 -0
- package/dist/openapi_client/models/SurfaceWebhookMode.js +9 -0
- package/dist/openapi_client/models/TeamsCredentialsInput.d.ts +6 -0
- package/dist/openapi_client/models/TeamsCredentialsInput.js +1 -0
- package/dist/openapi_client/models/TeamsSurfaceConfig.d.ts +9 -0
- package/dist/openapi_client/models/TeamsSurfaceConfig.js +1 -0
- package/dist/openapi_client/models/{TeamsSurfaceConfigCreate.d.ts → TeamsSurfaceConfigInput.d.ts} +1 -1
- package/dist/openapi_client/models/TeamsSurfaceConfigInput.js +1 -0
- package/dist/openapi_client/models/TelegramCredentialsInput.d.ts +5 -0
- package/dist/openapi_client/models/TelegramCredentialsInput.js +1 -0
- package/dist/openapi_client/models/TelegramSurfaceConfig.d.ts +6 -0
- package/dist/openapi_client/models/TelegramSurfaceConfig.js +1 -0
- package/dist/openapi_client/models/TelegramSurfaceConfigInput.d.ts +6 -0
- package/dist/openapi_client/models/TelegramSurfaceConfigInput.js +1 -0
- package/dist/openapi_client/models/UpdateSurfaceRequest.d.ts +17 -5
- package/dist/openapi_client/models/WhatsAppCredentialsInput.d.ts +8 -0
- package/dist/openapi_client/models/WhatsAppCredentialsInput.js +1 -0
- package/dist/openapi_client/models/WhatsAppSurfaceConfig.d.ts +6 -0
- package/dist/openapi_client/models/WhatsAppSurfaceConfig.js +1 -0
- package/dist/openapi_client/models/WhatsAppSurfaceConfigInput.d.ts +6 -0
- package/dist/openapi_client/models/WhatsAppSurfaceConfigInput.js +1 -0
- package/dist/openapi_client/models/WorkflowCreateRequest.d.ts +5 -2
- package/dist/openapi_client/models/WorkflowGraphUpdateRequest.d.ts +5 -2
- package/dist/openapi_client/models/WorkflowUpdateRequest.d.ts +5 -2
- package/dist/openapi_client/services/AssistantSurfacesIngressService.d.ts +51 -0
- package/dist/openapi_client/services/AssistantSurfacesIngressService.js +111 -0
- package/dist/openapi_client/services/AssistantSurfacesService.d.ts +27 -6
- package/dist/openapi_client/services/AssistantSurfacesService.js +62 -7
- package/dist/openapi_client/services/AuthorizationService.d.ts +47 -0
- package/dist/openapi_client/services/AuthorizationService.js +100 -0
- package/dist/openapi_client/services/DesksService.d.ts +4 -4
- package/dist/openapi_client/services/DesksService.js +6 -6
- package/dist/openapi_client/services/WorkflowsService.d.ts +3 -3
- package/dist/openapi_client/services/WorkflowsService.js +1 -1
- package/dist/react/index.d.ts +20 -0
- package/dist/react/index.js +10 -0
- package/dist/react/sql-utils.d.ts +8 -0
- package/dist/react/sql-utils.js +62 -0
- package/dist/react/useAddPodMember.d.ts +22 -0
- package/dist/react/useAddPodMember.js +51 -0
- package/dist/react/useCreateFolder.d.ts +22 -0
- package/dist/react/useCreateFolder.js +47 -0
- package/dist/react/useDatastoreQuery.d.ts +22 -0
- package/dist/react/useDatastoreQuery.js +67 -0
- package/dist/react/useDeleteFile.d.ts +19 -0
- package/dist/react/useDeleteFile.js +51 -0
- package/dist/react/useGlobalSearch.d.ts +62 -0
- package/dist/react/useGlobalSearch.js +170 -0
- package/dist/react/useRecordAggregates.d.ts +35 -0
- package/dist/react/useRecordAggregates.js +126 -0
- package/dist/react/useRemovePodMember.d.ts +19 -0
- package/dist/react/useRemovePodMember.js +50 -0
- package/dist/react/useTaskSession.js +3 -2
- package/dist/react/useUpdateFile.d.ts +29 -0
- package/dist/react/useUpdateFile.js +51 -0
- package/dist/react/useUpdatePodMemberRole.d.ts +20 -0
- package/dist/react/useUpdatePodMemberRole.js +50 -0
- package/dist/react/useUploadFile.d.ts +24 -0
- package/dist/react/useUploadFile.js +46 -0
- package/dist/react/useWorkflowStart.d.ts +2 -2
- package/dist/record-display.d.ts +20 -0
- package/dist/record-display.js +78 -0
- package/dist/record-form.d.ts +4 -0
- package/dist/record-form.js +16 -0
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
- package/dist/openapi_client/models/EmailSurfaceConfigCreate.d.ts +0 -5
- package/dist/openapi_client/models/FlowInstallEntity.d.ts +0 -16
- package/dist/openapi_client/models/FlowStartType.d.ts +0 -6
- package/dist/openapi_client/models/FlowStartType.js +0 -11
- package/dist/openapi_client/models/FlowStart_Input.d.ts +0 -14
- package/dist/openapi_client/models/FlowStart_Output.d.ts +0 -14
- package/dist/openapi_client/models/WhatsAppSurfaceConfigCreate.d.ts +0 -5
- package/dist/openapi_client/services/PublicDesksService.d.ts +0 -10
- package/dist/openapi_client/services/PublicDesksService.js +0 -22
- /package/dist/openapi_client/models/{DataStoreFlowStart.js → AdminConsentInfoResponse.js} +0 -0
- /package/dist/openapi_client/models/{EmailSurfaceConfigCreate.js → DataStoreFlowStartInput.js} +0 -0
- /package/dist/openapi_client/models/{EventFlowStart.js → DataStoreFlowStartOutput.js} +0 -0
- /package/dist/openapi_client/models/{FlowInstallEntity.js → DataStoreWorkflowStartInput.js} +0 -0
- /package/dist/openapi_client/models/{FlowStart_Input.js → DataStoreWorkflowStartOutput.js} +0 -0
- /package/dist/openapi_client/models/{FlowStart_Output.js → EventFlowStartInput.js} +0 -0
- /package/dist/openapi_client/models/{ScheduledFlowStart.js → EventFlowStartOutput.js} +0 -0
- /package/dist/openapi_client/models/{SlackSurfaceConfigCreate.js → EventWorkflowStartInput.js} +0 -0
- /package/dist/openapi_client/models/{TeamsSurfaceConfigCreate.js → EventWorkflowStartOutput.js} +0 -0
- /package/dist/openapi_client/models/{WhatsAppSurfaceConfigCreate.js → FlowInstallResponse.js} +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
function quoteIdentifierPart(value) {
|
|
2
|
+
return `"${value.replace(/"/g, "\"\"")}"`;
|
|
3
|
+
}
|
|
4
|
+
export function quoteIdentifierPath(value) {
|
|
5
|
+
return value
|
|
6
|
+
.split(".")
|
|
7
|
+
.map((part) => (part === "*" ? part : quoteIdentifierPart(part)))
|
|
8
|
+
.join(".");
|
|
9
|
+
}
|
|
10
|
+
export function isSimpleIdentifierPath(value) {
|
|
11
|
+
return /^[A-Za-z_][A-Za-z0-9_$]*(\.(\*|[A-Za-z_][A-Za-z0-9_$]*))*$/.test(value);
|
|
12
|
+
}
|
|
13
|
+
export function renderIdentifierPath(value) {
|
|
14
|
+
return isSimpleIdentifierPath(value) ? quoteIdentifierPath(value) : value;
|
|
15
|
+
}
|
|
16
|
+
export function escapeSqlString(value) {
|
|
17
|
+
return value.replace(/'/g, "''");
|
|
18
|
+
}
|
|
19
|
+
export function encodeSqlValue(value) {
|
|
20
|
+
if (value === null || typeof value === "undefined")
|
|
21
|
+
return "NULL";
|
|
22
|
+
if (typeof value === "boolean")
|
|
23
|
+
return value ? "TRUE" : "FALSE";
|
|
24
|
+
if (typeof value === "number") {
|
|
25
|
+
if (!Number.isFinite(value)) {
|
|
26
|
+
throw new Error("SQL values must be finite numbers.");
|
|
27
|
+
}
|
|
28
|
+
return String(value);
|
|
29
|
+
}
|
|
30
|
+
if (typeof value === "bigint")
|
|
31
|
+
return String(value);
|
|
32
|
+
if (value instanceof Date)
|
|
33
|
+
return `'${escapeSqlString(value.toISOString())}'`;
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
return `(${value.map((entry) => encodeSqlValue(entry)).join(", ")})`;
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === "object") {
|
|
38
|
+
return `'${escapeSqlString(JSON.stringify(value))}'`;
|
|
39
|
+
}
|
|
40
|
+
return `'${escapeSqlString(String(value))}'`;
|
|
41
|
+
}
|
|
42
|
+
export function renderRecordFilter(filter) {
|
|
43
|
+
const field = filter.field?.trim();
|
|
44
|
+
if (!field) {
|
|
45
|
+
throw new Error("Record filters require a field.");
|
|
46
|
+
}
|
|
47
|
+
const operator = filter.op.trim().toUpperCase();
|
|
48
|
+
const lhs = renderIdentifierPath(field);
|
|
49
|
+
const values = Array.isArray(filter.values) ? filter.values : undefined;
|
|
50
|
+
if ((operator === "IN" || operator === "NOT IN") && values) {
|
|
51
|
+
return `${lhs} ${operator} ${encodeSqlValue(values)}`;
|
|
52
|
+
}
|
|
53
|
+
if ((operator === "IS" || operator === "IS NOT") && typeof filter.value === "undefined") {
|
|
54
|
+
return `${lhs} ${operator} NULL`;
|
|
55
|
+
}
|
|
56
|
+
return `${lhs} ${operator} ${encodeSqlValue(filter.value)}`;
|
|
57
|
+
}
|
|
58
|
+
export function renderRecordFilters(filters) {
|
|
59
|
+
if (!filters?.length)
|
|
60
|
+
return "";
|
|
61
|
+
return filters.map((filter) => `(${renderRecordFilter(filter)})`).join(" AND ");
|
|
62
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LemmaClient } from "../client.js";
|
|
2
|
+
import { PodRole, type PodMember } from "../types.js";
|
|
3
|
+
export interface AddPodMemberInput {
|
|
4
|
+
organizationMemberId: string;
|
|
5
|
+
role?: PodRole;
|
|
6
|
+
}
|
|
7
|
+
export interface UseAddPodMemberOptions {
|
|
8
|
+
client: LemmaClient;
|
|
9
|
+
podId?: string;
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
defaultRole?: PodRole;
|
|
12
|
+
onSuccess?: (member: PodMember) => void;
|
|
13
|
+
onError?: (error: unknown) => void;
|
|
14
|
+
}
|
|
15
|
+
export interface UseAddPodMemberResult {
|
|
16
|
+
addedMember: PodMember | null;
|
|
17
|
+
isSubmitting: boolean;
|
|
18
|
+
error: Error | null;
|
|
19
|
+
add: (input: AddPodMemberInput) => Promise<PodMember | null>;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare function useAddPodMember({ client, podId, enabled, defaultRole, onSuccess, onError, }: UseAddPodMemberOptions): UseAddPodMemberResult;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { PodRole } from "../types.js";
|
|
3
|
+
import { normalizeError, resolvePodId } from "./utils.js";
|
|
4
|
+
export function useAddPodMember({ client, podId, enabled = true, defaultRole = PodRole.POD_USER, onSuccess, onError, }) {
|
|
5
|
+
const [addedMember, setAddedMember] = useState(null);
|
|
6
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
7
|
+
const [error, setError] = useState(null);
|
|
8
|
+
const onSuccessRef = useRef(onSuccess);
|
|
9
|
+
const onErrorRef = useRef(onError);
|
|
10
|
+
useEffect(() => { onSuccessRef.current = onSuccess; }, [onSuccess]);
|
|
11
|
+
useEffect(() => { onErrorRef.current = onError; }, [onError]);
|
|
12
|
+
const add = useCallback(async (input) => {
|
|
13
|
+
const organizationMemberId = input.organizationMemberId.trim();
|
|
14
|
+
if (!enabled || organizationMemberId.length === 0) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
setIsSubmitting(true);
|
|
18
|
+
setError(null);
|
|
19
|
+
try {
|
|
20
|
+
const resolvedPodId = resolvePodId(client, podId);
|
|
21
|
+
const nextMember = await client.podMembers.add(resolvedPodId, {
|
|
22
|
+
organization_member_id: organizationMemberId,
|
|
23
|
+
role: input.role ?? defaultRole,
|
|
24
|
+
});
|
|
25
|
+
setAddedMember(nextMember);
|
|
26
|
+
onSuccessRef.current?.(nextMember);
|
|
27
|
+
return nextMember;
|
|
28
|
+
}
|
|
29
|
+
catch (mutationError) {
|
|
30
|
+
const normalized = normalizeError(mutationError, "Failed to add pod member.");
|
|
31
|
+
setError(normalized);
|
|
32
|
+
onErrorRef.current?.(mutationError);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
setIsSubmitting(false);
|
|
37
|
+
}
|
|
38
|
+
}, [client, defaultRole, enabled, podId]);
|
|
39
|
+
const reset = useCallback(() => {
|
|
40
|
+
setAddedMember(null);
|
|
41
|
+
setError(null);
|
|
42
|
+
setIsSubmitting(false);
|
|
43
|
+
}, []);
|
|
44
|
+
return useMemo(() => ({
|
|
45
|
+
addedMember,
|
|
46
|
+
isSubmitting,
|
|
47
|
+
error,
|
|
48
|
+
add,
|
|
49
|
+
reset,
|
|
50
|
+
}), [add, addedMember, error, isSubmitting, reset]);
|
|
51
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LemmaClient } from "../client.js";
|
|
2
|
+
import type { FileResponse } from "../types.js";
|
|
3
|
+
export interface CreateFolderInput {
|
|
4
|
+
directoryPath?: string;
|
|
5
|
+
parentId?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface UseCreateFolderOptions {
|
|
9
|
+
client: LemmaClient;
|
|
10
|
+
podId?: string;
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
onSuccess?: (folder: FileResponse) => void;
|
|
13
|
+
onError?: (error: unknown) => void;
|
|
14
|
+
}
|
|
15
|
+
export interface UseCreateFolderResult<TFile extends FileResponse = FileResponse> {
|
|
16
|
+
createdFolder: TFile | null;
|
|
17
|
+
isSubmitting: boolean;
|
|
18
|
+
error: Error | null;
|
|
19
|
+
createFolder: (name: string, options?: CreateFolderInput) => Promise<TFile | null>;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare function useCreateFolder<TFile extends FileResponse = FileResponse>({ client, podId, enabled, onSuccess, onError, }: UseCreateFolderOptions): UseCreateFolderResult<TFile>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { normalizeError, resolvePodClient } from "./utils.js";
|
|
3
|
+
export function useCreateFolder({ client, podId, enabled = true, onSuccess, onError, }) {
|
|
4
|
+
const [createdFolder, setCreatedFolder] = useState(null);
|
|
5
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
6
|
+
const [error, setError] = useState(null);
|
|
7
|
+
const onSuccessRef = useRef(onSuccess);
|
|
8
|
+
const onErrorRef = useRef(onError);
|
|
9
|
+
useEffect(() => { onSuccessRef.current = onSuccess; }, [onSuccess]);
|
|
10
|
+
useEffect(() => { onErrorRef.current = onError; }, [onError]);
|
|
11
|
+
const createFolder = useCallback(async (name, options = {}) => {
|
|
12
|
+
const trimmedName = name.trim();
|
|
13
|
+
if (!enabled || trimmedName.length === 0) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
setIsSubmitting(true);
|
|
17
|
+
setError(null);
|
|
18
|
+
try {
|
|
19
|
+
const scopedClient = resolvePodClient(client, podId);
|
|
20
|
+
const nextFolder = await scopedClient.files.folder.create(trimmedName, options);
|
|
21
|
+
setCreatedFolder(nextFolder);
|
|
22
|
+
onSuccessRef.current?.(nextFolder);
|
|
23
|
+
return nextFolder;
|
|
24
|
+
}
|
|
25
|
+
catch (createError) {
|
|
26
|
+
const normalized = normalizeError(createError, "Failed to create folder.");
|
|
27
|
+
setError(normalized);
|
|
28
|
+
onErrorRef.current?.(createError);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
setIsSubmitting(false);
|
|
33
|
+
}
|
|
34
|
+
}, [client, enabled, podId]);
|
|
35
|
+
const reset = useCallback(() => {
|
|
36
|
+
setCreatedFolder(null);
|
|
37
|
+
setError(null);
|
|
38
|
+
setIsSubmitting(false);
|
|
39
|
+
}, []);
|
|
40
|
+
return useMemo(() => ({
|
|
41
|
+
createdFolder,
|
|
42
|
+
isSubmitting,
|
|
43
|
+
error,
|
|
44
|
+
createFolder,
|
|
45
|
+
reset,
|
|
46
|
+
}), [createFolder, createdFolder, error, isSubmitting, reset]);
|
|
47
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LemmaClient } from "../client.js";
|
|
2
|
+
import type { DatastoreQueryResponse } from "../types.js";
|
|
3
|
+
export interface UseDatastoreQueryOptions {
|
|
4
|
+
client: LemmaClient;
|
|
5
|
+
podId?: string;
|
|
6
|
+
query?: string | null;
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
autoLoad?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface UseDatastoreQueryResult<TRow extends Record<string, unknown> = Record<string, unknown>> {
|
|
11
|
+
response: DatastoreQueryResponse | null;
|
|
12
|
+
items: TRow[];
|
|
13
|
+
total: number;
|
|
14
|
+
sql: string;
|
|
15
|
+
isLoading: boolean;
|
|
16
|
+
error: Error | null;
|
|
17
|
+
refresh: (overrides?: {
|
|
18
|
+
query?: string | null;
|
|
19
|
+
}) => Promise<TRow[]>;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare function useDatastoreQuery<TRow extends Record<string, unknown> = Record<string, unknown>>({ client, podId, query, enabled, autoLoad, }: UseDatastoreQueryOptions): UseDatastoreQueryResult<TRow>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { normalizeError, resolvePodClient } from "./utils.js";
|
|
3
|
+
export function useDatastoreQuery({ client, podId, query = null, enabled = true, autoLoad = true, }) {
|
|
4
|
+
const [response, setResponse] = useState(null);
|
|
5
|
+
const [sql, setSql] = useState("");
|
|
6
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
7
|
+
const [error, setError] = useState(null);
|
|
8
|
+
const trimmedQuery = typeof query === "string" ? query.trim() : "";
|
|
9
|
+
const isEnabled = enabled && trimmedQuery.length > 0;
|
|
10
|
+
const reset = useCallback(() => {
|
|
11
|
+
setResponse(null);
|
|
12
|
+
setSql("");
|
|
13
|
+
setError(null);
|
|
14
|
+
setIsLoading(false);
|
|
15
|
+
}, []);
|
|
16
|
+
const refresh = useCallback(async (overrides = {}, signal) => {
|
|
17
|
+
const nextQuery = typeof overrides.query === "string"
|
|
18
|
+
? overrides.query.trim()
|
|
19
|
+
: trimmedQuery;
|
|
20
|
+
if (!enabled || nextQuery.length === 0) {
|
|
21
|
+
reset();
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
setIsLoading(true);
|
|
25
|
+
setError(null);
|
|
26
|
+
setSql(nextQuery);
|
|
27
|
+
try {
|
|
28
|
+
const scopedClient = resolvePodClient(client, podId);
|
|
29
|
+
const nextResponse = await scopedClient.datastore.query(nextQuery);
|
|
30
|
+
if (signal?.aborted)
|
|
31
|
+
return [];
|
|
32
|
+
setResponse(nextResponse);
|
|
33
|
+
return (nextResponse.items ?? []);
|
|
34
|
+
}
|
|
35
|
+
catch (queryError) {
|
|
36
|
+
if (signal?.aborted)
|
|
37
|
+
return [];
|
|
38
|
+
setError(normalizeError(queryError, "Failed to execute datastore query."));
|
|
39
|
+
setResponse(null);
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
if (!signal?.aborted)
|
|
44
|
+
setIsLoading(false);
|
|
45
|
+
}
|
|
46
|
+
}, [client, enabled, podId, reset, trimmedQuery]);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!isEnabled || !autoLoad) {
|
|
49
|
+
if (!isEnabled)
|
|
50
|
+
reset();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
void refresh({}, controller.signal);
|
|
55
|
+
return () => controller.abort();
|
|
56
|
+
}, [autoLoad, isEnabled, refresh, reset]);
|
|
57
|
+
return useMemo(() => ({
|
|
58
|
+
response,
|
|
59
|
+
items: (response?.items ?? []),
|
|
60
|
+
total: response?.total ?? 0,
|
|
61
|
+
sql,
|
|
62
|
+
isLoading,
|
|
63
|
+
error,
|
|
64
|
+
refresh,
|
|
65
|
+
reset,
|
|
66
|
+
}), [error, isLoading, refresh, reset, response, sql]);
|
|
67
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LemmaClient } from "../client.js";
|
|
2
|
+
export interface UseDeleteFileOptions {
|
|
3
|
+
client: LemmaClient;
|
|
4
|
+
podId?: string;
|
|
5
|
+
path?: string | null;
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
onSuccess?: (path: string) => void;
|
|
8
|
+
onError?: (error: unknown) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface UseDeleteFileResult {
|
|
11
|
+
deletedPath: string | null;
|
|
12
|
+
isSubmitting: boolean;
|
|
13
|
+
error: Error | null;
|
|
14
|
+
remove: (overrides?: {
|
|
15
|
+
path?: string | null;
|
|
16
|
+
}) => Promise<boolean>;
|
|
17
|
+
reset: () => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function useDeleteFile({ client, podId, path, enabled, onSuccess, onError, }: UseDeleteFileOptions): UseDeleteFileResult;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { normalizeError, resolvePodClient } from "./utils.js";
|
|
3
|
+
export function useDeleteFile({ client, podId, path = null, enabled = true, onSuccess, onError, }) {
|
|
4
|
+
const [deletedPath, setDeletedPath] = useState(null);
|
|
5
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
6
|
+
const [error, setError] = useState(null);
|
|
7
|
+
const onSuccessRef = useRef(onSuccess);
|
|
8
|
+
const onErrorRef = useRef(onError);
|
|
9
|
+
useEffect(() => { onSuccessRef.current = onSuccess; }, [onSuccess]);
|
|
10
|
+
useEffect(() => { onErrorRef.current = onError; }, [onError]);
|
|
11
|
+
const trimmedPath = typeof path === "string" ? path.trim() : "";
|
|
12
|
+
const isEnabled = enabled && trimmedPath.length > 0;
|
|
13
|
+
const remove = useCallback(async (overrides = {}) => {
|
|
14
|
+
const nextPath = typeof overrides.path === "string"
|
|
15
|
+
? overrides.path.trim()
|
|
16
|
+
: trimmedPath;
|
|
17
|
+
if (!isEnabled || nextPath.length === 0) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
setIsSubmitting(true);
|
|
21
|
+
setError(null);
|
|
22
|
+
try {
|
|
23
|
+
const scopedClient = resolvePodClient(client, podId);
|
|
24
|
+
await scopedClient.files.delete(nextPath);
|
|
25
|
+
setDeletedPath(nextPath);
|
|
26
|
+
onSuccessRef.current?.(nextPath);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch (removeError) {
|
|
30
|
+
const normalized = normalizeError(removeError, "Failed to delete file.");
|
|
31
|
+
setError(normalized);
|
|
32
|
+
onErrorRef.current?.(removeError);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
setIsSubmitting(false);
|
|
37
|
+
}
|
|
38
|
+
}, [client, isEnabled, podId, trimmedPath]);
|
|
39
|
+
const reset = useCallback(() => {
|
|
40
|
+
setDeletedPath(null);
|
|
41
|
+
setError(null);
|
|
42
|
+
setIsSubmitting(false);
|
|
43
|
+
}, []);
|
|
44
|
+
return useMemo(() => ({
|
|
45
|
+
deletedPath,
|
|
46
|
+
isSubmitting,
|
|
47
|
+
error,
|
|
48
|
+
remove,
|
|
49
|
+
reset,
|
|
50
|
+
}), [deletedPath, error, isSubmitting, remove, reset]);
|
|
51
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { LemmaClient } from "../client.js";
|
|
2
|
+
import type { FileSearchResultSchema, RecordFilter, SearchMethod } from "../types.js";
|
|
3
|
+
export interface GlobalSearchTableSource {
|
|
4
|
+
key?: string;
|
|
5
|
+
tableName: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
searchFields: string[];
|
|
8
|
+
displayField?: string;
|
|
9
|
+
subtitleField?: string;
|
|
10
|
+
limit?: number;
|
|
11
|
+
filters?: RecordFilter[];
|
|
12
|
+
}
|
|
13
|
+
export interface GlobalSearchFilesSource {
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
label?: string;
|
|
16
|
+
limit?: number;
|
|
17
|
+
searchMethod?: SearchMethod;
|
|
18
|
+
}
|
|
19
|
+
export interface GlobalSearchRecordResult {
|
|
20
|
+
kind: "record";
|
|
21
|
+
sourceKey: string;
|
|
22
|
+
sourceLabel: string;
|
|
23
|
+
tableName: string;
|
|
24
|
+
id: string;
|
|
25
|
+
title: string;
|
|
26
|
+
subtitle: string | null;
|
|
27
|
+
record: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
export interface GlobalSearchFileResult {
|
|
30
|
+
kind: "file";
|
|
31
|
+
sourceKey: string;
|
|
32
|
+
sourceLabel: string;
|
|
33
|
+
path: string;
|
|
34
|
+
title: string;
|
|
35
|
+
subtitle: string | null;
|
|
36
|
+
result: FileSearchResultSchema;
|
|
37
|
+
}
|
|
38
|
+
export type GlobalSearchResult = GlobalSearchRecordResult | GlobalSearchFileResult;
|
|
39
|
+
export interface UseGlobalSearchOptions {
|
|
40
|
+
client: LemmaClient;
|
|
41
|
+
podId?: string;
|
|
42
|
+
query?: string;
|
|
43
|
+
tables?: GlobalSearchTableSource[];
|
|
44
|
+
files?: GlobalSearchFilesSource | false;
|
|
45
|
+
enabled?: boolean;
|
|
46
|
+
autoLoad?: boolean;
|
|
47
|
+
minQueryLength?: number;
|
|
48
|
+
}
|
|
49
|
+
export interface UseGlobalSearchResult {
|
|
50
|
+
results: GlobalSearchResult[];
|
|
51
|
+
recordResults: GlobalSearchRecordResult[];
|
|
52
|
+
fileResults: GlobalSearchFileResult[];
|
|
53
|
+
totalResults: number;
|
|
54
|
+
sourceErrors: Record<string, Error>;
|
|
55
|
+
isLoading: boolean;
|
|
56
|
+
error: Error | null;
|
|
57
|
+
search: (overrides?: {
|
|
58
|
+
query?: string;
|
|
59
|
+
}) => Promise<GlobalSearchResult[]>;
|
|
60
|
+
reset: () => void;
|
|
61
|
+
}
|
|
62
|
+
export declare function useGlobalSearch({ client, podId, query, tables, files, enabled, autoLoad, minQueryLength, }: UseGlobalSearchOptions): UseGlobalSearchResult;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { escapeSqlString, quoteIdentifierPath, renderIdentifierPath, renderRecordFilters } from "./sql-utils.js";
|
|
3
|
+
import { normalizeError, resolvePodClient, stringifyComparable } from "./utils.js";
|
|
4
|
+
function buildTableSearchQuery(source, query) {
|
|
5
|
+
const fields = Array.from(new Set([
|
|
6
|
+
"id",
|
|
7
|
+
...source.searchFields,
|
|
8
|
+
source.displayField ?? "id",
|
|
9
|
+
source.subtitleField ?? "",
|
|
10
|
+
].filter((value) => value.trim().length > 0)));
|
|
11
|
+
const searchClauses = source.searchFields.map((field) => `${renderIdentifierPath(field)} ILIKE '%${escapeSqlString(query)}%'`);
|
|
12
|
+
const filterClause = renderRecordFilters(source.filters);
|
|
13
|
+
return [
|
|
14
|
+
`SELECT ${fields.map((field) => renderIdentifierPath(field)).join(", ")}`,
|
|
15
|
+
`FROM ${quoteIdentifierPath(source.tableName)}`,
|
|
16
|
+
`WHERE (${searchClauses.join(" OR ")})${filterClause ? ` AND ${filterClause}` : ""}`,
|
|
17
|
+
`LIMIT ${source.limit ?? 8}`,
|
|
18
|
+
].join(" ");
|
|
19
|
+
}
|
|
20
|
+
function readString(value) {
|
|
21
|
+
if (typeof value === "string" && value.trim().length > 0)
|
|
22
|
+
return value;
|
|
23
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
24
|
+
return String(value);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
export function useGlobalSearch({ client, podId, query = "", tables = [], files, enabled = true, autoLoad = true, minQueryLength = 1, }) {
|
|
28
|
+
const [results, setResults] = useState([]);
|
|
29
|
+
const [sourceErrors, setSourceErrors] = useState({});
|
|
30
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
31
|
+
const [error, setError] = useState(null);
|
|
32
|
+
const trimmedQuery = query.trim();
|
|
33
|
+
const tablesKey = stringifyComparable(tables);
|
|
34
|
+
const filesKey = stringifyComparable(files);
|
|
35
|
+
const stableTables = useMemo(() => tables, [tablesKey]);
|
|
36
|
+
const stableFiles = useMemo(() => files, [filesKey]);
|
|
37
|
+
const reset = useCallback(() => {
|
|
38
|
+
setResults([]);
|
|
39
|
+
setSourceErrors({});
|
|
40
|
+
setError(null);
|
|
41
|
+
setIsLoading(false);
|
|
42
|
+
}, []);
|
|
43
|
+
const search = useCallback(async (overrides = {}, signal) => {
|
|
44
|
+
const nextQuery = (overrides.query ?? trimmedQuery).trim();
|
|
45
|
+
if (!enabled || nextQuery.length < minQueryLength) {
|
|
46
|
+
reset();
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
setIsLoading(true);
|
|
50
|
+
setError(null);
|
|
51
|
+
try {
|
|
52
|
+
const scopedClient = resolvePodClient(client, podId);
|
|
53
|
+
const searchTasks = [];
|
|
54
|
+
stableTables.forEach((source, index) => {
|
|
55
|
+
const sourceKey = source.key?.trim() || source.tableName;
|
|
56
|
+
searchTasks.push((async () => {
|
|
57
|
+
try {
|
|
58
|
+
const sql = buildTableSearchQuery(source, nextQuery);
|
|
59
|
+
const response = await scopedClient.datastore.query(sql);
|
|
60
|
+
const rows = response.items ?? [];
|
|
61
|
+
const mapped = rows.map((record) => {
|
|
62
|
+
const displayField = source.displayField ?? source.searchFields[0] ?? "id";
|
|
63
|
+
const subtitleField = source.subtitleField;
|
|
64
|
+
const id = readString(record.id) ?? `${source.tableName}-${index}`;
|
|
65
|
+
return {
|
|
66
|
+
kind: "record",
|
|
67
|
+
sourceKey,
|
|
68
|
+
sourceLabel: source.label ?? source.tableName,
|
|
69
|
+
tableName: source.tableName,
|
|
70
|
+
id,
|
|
71
|
+
title: readString(record[displayField]) ?? id,
|
|
72
|
+
subtitle: subtitleField ? readString(record[subtitleField]) : null,
|
|
73
|
+
record,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
return { key: sourceKey, results: mapped };
|
|
77
|
+
}
|
|
78
|
+
catch (tableError) {
|
|
79
|
+
return {
|
|
80
|
+
key: sourceKey,
|
|
81
|
+
results: [],
|
|
82
|
+
error: normalizeError(tableError, `Failed to search ${source.tableName}.`),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
})());
|
|
86
|
+
});
|
|
87
|
+
if (stableFiles !== false && stableFiles?.enabled !== false) {
|
|
88
|
+
searchTasks.push((async () => {
|
|
89
|
+
const sourceKey = "files";
|
|
90
|
+
try {
|
|
91
|
+
const response = await scopedClient.files.search(nextQuery, {
|
|
92
|
+
limit: stableFiles?.limit ?? 8,
|
|
93
|
+
searchMethod: stableFiles?.searchMethod,
|
|
94
|
+
});
|
|
95
|
+
const mapped = (response.results ?? []).map((result) => ({
|
|
96
|
+
kind: "file",
|
|
97
|
+
sourceKey,
|
|
98
|
+
sourceLabel: stableFiles?.label ?? "Files",
|
|
99
|
+
path: result.path,
|
|
100
|
+
title: result.path.split("/").filter(Boolean).pop() || result.path,
|
|
101
|
+
subtitle: typeof result.content === "string" && result.content.trim().length > 0
|
|
102
|
+
? result.content.slice(0, 160)
|
|
103
|
+
: null,
|
|
104
|
+
result,
|
|
105
|
+
}));
|
|
106
|
+
return { key: sourceKey, results: mapped };
|
|
107
|
+
}
|
|
108
|
+
catch (fileError) {
|
|
109
|
+
return {
|
|
110
|
+
key: sourceKey,
|
|
111
|
+
results: [],
|
|
112
|
+
error: normalizeError(fileError, "Failed to search files."),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
})());
|
|
116
|
+
}
|
|
117
|
+
const settled = await Promise.all(searchTasks);
|
|
118
|
+
if (signal?.aborted)
|
|
119
|
+
return [];
|
|
120
|
+
const nextErrors = {};
|
|
121
|
+
const nextResults = settled.flatMap((entry) => {
|
|
122
|
+
if (entry.error) {
|
|
123
|
+
nextErrors[entry.key] = entry.error;
|
|
124
|
+
}
|
|
125
|
+
return entry.results;
|
|
126
|
+
});
|
|
127
|
+
setSourceErrors(nextErrors);
|
|
128
|
+
setResults(nextResults);
|
|
129
|
+
return nextResults;
|
|
130
|
+
}
|
|
131
|
+
catch (searchError) {
|
|
132
|
+
if (signal?.aborted)
|
|
133
|
+
return [];
|
|
134
|
+
const normalized = normalizeError(searchError, "Failed to run global search.");
|
|
135
|
+
setError(normalized);
|
|
136
|
+
setResults([]);
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
if (!signal?.aborted)
|
|
141
|
+
setIsLoading(false);
|
|
142
|
+
}
|
|
143
|
+
}, [client, enabled, minQueryLength, podId, reset, stableFiles, stableTables, trimmedQuery]);
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (!enabled || !autoLoad)
|
|
146
|
+
return;
|
|
147
|
+
if (trimmedQuery.length < minQueryLength) {
|
|
148
|
+
reset();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const controller = new AbortController();
|
|
152
|
+
void search({}, controller.signal);
|
|
153
|
+
return () => controller.abort();
|
|
154
|
+
}, [autoLoad, enabled, minQueryLength, reset, search, trimmedQuery]);
|
|
155
|
+
return useMemo(() => {
|
|
156
|
+
const recordResults = results.filter((entry) => entry.kind === "record");
|
|
157
|
+
const fileResults = results.filter((entry) => entry.kind === "file");
|
|
158
|
+
return {
|
|
159
|
+
results,
|
|
160
|
+
recordResults,
|
|
161
|
+
fileResults,
|
|
162
|
+
totalResults: results.length,
|
|
163
|
+
sourceErrors,
|
|
164
|
+
isLoading,
|
|
165
|
+
error,
|
|
166
|
+
search,
|
|
167
|
+
reset,
|
|
168
|
+
};
|
|
169
|
+
}, [error, isLoading, reset, results, search, sourceErrors]);
|
|
170
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { LemmaClient } from "../client.js";
|
|
2
|
+
import type { RecordFilter } from "../types.js";
|
|
3
|
+
export interface RecordAggregateMetric {
|
|
4
|
+
key: string;
|
|
5
|
+
op: "count" | "sum" | "avg" | "min" | "max";
|
|
6
|
+
field?: string;
|
|
7
|
+
distinct?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface RecordAggregateOrderBy {
|
|
10
|
+
field: string;
|
|
11
|
+
direction?: "asc" | "desc";
|
|
12
|
+
}
|
|
13
|
+
export interface UseRecordAggregatesOptions {
|
|
14
|
+
client: LemmaClient;
|
|
15
|
+
podId?: string;
|
|
16
|
+
tableName: string;
|
|
17
|
+
metrics: RecordAggregateMetric[];
|
|
18
|
+
groupBy?: string | string[];
|
|
19
|
+
filters?: RecordFilter[];
|
|
20
|
+
limit?: number;
|
|
21
|
+
offset?: number;
|
|
22
|
+
orderBy?: RecordAggregateOrderBy[];
|
|
23
|
+
enabled?: boolean;
|
|
24
|
+
autoLoad?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface UseRecordAggregatesResult<TRow extends Record<string, unknown> = Record<string, unknown>> {
|
|
27
|
+
rows: TRow[];
|
|
28
|
+
row: TRow | null;
|
|
29
|
+
total: number;
|
|
30
|
+
sql: string;
|
|
31
|
+
isLoading: boolean;
|
|
32
|
+
error: Error | null;
|
|
33
|
+
refresh: () => Promise<TRow[]>;
|
|
34
|
+
}
|
|
35
|
+
export declare function useRecordAggregates<TRow extends Record<string, unknown> = Record<string, unknown>>({ client, podId, tableName, metrics, groupBy, filters, limit, offset, orderBy, enabled, autoLoad, }: UseRecordAggregatesOptions): UseRecordAggregatesResult<TRow>;
|