@vertesia/ui 0.79.1 → 0.80.0-dev.20251121
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/lib/esm/core/components/TagsInput.js +194 -0
- package/lib/esm/core/components/TagsInput.js.map +1 -0
- package/lib/esm/core/components/index.js +2 -1
- package/lib/esm/core/components/index.js.map +1 -1
- package/lib/esm/core/components/shadcn/popover.js +1 -1
- package/lib/esm/core/components/shadcn/popover.js.map +1 -1
- package/lib/esm/env/index.js +1 -1
- package/lib/esm/env/index.js.map +1 -1
- package/lib/esm/features/store/collections/EditCollectionView.js +18 -7
- package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
- package/lib/esm/features/store/collections/SelectCollection.js +104 -39
- package/lib/esm/features/store/collections/SelectCollection.js.map +1 -1
- package/lib/esm/features/store/collections/SharedPropsEditor.js +40 -0
- package/lib/esm/features/store/collections/SharedPropsEditor.js.map +1 -0
- package/lib/esm/features/store/collections/SyncMemberHeadsToggle.js +35 -0
- package/lib/esm/features/store/collections/SyncMemberHeadsToggle.js.map +1 -0
- package/lib/esm/features/store/collections/index.js +2 -0
- package/lib/esm/features/store/collections/index.js.map +1 -1
- package/lib/esm/features/store/objects/upload/useSmartFileUploadProcessing.js +10 -9
- package/lib/esm/features/store/objects/upload/useSmartFileUploadProcessing.js.map +1 -1
- package/lib/esm/session/UserSessionProvider.js +2 -2
- package/lib/esm/session/UserSessionProvider.js.map +1 -1
- package/lib/esm/shell/apps/AppProjectSelector.js +2 -2
- package/lib/esm/shell/apps/AppProjectSelector.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/core/components/TagsInput.d.ts +16 -0
- package/lib/types/core/components/TagsInput.d.ts.map +1 -0
- package/lib/types/core/components/index.d.ts +2 -1
- package/lib/types/core/components/index.d.ts.map +1 -1
- package/lib/types/core/components/shadcn/popover.d.ts +7 -0
- package/lib/types/core/components/shadcn/popover.d.ts.map +1 -1
- package/lib/types/features/store/collections/EditCollectionView.d.ts.map +1 -1
- package/lib/types/features/store/collections/SelectCollection.d.ts +2 -1
- package/lib/types/features/store/collections/SelectCollection.d.ts.map +1 -1
- package/lib/types/features/store/collections/SharedPropsEditor.d.ts +7 -0
- package/lib/types/features/store/collections/SharedPropsEditor.d.ts.map +1 -0
- package/lib/types/features/store/collections/SyncMemberHeadsToggle.d.ts +7 -0
- package/lib/types/features/store/collections/SyncMemberHeadsToggle.d.ts.map +1 -0
- package/lib/types/features/store/collections/index.d.ts +2 -0
- package/lib/types/features/store/collections/index.d.ts.map +1 -1
- package/lib/types/features/store/objects/upload/useSmartFileUploadProcessing.d.ts.map +1 -1
- package/lib/vertesia-ui-core.js +1 -1
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-env.js +1 -1
- package/lib/vertesia-ui-env.js.map +1 -1
- package/lib/vertesia-ui-features.js +1 -1
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/lib/vertesia-ui-shell.js +1 -1
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/package.json +171 -166
- package/src/core/components/SelectBox.tsx +1 -1
- package/src/core/components/TagsInput.tsx +388 -0
- package/src/core/components/index.ts +2 -1
- package/src/core/components/shadcn/popover.tsx +2 -2
- package/src/core/hooks/CompositeState.tsx +156 -6
- package/src/env/index.ts +5 -4
- package/src/features/agent/PayloadBuilder.tsx +92 -65
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +2 -2
- package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +3 -3
- package/src/features/store/collections/EditCollectionView.tsx +31 -10
- package/src/features/store/collections/SharedPropsEditor.tsx +61 -0
- package/src/features/store/collections/SyncMemberHeadsToggle.tsx +48 -0
- package/src/features/store/collections/index.ts +3 -1
- package/src/features/store/objects/DocumentSearchResults.tsx +11 -2
- package/src/features/store/objects/components/useDownloadObject.ts +7 -2
- package/src/features/store/objects/upload/useSmartFileUploadProcessing.ts +1 -3
- package/src/features/user/UserInfo.tsx +2 -0
- package/src/session/UserSession.ts +1 -0
- package/src/session/UserSessionProvider.tsx +10 -2
- package/src/session/auth/composable.ts +71 -70
- package/src/shell/apps/AppProjectSelector.tsx +2 -2
- package/src/widgets/form/Form.tsx +1 -1
- package/src/widgets/form/ManagedObject.ts +4 -0
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
import { AsyncExecutionResult, VertesiaClient } from "@vertesia/client";
|
|
2
|
-
import {
|
|
2
|
+
import { AgentSearchScope, ExecutionEnvironmentRef, InCodeInteraction, mergeInCodePromptSchemas, supportsToolUse, WorkflowInteractionVars } from "@vertesia/common";
|
|
3
3
|
import { JSONObject } from "@vertesia/json";
|
|
4
4
|
import { useUserSession } from "@vertesia/ui/session";
|
|
5
5
|
import Ajv, { ValidateFunction } from "ajv";
|
|
6
6
|
import type { JSONSchema4 } from "json-schema";
|
|
7
7
|
import React, { createContext, useContext, useEffect, useState } from "react";
|
|
8
8
|
|
|
9
|
-
export interface ConversationWorkflowPayload {
|
|
10
|
-
interaction?: Interaction | undefined;
|
|
11
|
-
config: {
|
|
12
|
-
environment?: ExecutionEnvironmentRef | undefined;
|
|
13
|
-
model?: string;
|
|
14
|
-
}
|
|
15
|
-
data?: JSONObject | undefined,
|
|
16
|
-
tool_names: string[],
|
|
17
|
-
}
|
|
18
9
|
|
|
19
|
-
export
|
|
10
|
+
// export interface ConversationWorkflowPayload {
|
|
11
|
+
// config: {
|
|
12
|
+
// environment?: ExecutionEnvironmentRef | undefined;
|
|
13
|
+
// model?: string;
|
|
14
|
+
// }
|
|
15
|
+
// data?: JSONObject | undefined,
|
|
16
|
+
// tool_names: string[],
|
|
17
|
+
// }
|
|
18
|
+
|
|
19
|
+
export class PayloadBuilder {
|
|
20
20
|
_interactive: boolean = true;
|
|
21
21
|
_debug_mode: boolean = false;
|
|
22
22
|
_collection: string | undefined;
|
|
23
23
|
_start: boolean = false;
|
|
24
24
|
_preserveRunValues: boolean = false;
|
|
25
|
+
_interaction: InCodeInteraction | undefined;
|
|
26
|
+
_environment: ExecutionEnvironmentRef | undefined;
|
|
27
|
+
_model: string = '';
|
|
28
|
+
_tool_names: string[] = [];
|
|
29
|
+
_data: JSONObject | undefined;
|
|
25
30
|
|
|
26
|
-
payload: ConversationWorkflowPayload;
|
|
27
31
|
private _interactionParamsSchema?: JSONSchema4 | null;
|
|
28
32
|
private _inputValidator?: {
|
|
29
33
|
validate: ValidateFunction;
|
|
@@ -31,12 +35,6 @@ export class PayloadBuilder implements ConversationWorkflowPayload {
|
|
|
31
35
|
};
|
|
32
36
|
|
|
33
37
|
constructor(public vertesia: VertesiaClient, public updateState: (data: PayloadBuilder) => void) {
|
|
34
|
-
this.payload = {
|
|
35
|
-
config: {
|
|
36
|
-
model: '',
|
|
37
|
-
},
|
|
38
|
-
tool_names: [],
|
|
39
|
-
}
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
onStateChanged() {
|
|
@@ -47,7 +45,11 @@ export class PayloadBuilder implements ConversationWorkflowPayload {
|
|
|
47
45
|
clone() {
|
|
48
46
|
const builder = new PayloadBuilder(this.vertesia, this.updateState);
|
|
49
47
|
builder._interactionParamsSchema = this._interactionParamsSchema;
|
|
50
|
-
builder.
|
|
48
|
+
builder._interaction = this._interaction;
|
|
49
|
+
builder._data = this._data;
|
|
50
|
+
builder._environment = this._environment;
|
|
51
|
+
builder._model = this._model;
|
|
52
|
+
builder._tool_names = [...this._tool_names];
|
|
51
53
|
builder._interactive = this._interactive;
|
|
52
54
|
builder._debug_mode = this._debug_mode;
|
|
53
55
|
builder._inputValidator = this._inputValidator;
|
|
@@ -91,31 +93,64 @@ export class PayloadBuilder implements ConversationWorkflowPayload {
|
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
get search_scope() {
|
|
94
|
-
return this._collection ?
|
|
96
|
+
return this._collection ? AgentSearchScope.Collection : undefined;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async restoreConversation(context: WorkflowInteractionVars) {
|
|
100
|
+
|
|
101
|
+
// Handle version-specific interaction resolution
|
|
102
|
+
let interactionRef = context.interaction;
|
|
103
|
+
if (context.version) {
|
|
104
|
+
const objectIdRegex = /^[a-fA-F0-9]{24}$/;
|
|
105
|
+
if (!objectIdRegex.test(interactionRef)) {
|
|
106
|
+
// regex to check if interactionRef is an object id (24 hex characters), only append version if not an object id
|
|
107
|
+
interactionRef = `${interactionRef}@${context.version}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const inter = await this.vertesia.interactions.catalog.resolve(interactionRef);
|
|
112
|
+
const envId = inter.runtime?.environment || context.config?.environment;
|
|
113
|
+
const model = context.config?.model;
|
|
114
|
+
const env = await (envId ?
|
|
115
|
+
this.vertesia.environments.retrieve(context.config?.environment)
|
|
116
|
+
:
|
|
117
|
+
Promise.resolve(undefined)
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
this.interactionParamsSchema = context.interactionParamsSchema ?? null;
|
|
122
|
+
// trigger the setter to update the corresponding interactionParamsSchema
|
|
123
|
+
this.interaction = inter;
|
|
124
|
+
|
|
125
|
+
this._tool_names = context.tool_names || [];
|
|
126
|
+
this._data = context.data;
|
|
127
|
+
this._interactive = context.interactive;
|
|
128
|
+
this._debug_mode = context.debug_mode ?? false;
|
|
129
|
+
this.collection = context.collection_id ?? undefined;
|
|
130
|
+
|
|
131
|
+
// we need to trigger the setter to deal with default models
|
|
132
|
+
this.environment = env;
|
|
133
|
+
if (model) {
|
|
134
|
+
this._model = model;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.onStateChanged();
|
|
95
138
|
}
|
|
96
139
|
|
|
97
140
|
get interaction() {
|
|
98
|
-
return this.
|
|
141
|
+
return this._interaction;
|
|
99
142
|
}
|
|
100
|
-
set interaction(interaction:
|
|
101
|
-
if (interaction?.id !== this.
|
|
102
|
-
this.
|
|
103
|
-
|
|
143
|
+
set interaction(interaction: InCodeInteraction | undefined) {
|
|
144
|
+
if (interaction?.id !== this._interaction?.id) {
|
|
145
|
+
this._interaction = interaction;
|
|
146
|
+
// trigger the setter to update the onChange state
|
|
147
|
+
this.interactionParamsSchema = interaction ? mergeInCodePromptSchemas(interaction.prompts) as JSONSchema4 : undefined;
|
|
104
148
|
// Reset the validator when schema changes
|
|
105
149
|
this._inputValidator = undefined;
|
|
106
150
|
if (interaction && !this._preserveRunValues) {
|
|
107
|
-
if (interaction.environment) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
} else {
|
|
111
|
-
this.payload.config.environment = interaction.environment;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (interaction.model) {
|
|
115
|
-
this.payload.config.model = interaction.model;
|
|
116
|
-
} else {
|
|
117
|
-
this.payload.config.model = this.environment?.default_model && supportsToolUse(this.environment.default_model, this.environment.provider)
|
|
118
|
-
? this.environment.default_model : undefined;
|
|
151
|
+
if (interaction.runtime?.environment) {
|
|
152
|
+
const envId = interaction.runtime.environment;
|
|
153
|
+
this.vertesia.environments.retrieve(envId).then((environment) => this.environment = environment);
|
|
119
154
|
}
|
|
120
155
|
}
|
|
121
156
|
this.onStateChanged();
|
|
@@ -123,19 +158,19 @@ export class PayloadBuilder implements ConversationWorkflowPayload {
|
|
|
123
158
|
}
|
|
124
159
|
|
|
125
160
|
get environment() {
|
|
126
|
-
return this.
|
|
161
|
+
return this._environment;
|
|
127
162
|
}
|
|
128
163
|
set environment(environment: ExecutionEnvironmentRef | undefined) {
|
|
129
|
-
if (environment?.id !== this.
|
|
130
|
-
this.
|
|
164
|
+
if (environment?.id !== this._environment?.id) {
|
|
165
|
+
this._environment = environment;
|
|
131
166
|
if (!this._preserveRunValues) {
|
|
132
167
|
// First try to use the interaction model, then the environment default model
|
|
133
|
-
const interactionModel = this.
|
|
168
|
+
const interactionModel = this.interaction?.runtime?.model;
|
|
134
169
|
if (interactionModel && environment && supportsToolUse(interactionModel, environment.provider)) {
|
|
135
|
-
this.
|
|
170
|
+
this._model = interactionModel;
|
|
136
171
|
} else {
|
|
137
|
-
this.
|
|
138
|
-
? environment.default_model :
|
|
172
|
+
this._model = environment?.default_model && supportsToolUse(environment.default_model, environment.provider)
|
|
173
|
+
? environment.default_model : '';
|
|
139
174
|
}
|
|
140
175
|
}
|
|
141
176
|
|
|
@@ -144,35 +179,31 @@ export class PayloadBuilder implements ConversationWorkflowPayload {
|
|
|
144
179
|
}
|
|
145
180
|
|
|
146
181
|
get model() {
|
|
147
|
-
return this.
|
|
182
|
+
return this._model;
|
|
148
183
|
}
|
|
149
184
|
set model(model: string | undefined) {
|
|
150
|
-
if (model !== this.
|
|
151
|
-
this.
|
|
185
|
+
if (model !== this._model) {
|
|
186
|
+
this._model = model || '';
|
|
152
187
|
this.onStateChanged();
|
|
153
188
|
}
|
|
154
189
|
}
|
|
155
190
|
|
|
156
191
|
get tool_names() {
|
|
157
|
-
return this.
|
|
192
|
+
return this._tool_names;
|
|
158
193
|
}
|
|
159
194
|
set tool_names(tools: string[]) {
|
|
160
|
-
this.
|
|
195
|
+
this._tool_names = tools;
|
|
161
196
|
this.onStateChanged();
|
|
162
197
|
}
|
|
163
198
|
|
|
164
199
|
get data(): JSONObject | undefined {
|
|
165
|
-
return this.
|
|
200
|
+
return this._data;
|
|
166
201
|
}
|
|
167
202
|
set data(prompt_data: JSONObject) {
|
|
168
|
-
this.
|
|
203
|
+
this._data = prompt_data;
|
|
169
204
|
this.onStateChanged();
|
|
170
205
|
}
|
|
171
206
|
|
|
172
|
-
get config() {
|
|
173
|
-
return this.payload.config;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
207
|
set run(run: AsyncExecutionResult | { workflow_id: string; run_id: string }) {
|
|
177
208
|
console.log("run", run);
|
|
178
209
|
this.onStateChanged();
|
|
@@ -214,15 +245,11 @@ export class PayloadBuilder implements ConversationWorkflowPayload {
|
|
|
214
245
|
this._debug_mode = false;
|
|
215
246
|
this._collection = undefined;
|
|
216
247
|
this._preserveRunValues = false;
|
|
217
|
-
this.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
tool_names: [],
|
|
223
|
-
interaction: undefined,
|
|
224
|
-
data: undefined
|
|
225
|
-
};
|
|
248
|
+
this._model = '';
|
|
249
|
+
this._environment = undefined;
|
|
250
|
+
this._tool_names = [];
|
|
251
|
+
this._interaction = undefined;
|
|
252
|
+
this._data = undefined;
|
|
226
253
|
this._interactionParamsSchema = null;
|
|
227
254
|
this._inputValidator = undefined;
|
|
228
255
|
this.model = undefined;
|
|
@@ -250,7 +277,7 @@ export class PayloadBuilder implements ConversationWorkflowPayload {
|
|
|
250
277
|
};
|
|
251
278
|
}
|
|
252
279
|
|
|
253
|
-
const prompt_data = this.
|
|
280
|
+
const prompt_data = this._data || {};
|
|
254
281
|
const isValid = this._inputValidator.validate(prompt_data);
|
|
255
282
|
|
|
256
283
|
if (!isValid) {
|
|
@@ -119,7 +119,7 @@ export default function AllMessagesMixed({
|
|
|
119
119
|
return (
|
|
120
120
|
<div
|
|
121
121
|
ref={containerRef}
|
|
122
|
-
className="flex-1 min-h-0 h-full overflow-y-auto
|
|
122
|
+
className="flex-1 min-h-0 h-full overflow-y-auto px-4 sm:px-2 lg:px-4 flex flex-col relative"
|
|
123
123
|
data-testid="all-messages-mixed"
|
|
124
124
|
>
|
|
125
125
|
|
|
@@ -37,7 +37,7 @@ export default function Header({
|
|
|
37
37
|
}: HeaderProps) {
|
|
38
38
|
return (
|
|
39
39
|
<PayloadBuilderProvider>
|
|
40
|
-
<div className="flex items-
|
|
40
|
+
<div className="flex flex-wrap items-end justify-between py-1.5 px-2 border-b shadow-sm flex-shrink-0">
|
|
41
41
|
<div className="flex flex-wrap items-center space-x-2">
|
|
42
42
|
<div className="flex items-center space-x-1">
|
|
43
43
|
<Bot className="size-5 text-muted" />
|
|
@@ -47,7 +47,7 @@ export default function Header({
|
|
|
47
47
|
(Run ID: {run.runId.substring(0, 8)}...)
|
|
48
48
|
</span>
|
|
49
49
|
</div>
|
|
50
|
-
<div className="flex items-center space-x-2">
|
|
50
|
+
<div className="flex justify-end items-center space-x-2 ml-auto">
|
|
51
51
|
{/* View Mode Toggle */}
|
|
52
52
|
<div className="flex items-center space-x-1 bg-muted rounded p-0.5">
|
|
53
53
|
<Button variant={viewMode === "stacked" ? "outline" : "ghost"} size="xs" className="rounded-l-md" onClick={() => onViewModeChange("stacked")}>
|
|
@@ -62,11 +62,11 @@ export default function WorkstreamTabs({
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
return (
|
|
65
|
-
<div className="flex overflow-x-auto space-x-1 mb-2 border-b-2 border-muted/20 sticky top-0 z-10
|
|
65
|
+
<div className="flex overflow-x-auto space-x-1 mb-2 bg-muted border-b-2 border-muted/20 sticky top-0 z-10">
|
|
66
66
|
{sortedWorkstreams.map(([id, name]) => (
|
|
67
67
|
<button
|
|
68
68
|
key={id}
|
|
69
|
-
className={`px-
|
|
69
|
+
className={`px-2 py-1 text-xs font-medium whitespace-nowrap transition-colors flex items-center gap-1.5
|
|
70
70
|
${activeWorkstream === id
|
|
71
71
|
? "bg-info text-info border-b-2 border-info"
|
|
72
72
|
: "text-muted hover:bg-muted border-b-2 border-transparent"
|
|
@@ -79,7 +79,7 @@ export default function WorkstreamTabs({
|
|
|
79
79
|
{count && count.has(id) && count.get(id)! > 0 && (
|
|
80
80
|
<div className="flex items-center space-x-1">
|
|
81
81
|
<span
|
|
82
|
-
className={`inline-flex items-center justify-center
|
|
82
|
+
className={`inline-flex items-center justify-center p-1 text-xs rounded-full
|
|
83
83
|
${activeWorkstream === id
|
|
84
84
|
? "bg-info text-info"
|
|
85
85
|
: "bg-muted text-muted"
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { json } from "@codemirror/lang-json";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { useMemo, useRef, useState } from "react";
|
|
2
|
+
import { Collection, CreateCollectionPayload, JSONSchemaObject } from "@vertesia/common";
|
|
3
|
+
import { Button, ErrorBox, FormItem, Input, Panel, Styles, Textarea, useFetch, useToast } from "@vertesia/ui/core";
|
|
5
4
|
import { UserInfo } from "@vertesia/ui/features";
|
|
5
|
+
import { SharedPropsEditor } from "@vertesia/ui/features";
|
|
6
|
+
import { SyncMemberHeadsToggle } from "@vertesia/ui/features";
|
|
6
7
|
import { useUserSession } from "@vertesia/ui/session";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
8
|
+
import { CodeMirrorEditor, EditorApi, GeneratedForm, ManagedObject, Node } from "@vertesia/ui/widgets";
|
|
9
|
+
import { basicSetup } from "codemirror";
|
|
10
|
+
import dayjs from "dayjs";
|
|
11
|
+
import { useMemo, useRef, useState } from "react";
|
|
10
12
|
import { SelectContentType, stringifyTableLayout } from "../types";
|
|
11
13
|
|
|
12
14
|
const extensions = [basicSetup, json()];
|
|
@@ -211,7 +213,16 @@ export function EditCollectionView({ refetch, collection }: EditCollectionViewPr
|
|
|
211
213
|
</Panel>
|
|
212
214
|
|
|
213
215
|
{typeId && <PropertiesEditor typeId={typeId} collection={collection} />}
|
|
214
|
-
|
|
216
|
+
{
|
|
217
|
+
!collection.dynamic && (
|
|
218
|
+
<>
|
|
219
|
+
<SyncMemberHeadsToggle collection={collection} />
|
|
220
|
+
<SharedPropsEditor collection={collection} />
|
|
221
|
+
</>
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
</div >
|
|
215
226
|
);
|
|
216
227
|
}
|
|
217
228
|
|
|
@@ -220,6 +231,7 @@ interface PropertiesEditorProps {
|
|
|
220
231
|
collection: Collection;
|
|
221
232
|
}
|
|
222
233
|
function PropertiesEditor({ typeId, collection }: PropertiesEditorProps) {
|
|
234
|
+
const [formData, setFormData] = useState<JSONSchemaObject>({});
|
|
223
235
|
const toast = useToast();
|
|
224
236
|
const { client } = useUserSession();
|
|
225
237
|
const [isUpdating, setIsUpdating] = useState(false);
|
|
@@ -237,7 +249,10 @@ function PropertiesEditor({ typeId, collection }: PropertiesEditorProps) {
|
|
|
237
249
|
}
|
|
238
250
|
|
|
239
251
|
|
|
240
|
-
const _onSave = (data:
|
|
252
|
+
const _onSave = (data: JSONSchemaObject) => {
|
|
253
|
+
if (!data || !Object.keys(data).length) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
241
256
|
const payload = { properties: data || {} };
|
|
242
257
|
setIsUpdating(true);
|
|
243
258
|
client.store.collections
|
|
@@ -263,13 +278,19 @@ function PropertiesEditor({ typeId, collection }: PropertiesEditorProps) {
|
|
|
263
278
|
});
|
|
264
279
|
};
|
|
265
280
|
|
|
281
|
+
const onDataChanged = (data: Node) => {
|
|
282
|
+
if (data instanceof ManagedObject) {
|
|
283
|
+
setFormData(data.value);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
266
287
|
return (
|
|
267
288
|
<Panel title="Properties" action={
|
|
268
|
-
<Button size="lg" isLoading={isUpdating} type="submit">
|
|
289
|
+
<Button size="lg" isLoading={isUpdating} type="submit" onClick={() => _onSave(formData)}>
|
|
269
290
|
Save
|
|
270
291
|
</Button>}
|
|
271
292
|
>
|
|
272
|
-
<GeneratedForm object={object}
|
|
293
|
+
<GeneratedForm object={object} onChange={onDataChanged} />
|
|
273
294
|
</Panel>
|
|
274
295
|
);
|
|
275
296
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Collection, ContentObjectType } from "@vertesia/common";
|
|
2
|
+
import { Button, Panel, useToast } from "@vertesia/ui/core";
|
|
3
|
+
import { TagsInput } from "@vertesia/ui/core";
|
|
4
|
+
import { useUserSession } from "@vertesia/ui/session";
|
|
5
|
+
import { useEffect, useState } from "react";
|
|
6
|
+
|
|
7
|
+
interface SharedPropsEditorProps {
|
|
8
|
+
collection: Collection;
|
|
9
|
+
}
|
|
10
|
+
export function SharedPropsEditor({ collection }: SharedPropsEditorProps) {
|
|
11
|
+
|
|
12
|
+
const { client } = useUserSession();
|
|
13
|
+
const [colType, setColType] = useState<ContentObjectType | undefined>(undefined);
|
|
14
|
+
const [sharedProps, setSharedProps] = useState<string[]>(collection.shared_properties || []);
|
|
15
|
+
const toast = useToast();
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (collection.type?.id) {
|
|
19
|
+
client.store.types.retrieve(collection.type.id).then(setColType);
|
|
20
|
+
}
|
|
21
|
+
}, [collection.type?.id]);
|
|
22
|
+
|
|
23
|
+
const options: string[] = colType ? Object.keys(colType.object_schema?.properties || {}) : [];
|
|
24
|
+
|
|
25
|
+
const onSelect = (selected: string[]) => {
|
|
26
|
+
setSharedProps(selected);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const onSave = () => {
|
|
30
|
+
client.store.collections.update(collection.id, {
|
|
31
|
+
shared_properties: sharedProps
|
|
32
|
+
}).then(() => {
|
|
33
|
+
// Handle success
|
|
34
|
+
toast({
|
|
35
|
+
title: "Updated shared properties",
|
|
36
|
+
status: "success"
|
|
37
|
+
})
|
|
38
|
+
}).catch((error) => {
|
|
39
|
+
toast({
|
|
40
|
+
title: "Failed to update shared properties",
|
|
41
|
+
description: error.message,
|
|
42
|
+
status: "error"
|
|
43
|
+
})
|
|
44
|
+
// Handle error
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Panel title="Shared Properties" description="Add properties to share across all members in the collection. This feature requires to enable shared property synchronization on the project."
|
|
50
|
+
action={
|
|
51
|
+
<Button size="lg" isLoading={false} onClick={onSave}>
|
|
52
|
+
Save
|
|
53
|
+
</Button>}
|
|
54
|
+
>
|
|
55
|
+
<div className=''>
|
|
56
|
+
<TagsInput value={sharedProps} onChange={onSelect} options={options} placeholder="Select properties to share" />
|
|
57
|
+
</div>
|
|
58
|
+
</Panel>
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Collection } from "@vertesia/common";
|
|
2
|
+
import { Panel, Switch, useToast } from "@vertesia/ui/core";
|
|
3
|
+
import { useUserSession } from "@vertesia/ui/session";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
|
|
6
|
+
interface SyncMemberHeadsToggleProps {
|
|
7
|
+
collection: Collection;
|
|
8
|
+
}
|
|
9
|
+
export function SyncMemberHeadsToggle({ collection }: SyncMemberHeadsToggleProps) {
|
|
10
|
+
|
|
11
|
+
const { client } = useUserSession();
|
|
12
|
+
const [skipHeadSync, setSkipHeadSync] = useState<boolean>(collection.skip_head_sync ?? false);
|
|
13
|
+
const [isSaving, setIsSaving] = useState<boolean>(false);
|
|
14
|
+
const toast = useToast();
|
|
15
|
+
|
|
16
|
+
const onSaveSkipHeadSync = (enableSyncHeads: boolean) => {
|
|
17
|
+
const skip_head_sync = !enableSyncHeads;
|
|
18
|
+
setIsSaving(true);
|
|
19
|
+
client.store.collections.update(collection.id, {
|
|
20
|
+
skip_head_sync: skip_head_sync
|
|
21
|
+
}).then(() => {
|
|
22
|
+
// Handle success
|
|
23
|
+
toast({
|
|
24
|
+
title: "Updated skip head sync setting",
|
|
25
|
+
status: "success"
|
|
26
|
+
})
|
|
27
|
+
setSkipHeadSync(skip_head_sync);
|
|
28
|
+
}).catch((error) => {
|
|
29
|
+
toast({
|
|
30
|
+
title: "Failed to update skip head sync",
|
|
31
|
+
description: error.message,
|
|
32
|
+
status: "error"
|
|
33
|
+
})
|
|
34
|
+
// Handle error
|
|
35
|
+
}).finally(() => {
|
|
36
|
+
setIsSaving(false);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Panel title="Synchronize Member Heads" description="When a new HEAD version of a member is created the colleciton will be updated to point to the new HEAD.">
|
|
42
|
+
<Switch disabled={isSaving} value={!skipHeadSync} onChange={onSaveSkipHeadSync}>
|
|
43
|
+
Enable synchronizing member heads
|
|
44
|
+
</Switch>
|
|
45
|
+
</Panel>
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
}
|
|
@@ -2,4 +2,6 @@ export * from "./BrowseCollectionView";
|
|
|
2
2
|
export * from "./CollectionsTable";
|
|
3
3
|
export * from "./EditCollectionView";
|
|
4
4
|
export * from "./CreateCollection";
|
|
5
|
-
export * from "./SelectCollection";
|
|
5
|
+
export * from "./SelectCollection";
|
|
6
|
+
export * from "./SharedPropsEditor";
|
|
7
|
+
export * from "./SyncMemberHeadsToggle";
|
|
@@ -27,7 +27,13 @@ const defaultLayout: ColumnLayout[] = [
|
|
|
27
27
|
|
|
28
28
|
function getTableLayout(registry: TypeRegistry, type: string | undefined): ColumnLayout[] {
|
|
29
29
|
const layout = type ? registry.getTypeLayout(type) : defaultLayout;
|
|
30
|
-
|
|
30
|
+
console.log('[DEBUG] getTableLayout called with type:', type);
|
|
31
|
+
console.log('[DEBUG] Layout from registry:', layout);
|
|
32
|
+
console.log('[DEBUG] Using defaultLayout?', layout === defaultLayout);
|
|
33
|
+
const result = layout ?? defaultLayout;
|
|
34
|
+
console.log('[DEBUG] Final layout:', result);
|
|
35
|
+
console.log('[DEBUG] Has Status field?', result.some(col => col.field === 'status'));
|
|
36
|
+
return result;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
interface DocumentSearchResultsWithDropZoneProps {
|
|
@@ -94,6 +100,9 @@ export function DocumentSearchResults({ layout, onUpload, allowFilter = true, al
|
|
|
94
100
|
const [actualLayout, setActualLayout] = useState<ColumnLayout[]>(
|
|
95
101
|
typeRegistry ? layout || getTableLayout(typeRegistry, search.query.type) : defaultLayout,
|
|
96
102
|
);
|
|
103
|
+
|
|
104
|
+
console.log('[DEBUG] DocumentSearchResults - actualLayout:', actualLayout);
|
|
105
|
+
console.log('[DEBUG] DocumentSearchResults - actualLayout has Status?', actualLayout.some(col => col.field === 'status'));
|
|
97
106
|
//TODO _setRefreshTrigger state not used
|
|
98
107
|
const [refreshTrigger, _setRefreshTrigger] = useState(0);
|
|
99
108
|
const [loaded, setLoaded] = useState(0);
|
|
@@ -344,7 +353,7 @@ function OverviewDrawer({ object, onClose }: OverviewDrawerProps) {
|
|
|
344
353
|
const { store } = useUserSession();
|
|
345
354
|
const toast = useToast();
|
|
346
355
|
const navigate = useNavigate();
|
|
347
|
-
const onDownload = useDownloadDocument(store, toast, object?.content?.source);
|
|
356
|
+
const onDownload = useDownloadDocument(store, toast, object?.content?.source, object?.name || object?.content?.name);
|
|
348
357
|
|
|
349
358
|
return object ? (
|
|
350
359
|
<SidePanel title={object.properties?.title || object.name} isOpen={true} onClose={onClose}>
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { VertesiaClient, ZenoClient } from "@vertesia/client";
|
|
2
2
|
import { ToastFn } from "@vertesia/ui/core";
|
|
3
3
|
|
|
4
|
-
export function useDownloadDocument(
|
|
4
|
+
export function useDownloadDocument(
|
|
5
|
+
client: VertesiaClient | ZenoClient,
|
|
6
|
+
toast: ToastFn,
|
|
7
|
+
uri: string | undefined,
|
|
8
|
+
name?: string,
|
|
9
|
+
) {
|
|
5
10
|
const onDownload = () => {
|
|
6
11
|
if (uri) {
|
|
7
12
|
client.files
|
|
8
|
-
.
|
|
13
|
+
.getDownloadUrlWithOptions({ file: uri, name })
|
|
9
14
|
.then((r) => {
|
|
10
15
|
window.open(r.url, "_blank");
|
|
11
16
|
})
|
|
@@ -181,9 +181,7 @@ export function useSmartFileUploadProcessing() {
|
|
|
181
181
|
queries.push(res);
|
|
182
182
|
} else {
|
|
183
183
|
const res = client.store.objects.find({
|
|
184
|
-
query:
|
|
185
|
-
match: query,
|
|
186
|
-
},
|
|
184
|
+
query: query,
|
|
187
185
|
select: "id content.name location" // Only fetch fields needed for comparison
|
|
188
186
|
});
|
|
189
187
|
queries.push(res);
|
|
@@ -125,6 +125,8 @@ export function UserInfo({ userRef, showTitle = false, size = "md" }: UserInfoPr
|
|
|
125
125
|
return <SystemAvatar showTitle={showTitle} size={size} />
|
|
126
126
|
case PrincipalType.ServiceAccount:
|
|
127
127
|
return <ServiceAccountAvatar accountId={id} showTitle={showTitle} size={size} />
|
|
128
|
+
case PrincipalType.Agent:
|
|
129
|
+
return <ServiceAccountAvatar accountId={id} showTitle={showTitle} size={size} />
|
|
128
130
|
case PrincipalType.ApiKey:
|
|
129
131
|
return <ApiKeyAvatar keyId={id} size={size} showTitle={showTitle} />
|
|
130
132
|
default:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { onAuthStateChanged } from "firebase/auth";
|
|
2
|
-
import { ReactNode, useEffect, useState } from "react";
|
|
2
|
+
import { ReactNode, useEffect, useRef, useState } from "react";
|
|
3
3
|
import { UserNotFoundError, getComposableToken } from "./auth/composable";
|
|
4
4
|
import { getFirebaseAuth } from "./auth/firebase";
|
|
5
5
|
import { useAuthState } from "./auth/useAuthState";
|
|
@@ -27,9 +27,10 @@ export function UserSessionProvider({ children }: UserSessionProviderProps) {
|
|
|
27
27
|
const state = hashParams.get("state");
|
|
28
28
|
const [session, setSession] = useState<UserSession>(new UserSession());
|
|
29
29
|
const { generateState, verifyState, clearState } = useAuthState();
|
|
30
|
+
const hasInitiatedAuthRef = useRef(false);
|
|
30
31
|
|
|
31
32
|
const redirectToCentralAuth = (projectId?: string, accountId?: string) => {
|
|
32
|
-
const url = new URL(CENTRAL_AUTH_REDIRECT);
|
|
33
|
+
const url = new URL(`${CENTRAL_AUTH_REDIRECT}?sts=${Env.endpoints.sts ?? "https://sts.vertesia.io"}`);
|
|
33
34
|
const currentUrl = new URL(window.location.href);
|
|
34
35
|
currentUrl.hash = "";
|
|
35
36
|
if (projectId) currentUrl.searchParams.set("p", projectId);
|
|
@@ -40,6 +41,13 @@ export function UserSessionProvider({ children }: UserSessionProviderProps) {
|
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
useEffect(() => {
|
|
44
|
+
// Make this effect idempotent - only run auth flow once
|
|
45
|
+
if (hasInitiatedAuthRef.current) {
|
|
46
|
+
console.log("Auth: skipping duplicate auth flow initiation");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
hasInitiatedAuthRef.current = true;
|
|
50
|
+
|
|
43
51
|
console.log("Auth: starting auth flow");
|
|
44
52
|
Env.logger.info("Starting auth flow");
|
|
45
53
|
const currentUrl = new URL(window.location.href);
|