@tutti-os/workspace-app-center 0.0.43 → 0.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TEGNWC7E.js → chunk-N4YVSUX5.js} +17 -2
- package/dist/{chunk-TEGNWC7E.js.map → chunk-N4YVSUX5.js.map} +1 -1
- package/dist/contracts/index.d.ts +22 -0
- package/dist/core/index.js +1 -1
- package/dist/i18n/index.js +12 -0
- package/dist/i18n/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/ui/index.d.ts +5 -1
- package/dist/ui/index.js +263 -25
- package/dist/ui/index.js.map +1 -1
- package/package.json +3 -3
package/dist/ui/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "../chunk-DXJSCFY7.js";
|
|
8
8
|
|
|
9
9
|
// src/ui/AppCard.tsx
|
|
10
|
-
import { memo, useCallback, useMemo } from "react";
|
|
10
|
+
import { memo, useCallback, useMemo, useRef, useState } from "react";
|
|
11
11
|
import {
|
|
12
12
|
Button,
|
|
13
13
|
ChatIcon,
|
|
@@ -19,8 +19,12 @@ import {
|
|
|
19
19
|
DropdownMenuItem,
|
|
20
20
|
DropdownMenuTrigger,
|
|
21
21
|
FolderIcon,
|
|
22
|
+
GitHubBrandIcon,
|
|
22
23
|
MoreHorizontalIcon,
|
|
23
24
|
NavApplicationsFilledIcon,
|
|
25
|
+
Popover,
|
|
26
|
+
PopoverContent,
|
|
27
|
+
PopoverTrigger,
|
|
24
28
|
RefreshIcon,
|
|
25
29
|
UninstallIcon,
|
|
26
30
|
UploadIcon,
|
|
@@ -31,7 +35,9 @@ var AppCard = memo(function AppCard2({
|
|
|
31
35
|
actions,
|
|
32
36
|
app,
|
|
33
37
|
className,
|
|
34
|
-
copy
|
|
38
|
+
copy,
|
|
39
|
+
officialDeveloperIconUrl = null,
|
|
40
|
+
showDeveloperSources = false
|
|
35
41
|
}) {
|
|
36
42
|
const statusLabel = copy.t(app.statusLabelKey);
|
|
37
43
|
const installBusy = app.installProgress != null || app.status === "installing";
|
|
@@ -173,7 +179,15 @@ var AppCard = memo(function AppCard2({
|
|
|
173
179
|
title: app.errorMessage,
|
|
174
180
|
children: copy.t("messages.appRuntimeFailed")
|
|
175
181
|
}
|
|
176
|
-
) }) : null
|
|
182
|
+
) }) : null,
|
|
183
|
+
showDeveloperSources ? /* @__PURE__ */ jsx(
|
|
184
|
+
AppDeveloperSourceRow,
|
|
185
|
+
{
|
|
186
|
+
app,
|
|
187
|
+
copy,
|
|
188
|
+
officialDeveloperIconUrl
|
|
189
|
+
}
|
|
190
|
+
) : null
|
|
177
191
|
] })
|
|
178
192
|
]
|
|
179
193
|
}
|
|
@@ -186,6 +200,214 @@ function createWorkspaceAppActionContext(app) {
|
|
|
186
200
|
launchUrl: app.launchUrl ?? null
|
|
187
201
|
};
|
|
188
202
|
}
|
|
203
|
+
function AppDeveloperSourceRow({
|
|
204
|
+
app,
|
|
205
|
+
copy,
|
|
206
|
+
officialDeveloperIconUrl
|
|
207
|
+
}) {
|
|
208
|
+
const sourceAuthors = app.authors ?? [];
|
|
209
|
+
const repository = app.repository ?? null;
|
|
210
|
+
const authors = sourceAuthors.length > 0 ? sourceAuthors : app.sourceKind === "bundled" ? [{ name: "Tutti" }] : [];
|
|
211
|
+
const [popoverOpen, setPopoverOpen] = useState(false);
|
|
212
|
+
const closeTimerRef = useRef(null);
|
|
213
|
+
const clearCloseTimer = useCallback(() => {
|
|
214
|
+
if (closeTimerRef.current === null) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
window.clearTimeout(closeTimerRef.current);
|
|
218
|
+
closeTimerRef.current = null;
|
|
219
|
+
}, []);
|
|
220
|
+
const openPopover = useCallback(() => {
|
|
221
|
+
clearCloseTimer();
|
|
222
|
+
setPopoverOpen(true);
|
|
223
|
+
}, [clearCloseTimer]);
|
|
224
|
+
const scheduleClosePopover = useCallback(() => {
|
|
225
|
+
clearCloseTimer();
|
|
226
|
+
closeTimerRef.current = window.setTimeout(() => {
|
|
227
|
+
setPopoverOpen(false);
|
|
228
|
+
closeTimerRef.current = null;
|
|
229
|
+
}, 120);
|
|
230
|
+
}, [clearCloseTimer]);
|
|
231
|
+
if (authors.length === 0 && repository === null) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
const primaryAuthor = authors[0] ?? null;
|
|
235
|
+
const rowLabel = authors.length > 1 ? copy.t("sources.developerCount", { count: String(authors.length) }) : primaryAuthor?.name || (repository ? copy.t("sources.githubRepository") : "");
|
|
236
|
+
const official = isOfficialAuthor(primaryAuthor?.name);
|
|
237
|
+
const canOpenPopover = repository !== null || authors.some((author) => Boolean(author.url));
|
|
238
|
+
const content = /* @__PURE__ */ jsx("div", { className: "mt-auto min-w-0 pt-3", children: /* @__PURE__ */ jsxs("div", { className: "group/source flex min-h-7 min-w-0 items-center gap-2 border-t border-[color:var(--line-2)] pt-2 text-[12px] leading-4 text-[var(--text-secondary)]", children: [
|
|
239
|
+
/* @__PURE__ */ jsx(
|
|
240
|
+
AvatarStack,
|
|
241
|
+
{
|
|
242
|
+
authors,
|
|
243
|
+
fallbackIconUrl: official ? officialDeveloperIconUrl : null
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: rowLabel }),
|
|
247
|
+
official ? /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-[5px] border border-[color:var(--line-2)] px-1.5 py-0 text-[10px] font-medium leading-4 text-[var(--text-secondary)]", children: copy.t("sources.official") }) : null,
|
|
248
|
+
canOpenPopover ? /* @__PURE__ */ jsxs("span", { className: "flex size-5 shrink-0 items-center justify-center text-[var(--text-secondary)]", children: [
|
|
249
|
+
/* @__PURE__ */ jsx(GitHubBrandIcon, { className: "size-4 group-hover/source:hidden" }),
|
|
250
|
+
/* @__PURE__ */ jsx(
|
|
251
|
+
"span",
|
|
252
|
+
{
|
|
253
|
+
"aria-hidden": "true",
|
|
254
|
+
className: "hidden text-[18px] leading-none group-hover/source:block",
|
|
255
|
+
children: "\u203A"
|
|
256
|
+
}
|
|
257
|
+
)
|
|
258
|
+
] }) : null
|
|
259
|
+
] }) });
|
|
260
|
+
if (!canOpenPopover) {
|
|
261
|
+
return content;
|
|
262
|
+
}
|
|
263
|
+
return /* @__PURE__ */ jsxs(Popover, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [
|
|
264
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
265
|
+
"button",
|
|
266
|
+
{
|
|
267
|
+
className: "block w-full min-w-0 border-0 bg-transparent p-0 text-left",
|
|
268
|
+
type: "button",
|
|
269
|
+
onClick: (event) => {
|
|
270
|
+
event.stopPropagation();
|
|
271
|
+
},
|
|
272
|
+
onPointerEnter: openPopover,
|
|
273
|
+
onPointerLeave: scheduleClosePopover,
|
|
274
|
+
onPointerDown: (event) => {
|
|
275
|
+
event.stopPropagation();
|
|
276
|
+
},
|
|
277
|
+
children: content
|
|
278
|
+
}
|
|
279
|
+
) }),
|
|
280
|
+
/* @__PURE__ */ jsxs(
|
|
281
|
+
PopoverContent,
|
|
282
|
+
{
|
|
283
|
+
align: "start",
|
|
284
|
+
className: "w-[280px] max-w-[min(280px,calc(100vw-32px))]",
|
|
285
|
+
collisionPadding: 12,
|
|
286
|
+
side: "bottom",
|
|
287
|
+
style: { zIndex: "var(--z-panel-popover)" },
|
|
288
|
+
onPointerEnter: openPopover,
|
|
289
|
+
onPointerLeave: scheduleClosePopover,
|
|
290
|
+
onCloseAutoFocus: (event) => {
|
|
291
|
+
event.preventDefault();
|
|
292
|
+
},
|
|
293
|
+
onClick: (event) => {
|
|
294
|
+
event.stopPropagation();
|
|
295
|
+
},
|
|
296
|
+
onOpenAutoFocus: (event) => {
|
|
297
|
+
event.preventDefault();
|
|
298
|
+
},
|
|
299
|
+
onPointerDown: (event) => {
|
|
300
|
+
event.stopPropagation();
|
|
301
|
+
},
|
|
302
|
+
onKeyDown: (event) => {
|
|
303
|
+
event.stopPropagation();
|
|
304
|
+
},
|
|
305
|
+
children: [
|
|
306
|
+
/* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-[12px] font-semibold leading-4 text-[var(--text-primary)]", children: copy.t("sources.title") }),
|
|
307
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-[2px]", children: [
|
|
308
|
+
authors.map((author, index) => /* @__PURE__ */ jsxs(
|
|
309
|
+
"button",
|
|
310
|
+
{
|
|
311
|
+
className: "flex min-h-8 min-w-0 items-center gap-2 rounded-[6px] px-2 py-1 text-left text-[12px] font-normal leading-4 text-[var(--text-primary)] hover:bg-[var(--transparency-hover)] disabled:cursor-default disabled:opacity-60",
|
|
312
|
+
disabled: !author.url,
|
|
313
|
+
type: "button",
|
|
314
|
+
onClick: (event) => {
|
|
315
|
+
event.stopPropagation();
|
|
316
|
+
openExternalURL(author.url);
|
|
317
|
+
},
|
|
318
|
+
children: [
|
|
319
|
+
/* @__PURE__ */ jsx(
|
|
320
|
+
AuthorAvatar,
|
|
321
|
+
{
|
|
322
|
+
author,
|
|
323
|
+
fallbackIconUrl: index === 0 && isOfficialAuthor(author.name) ? officialDeveloperIconUrl : null
|
|
324
|
+
}
|
|
325
|
+
),
|
|
326
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: author.name })
|
|
327
|
+
]
|
|
328
|
+
},
|
|
329
|
+
`${author.name}:${author.url ?? ""}`
|
|
330
|
+
)),
|
|
331
|
+
repository ? /* @__PURE__ */ jsxs(
|
|
332
|
+
"button",
|
|
333
|
+
{
|
|
334
|
+
className: "flex min-h-8 min-w-0 items-center gap-2 rounded-[6px] px-2 py-1 text-left text-[12px] font-normal leading-4 text-[var(--text-primary)] hover:bg-[var(--transparency-hover)]",
|
|
335
|
+
type: "button",
|
|
336
|
+
onClick: (event) => {
|
|
337
|
+
event.stopPropagation();
|
|
338
|
+
openExternalURL(repository.url);
|
|
339
|
+
},
|
|
340
|
+
children: [
|
|
341
|
+
/* @__PURE__ */ jsx(GitHubBrandIcon, { className: "size-4" }),
|
|
342
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: displayRepositoryURL(repository.url) })
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
) : null
|
|
346
|
+
] })
|
|
347
|
+
]
|
|
348
|
+
}
|
|
349
|
+
)
|
|
350
|
+
] });
|
|
351
|
+
}
|
|
352
|
+
function AvatarStack({
|
|
353
|
+
authors,
|
|
354
|
+
fallbackIconUrl
|
|
355
|
+
}) {
|
|
356
|
+
const visibleAuthors = authors.slice(0, 2);
|
|
357
|
+
if (visibleAuthors.length === 0) {
|
|
358
|
+
return /* @__PURE__ */ jsx("span", { className: "flex size-5 shrink-0 items-center justify-center rounded-full bg-[var(--transparency-block)]", children: /* @__PURE__ */ jsx(GitHubBrandIcon, { className: "size-3.5" }) });
|
|
359
|
+
}
|
|
360
|
+
return /* @__PURE__ */ jsx("span", { className: "flex shrink-0 -space-x-1", children: visibleAuthors.map((author, index) => /* @__PURE__ */ jsx(
|
|
361
|
+
AuthorAvatar,
|
|
362
|
+
{
|
|
363
|
+
author,
|
|
364
|
+
fallbackIconUrl: index === 0 ? fallbackIconUrl : null
|
|
365
|
+
},
|
|
366
|
+
`${author.name}:${author.url ?? ""}`
|
|
367
|
+
)) });
|
|
368
|
+
}
|
|
369
|
+
function AuthorAvatar({
|
|
370
|
+
author,
|
|
371
|
+
fallbackIconUrl
|
|
372
|
+
}) {
|
|
373
|
+
if (author.avatarUrl) {
|
|
374
|
+
return /* @__PURE__ */ jsx(
|
|
375
|
+
"img",
|
|
376
|
+
{
|
|
377
|
+
alt: "",
|
|
378
|
+
className: "size-5 shrink-0 rounded-full border border-[var(--background-fronted)] object-cover",
|
|
379
|
+
draggable: false,
|
|
380
|
+
src: author.avatarUrl
|
|
381
|
+
}
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
if (fallbackIconUrl) {
|
|
385
|
+
return /* @__PURE__ */ jsx(
|
|
386
|
+
"img",
|
|
387
|
+
{
|
|
388
|
+
alt: "",
|
|
389
|
+
className: "size-5 shrink-0 rounded-[5px] border border-[var(--background-fronted)] object-contain",
|
|
390
|
+
draggable: false,
|
|
391
|
+
src: fallbackIconUrl
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
return /* @__PURE__ */ jsx("span", { className: "flex size-5 shrink-0 items-center justify-center rounded-full border border-[var(--background-fronted)] bg-[var(--transparency-block)] text-[10px] font-semibold uppercase text-[var(--text-secondary)]", children: author.name.slice(0, 1) });
|
|
396
|
+
}
|
|
397
|
+
function isOfficialAuthor(name) {
|
|
398
|
+
const normalized = name?.trim().toLowerCase() ?? "";
|
|
399
|
+
return normalized === "tutti" || normalized === "tutti official";
|
|
400
|
+
}
|
|
401
|
+
function displayRepositoryURL(url) {
|
|
402
|
+
return url.replace(/^https?:\/\//u, "");
|
|
403
|
+
}
|
|
404
|
+
function openExternalURL(url) {
|
|
405
|
+
const target = url?.trim();
|
|
406
|
+
if (!target) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
window.open(target, "_blank", "noopener,noreferrer");
|
|
410
|
+
}
|
|
189
411
|
function AppCardMoreActions({
|
|
190
412
|
actions,
|
|
191
413
|
app,
|
|
@@ -501,7 +723,7 @@ function statusClassName(status) {
|
|
|
501
723
|
}
|
|
502
724
|
|
|
503
725
|
// src/ui/AppCenterPanel.tsx
|
|
504
|
-
import { useEffect, useId, useMemo as useMemo2, useState } from "react";
|
|
726
|
+
import { useEffect, useId, useMemo as useMemo2, useState as useState2 } from "react";
|
|
505
727
|
import {
|
|
506
728
|
Badge,
|
|
507
729
|
BareIconButton,
|
|
@@ -592,29 +814,31 @@ function AppCenterPanel({
|
|
|
592
814
|
errorMessage,
|
|
593
815
|
loadProviderConfiguration,
|
|
594
816
|
onActiveAppTabChange,
|
|
817
|
+
officialDeveloperIconUrl = null,
|
|
595
818
|
providerErrorMessage = null,
|
|
596
819
|
providerLoading = false,
|
|
597
820
|
providerOptions = [],
|
|
821
|
+
showDeveloperSources = false,
|
|
598
822
|
viewModel
|
|
599
823
|
}) {
|
|
600
824
|
const promptTextareaId = useId();
|
|
601
|
-
const [factoryDialogOpen, setFactoryDialogOpen] =
|
|
602
|
-
const [deleteAppBusy, setDeleteAppBusy] =
|
|
603
|
-
const [pendingDeleteApp, setPendingDeleteApp] =
|
|
604
|
-
const [uninstallAppBusy, setUninstallAppBusy] =
|
|
605
|
-
const [pendingUninstallApp, setPendingUninstallApp] =
|
|
606
|
-
const [pendingLocalRepairRequest, setPendingLocalRepairRequest] =
|
|
607
|
-
const [updateAppBusy, setUpdateAppBusy] =
|
|
608
|
-
const [localRepairBusy, setLocalRepairBusy] =
|
|
609
|
-
const [pendingUpdateApp, setPendingUpdateApp] =
|
|
610
|
-
const [displayName, setDisplayName] =
|
|
611
|
-
const [prompt, setPrompt] =
|
|
612
|
-
const [providerConfiguration, setProviderConfiguration] =
|
|
613
|
-
const [providerConfigurationStatus, setProviderConfigurationStatus] =
|
|
614
|
-
const [openFactorySettingsMenu, setOpenFactorySettingsMenu] =
|
|
615
|
-
const [selectedModel, setSelectedModel] =
|
|
616
|
-
const [selectedPermissionModeId, setSelectedPermissionModeId] =
|
|
617
|
-
const [selectedReasoningEffort, setSelectedReasoningEffort] =
|
|
825
|
+
const [factoryDialogOpen, setFactoryDialogOpen] = useState2(false);
|
|
826
|
+
const [deleteAppBusy, setDeleteAppBusy] = useState2(false);
|
|
827
|
+
const [pendingDeleteApp, setPendingDeleteApp] = useState2(null);
|
|
828
|
+
const [uninstallAppBusy, setUninstallAppBusy] = useState2(false);
|
|
829
|
+
const [pendingUninstallApp, setPendingUninstallApp] = useState2(null);
|
|
830
|
+
const [pendingLocalRepairRequest, setPendingLocalRepairRequest] = useState2(null);
|
|
831
|
+
const [updateAppBusy, setUpdateAppBusy] = useState2(false);
|
|
832
|
+
const [localRepairBusy, setLocalRepairBusy] = useState2(false);
|
|
833
|
+
const [pendingUpdateApp, setPendingUpdateApp] = useState2(null);
|
|
834
|
+
const [displayName, setDisplayName] = useState2("");
|
|
835
|
+
const [prompt, setPrompt] = useState2("");
|
|
836
|
+
const [providerConfiguration, setProviderConfiguration] = useState2(null);
|
|
837
|
+
const [providerConfigurationStatus, setProviderConfigurationStatus] = useState2("idle");
|
|
838
|
+
const [openFactorySettingsMenu, setOpenFactorySettingsMenu] = useState2(null);
|
|
839
|
+
const [selectedModel, setSelectedModel] = useState2("");
|
|
840
|
+
const [selectedPermissionModeId, setSelectedPermissionModeId] = useState2("");
|
|
841
|
+
const [selectedReasoningEffort, setSelectedReasoningEffort] = useState2("");
|
|
618
842
|
const normalizedProviderOptions = useMemo2(
|
|
619
843
|
() => providerOptions.map((option) => {
|
|
620
844
|
const provider = option.provider.trim();
|
|
@@ -632,14 +856,14 @@ function AppCenterPanel({
|
|
|
632
856
|
}).filter((option) => option != null),
|
|
633
857
|
[providerOptions]
|
|
634
858
|
);
|
|
635
|
-
const [selectedProvider, setSelectedProvider] =
|
|
859
|
+
const [selectedProvider, setSelectedProvider] = useState2(
|
|
636
860
|
() => resolveDefaultAppFactoryProvider(
|
|
637
861
|
normalizedProviderOptions,
|
|
638
862
|
defaultAgentProvider
|
|
639
863
|
)
|
|
640
864
|
);
|
|
641
|
-
const [uncontrolledActiveAppTab, setUncontrolledActiveAppTab] =
|
|
642
|
-
const [activeRecommendedCategoryTab, setActiveRecommendedCategoryTab] =
|
|
865
|
+
const [uncontrolledActiveAppTab, setUncontrolledActiveAppTab] = useState2("recommended");
|
|
866
|
+
const [activeRecommendedCategoryTab, setActiveRecommendedCategoryTab] = useState2("all");
|
|
643
867
|
const activeAppTab = controlledActiveAppTab ?? uncontrolledActiveAppTab;
|
|
644
868
|
useEffect(() => {
|
|
645
869
|
setSelectedProvider(
|
|
@@ -1086,6 +1310,8 @@ function AppCenterPanel({
|
|
|
1086
1310
|
apps: activeApps,
|
|
1087
1311
|
copy,
|
|
1088
1312
|
emptyMessage: activeAppEmptyMessage,
|
|
1313
|
+
officialDeveloperIconUrl,
|
|
1314
|
+
showDeveloperSources,
|
|
1089
1315
|
title: activeAppTabTitle
|
|
1090
1316
|
}
|
|
1091
1317
|
)
|
|
@@ -1630,6 +1856,8 @@ function AppCardGrid({
|
|
|
1630
1856
|
apps,
|
|
1631
1857
|
copy,
|
|
1632
1858
|
emptyMessage,
|
|
1859
|
+
officialDeveloperIconUrl,
|
|
1860
|
+
showDeveloperSources,
|
|
1633
1861
|
title
|
|
1634
1862
|
}) {
|
|
1635
1863
|
if (apps.length === 0) {
|
|
@@ -1650,7 +1878,17 @@ function AppCardGrid({
|
|
|
1650
1878
|
"aria-label": title,
|
|
1651
1879
|
className: "grid min-h-0 min-w-0 grid-cols-[repeat(auto-fill,minmax(min(100%,260px),1fr))] gap-3",
|
|
1652
1880
|
role: "list",
|
|
1653
|
-
children: apps.map((app) => /* @__PURE__ */ jsx2(
|
|
1881
|
+
children: apps.map((app) => /* @__PURE__ */ jsx2(
|
|
1882
|
+
AppCard,
|
|
1883
|
+
{
|
|
1884
|
+
actions,
|
|
1885
|
+
app,
|
|
1886
|
+
copy,
|
|
1887
|
+
officialDeveloperIconUrl,
|
|
1888
|
+
showDeveloperSources
|
|
1889
|
+
},
|
|
1890
|
+
app.id
|
|
1891
|
+
))
|
|
1654
1892
|
}
|
|
1655
1893
|
),
|
|
1656
1894
|
/* @__PURE__ */ jsx2("div", { "aria-hidden": "true", className: "h-6 shrink-0" })
|