@fungi.computer/tourtois 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +127 -2
- package/dist/AgentMcpServers.d.ts +34 -0
- package/dist/AgentMcpServers.js +124 -0
- package/dist/AppAccessConsent.d.ts +23 -0
- package/dist/AppAccessConsent.js +122 -0
- package/dist/AppCallPermissions.d.ts +9 -0
- package/dist/AppCallPermissions.js +21 -0
- package/dist/AppDesktopSettings.d.ts +11 -0
- package/dist/AppDesktopSettings.js +102 -0
- package/dist/AppPane.d.ts +37 -0
- package/dist/AppPane.js +184 -0
- package/dist/AppWorkbench.d.ts +44 -0
- package/dist/AppWorkbench.js +575 -0
- package/dist/AvatarPicker.d.ts +7 -0
- package/dist/AvatarPicker.js +78 -0
- package/dist/AvatarPreview.d.ts +10 -0
- package/dist/AvatarPreview.js +6 -0
- package/dist/DesktopMenuBar.d.ts +18 -0
- package/dist/DesktopMenuBar.js +23 -0
- package/dist/FocusedAppMenus.d.ts +2 -0
- package/dist/FocusedAppMenus.js +10 -0
- package/dist/Keys.d.ts +131 -0
- package/dist/Keys.js +201 -0
- package/dist/MushroomMark.d.ts +2 -0
- package/dist/MushroomMark.js +5 -0
- package/dist/SettingsHome.d.ts +18 -0
- package/dist/SettingsHome.js +48 -0
- package/dist/SettingsNavigation.d.ts +17 -0
- package/dist/SettingsNavigation.js +153 -0
- package/dist/SystemSettings.d.ts +24 -0
- package/dist/SystemSettings.js +177 -0
- package/dist/TeamDesktop.d.ts +36 -0
- package/dist/TeamDesktop.js +39 -0
- package/dist/WorkbenchAppBar.d.ts +5 -0
- package/dist/WorkbenchAppBar.js +12 -0
- package/dist/app-authority.d.ts +150 -0
- package/dist/app-authority.js +41 -0
- package/dist/app-directory-reconciliation.d.ts +14 -0
- package/dist/app-directory-reconciliation.js +72 -0
- package/dist/app-directory.d.ts +206 -0
- package/dist/app-directory.js +21 -0
- package/dist/app-icon.d.ts +9 -0
- package/dist/app-icon.js +27 -0
- package/dist/app-launch.d.ts +53 -0
- package/dist/app-launch.js +204 -0
- package/dist/app-menus.d.ts +6 -0
- package/dist/app-menus.js +81 -0
- package/dist/app-open-url.d.ts +8 -0
- package/dist/app-open-url.js +63 -0
- package/dist/app-surface.d.ts +62 -0
- package/dist/app-surface.js +10 -0
- package/dist/app-windows.d.ts +107 -0
- package/dist/app-windows.js +21 -0
- package/dist/chrome.css +153 -0
- package/dist/command-dialogs.d.ts +42 -0
- package/dist/command-dialogs.js +194 -0
- package/dist/desktop/Desktop.d.ts +34 -0
- package/dist/desktop/Desktop.js +275 -0
- package/dist/desktop/consent.d.ts +4 -0
- package/dist/desktop/consent.js +64 -0
- package/dist/desktop/gill-frame.d.ts +14 -0
- package/dist/desktop/gill-frame.js +41 -0
- package/dist/desktop/gill-param-picker.d.ts +15 -0
- package/dist/desktop/gill-param-picker.js +145 -0
- package/dist/desktop/launcher-gill.d.ts +20 -0
- package/dist/desktop/launcher-gill.js +49 -0
- package/dist/desktop/own-launchers.d.ts +9 -0
- package/dist/desktop/own-launchers.js +9 -0
- package/dist/desktop/row-gill.d.ts +24 -0
- package/dist/desktop/row-gill.js +136 -0
- package/dist/desktop-api.d.ts +63 -0
- package/dist/desktop-api.js +31 -0
- package/dist/desktop-client.d.ts +19 -0
- package/dist/desktop-client.js +127 -0
- package/dist/desktop-layout.d.ts +117 -0
- package/dist/desktop-layout.js +305 -0
- package/dist/desktop-visibility.d.ts +8 -0
- package/dist/desktop-visibility.js +5 -0
- package/dist/layers.d.ts +5 -0
- package/dist/layers.js +31 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +17 -0
- package/dist/member-avatar-cache.d.ts +15 -0
- package/dist/member-avatar-cache.js +69 -0
- package/dist/member-avatar.d.ts +39 -0
- package/dist/member-avatar.js +88 -0
- package/dist/menu-bar.d.ts +5 -0
- package/dist/menu-bar.js +5 -0
- package/dist/model.d.ts +6 -0
- package/dist/model.js +13 -0
- package/dist/oyster-platform-controls.d.ts +4 -0
- package/dist/oyster-platform-controls.js +107 -0
- package/dist/platform-controls.d.ts +84 -0
- package/dist/platform-controls.js +266 -0
- package/dist/queries.d.ts +7 -0
- package/dist/queries.js +7 -0
- package/dist/session-registry.d.ts +16 -0
- package/dist/session-registry.js +69 -0
- package/dist/session-selection.d.ts +6 -0
- package/dist/session-selection.js +22 -0
- package/dist/settings-leave-guard.d.ts +5 -0
- package/dist/settings-leave-guard.js +9 -0
- package/dist/settings-navigation.css +129 -0
- package/dist/settings-routes.d.ts +118 -0
- package/dist/settings-routes.js +216 -0
- package/dist/settings-sections.d.ts +74 -0
- package/dist/settings-sections.js +17 -0
- package/dist/shell-commands.d.ts +15 -0
- package/dist/shell-commands.js +95 -0
- package/dist/shell-host.d.ts +52 -0
- package/dist/shell-host.js +224 -0
- package/dist/shell-module.d.ts +12 -0
- package/dist/shell-module.js +17 -0
- package/dist/shell-release.d.ts +3 -0
- package/dist/shell-release.js +4 -0
- package/dist/shell.css +858 -0
- package/dist/shell.d.ts +6 -0
- package/dist/shell.js +83 -0
- package/dist/spa.css +11 -0
- package/dist/status-bar.d.ts +9 -0
- package/dist/status-bar.js +51 -0
- package/dist/team-directory.d.ts +3 -0
- package/dist/team-directory.js +6 -0
- package/dist/use-window-motion.d.ts +3 -0
- package/dist/use-window-motion.js +37 -0
- package/dist/useAppOpenUrlHandoff.d.ts +11 -0
- package/dist/useAppOpenUrlHandoff.js +62 -0
- package/dist/useAppWindowManager.d.ts +323 -0
- package/dist/useAppWindowManager.js +47 -0
- package/dist/useDirectoryCommands.d.ts +12 -0
- package/dist/useDirectoryCommands.js +80 -0
- package/dist/workbench.d.ts +3 -0
- package/dist/workbench.js +2 -0
- package/package.json +222 -3
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from "@fungi.computer/caps/components/button";
|
|
3
|
+
import { Select } from "@fungi.computer/caps/components/select";
|
|
4
|
+
import { AppIcon } from "./app-icon.js";
|
|
5
|
+
import { addressKey, } from "@fungi.computer/oyster/shell/app-directory";
|
|
6
|
+
import { OwnSprite } from "./member-avatar.js";
|
|
7
|
+
export function SettingsNavigation({ location, apps, sections, desktopOnly = false, onNavigate, }) {
|
|
8
|
+
const groups = navigationGroups(apps, sections, desktopOnly);
|
|
9
|
+
const selectedValue = navigationValue(location, apps);
|
|
10
|
+
const selectOption = (value) => {
|
|
11
|
+
const option = groups
|
|
12
|
+
.flatMap(({ options }) => options)
|
|
13
|
+
.find((candidate) => candidate.value === value);
|
|
14
|
+
if (option)
|
|
15
|
+
onNavigate(option.location);
|
|
16
|
+
};
|
|
17
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "tourtois-settings-mobile-select", children: _jsxs(Select, { "aria-label": "Settings category", value: selectedValue, onChange: (event) => {
|
|
18
|
+
selectOption(event.currentTarget.value);
|
|
19
|
+
}, children: [_jsx("option", { value: "", disabled: true, children: "Choose a settings category" }), groups.map(({ label, options }) => (_jsx("optgroup", { label: label, children: options.map(({ value, label: optionLabel }) => (_jsx("option", { value: value, children: optionLabel }, value))) }, label)))] }) }), _jsx("nav", { className: "tourtois-settings-nav", "aria-label": "Settings categories", children: groups.map(({ label, showRailLabel, options }) => (_jsxs("div", { className: "tourtois-settings-nav-group", children: [showRailLabel === false ? null : (_jsx("span", { className: "caps-eyebrow tourtois-settings-nav-label", children: label })), options.map((option) => (_jsxs(Button, { type: "button", size: "sm", variant: "ghost", className: option.value === selectedValue
|
|
20
|
+
? "bg-base-300 text-base-content"
|
|
21
|
+
: undefined, "aria-pressed": option.value === selectedValue, onClick: () => {
|
|
22
|
+
onNavigate(option.location);
|
|
23
|
+
}, children: [option.icon, _jsx("span", { className: "tourtois-settings-nav-item-label", children: option.label })] }, option.value)))] }, label))) })] }));
|
|
24
|
+
}
|
|
25
|
+
function navigationGroups(apps, sections, desktopOnly) {
|
|
26
|
+
const groups = [
|
|
27
|
+
{
|
|
28
|
+
label: "Settings",
|
|
29
|
+
// The dialog header already reads "System Settings"; don't repeat it
|
|
30
|
+
// as a rail heading above this single "Settings home" item.
|
|
31
|
+
showRailLabel: false,
|
|
32
|
+
options: [
|
|
33
|
+
{
|
|
34
|
+
value: "home",
|
|
35
|
+
label: "Settings home",
|
|
36
|
+
location: { category: "home" },
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
label: "You",
|
|
42
|
+
options: [
|
|
43
|
+
{
|
|
44
|
+
value: "avatar",
|
|
45
|
+
label: "Avatar",
|
|
46
|
+
location: { category: "avatar" },
|
|
47
|
+
icon: (_jsx(OwnSprite, { "aria-hidden": "true", className: "tourtois-settings-nav-sprite" })),
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: "Apps",
|
|
53
|
+
options: [
|
|
54
|
+
{
|
|
55
|
+
value: "defaults",
|
|
56
|
+
label: "Default Apps",
|
|
57
|
+
location: { category: "defaults" },
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
value: "app-permissions",
|
|
61
|
+
label: desktopOnly ? "App desktop" : "App permissions",
|
|
62
|
+
location: {
|
|
63
|
+
category: "apps",
|
|
64
|
+
appKey: null,
|
|
65
|
+
section: desktopOnly ? "desktop" : "permissions",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
...apps.map((app) => {
|
|
69
|
+
const key = addressKey(app.address);
|
|
70
|
+
return {
|
|
71
|
+
value: `app:${key}`,
|
|
72
|
+
label: app.displayName ?? app.appId,
|
|
73
|
+
location: {
|
|
74
|
+
category: "apps",
|
|
75
|
+
appKey: key,
|
|
76
|
+
section: desktopOnly
|
|
77
|
+
? "desktop"
|
|
78
|
+
: "permissions",
|
|
79
|
+
},
|
|
80
|
+
icon: _jsx(AppIcon, { roles: app.roles, icon: app.icon }),
|
|
81
|
+
};
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
label: "Team",
|
|
87
|
+
options: [
|
|
88
|
+
{
|
|
89
|
+
value: "selling",
|
|
90
|
+
label: "Selling",
|
|
91
|
+
location: { category: "selling", appId: null },
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
value: "channels",
|
|
95
|
+
label: "Channels",
|
|
96
|
+
location: { category: "channels" },
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
value: "connectors",
|
|
100
|
+
label: "Connectors",
|
|
101
|
+
location: { category: "connectors", target: { kind: "list" } },
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
value: "computers",
|
|
105
|
+
label: "Internet access",
|
|
106
|
+
location: { category: "computers" },
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
value: "keys",
|
|
110
|
+
label: "Keys",
|
|
111
|
+
location: { category: "keys" },
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
return groups
|
|
117
|
+
.map((group) => ({
|
|
118
|
+
...group,
|
|
119
|
+
options: group.options.filter((option) => sections.includes(option.location.category)),
|
|
120
|
+
}))
|
|
121
|
+
.filter((group) => group.options.length > 0);
|
|
122
|
+
}
|
|
123
|
+
function navigationValue(location, apps) {
|
|
124
|
+
switch (location?.category) {
|
|
125
|
+
case "selling":
|
|
126
|
+
return "selling";
|
|
127
|
+
case "home":
|
|
128
|
+
return "home";
|
|
129
|
+
case "avatar":
|
|
130
|
+
return "avatar";
|
|
131
|
+
case "defaults":
|
|
132
|
+
return "defaults";
|
|
133
|
+
case "connectors":
|
|
134
|
+
return "connectors";
|
|
135
|
+
case "computers":
|
|
136
|
+
return "computers";
|
|
137
|
+
case "keys":
|
|
138
|
+
return "keys";
|
|
139
|
+
case "channels":
|
|
140
|
+
return "channels";
|
|
141
|
+
case "apps":
|
|
142
|
+
return location.appKey === null
|
|
143
|
+
? "app-permissions"
|
|
144
|
+
: appNavigationValue(location.appKey, apps);
|
|
145
|
+
default:
|
|
146
|
+
return "home";
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function appNavigationValue(appKey, apps) {
|
|
150
|
+
if (!appKey || !apps.some((app) => addressKey(app.address) === appKey))
|
|
151
|
+
return "";
|
|
152
|
+
return `app:${appKey}`;
|
|
153
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type AppDesktopSettingsApp } from "./AppDesktopSettings.js";
|
|
2
|
+
import { type AppDirectoryEntry } from "@fungi.computer/oyster/shell/app-directory";
|
|
3
|
+
import type { WorkbenchDesktopSettings } from "@fungi.computer/oyster/shell/workbench";
|
|
4
|
+
import { type SettingsSectionPorts } from "./settings-sections.js";
|
|
5
|
+
import type { SettingsLocation } from "./settings-routes.js";
|
|
6
|
+
/** One system-settings surface. The menu only requests opening it. */
|
|
7
|
+
export declare function SystemSettings({ location: requestedLocation, sections: ceiling, onNavigate, apps, appCount, onAccepted, desktopSettings, desktopConsentReadyAt, onClosed, restoreFocus, ports, }: {
|
|
8
|
+
location: SettingsLocation | null;
|
|
9
|
+
/** The host's navigation ceiling; a section also needs its port. */
|
|
10
|
+
sections?: readonly SettingsLocation["category"][] | undefined;
|
|
11
|
+
onNavigate: (location: SettingsLocation | null) => void;
|
|
12
|
+
apps: readonly (AppDesktopSettingsApp & Pick<AppDirectoryEntry, "address" | "installationId" | "appId" | "displayName" | "icon" | "calls"> & Readonly<{
|
|
13
|
+
roles: readonly string[];
|
|
14
|
+
}>)[];
|
|
15
|
+
/** The directory's App count once read; null is not zero. */
|
|
16
|
+
appCount: number | null;
|
|
17
|
+
onAccepted: () => Promise<void>;
|
|
18
|
+
desktopSettings: WorkbenchDesktopSettings;
|
|
19
|
+
desktopConsentReadyAt: number;
|
|
20
|
+
onClosed: () => void;
|
|
21
|
+
restoreFocus: boolean;
|
|
22
|
+
/** The sections this host implements. */
|
|
23
|
+
ports: SettingsSectionPorts;
|
|
24
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AppCallPermissions } from "./AppCallPermissions.js";
|
|
3
|
+
import { SectionHeading } from "@fungi.computer/caps/blocks/section-heading";
|
|
4
|
+
import { AppDesktopSettings, } from "./AppDesktopSettings.js";
|
|
5
|
+
import { addressKey, } from "@fungi.computer/oyster/shell/app-directory";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { AgentMcpServers } from "./AgentMcpServers.js";
|
|
8
|
+
import { Keys } from "./Keys.js";
|
|
9
|
+
import { AppIcon } from "./app-icon.js";
|
|
10
|
+
import { AvatarSettings } from "./member-avatar.js";
|
|
11
|
+
import { SettingsNavigation } from "./SettingsNavigation.js";
|
|
12
|
+
import { SettingsHome } from "./SettingsHome.js";
|
|
13
|
+
import { offeredSettings, } from "./settings-sections.js";
|
|
14
|
+
import { ActionRow } from "@fungi.computer/caps/components/action-row";
|
|
15
|
+
import { DataList, DataRow } from "@fungi.computer/caps/components/data-list";
|
|
16
|
+
import { SettingsLeaveContext, } from "./settings-leave-guard.js";
|
|
17
|
+
import { Button } from "@fungi.computer/caps/components/button";
|
|
18
|
+
import { WindowFrame, WindowHeader, WindowActions, } from "@fungi.computer/caps/components/window";
|
|
19
|
+
import { Dialog, DialogContent, DialogTitle, DialogDescription, } from "@fungi.computer/caps/components/dialog";
|
|
20
|
+
/** One system-settings surface. The menu only requests opening it. */
|
|
21
|
+
export function SystemSettings({ location: requestedLocation, sections: ceiling, onNavigate, apps, appCount, onAccepted, desktopSettings, desktopConsentReadyAt, onClosed, restoreFocus, ports, }) {
|
|
22
|
+
const sections = useMemo(() => offeredSettings(ceiling, ports), [ceiling, ports]);
|
|
23
|
+
const location = requestedLocation !== null && sections.includes(requestedLocation.category)
|
|
24
|
+
? requestedLocation
|
|
25
|
+
: null;
|
|
26
|
+
const { agentMcpServers, keys, appPermissions: AppPermissions, appAdvanced: AppAdvanced, } = ports;
|
|
27
|
+
const avatar = location?.category === "avatar";
|
|
28
|
+
const connectors = location?.category === "connectors";
|
|
29
|
+
const computersSection = location?.category === "computers";
|
|
30
|
+
const keysSection = location?.category === "keys";
|
|
31
|
+
const keyableApps = useMemo(() => apps.flatMap((app) => app.installationId === null
|
|
32
|
+
? []
|
|
33
|
+
: [
|
|
34
|
+
{
|
|
35
|
+
installationId: app.installationId,
|
|
36
|
+
displayName: app.displayName ?? app.appId,
|
|
37
|
+
},
|
|
38
|
+
]), [apps]);
|
|
39
|
+
const defaults = location?.category === "defaults";
|
|
40
|
+
const home = location?.category === "home";
|
|
41
|
+
const appSection = location?.category === "apps";
|
|
42
|
+
// Load App editors only after an App is chosen, then retain their drafts
|
|
43
|
+
// while moving between categories in this dialog.
|
|
44
|
+
const [appsLoaded, setAppsLoaded] = useState(false);
|
|
45
|
+
if (appSection && location.appKey !== null && !appsLoaded)
|
|
46
|
+
setAppsLoaded(true);
|
|
47
|
+
const appLocation = location?.category === "apps" ? location : null;
|
|
48
|
+
const appKey = appLocation?.appKey ?? null;
|
|
49
|
+
// A host without a Permissions or Advanced port never renders that tab.
|
|
50
|
+
// Route requests for those sections (the window chrome's shield and gear)
|
|
51
|
+
// land here too, so fold them into Desktop instead of a blank content area.
|
|
52
|
+
const desktopOnly = AppPermissions === undefined;
|
|
53
|
+
const advanced = AppAdvanced !== undefined && appLocation?.section === "advanced";
|
|
54
|
+
const desktop = appLocation !== null &&
|
|
55
|
+
!advanced &&
|
|
56
|
+
(desktopOnly || appLocation.section !== "permissions");
|
|
57
|
+
const selected = apps.find((app) => addressKey(app.address) === appKey);
|
|
58
|
+
const guards = useRef(new Set());
|
|
59
|
+
const register = useCallback((guard) => {
|
|
60
|
+
guards.current.add(guard);
|
|
61
|
+
return () => {
|
|
62
|
+
guards.current.delete(guard);
|
|
63
|
+
};
|
|
64
|
+
}, []);
|
|
65
|
+
const [discard, setDiscard] = useState(false);
|
|
66
|
+
const discardDestination = useRef(null);
|
|
67
|
+
const [leaveError, setLeaveError] = useState(null);
|
|
68
|
+
const canClose = () => {
|
|
69
|
+
const states = [...guards.current].map((read) => read());
|
|
70
|
+
if (states.includes("pending") || states.includes("uncertain")) {
|
|
71
|
+
setLeaveError(states.includes("pending")
|
|
72
|
+
? "Wait for the current request to finish before closing."
|
|
73
|
+
: "Retry the uncertain request before closing so its request identity is preserved.");
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
setLeaveError(null);
|
|
77
|
+
return true;
|
|
78
|
+
};
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!location)
|
|
81
|
+
return;
|
|
82
|
+
const beforeUnload = (event) => {
|
|
83
|
+
if ([...guards.current].some((read) => read() !== "clean"))
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
};
|
|
86
|
+
window.addEventListener("beforeunload", beforeUnload);
|
|
87
|
+
return () => {
|
|
88
|
+
window.removeEventListener("beforeunload", beforeUnload);
|
|
89
|
+
};
|
|
90
|
+
}, [location]);
|
|
91
|
+
const requestNavigation = (next) => {
|
|
92
|
+
if (!canClose())
|
|
93
|
+
return;
|
|
94
|
+
if ([...guards.current].some((read) => read() === "dirty")) {
|
|
95
|
+
discardDestination.current = next;
|
|
96
|
+
setDiscard(true);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
onNavigate(next);
|
|
100
|
+
};
|
|
101
|
+
const close = () => {
|
|
102
|
+
requestNavigation(null);
|
|
103
|
+
};
|
|
104
|
+
const headerProps = {
|
|
105
|
+
title: "System Settings",
|
|
106
|
+
actions: _jsx(WindowActions, { title: "System Settings", onClose: close }),
|
|
107
|
+
};
|
|
108
|
+
if (location?.category === "selling" && location.appId !== null)
|
|
109
|
+
headerProps.back = {
|
|
110
|
+
label: "Back to Selling",
|
|
111
|
+
onBack: () => {
|
|
112
|
+
requestNavigation({ category: "selling", appId: null });
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
return (_jsx(Dialog, { open: location !== null, onOpenChangeComplete: (open) => {
|
|
116
|
+
if (!open) {
|
|
117
|
+
setAppsLoaded(false);
|
|
118
|
+
onClosed();
|
|
119
|
+
}
|
|
120
|
+
}, onOpenChange: (next) => {
|
|
121
|
+
if (!next)
|
|
122
|
+
close();
|
|
123
|
+
}, children: _jsxs(DialogContent, { finalFocus: restoreFocus, render: _jsx(WindowFrame, { floating: true }), keepMounted: false, className: "tourtois-system-settings", children: [_jsx(DialogTitle, { className: "sr-only", children: "System Settings" }), _jsx(DialogDescription, { className: "sr-only", children: desktopOnly
|
|
124
|
+
? "Your desktop and App settings."
|
|
125
|
+
: "Your avatar, Channels, Connectors, App access and App settings." }), _jsx(WindowHeader, { ...headerProps }), _jsx(SettingsLeaveContext.Provider, { value: register, children: _jsxs("div", { className: "tourtois-settings-layout", children: [_jsx(SettingsNavigation, { sections: sections, desktopOnly: desktopOnly, location: location, apps: apps, onNavigate: (next) => {
|
|
126
|
+
if (location?.category === "selling" && location.appId !== null)
|
|
127
|
+
requestNavigation(next);
|
|
128
|
+
else
|
|
129
|
+
onNavigate(next);
|
|
130
|
+
} }), home ? (_jsx(SettingsHome, { sections: sections, desktopOnly: desktopOnly, team: ports.team, summary: {
|
|
131
|
+
appCount,
|
|
132
|
+
defaultAppCount: ports.summary?.defaultAppCount ?? null,
|
|
133
|
+
computerCount: ports.summary?.computerCount ?? null,
|
|
134
|
+
}, onNavigate: onNavigate })) : null, avatar && ports.avatar !== undefined ? (_jsx("div", { className: "tourtois-settings-content", children: _jsx(AvatarSettings, { save: ports.avatar.save }) })) : null, connectors && agentMcpServers !== undefined ? (_jsx(AgentMcpServers, { port: agentMcpServers })) : null, connectors &&
|
|
135
|
+
agentMcpServers === undefined &&
|
|
136
|
+
ports.connectors !== undefined ? (_jsx(ports.connectors, { target: location.target, onNavigate: onNavigate })) : null, location?.category === "selling" && ports.selling !== undefined ? (_jsx(ports.selling, { appId: location.appId, onNavigate: onNavigate })) : null, computersSection && ports.computers !== undefined ? (_jsx("div", { className: "tourtois-settings-content", children: _jsx(ports.computers, {}) })) : null, keysSection && keys !== undefined ? (_jsx(Keys, { port: keys, apps: keyableApps })) : null, location?.category === "channels" &&
|
|
137
|
+
ports.channels !== undefined ? (_jsx(ports.channels, {})) : null, defaults && ports.defaults !== undefined ? (_jsx("div", { className: "tourtois-settings-content", children: _jsx(ports.defaults, { onAccepted: onAccepted }) })) : null, appSection && appKey === null ? (_jsxs("section", { className: "tourtois-settings-content", "aria-label": "Choose an App", children: [_jsx(SectionHeading, { className: "tourtois-settings-app-heading", children: desktopOnly ? "App desktop" : "App permissions" }), _jsx(DataList, { density: "compact", "aria-label": "Apps to review", children: apps.map((app) => (_jsx(DataRow, { className: "p-0", children: _jsx(ActionRow, { label: app.displayName ?? app.appId, icon: _jsx(AppIcon, { roles: app.roles, icon: app.icon }), onClick: () => {
|
|
138
|
+
onNavigate({
|
|
139
|
+
category: "apps",
|
|
140
|
+
appKey: addressKey(app.address),
|
|
141
|
+
section: desktopOnly ? "desktop" : "permissions",
|
|
142
|
+
});
|
|
143
|
+
} }) }, addressKey(app.address)))) }), appCount === 0 ? (_jsx("p", { children: desktopOnly
|
|
144
|
+
? "No Apps installed yet."
|
|
145
|
+
: "No Apps in this Team yet." })) : null] })) : null, appsLoaded ? (_jsxs("section", { className: "tourtois-settings-content", "aria-label": "App settings", hidden: !appSection || appKey === null, children: [_jsxs("div", { className: "tourtois-settings-app-header", children: [_jsxs(SectionHeading, { className: "tourtois-settings-app-heading", children: [selected ? (_jsx(AppIcon, { roles: selected.roles, icon: selected.icon })) : null, selected
|
|
146
|
+
? (selected.displayName ?? selected.appId)
|
|
147
|
+
: "Apps"] }), selected ? (_jsxs("div", { className: "tourtois-settings-app-tabs", role: "group", "aria-label": "App settings sections", children: [!desktopOnly ? (_jsx(Button, { type: "button", size: "sm", variant: "ghost", className: !advanced && !desktop
|
|
148
|
+
? "bg-base-300 text-base-content"
|
|
149
|
+
: undefined, "aria-pressed": !advanced && !desktop, onClick: () => {
|
|
150
|
+
onNavigate({
|
|
151
|
+
category: "apps",
|
|
152
|
+
appKey,
|
|
153
|
+
section: "permissions",
|
|
154
|
+
});
|
|
155
|
+
}, children: "Permissions" })) : null, _jsx(Button, { type: "button", size: "sm", variant: "ghost", className: desktop ? "bg-base-300 text-base-content" : undefined, "aria-pressed": desktop, onClick: () => {
|
|
156
|
+
onNavigate({
|
|
157
|
+
category: "apps",
|
|
158
|
+
appKey,
|
|
159
|
+
section: "desktop",
|
|
160
|
+
});
|
|
161
|
+
}, children: "Desktop" }), AppAdvanced !== undefined ? (_jsx(Button, { type: "button", size: "sm", variant: "ghost", className: advanced
|
|
162
|
+
? "bg-base-300 text-base-content"
|
|
163
|
+
: undefined, "aria-pressed": advanced, onClick: () => {
|
|
164
|
+
onNavigate({
|
|
165
|
+
category: "apps",
|
|
166
|
+
appKey,
|
|
167
|
+
section: "advanced",
|
|
168
|
+
});
|
|
169
|
+
}, children: "Advanced" })) : null] })) : null] }), _jsxs("div", { className: "tourtois-settings-app-content", children: [!selected ? (_jsx("p", { children: "Choose an app to manage its permissions and advanced settings." })) : null, _jsx("div", { className: "tourtois-settings-permissions", hidden: !selected || advanced || desktop, children: AppPermissions !== undefined ? (_jsx(AppPermissions, { selectedKey: appKey, onAccepted: onAccepted })) : null }), selected && desktop && desktopOnly ? (_jsx(AppCallPermissions, { calls: selected.calls, apps: apps })) : null, selected && desktop ? (_jsx(AppDesktopSettings, { app: selected, desktop: desktopSettings, consentReadyAt: desktopConsentReadyAt }, selected.surfaceId)) : null, AppAdvanced !== undefined ? (_jsx(AppAdvanced, { selectedKey: appKey, visible: advanced, onNavigate: onNavigate, onAccepted: onAccepted })) : null] })] })) : null] }) }), leaveError ? (_jsx("div", { className: "tourtois-settings-discard", role: "alert", children: leaveError })) : null, discard ? (_jsxs("div", { className: "tourtois-settings-discard", role: "alert", children: [_jsx("p", { children: "Discard unsaved changes?" }), _jsxs("div", { className: "tourtois-settings-actions", children: [_jsx(Button, { type: "button", size: "sm", variant: "ghost", onClick: () => {
|
|
170
|
+
setDiscard(false);
|
|
171
|
+
}, children: "Keep editing" }), _jsx(Button, { type: "button", size: "sm", onClick: () => {
|
|
172
|
+
if (!canClose())
|
|
173
|
+
return;
|
|
174
|
+
setDiscard(false);
|
|
175
|
+
onNavigate(discardDestination.current);
|
|
176
|
+
}, children: "Discard changes" })] })] })) : null] }) }));
|
|
177
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { DesktopMethods } from "./desktop-api.js";
|
|
2
|
+
import type { ComputerOption } from "./app-launch.js";
|
|
3
|
+
import type { SettingsLocation } from "./settings-routes.js";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
import type { AppBarItem } from "@fungi.computer/caps/blocks/app-bar";
|
|
6
|
+
import type { WorkbenchDirectory } from "@fungi.computer/oyster/shell/workbench-directory";
|
|
7
|
+
import type { PlatformControls } from "./platform-controls.js";
|
|
8
|
+
import type { AppStorage } from "@fungi.computer/agar/storage";
|
|
9
|
+
import type { DesktopGillTransport } from "./desktop/row-gill.js";
|
|
10
|
+
import type { AppOpenInput } from "@fungi.computer/agar/apps";
|
|
11
|
+
export type TeamTourtoisProps = Readonly<{
|
|
12
|
+
teamId: string;
|
|
13
|
+
/** Local host views share the shell layers without giving the dashboard their authority. */
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
teamName?: string;
|
|
16
|
+
extraLaunchers?: readonly AppBarItem[];
|
|
17
|
+
settingsLaunchers?: readonly Readonly<{
|
|
18
|
+
id: string;
|
|
19
|
+
label: string;
|
|
20
|
+
icon?: ReactNode;
|
|
21
|
+
location: SettingsLocation;
|
|
22
|
+
}>[];
|
|
23
|
+
systemMenuItems?: ReactNode;
|
|
24
|
+
/** Read the Team's Computers through the host's `computers()` port. */
|
|
25
|
+
computersReader: (signal: AbortSignal) => Promise<readonly ComputerOption[]>;
|
|
26
|
+
/** Read the Team's App directory through the host's `directory()` port. */
|
|
27
|
+
directoryReader: () => Promise<WorkbenchDirectory>;
|
|
28
|
+
/** Take the host address's App-open handoff once, instead of this URL's. */
|
|
29
|
+
takeAppOpenRequest?: () => Promise<AppOpenInput | null>;
|
|
30
|
+
/** Team administration, rendered by the host with the owner's authority. */
|
|
31
|
+
platform: PlatformControls;
|
|
32
|
+
desktopStorage: AppStorage;
|
|
33
|
+
desktopMethods: DesktopMethods;
|
|
34
|
+
gills: DesktopGillTransport;
|
|
35
|
+
}>;
|
|
36
|
+
export declare function TeamTourtois({ children, teamId, teamName, extraLaunchers, settingsLaunchers, systemMenuItems, computersReader, directoryReader, takeAppOpenRequest, platform, desktopStorage, desktopMethods, gills, }: TeamTourtoisProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { tourtoisQueryKeys } from "./queries.js";
|
|
3
|
+
import { TourtoisLayers } from "./layers.js";
|
|
4
|
+
import { useQuery } from "@tanstack/react-query";
|
|
5
|
+
import { MaosaicoRoot } from "@fungi.computer/maosaico";
|
|
6
|
+
import { useEffect, useRef, useState } from "react";
|
|
7
|
+
import { AppWorkbench } from "./AppWorkbench.js";
|
|
8
|
+
function useWorkbenchBounds() {
|
|
9
|
+
const ref = useRef(null);
|
|
10
|
+
const [bounds, setBounds] = useState({ height: 0, width: 0 });
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const element = ref.current;
|
|
13
|
+
if (!element)
|
|
14
|
+
return;
|
|
15
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
16
|
+
setBounds({
|
|
17
|
+
height: Math.max(0, entry?.contentRect.height ?? 0),
|
|
18
|
+
width: Math.max(0, entry?.contentRect.width ?? 0),
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
observer.observe(element);
|
|
22
|
+
return () => {
|
|
23
|
+
observer.disconnect();
|
|
24
|
+
};
|
|
25
|
+
}, []);
|
|
26
|
+
return { bounds, ref };
|
|
27
|
+
}
|
|
28
|
+
export function TeamTourtois({ children, teamId, teamName, extraLaunchers, settingsLaunchers, systemMenuItems, computersReader, directoryReader, takeAppOpenRequest, platform, desktopStorage, desktopMethods, gills, }) {
|
|
29
|
+
const { bounds, ref: paneLayerRef } = useWorkbenchBounds();
|
|
30
|
+
const phone = bounds.width <= 540;
|
|
31
|
+
const [tiled, setTiled] = useState(true);
|
|
32
|
+
const { data, isError, isLoading } = useQuery({
|
|
33
|
+
queryKey: tourtoisQueryKeys.workbenchComputers(teamId),
|
|
34
|
+
queryFn: ({ signal }) => computersReader(signal),
|
|
35
|
+
});
|
|
36
|
+
return (_jsx("main", { className: "tourtois-shell", "data-tourtois-shell": true, children: _jsxs(TourtoisLayers, { children: [_jsx("div", { className: "tourtois-workbench", children: _jsx(MaosaicoRoot, { bounds: bounds, containerRef: paneLayerRef, tiling: tiled || phone
|
|
37
|
+
? { mainSize: Math.max(0, Math.min(640, bounds.width)), gap: 8 }
|
|
38
|
+
: undefined, children: _jsx(AppWorkbench, { paneLayerRef: paneLayerRef, phone: phone, teamId: teamId, teamName: teamName ?? teamId, initialComputerId: data?.[0]?.computerId ?? null, computers: data ?? [], computersUnavailable: isLoading || isError, onLayoutChange: phone ? undefined : setTiled, platform: platform, desktopStorage: desktopStorage, desktopMethods: desktopMethods, gills: gills, ...(extraLaunchers ? { extraLaunchers } : {}), ...(settingsLaunchers ? { settingsLaunchers } : {}), ...(systemMenuItems ? { systemMenuItems } : {}), directoryReader: directoryReader, ...(takeAppOpenRequest ? { takeAppOpenRequest } : {}) }) }) }), children] }) }));
|
|
39
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type AppBarProps } from "@fungi.computer/caps/blocks/app-bar";
|
|
2
|
+
/** Disclosure only; the supplied callbacks retain window lifecycle ownership. */
|
|
3
|
+
export declare function WorkbenchAppBar({ phone, ...props }: AppBarProps & {
|
|
4
|
+
phone: boolean;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { AppBar } from "@fungi.computer/caps/blocks/app-bar";
|
|
3
|
+
import { IconButton } from "@fungi.computer/caps/components/icon-button";
|
|
4
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, } from "@fungi.computer/caps/components/dropdown-menu";
|
|
5
|
+
import { useLayer } from "@fungi.computer/maosaico";
|
|
6
|
+
import { Check, PanelsTopLeft } from "lucide-react";
|
|
7
|
+
/** Disclosure only; the supplied callbacks retain window lifecycle ownership. */
|
|
8
|
+
export function WorkbenchAppBar({ phone, ...props }) {
|
|
9
|
+
const popover = useLayer("popover");
|
|
10
|
+
const collapsed = phone && props.windows.length > 0;
|
|
11
|
+
return (_jsxs(_Fragment, { children: [collapsed ? (_jsxs(DropdownMenu, { modal: false, children: [_jsx(DropdownMenuTrigger, { render: _jsx(IconButton, { size: "responsive", icon: props.windows.find((item) => item.active)?.icon ?? (_jsx(PanelsTopLeft, {})), "aria-label": "Switch open Apps" }), "aria-label": "Switch open Apps", title: "Switch open Apps" }), _jsxs(DropdownMenuContent, { container: popover, align: "start", children: [props.windows.map((item) => (_jsxs(DropdownMenuItem, { role: "menuitemradio", "aria-checked": item.active ?? false, "aria-current": item.active ? "page" : undefined, onSelect: item.onSelect, children: [_jsx("span", { "aria-hidden": "true", className: "grid size-7 shrink-0 place-items-center [&_svg]:size-5", children: item.icon }), _jsx("span", { className: "flex-1", children: item.label }), item.active ? _jsx(Check, { "aria-hidden": "true", size: 16 }) : null] }, item.id))), _jsx(DropdownMenuSeparator, {}), props.windows.map((item) => item.onClose ? (_jsxs(DropdownMenuItem, { onSelect: item.onClose, children: ["Close ", item.label] }, item.id)) : null)] })] })) : null, _jsx(AppBar, { ...props, windows: collapsed ? [] : props.windows })] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { type AppAddress } from "@fungi.computer/oyster/shell/app-directory";
|
|
3
|
+
export declare const appPermissionChangesSchema: z.ZodObject<{
|
|
4
|
+
computer: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
5
|
+
kind: z.ZodLiteral<"selected-computers">;
|
|
6
|
+
computers: z.ZodArray<z.ZodObject<{
|
|
7
|
+
computerId: z.ZodString;
|
|
8
|
+
operations: z.ZodArray<z.ZodEnum<{
|
|
9
|
+
"computer.list": "computer.list";
|
|
10
|
+
"computer.readFile": "computer.readFile";
|
|
11
|
+
"computer.writeFile": "computer.writeFile";
|
|
12
|
+
"computer.execute": "computer.execute";
|
|
13
|
+
}>>;
|
|
14
|
+
}, z.core.$strict>>;
|
|
15
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
16
|
+
kind: z.ZodLiteral<"all-team-computers">;
|
|
17
|
+
operations: z.ZodArray<z.ZodEnum<{
|
|
18
|
+
"computer.list": "computer.list";
|
|
19
|
+
"computer.readFile": "computer.readFile";
|
|
20
|
+
"computer.writeFile": "computer.writeFile";
|
|
21
|
+
"computer.execute": "computer.execute";
|
|
22
|
+
}>>;
|
|
23
|
+
}, z.core.$strict>], "kind">>;
|
|
24
|
+
agents: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
25
|
+
kind: z.ZodLiteral<"all-team-agents">;
|
|
26
|
+
directoryOperations: z.ZodArray<z.ZodEnum<{
|
|
27
|
+
"agent.list": "agent.list";
|
|
28
|
+
}>>;
|
|
29
|
+
sessionOperations: z.ZodArray<z.ZodEnum<{
|
|
30
|
+
"agent.read": "agent.read";
|
|
31
|
+
"agent.send": "agent.send";
|
|
32
|
+
"agent.manage": "agent.manage";
|
|
33
|
+
}>>;
|
|
34
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
35
|
+
kind: z.ZodLiteral<"selected-agents">;
|
|
36
|
+
directoryOperations: z.ZodArray<z.ZodEnum<{
|
|
37
|
+
"agent.list": "agent.list";
|
|
38
|
+
}>>;
|
|
39
|
+
agents: z.ZodArray<z.ZodObject<{
|
|
40
|
+
agentId: z.ZodString;
|
|
41
|
+
sessionOperations: z.ZodArray<z.ZodEnum<{
|
|
42
|
+
"agent.read": "agent.read";
|
|
43
|
+
"agent.send": "agent.send";
|
|
44
|
+
"agent.manage": "agent.manage";
|
|
45
|
+
}>>;
|
|
46
|
+
}, z.core.$strict>>;
|
|
47
|
+
}, z.core.$strict>], "kind">>;
|
|
48
|
+
generation: z.ZodOptional<z.ZodObject<{
|
|
49
|
+
llm: z.ZodBoolean;
|
|
50
|
+
media: z.ZodBoolean;
|
|
51
|
+
}, z.core.$strict>>;
|
|
52
|
+
marketplace: z.ZodOptional<z.ZodObject<{
|
|
53
|
+
browse: z.ZodBoolean;
|
|
54
|
+
purchase: z.ZodBoolean;
|
|
55
|
+
installFree: z.ZodBoolean;
|
|
56
|
+
}, z.core.$strict>>;
|
|
57
|
+
}, z.core.$strict>;
|
|
58
|
+
export type AppPermissionChanges = z.output<typeof appPermissionChangesSchema>;
|
|
59
|
+
export declare const appPermissionReceiptSchema: z.ZodObject<{
|
|
60
|
+
authorityVersion: z.ZodNumber;
|
|
61
|
+
computerPermission: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
62
|
+
kind: z.ZodLiteral<"selected-computers">;
|
|
63
|
+
computers: z.ZodArray<z.ZodObject<{
|
|
64
|
+
computerId: z.ZodString;
|
|
65
|
+
operations: z.ZodArray<z.ZodEnum<{
|
|
66
|
+
"computer.list": "computer.list";
|
|
67
|
+
"computer.readFile": "computer.readFile";
|
|
68
|
+
"computer.writeFile": "computer.writeFile";
|
|
69
|
+
"computer.execute": "computer.execute";
|
|
70
|
+
}>>;
|
|
71
|
+
}, z.core.$strict>>;
|
|
72
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
73
|
+
kind: z.ZodLiteral<"all-team-computers">;
|
|
74
|
+
operations: z.ZodArray<z.ZodEnum<{
|
|
75
|
+
"computer.list": "computer.list";
|
|
76
|
+
"computer.readFile": "computer.readFile";
|
|
77
|
+
"computer.writeFile": "computer.writeFile";
|
|
78
|
+
"computer.execute": "computer.execute";
|
|
79
|
+
}>>;
|
|
80
|
+
}, z.core.$strict>], "kind">>;
|
|
81
|
+
agentPermission: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
82
|
+
kind: z.ZodLiteral<"all-team-agents">;
|
|
83
|
+
directoryOperations: z.ZodArray<z.ZodEnum<{
|
|
84
|
+
"agent.list": "agent.list";
|
|
85
|
+
}>>;
|
|
86
|
+
sessionOperations: z.ZodArray<z.ZodEnum<{
|
|
87
|
+
"agent.read": "agent.read";
|
|
88
|
+
"agent.send": "agent.send";
|
|
89
|
+
"agent.manage": "agent.manage";
|
|
90
|
+
}>>;
|
|
91
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
92
|
+
kind: z.ZodLiteral<"selected-agents">;
|
|
93
|
+
directoryOperations: z.ZodArray<z.ZodEnum<{
|
|
94
|
+
"agent.list": "agent.list";
|
|
95
|
+
}>>;
|
|
96
|
+
agents: z.ZodArray<z.ZodObject<{
|
|
97
|
+
agentId: z.ZodString;
|
|
98
|
+
sessionOperations: z.ZodArray<z.ZodEnum<{
|
|
99
|
+
"agent.read": "agent.read";
|
|
100
|
+
"agent.send": "agent.send";
|
|
101
|
+
"agent.manage": "agent.manage";
|
|
102
|
+
}>>;
|
|
103
|
+
}, z.core.$strict>>;
|
|
104
|
+
}, z.core.$strict>], "kind">;
|
|
105
|
+
generationPermissions: z.ZodObject<{
|
|
106
|
+
llm: z.ZodBoolean;
|
|
107
|
+
media: z.ZodBoolean;
|
|
108
|
+
}, z.core.$strict>;
|
|
109
|
+
marketplacePermissions: z.ZodObject<{
|
|
110
|
+
browse: z.ZodBoolean;
|
|
111
|
+
purchase: z.ZodBoolean;
|
|
112
|
+
installFree: z.ZodBoolean;
|
|
113
|
+
}, z.core.$strict>;
|
|
114
|
+
}, z.core.$strip>;
|
|
115
|
+
export declare function appPermissionsMutationRequest(teamId: string, requestId: string, address: AppAddress, expectedAuthorityVersion: number, permissions: AppPermissionChanges): {
|
|
116
|
+
url: string;
|
|
117
|
+
init: {
|
|
118
|
+
method: string;
|
|
119
|
+
credentials: "include";
|
|
120
|
+
headers: {
|
|
121
|
+
"Content-Type": string;
|
|
122
|
+
Origin: string;
|
|
123
|
+
"X-Request-Id": string;
|
|
124
|
+
};
|
|
125
|
+
body: string;
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
export type AppMutationRequest = ReturnType<typeof appPermissionsMutationRequest>;
|
|
129
|
+
export declare const appMutationResponseSchema: z.ZodObject<{
|
|
130
|
+
kind: z.ZodLiteral<"accepted">;
|
|
131
|
+
receipt: z.ZodUnknown;
|
|
132
|
+
enforcement: z.ZodNullable<z.ZodObject<{
|
|
133
|
+
requestId: z.ZodString;
|
|
134
|
+
address: z.ZodUnion<readonly [z.ZodObject<{
|
|
135
|
+
kind: z.ZodLiteral<"default">;
|
|
136
|
+
appId: z.ZodString;
|
|
137
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
138
|
+
kind: z.ZodLiteral<"installation">;
|
|
139
|
+
installationId: z.ZodString;
|
|
140
|
+
}, z.core.$strict>]>;
|
|
141
|
+
authorityVersion: z.ZodNumber;
|
|
142
|
+
state: z.ZodEnum<{
|
|
143
|
+
unaffected: "unaffected";
|
|
144
|
+
pending: "pending";
|
|
145
|
+
applied: "applied";
|
|
146
|
+
expired: "expired";
|
|
147
|
+
}>;
|
|
148
|
+
outstanding: z.ZodNumber;
|
|
149
|
+
}, z.core.$strict>>;
|
|
150
|
+
}, z.core.$strict>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { appAuthorityEnforcementSchema, appComputerPermissionSchema, appAgentPermissionSchema, appGenerationPermissionsSchema, appMarketplacePermissionsSchema, } from "@fungi.computer/oyster/shell/app-directory";
|
|
3
|
+
export const appPermissionChangesSchema = z
|
|
4
|
+
.strictObject({
|
|
5
|
+
computer: appComputerPermissionSchema.optional(),
|
|
6
|
+
agents: appAgentPermissionSchema.optional(),
|
|
7
|
+
generation: appGenerationPermissionsSchema.optional(),
|
|
8
|
+
marketplace: appMarketplacePermissionsSchema.optional(),
|
|
9
|
+
})
|
|
10
|
+
.refine((changes) => Object.values(changes).some((value) => value !== undefined), "At least one permission section must change");
|
|
11
|
+
export const appPermissionReceiptSchema = z.object({
|
|
12
|
+
authorityVersion: z.number().int().positive(),
|
|
13
|
+
computerPermission: appComputerPermissionSchema.nullable(),
|
|
14
|
+
agentPermission: appAgentPermissionSchema,
|
|
15
|
+
generationPermissions: appGenerationPermissionsSchema,
|
|
16
|
+
marketplacePermissions: appMarketplacePermissionsSchema,
|
|
17
|
+
});
|
|
18
|
+
export function appPermissionsMutationRequest(teamId, requestId, address, expectedAuthorityVersion, permissions) {
|
|
19
|
+
return {
|
|
20
|
+
url: "/api/teams/" + encodeURIComponent(teamId) + "/apps",
|
|
21
|
+
init: {
|
|
22
|
+
method: "POST",
|
|
23
|
+
credentials: "include",
|
|
24
|
+
headers: {
|
|
25
|
+
"Content-Type": "application/json",
|
|
26
|
+
Origin: window.location.origin,
|
|
27
|
+
"X-Request-Id": requestId,
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
target: address,
|
|
31
|
+
expectedVersion: expectedAuthorityVersion,
|
|
32
|
+
command: { kind: "set-permissions", permissions },
|
|
33
|
+
}),
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export const appMutationResponseSchema = z.strictObject({
|
|
38
|
+
kind: z.literal("accepted"),
|
|
39
|
+
receipt: z.unknown(),
|
|
40
|
+
enforcement: appAuthorityEnforcementSchema.nullable(),
|
|
41
|
+
});
|