@abstractframework/ui-kit 0.1.3 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -3
- package/dist/af_select.d.ts +7 -1
- package/dist/af_select.d.ts.map +1 -1
- package/dist/af_select.js +16 -6
- package/dist/gateway_session_signin.d.ts +41 -0
- package/dist/gateway_session_signin.d.ts.map +1 -0
- package/dist/gateway_session_signin.js +15 -0
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -7
- package/dist/provider_model_select.js +1 -1
- package/dist/theme_select.d.ts +1 -1
- package/dist/theme_select.d.ts.map +1 -1
- package/dist/theme_select.js +2 -2
- package/dist/tool_policy_editor.d.ts +35 -0
- package/dist/tool_policy_editor.d.ts.map +1 -0
- package/dist/tool_policy_editor.js +161 -0
- package/dist/typography_select.d.ts +1 -1
- package/dist/typography_select.d.ts.map +1 -1
- package/dist/typography_select.js +2 -2
- package/package.json +3 -3
- package/src/theme.css +498 -0
package/README.md
CHANGED
|
@@ -6,7 +6,8 @@ This package provides:
|
|
|
6
6
|
|
|
7
7
|
- **Theme tokens** (CSS variables + theme classes): `ui-kit/src/theme.css`
|
|
8
8
|
- **Theme + typography helpers**: `applyTheme(...)`, `applyTypography(...)`
|
|
9
|
-
- **Common inputs**: `AfSelect`, `ThemeSelect`, `ProviderModelSelect`, etc.
|
|
9
|
+
- **Common inputs**: `AfSelect`, `ThemeSelect`, `ProviderModelSelect`, `ToolPolicyEditor`, etc.
|
|
10
|
+
- **Gateway session UI**: `GatewaySessionSignInCard` for the shared user/token browser-session sign-in form used by thin clients.
|
|
10
11
|
- **Icons**: `Icon` (used by `@abstractframework/panel-chat`)
|
|
11
12
|
|
|
12
13
|
## Install / peer dependencies
|
|
@@ -16,7 +17,7 @@ This is a React package with peer dependencies on `react@^18` and `react-dom@^18
|
|
|
16
17
|
## Install
|
|
17
18
|
|
|
18
19
|
- Workspace: add a dependency on `@abstractframework/ui-kit`
|
|
19
|
-
- npm
|
|
20
|
+
- npm: `npm i @abstractframework/ui-kit`
|
|
20
21
|
|
|
21
22
|
## Usage
|
|
22
23
|
|
|
@@ -37,9 +38,22 @@ applyTheme("dark"); // sets a `theme-*` class on <html>
|
|
|
37
38
|
Use UI components:
|
|
38
39
|
|
|
39
40
|
```tsx
|
|
40
|
-
import { ThemeSelect, Icon } from "@abstractframework/ui-kit";
|
|
41
|
+
import { ThemeSelect, Icon, ToolPolicyEditor, GatewaySessionSignInCard } from "@abstractframework/ui-kit";
|
|
41
42
|
```
|
|
42
43
|
|
|
44
|
+
### Gateway session sign-in
|
|
45
|
+
|
|
46
|
+
`GatewaySessionSignInCard` renders the shared Gateway browser-session sign-in
|
|
47
|
+
card. Host apps own the network calls and session storage; the component only
|
|
48
|
+
collects Gateway URL (optional), user id, token, and remember-browser state, and
|
|
49
|
+
calls the callbacks you provide.
|
|
50
|
+
|
|
51
|
+
### Tool policy editor
|
|
52
|
+
|
|
53
|
+
`ToolPolicyEditor` renders the shared allowlist + approve/ask picker for gateway tools. It intentionally **does not** include a deny mode; tools are denied by removing them from the allowlist. Pass `toolMode` (and optional `toolModeLabel`/`toolModeDetail`) to surface the gateway tool execution mode in a prominent banner.
|
|
54
|
+
|
|
55
|
+
The default approve/ask classification is exposed as `TOOL_POLICY_DEFAULTS` (mirrors the AbstractRuntime `ToolApprovalPolicy` defaults).
|
|
56
|
+
|
|
43
57
|
## Exported API
|
|
44
58
|
|
|
45
59
|
See `ui-kit/src/index.ts` for the authoritative export list.
|
package/dist/af_select.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export type AfSelectOption = {
|
|
|
3
3
|
value: string;
|
|
4
4
|
label: string;
|
|
5
5
|
group?: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
reason?: string;
|
|
6
8
|
};
|
|
7
9
|
export type AfSelectProps = {
|
|
8
10
|
value: string;
|
|
@@ -18,6 +20,10 @@ export type AfSelectProps = {
|
|
|
18
20
|
variant?: "pin" | "panel";
|
|
19
21
|
className?: string;
|
|
20
22
|
triggerClassName?: string;
|
|
23
|
+
customOptionLabel?: (value: string) => string;
|
|
24
|
+
validateCustomValue?: (value: string, context: {
|
|
25
|
+
options: AfSelectOption[];
|
|
26
|
+
}) => string | null | undefined;
|
|
21
27
|
onChange: (value: string) => void;
|
|
22
28
|
renderOption?: (opt: AfSelectOption, state: {
|
|
23
29
|
selected: boolean;
|
|
@@ -25,6 +31,6 @@ export type AfSelectProps = {
|
|
|
25
31
|
}) => React.ReactNode;
|
|
26
32
|
renderValue?: (opt: AfSelectOption | null, value: string) => React.ReactNode;
|
|
27
33
|
};
|
|
28
|
-
export declare function AfSelect({ value, options, placeholder, disabled, loading, searchable, searchPlaceholder, allowCustom, clearable, minPopoverWidth, variant, className, triggerClassName, onChange, renderOption, renderValue, }: AfSelectProps): React.ReactElement;
|
|
34
|
+
export declare function AfSelect({ value, options, placeholder, disabled, loading, searchable, searchPlaceholder, allowCustom, clearable, minPopoverWidth, variant, className, triggerClassName, customOptionLabel, validateCustomValue, onChange, renderOption, renderValue, }: AfSelectProps): React.ReactElement;
|
|
29
35
|
export default AfSelect;
|
|
30
36
|
//# sourceMappingURL=af_select.d.ts.map
|
package/dist/af_select.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"af_select.d.ts","sourceRoot":"","sources":["../src/af_select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAOjF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"af_select.d.ts","sourceRoot":"","sources":["../src/af_select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAOjF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,cAAc,EAAE,CAAA;KAAE,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC3G,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC;IAC5G,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;CAC9E,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,OAAO,EACP,WAAuB,EACvB,QAAgB,EAChB,OAAe,EACf,UAAiB,EACjB,iBAA6B,EAC7B,WAAmB,EACnB,SAAiB,EACjB,eAAqB,EACrB,OAAiB,EACjB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,QAAQ,EACR,YAAY,EACZ,WAAW,GACZ,EAAE,aAAa,GAAG,KAAK,CAAC,YAAY,CA4RpC;AAED,eAAe,QAAQ,CAAC"}
|
package/dist/af_select.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createPortal } from "react-dom";
|
|
|
4
4
|
function cx(...parts) {
|
|
5
5
|
return parts.filter(Boolean).join(" ");
|
|
6
6
|
}
|
|
7
|
-
export function AfSelect({ value, options, placeholder = "Select…", disabled = false, loading = false, searchable = true, searchPlaceholder = "Search…", allowCustom = false, clearable = false, minPopoverWidth = 240, variant = "panel", className, triggerClassName, onChange, renderOption, renderValue, }) {
|
|
7
|
+
export function AfSelect({ value, options, placeholder = "Select…", disabled = false, loading = false, searchable = true, searchPlaceholder = "Search…", allowCustom = false, clearable = false, minPopoverWidth = 240, variant = "panel", className, triggerClassName, customOptionLabel, validateCustomValue, onChange, renderOption, renderValue, }) {
|
|
8
8
|
const triggerRef = useRef(null);
|
|
9
9
|
const popoverRef = useRef(null);
|
|
10
10
|
const searchRef = useRef(null);
|
|
@@ -35,8 +35,14 @@ export function AfSelect({ value, options, placeholder = "Select…", disabled =
|
|
|
35
35
|
const exists = options.some((o) => o.value === q);
|
|
36
36
|
if (exists)
|
|
37
37
|
return null;
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const reason = validateCustomValue?.(q, { options }) || "";
|
|
39
|
+
return {
|
|
40
|
+
value: q,
|
|
41
|
+
label: customOptionLabel ? customOptionLabel(q) : `Use "${q}"`,
|
|
42
|
+
disabled: Boolean(reason),
|
|
43
|
+
reason,
|
|
44
|
+
};
|
|
45
|
+
}, [allowCustom, customOptionLabel, options, search, validateCustomValue]);
|
|
40
46
|
const visibleOptions = useMemo(() => {
|
|
41
47
|
if (!customOption)
|
|
42
48
|
return filtered;
|
|
@@ -98,6 +104,9 @@ export function AfSelect({ value, options, placeholder = "Select…", disabled =
|
|
|
98
104
|
}
|
|
99
105
|
}, [open, searchable, value, visibleOptions]);
|
|
100
106
|
const pick = (v) => {
|
|
107
|
+
const option = visibleOptions.find((o) => o.value === v);
|
|
108
|
+
if (option?.disabled)
|
|
109
|
+
return;
|
|
101
110
|
onChange(v);
|
|
102
111
|
close();
|
|
103
112
|
};
|
|
@@ -138,6 +147,7 @@ export function AfSelect({ value, options, placeholder = "Select…", disabled =
|
|
|
138
147
|
};
|
|
139
148
|
const showValue = Boolean(String(value || "").trim());
|
|
140
149
|
const triggerText = showValue ? selectedLabel : placeholder;
|
|
150
|
+
const customError = customOption?.disabled ? customOption.reason || "Unavailable" : "";
|
|
141
151
|
const defaultValueNode = (_jsx("span", { className: cx("af-select-value", !showValue && "af-select-value--placeholder"), children: loading ? "Loading…" : triggerText }));
|
|
142
152
|
const valueNode = renderValue ? renderValue(selectedOpt, String(value || "")) : defaultValueNode;
|
|
143
153
|
return (_jsxs("span", { className: cx("af-select", variant === "pin" ? "af-select--pin" : "af-select--panel", className), children: [_jsxs("button", { ref: triggerRef, type: "button", className: cx("af-select-trigger", triggerClassName), disabled: disabled, onMouseDown: (e) => e.stopPropagation(), onClick: (e) => {
|
|
@@ -154,16 +164,16 @@ export function AfSelect({ value, options, placeholder = "Select…", disabled =
|
|
|
154
164
|
onChange("");
|
|
155
165
|
close();
|
|
156
166
|
}, title: "Clear", children: "\u00D7" })) : null, _jsx("span", { className: cx("af-select-caret", open && "af-select-caret--open"), children: "\u25BE" })] }), open
|
|
157
|
-
? createPortal(_jsxs("div", { ref: popoverRef, className: cx("af-select-popover", placement === "top" && "af-select-popover--top"), style: { position: "fixed", left: `${pos.left}px`, top: `${pos.top}px`, width: `${pos.width}px` }, onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), onKeyDown: onPopoverKeyDown, role: "listbox", tabIndex: -1, children: [searchable ? (
|
|
167
|
+
? createPortal(_jsxs("div", { ref: popoverRef, className: cx("af-select-popover", placement === "top" && "af-select-popover--top"), style: { position: "fixed", left: `${pos.left}px`, top: `${pos.top}px`, width: `${pos.width}px` }, onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), onWheel: (e) => e.stopPropagation(), onKeyDown: onPopoverKeyDown, role: "listbox", tabIndex: -1, children: [searchable ? (_jsxs("div", { className: "af-select-search", children: [_jsx("input", { ref: searchRef, className: "af-select-search-input", value: search, onChange: (e) => setSearch(e.target.value), placeholder: searchPlaceholder, onKeyDown: onPopoverKeyDown, "aria-invalid": Boolean(customError), "aria-describedby": customError ? "af-select-custom-error" : undefined }), customError ? (_jsx("div", { id: "af-select-custom-error", className: "af-select-custom-error", role: "alert", children: customError })) : null] })) : null, _jsx("div", { className: "af-select-options", children: loading && visibleOptions.length === 0 ? (_jsx("div", { className: "af-select-empty", children: "Loading\u2026" })) : visibleOptions.length === 0 ? (_jsx("div", { className: "af-select-empty", children: "No results" })) : (visibleOptions.map((o, i) => {
|
|
158
168
|
const isSelected = o.value === value;
|
|
159
169
|
const isHighlighted = i === highlightIdx;
|
|
160
170
|
const group = String(o.group || "").trim();
|
|
161
171
|
const prevGroup = i > 0 ? String(visibleOptions[i - 1]?.group || "").trim() : "";
|
|
162
172
|
const showGroup = Boolean(group) && group !== prevGroup;
|
|
163
|
-
return (_jsxs(React.Fragment, { children: [showGroup ? _jsx("div", { className: "af-select-group", children: group }) : null, _jsx("div", { className: cx("af-select-option", isSelected && "af-select-option--selected", isHighlighted && "af-select-option--highlighted"), onMouseEnter: () => setHighlightIdx(i), onMouseDown: (e) => {
|
|
173
|
+
return (_jsxs(React.Fragment, { children: [showGroup ? _jsx("div", { className: "af-select-group", children: group }) : null, _jsx("div", { className: cx("af-select-option", isSelected && "af-select-option--selected", isHighlighted && "af-select-option--highlighted", o.disabled && "af-select-option--disabled"), title: o.disabled ? o.reason || "Unavailable" : undefined, onMouseEnter: () => setHighlightIdx(i), onMouseDown: (e) => {
|
|
164
174
|
e.preventDefault();
|
|
165
175
|
e.stopPropagation();
|
|
166
|
-
}, onClick: () => pick(o.value), children: renderOption ? (renderOption(o, { selected: isSelected, highlighted: isHighlighted })) : (_jsxs(_Fragment, { children: [
|
|
176
|
+
}, onClick: () => pick(o.value), "aria-disabled": o.disabled ? true : undefined, children: renderOption ? (renderOption(o, { selected: isSelected, highlighted: isHighlighted })) : (_jsxs(_Fragment, { children: [_jsxs("span", { className: "af-select-option-label", children: [_jsx("span", { children: o.label }), o.reason ? _jsx("small", { className: "af-select-option-reason", children: o.reason }) : null] }), isSelected ? _jsx("span", { className: "af-select-check", children: "\u2713" }) : null] })) })] }, o.value));
|
|
167
177
|
})) })] }), document.body)
|
|
168
178
|
: null] }));
|
|
169
179
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type GatewaySessionStatusTone = "ok" | "warn" | "err";
|
|
3
|
+
export type GatewaySessionSignInCardProps = {
|
|
4
|
+
kicker?: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: React.ReactNode;
|
|
7
|
+
statusLabel?: string;
|
|
8
|
+
statusTone?: GatewaySessionStatusTone;
|
|
9
|
+
tokenSourceLabel?: string;
|
|
10
|
+
showGatewayUrl?: boolean;
|
|
11
|
+
gatewayUrl?: string;
|
|
12
|
+
gatewayUrlPlaceholder?: string;
|
|
13
|
+
onGatewayUrlChange?: (value: string) => void;
|
|
14
|
+
userId: string;
|
|
15
|
+
userPlaceholder?: string;
|
|
16
|
+
onUserIdChange: (value: string) => void;
|
|
17
|
+
token: string;
|
|
18
|
+
tokenPlaceholder?: string;
|
|
19
|
+
showToken?: boolean;
|
|
20
|
+
onTokenChange: (value: string) => void;
|
|
21
|
+
onShowTokenChange?: (value: boolean) => void;
|
|
22
|
+
remember?: boolean;
|
|
23
|
+
rememberLabel?: string;
|
|
24
|
+
onRememberChange?: (value: boolean) => void;
|
|
25
|
+
loading?: boolean;
|
|
26
|
+
submitting?: boolean;
|
|
27
|
+
submitDisabled?: boolean;
|
|
28
|
+
submitLabel?: string;
|
|
29
|
+
submittingLabel?: string;
|
|
30
|
+
closeLabel?: string;
|
|
31
|
+
signOutLabel?: string;
|
|
32
|
+
showClose?: boolean;
|
|
33
|
+
showSignOut?: boolean;
|
|
34
|
+
error?: string;
|
|
35
|
+
className?: string;
|
|
36
|
+
onSubmit: () => void | Promise<void>;
|
|
37
|
+
onClose?: () => void;
|
|
38
|
+
onSignOut?: () => void | Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
export declare function GatewaySessionSignInCard({ kicker, title, description, statusLabel, statusTone, tokenSourceLabel, showGatewayUrl, gatewayUrl, gatewayUrlPlaceholder, onGatewayUrlChange, userId, userPlaceholder, onUserIdChange, token, tokenPlaceholder, showToken, onTokenChange, onShowTokenChange, remember, rememberLabel, onRememberChange, loading, submitting, submitDisabled, submitLabel, submittingLabel, closeLabel, signOutLabel, showClose, showSignOut, error, className, onSubmit, onClose, onSignOut, }: GatewaySessionSignInCardProps): React.ReactElement;
|
|
41
|
+
//# sourceMappingURL=gateway_session_signin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway_session_signin.d.ts","sourceRoot":"","sources":["../src/gateway_session_signin.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,MAAM,wBAAwB,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAE7C,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAE7C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAE5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAMF,wBAAgB,wBAAwB,CAAC,EACvC,MAAqC,EACrC,KAAoC,EACpC,WAAkF,EAClF,WAAqC,EACrC,UAAmB,EACnB,gBAAmC,EACnC,cAAsB,EACtB,UAAe,EACf,qBAA+C,EAC/C,kBAAkB,EAClB,MAAM,EACN,eAAyB,EACzB,cAAc,EACd,KAAK,EACL,gBAA6C,EAC7C,SAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,QAAgB,EAChB,aAAuC,EACvC,gBAAgB,EAChB,OAAe,EACf,UAAkB,EAClB,cAAsB,EACtB,WAAuB,EACvB,eAAiC,EACjC,UAAoB,EACpB,YAAyB,EACzB,SAAiB,EACjB,WAAmB,EACnB,KAAK,EACL,SAAS,EACT,QAAQ,EACR,OAAO,EACP,SAAS,GACV,EAAE,6BAA6B,GAAG,KAAK,CAAC,YAAY,CA+GpD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
function cx(...parts) {
|
|
3
|
+
return parts.filter(Boolean).join(" ");
|
|
4
|
+
}
|
|
5
|
+
export function GatewaySessionSignInCard({ kicker = "AbstractGateway connection", title = "Connect to AbstractGateway", description = "Sign in with the Gateway user token assigned by the Gateway admin.", statusLabel = "Gateway token missing", statusTone = "warn", tokenSourceLabel = "token: missing", showGatewayUrl = false, gatewayUrl = "", gatewayUrlPlaceholder = "http://127.0.0.1:8080", onGatewayUrlChange, userId, userPlaceholder = "admin", onUserIdChange, token, tokenPlaceholder = "Paste Gateway user token", showToken = false, onTokenChange, onShowTokenChange, remember = false, rememberLabel = "Remember this browser", onRememberChange, loading = false, submitting = false, submitDisabled = false, submitLabel = "Sign in", submittingLabel = "Signing in...", closeLabel = "Close", signOutLabel = "Sign out", showClose = false, showSignOut = false, error, className, onSubmit, onClose, onSignOut, }) {
|
|
6
|
+
const busy = loading || submitting;
|
|
7
|
+
const disabled = busy || submitDisabled || !String(userId || "").trim() || !String(token || "").trim();
|
|
8
|
+
const handleSubmit = (event) => {
|
|
9
|
+
event.preventDefault();
|
|
10
|
+
if (disabled)
|
|
11
|
+
return;
|
|
12
|
+
void onSubmit();
|
|
13
|
+
};
|
|
14
|
+
return (_jsxs("form", { className: cx("af-gateway-signin", className), onSubmit: handleSubmit, children: [_jsxs("div", { className: "af-gateway-signin__hero", children: [_jsxs("div", { children: [_jsx("div", { className: "af-gateway-signin__kicker", children: kicker }), _jsx("h2", { children: title }), description ? _jsx("p", { children: description }) : null] }), _jsx("div", { className: "af-gateway-signin__mark", "aria-hidden": "true", children: "\u2194" })] }), _jsxs("div", { className: "af-gateway-signin__status-row", children: [_jsx("span", { className: cx("af-gateway-signin__status", `af-gateway-signin__status--${statusTone}`), children: statusLabel }), tokenSourceLabel ? _jsx("span", { className: "af-gateway-signin__source", children: tokenSourceLabel }) : null] }), _jsxs("div", { className: "af-gateway-signin__form", children: [showGatewayUrl ? (_jsxs(_Fragment, { children: [_jsx("label", { className: "af-gateway-signin__label", htmlFor: "gateway-session-url", children: "Gateway URL" }), _jsx("input", { id: "gateway-session-url", value: gatewayUrl, onChange: (event) => onGatewayUrlChange?.(event.target.value), placeholder: gatewayUrlPlaceholder, autoComplete: "url", disabled: busy })] })) : null, _jsx("label", { className: "af-gateway-signin__label", htmlFor: "gateway-session-user", children: "Gateway user" }), _jsx("input", { id: "gateway-session-user", value: userId, onChange: (event) => onUserIdChange(event.target.value), placeholder: userPlaceholder, autoComplete: "username", disabled: busy }), _jsx("label", { className: "af-gateway-signin__label", htmlFor: "gateway-session-token", children: "Gateway token" }), _jsxs("div", { className: "af-gateway-signin__token-input", children: [_jsx("input", { id: "gateway-session-token", type: showToken ? "text" : "password", value: token, onChange: (event) => onTokenChange(event.target.value), placeholder: tokenPlaceholder, autoComplete: "current-password", disabled: busy }), _jsx("button", { className: "af-gateway-signin__secondary", type: "button", onClick: () => onShowTokenChange?.(!showToken), disabled: busy, children: showToken ? "Hide" : "Show" })] }), _jsx("label", { className: "af-gateway-signin__label", children: "Browser session" }), _jsxs("label", { className: "af-gateway-signin__checkbox", children: [_jsx("input", { type: "checkbox", checked: Boolean(remember), onChange: (event) => onRememberChange?.(event.target.checked), disabled: busy }), rememberLabel] })] }), error ? _jsx("div", { className: "af-gateway-signin__message af-gateway-signin__message--error", children: error }) : null, _jsxs("div", { className: "af-gateway-signin__actions", children: [showClose ? (_jsx("button", { className: "af-gateway-signin__secondary", type: "button", onClick: onClose, disabled: busy, children: closeLabel })) : null, showSignOut ? (_jsx("button", { className: "af-gateway-signin__secondary", type: "button", onClick: () => void onSignOut?.(), disabled: busy, children: signOutLabel })) : null, _jsx("button", { className: "af-gateway-signin__primary", type: "submit", disabled: disabled, children: submitting ? submittingLabel : submitLabel })] })] }));
|
|
15
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
export { THEMES, THEME_SPECS, applyTheme, getThemeSpec, themeClassName, type ThemeOption, type ThemeSpec } from "./theme";
|
|
2
|
-
export { FONT_SCALES, HEADER_DENSITIES, applyTypography, getFontScaleSpec, getHeaderDensitySpec, type FontScaleOption, type HeaderDensityOption } from "./typography";
|
|
3
|
-
export { AfSelect, type AfSelectProps, type AfSelectOption } from "./af_select";
|
|
4
|
-
export { ProviderModelSelect, type ProviderModelSelectProps, type ProviderOption } from "./provider_model_select";
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
1
|
+
export { THEMES, THEME_SPECS, applyTheme, getThemeSpec, themeClassName, type ThemeOption, type ThemeSpec } from "./theme.js";
|
|
2
|
+
export { FONT_SCALES, HEADER_DENSITIES, applyTypography, getFontScaleSpec, getHeaderDensitySpec, type FontScaleOption, type HeaderDensityOption } from "./typography.js";
|
|
3
|
+
export { AfSelect, type AfSelectProps, type AfSelectOption } from "./af_select.js";
|
|
4
|
+
export { ProviderModelSelect, type ProviderModelSelectProps, type ProviderOption } from "./provider_model_select.js";
|
|
5
|
+
export { GatewaySessionSignInCard, type GatewaySessionSignInCardProps, type GatewaySessionStatusTone, } from "./gateway_session_signin.js";
|
|
6
|
+
export { ThemeSelect, type ThemeSelectProps } from "./theme_select.js";
|
|
7
|
+
export { FontScaleSelect, HeaderDensitySelect, type FontScaleSelectProps, type HeaderDensitySelectProps } from "./typography_select.js";
|
|
8
|
+
export { Icon, type IconName } from "./icon.js";
|
|
9
|
+
export { ToolPolicyEditor, TOOL_POLICY_DEFAULTS, type ToolPolicyEditorProps, type ToolPolicySelection, type ToolPolicyDefaults, type ToolSpec, type ToolApprovalMode, } from "./tool_policy_editor.js";
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7H,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,KAAK,eAAe,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACzK,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACrH,OAAO,EACL,wBAAwB,EACxB,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,GAC9B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,KAAK,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACxI,OAAO,EAAE,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export { THEMES, THEME_SPECS, applyTheme, getThemeSpec, themeClassName } from "./theme";
|
|
2
|
-
export { FONT_SCALES, HEADER_DENSITIES, applyTypography, getFontScaleSpec, getHeaderDensitySpec } from "./typography";
|
|
3
|
-
export { AfSelect } from "./af_select";
|
|
4
|
-
export { ProviderModelSelect } from "./provider_model_select";
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
1
|
+
export { THEMES, THEME_SPECS, applyTheme, getThemeSpec, themeClassName } from "./theme.js";
|
|
2
|
+
export { FONT_SCALES, HEADER_DENSITIES, applyTypography, getFontScaleSpec, getHeaderDensitySpec } from "./typography.js";
|
|
3
|
+
export { AfSelect } from "./af_select.js";
|
|
4
|
+
export { ProviderModelSelect } from "./provider_model_select.js";
|
|
5
|
+
export { GatewaySessionSignInCard, } from "./gateway_session_signin.js";
|
|
6
|
+
export { ThemeSelect } from "./theme_select.js";
|
|
7
|
+
export { FontScaleSelect, HeaderDensitySelect } from "./typography_select.js";
|
|
8
|
+
export { Icon } from "./icon.js";
|
|
9
|
+
export { ToolPolicyEditor, TOOL_POLICY_DEFAULTS, } from "./tool_policy_editor.js";
|
package/dist/theme_select.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme_select.d.ts","sourceRoot":"","sources":["../src/theme_select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"theme_select.d.ts","sourceRoot":"","sources":["../src/theme_select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAMF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,KAAK,CAAC,YAAY,CAqEvE;AAED,eAAe,WAAW,CAAC"}
|
package/dist/theme_select.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
|
-
import { AfSelect } from "./af_select";
|
|
4
|
-
import { THEME_SPECS } from "./theme";
|
|
3
|
+
import { AfSelect } from "./af_select.js";
|
|
4
|
+
import { THEME_SPECS } from "./theme.js";
|
|
5
5
|
function theme_group_label(group) {
|
|
6
6
|
return group === "light" ? "Light" : "Dark";
|
|
7
7
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type ToolSpec = {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
toolset?: string;
|
|
6
|
+
when_to_use?: string;
|
|
7
|
+
};
|
|
8
|
+
export type ToolApprovalMode = "approve" | "ask";
|
|
9
|
+
export type ToolPolicyDefaults = {
|
|
10
|
+
autoApprove: string[];
|
|
11
|
+
requireApproval: string[];
|
|
12
|
+
};
|
|
13
|
+
export type ToolPolicySelection = {
|
|
14
|
+
mode: "all" | "custom";
|
|
15
|
+
selected: string[];
|
|
16
|
+
approval: Record<string, ToolApprovalMode>;
|
|
17
|
+
};
|
|
18
|
+
export type ToolPolicyEditorProps = {
|
|
19
|
+
tools: ToolSpec[];
|
|
20
|
+
value: ToolPolicySelection;
|
|
21
|
+
onChange: (next: ToolPolicySelection) => void;
|
|
22
|
+
defaults?: ToolPolicyDefaults;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
title?: string;
|
|
25
|
+
subtitle?: string;
|
|
26
|
+
note?: string;
|
|
27
|
+
toolMode?: string;
|
|
28
|
+
toolModeLabel?: string;
|
|
29
|
+
toolModeDetail?: string;
|
|
30
|
+
className?: string;
|
|
31
|
+
};
|
|
32
|
+
export declare const TOOL_POLICY_DEFAULTS: ToolPolicyDefaults;
|
|
33
|
+
export declare function ToolPolicyEditor(props: ToolPolicyEditorProps): React.ReactElement;
|
|
34
|
+
export default ToolPolicyEditor;
|
|
35
|
+
//# sourceMappingURL=tool_policy_editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool_policy_editor.d.ts","sourceRoot":"","sources":["../src/tool_policy_editor.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAEjD,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,KAAK,CAAC;AAEjD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,KAAK,GAAG,QAAQ,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,kBAwBlC,CAAC;AAgEF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,KAAK,CAAC,YAAY,CA4KjF;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* ToolPolicyEditor: shared allowlist + approval selector for thin clients.
|
|
4
|
+
*/
|
|
5
|
+
import { useMemo, useState } from "react";
|
|
6
|
+
// Mirrors AbstractRuntime ToolApprovalPolicy defaults (keep in sync).
|
|
7
|
+
export const TOOL_POLICY_DEFAULTS = {
|
|
8
|
+
autoApprove: [
|
|
9
|
+
"list_files",
|
|
10
|
+
"skim_folders",
|
|
11
|
+
"analyze_code",
|
|
12
|
+
"read_file",
|
|
13
|
+
"skim_files",
|
|
14
|
+
"search_files",
|
|
15
|
+
"open_attachment",
|
|
16
|
+
"web_search",
|
|
17
|
+
"skim_websearch",
|
|
18
|
+
"skim_url",
|
|
19
|
+
"fetch_url",
|
|
20
|
+
"list_email_accounts",
|
|
21
|
+
"list_emails",
|
|
22
|
+
"read_email",
|
|
23
|
+
"list_whatsapp_messages",
|
|
24
|
+
"read_whatsapp_message",
|
|
25
|
+
"send_email",
|
|
26
|
+
"send_whatsapp_message",
|
|
27
|
+
"send_telegram_message",
|
|
28
|
+
"send_telegram_artifact",
|
|
29
|
+
],
|
|
30
|
+
requireApproval: ["write_file", "edit_file", "execute_command"],
|
|
31
|
+
};
|
|
32
|
+
function normalize_tools(items) {
|
|
33
|
+
const seen = new Set();
|
|
34
|
+
const out = [];
|
|
35
|
+
for (const it of items || []) {
|
|
36
|
+
if (!it)
|
|
37
|
+
continue;
|
|
38
|
+
const name = String(it.name || "").trim();
|
|
39
|
+
if (!name || seen.has(name))
|
|
40
|
+
continue;
|
|
41
|
+
seen.add(name);
|
|
42
|
+
out.push({
|
|
43
|
+
name,
|
|
44
|
+
description: typeof it.description === "string" ? it.description : undefined,
|
|
45
|
+
toolset: typeof it.toolset === "string" ? it.toolset : undefined,
|
|
46
|
+
when_to_use: typeof it.when_to_use === "string" ? it.when_to_use : undefined,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
out.sort((a, b) => {
|
|
50
|
+
const a_set = String(a.toolset || "");
|
|
51
|
+
const b_set = String(b.toolset || "");
|
|
52
|
+
if (a_set !== b_set)
|
|
53
|
+
return a_set.localeCompare(b_set);
|
|
54
|
+
return a.name.localeCompare(b.name);
|
|
55
|
+
});
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
function default_mode_for(name, defaults) {
|
|
59
|
+
if (defaults.requireApproval.includes(name))
|
|
60
|
+
return "ask";
|
|
61
|
+
if (defaults.autoApprove.includes(name))
|
|
62
|
+
return "approve";
|
|
63
|
+
return "ask";
|
|
64
|
+
}
|
|
65
|
+
function describe_tool_mode(raw, override_label, override_detail) {
|
|
66
|
+
const mode = String(raw || "").trim().toLowerCase();
|
|
67
|
+
if (!mode && !override_label && !override_detail)
|
|
68
|
+
return null;
|
|
69
|
+
let info;
|
|
70
|
+
if (mode === "approval" || mode === "local_approval" || mode === "local-approval") {
|
|
71
|
+
info = { label: "APPROVAL", detail: "Safe tools auto-run; mutating tools ask for approval.", tone: "safe" };
|
|
72
|
+
}
|
|
73
|
+
else if (mode === "passthrough") {
|
|
74
|
+
info = { label: "PASSTHROUGH", detail: "All tools require approval before execution.", tone: "warn" };
|
|
75
|
+
}
|
|
76
|
+
else if (mode === "delegated" || mode === "delegate" || mode === "job") {
|
|
77
|
+
info = { label: "DELEGATED", detail: "Tool calls wait for external executors.", tone: "info" };
|
|
78
|
+
}
|
|
79
|
+
else if (mode === "local" || mode === "local_all" || mode === "local-all") {
|
|
80
|
+
info = { label: "LOCAL", detail: "All tools run locally; client policy may still require approval.", tone: "danger" };
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
info = { label: "UNKNOWN", detail: "#FALLBACK: gateway tool mode not reported.", tone: "warn" };
|
|
84
|
+
}
|
|
85
|
+
if (override_label)
|
|
86
|
+
info = { ...info, label: override_label };
|
|
87
|
+
if (override_detail)
|
|
88
|
+
info = { ...info, detail: override_detail };
|
|
89
|
+
return info;
|
|
90
|
+
}
|
|
91
|
+
export function ToolPolicyEditor(props) {
|
|
92
|
+
const defaults = props.defaults || TOOL_POLICY_DEFAULTS;
|
|
93
|
+
const disabled = props.disabled === true;
|
|
94
|
+
const title = props.title || "Tools";
|
|
95
|
+
const subtitle = props.subtitle ||
|
|
96
|
+
"Default is all tools. Safe/read-only tools auto-approve; mutating tools ask for approval.";
|
|
97
|
+
const note = String(props.note || "").trim();
|
|
98
|
+
const tool_mode = useMemo(() => describe_tool_mode(props.toolMode, props.toolModeLabel, props.toolModeDetail), [props.toolMode, props.toolModeLabel, props.toolModeDetail]);
|
|
99
|
+
const tools = useMemo(() => normalize_tools(props.tools), [props.tools]);
|
|
100
|
+
const all_names = useMemo(() => tools.map((t) => t.name), [tools]);
|
|
101
|
+
const all_names_set = useMemo(() => new Set(all_names), [all_names]);
|
|
102
|
+
const [filter, setFilter] = useState("");
|
|
103
|
+
const selected = useMemo(() => {
|
|
104
|
+
const raw = Array.isArray(props.value?.selected) ? props.value.selected : [];
|
|
105
|
+
return raw.map((n) => String(n || "").trim()).filter((n) => n && all_names_set.has(n));
|
|
106
|
+
}, [props.value?.selected, all_names_set]);
|
|
107
|
+
const mode = props.value?.mode === "custom" ? "custom" : "all";
|
|
108
|
+
const filtered = useMemo(() => {
|
|
109
|
+
const q = filter.trim().toLowerCase();
|
|
110
|
+
if (!q)
|
|
111
|
+
return tools;
|
|
112
|
+
return tools.filter((t) => {
|
|
113
|
+
const name = t.name.toLowerCase();
|
|
114
|
+
const desc = (t.description || "").toLowerCase();
|
|
115
|
+
return name.includes(q) || desc.includes(q);
|
|
116
|
+
});
|
|
117
|
+
}, [tools, filter]);
|
|
118
|
+
const effective_selected = mode === "all" ? new Set(all_names) : new Set(selected);
|
|
119
|
+
const on_change = (next) => {
|
|
120
|
+
props.onChange(next);
|
|
121
|
+
};
|
|
122
|
+
const toggle_mode = (next) => {
|
|
123
|
+
if (disabled)
|
|
124
|
+
return;
|
|
125
|
+
on_change({ ...props.value, mode: next, selected });
|
|
126
|
+
};
|
|
127
|
+
const toggle_tool = (name, enabled) => {
|
|
128
|
+
if (disabled)
|
|
129
|
+
return;
|
|
130
|
+
const set = new Set(selected);
|
|
131
|
+
if (enabled)
|
|
132
|
+
set.add(name);
|
|
133
|
+
else
|
|
134
|
+
set.delete(name);
|
|
135
|
+
on_change({ ...props.value, selected: Array.from(set), mode: "custom" });
|
|
136
|
+
};
|
|
137
|
+
const set_approval = (name, mode_value) => {
|
|
138
|
+
if (disabled)
|
|
139
|
+
return;
|
|
140
|
+
const next = { ...(props.value?.approval || {}) };
|
|
141
|
+
next[name] = mode_value;
|
|
142
|
+
on_change({ ...props.value, approval: next });
|
|
143
|
+
};
|
|
144
|
+
const select_all = () => {
|
|
145
|
+
if (disabled)
|
|
146
|
+
return;
|
|
147
|
+
on_change({ ...props.value, selected: Array.from(all_names), mode: "custom" });
|
|
148
|
+
};
|
|
149
|
+
const select_none = () => {
|
|
150
|
+
if (disabled)
|
|
151
|
+
return;
|
|
152
|
+
on_change({ ...props.value, selected: [], mode: "custom" });
|
|
153
|
+
};
|
|
154
|
+
const selected_count = effective_selected.size;
|
|
155
|
+
return (_jsxs("div", { className: `af-tool-policy ${props.className || ""}`.trim(), children: [_jsxs("div", { className: "af-tool-policy__header", children: [_jsx("div", { className: "af-tool-policy__title", children: title }), _jsx("div", { className: "af-tool-policy__subtitle", children: subtitle }), tool_mode ? (_jsxs("div", { className: `af-tool-policy__mode is-${tool_mode.tone}`, children: [_jsx("div", { className: "af-tool-policy__mode-badge", children: "Tool mode" }), _jsx("div", { className: "af-tool-policy__mode-value", children: tool_mode.label }), _jsx("div", { className: "af-tool-policy__mode-detail", children: tool_mode.detail })] })) : null, note ? _jsx("div", { className: "af-tool-policy__note", children: note }) : null] }), _jsxs("div", { className: "af-tool-policy__controls", children: [_jsxs("div", { className: "af-tool-policy__segmented", role: "tablist", "aria-label": "Tool allowlist mode", children: [_jsx("button", { type: "button", className: `af-tool-policy__seg-btn ${mode === "all" ? "is-active" : ""}`.trim(), onClick: () => toggle_mode("all"), disabled: disabled, children: "All tools" }), _jsx("button", { type: "button", className: `af-tool-policy__seg-btn ${mode === "custom" ? "is-active" : ""}`.trim(), onClick: () => toggle_mode("custom"), disabled: disabled, children: "Custom allowlist" })] }), _jsxs("div", { className: "af-tool-policy__count", children: [selected_count, " / ", all_names.length, " enabled"] }), _jsxs("div", { className: "af-tool-policy__bulk", children: [_jsx("button", { type: "button", onClick: select_all, disabled: disabled || mode !== "custom", children: "Select all" }), _jsx("button", { type: "button", onClick: select_none, disabled: disabled || mode !== "custom", children: "Select none" })] })] }), _jsx("div", { className: "af-tool-policy__filter", children: _jsx("input", { type: "text", placeholder: "Filter tools...", value: filter, onChange: (e) => setFilter(e.target.value), disabled: disabled }) }), _jsxs("div", { className: "af-tool-policy__list", children: [filtered.map((tool) => {
|
|
156
|
+
const is_checked = effective_selected.has(tool.name);
|
|
157
|
+
const approval = props.value?.approval?.[tool.name] || default_mode_for(tool.name, defaults);
|
|
158
|
+
return (_jsxs("div", { className: `af-tool-row ${is_checked ? "is-enabled" : ""}`.trim(), children: [_jsx("label", { className: "af-tool-row__check", children: _jsx("input", { type: "checkbox", checked: is_checked, disabled: disabled || mode !== "custom", onChange: (e) => toggle_tool(tool.name, e.target.checked) }) }), _jsxs("div", { className: "af-tool-row__meta", children: [_jsxs("div", { className: "af-tool-row__title", children: [_jsx("span", { className: "af-tool-row__name", children: tool.name }), tool.toolset ? _jsx("span", { className: "af-tool-row__badge", children: tool.toolset }) : null] }), tool.description ? _jsx("div", { className: "af-tool-row__desc", children: tool.description }) : null, tool.when_to_use ? _jsx("div", { className: "af-tool-row__hint", children: tool.when_to_use }) : null] }), _jsx("div", { className: "af-tool-row__approval", children: _jsxs("select", { value: approval, disabled: disabled || !is_checked, onChange: (e) => set_approval(tool.name, e.target.value), children: [_jsx("option", { value: "approve", children: "Approve" }), _jsx("option", { value: "ask", children: "Ask" })] }) })] }, tool.name));
|
|
159
|
+
}), !filtered.length ? _jsx("div", { className: "af-tool-policy__empty", children: "No tools match the filter." }) : null] })] }));
|
|
160
|
+
}
|
|
161
|
+
export default ToolPolicyEditor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { type FontScaleOption, type HeaderDensityOption } from "./typography";
|
|
2
|
+
import { type FontScaleOption, type HeaderDensityOption } from "./typography.js";
|
|
3
3
|
export type FontScaleSelectProps = {
|
|
4
4
|
value: string;
|
|
5
5
|
onChange: (font_scale_id: string) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typography_select.d.ts","sourceRoot":"","sources":["../src/typography_select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAiC,KAAK,eAAe,EAAE,KAAK,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"typography_select.d.ts","sourceRoot":"","sources":["../src/typography_select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAiC,KAAK,eAAe,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEhH,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,CAuB/E;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,KAAK,CAAC,YAAY,CAuBvF;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
|
-
import { AfSelect } from "./af_select";
|
|
4
|
-
import { FONT_SCALES, HEADER_DENSITIES } from "./typography";
|
|
3
|
+
import { AfSelect } from "./af_select.js";
|
|
4
|
+
import { FONT_SCALES, HEADER_DENSITIES } from "./typography.js";
|
|
5
5
|
export function FontScaleSelect(props) {
|
|
6
6
|
const scales = props.scales && props.scales.length ? props.scales : FONT_SCALES;
|
|
7
7
|
const variant = props.variant || "panel";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abstractframework/ui-kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Shared UI tokens + themes for AbstractFramework thin clients (AbstractFlow, AbstractObserver, etc.).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Laurent-Philippe Albou",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"react-dom": "^18.0.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"react": "^18.0.0",
|
|
48
|
-
"react-dom": "^18.0.0",
|
|
49
47
|
"@types/react": "^18.2.48",
|
|
50
48
|
"@types/react-dom": "^18.2.18",
|
|
49
|
+
"react": "^18.0.0",
|
|
50
|
+
"react-dom": "^18.0.0",
|
|
51
51
|
"typescript": "^5.3.3"
|
|
52
52
|
},
|
|
53
53
|
"sideEffects": [
|
package/src/theme.css
CHANGED
|
@@ -112,6 +112,224 @@
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/* Shared Gateway browser-session sign-in card */
|
|
116
|
+
.af-gateway-signin {
|
|
117
|
+
display: block;
|
|
118
|
+
width: min(760px, 100%);
|
|
119
|
+
border: 1px solid rgba(0, 210, 255, 0.20);
|
|
120
|
+
border-radius: var(--radius-md);
|
|
121
|
+
padding: 24px;
|
|
122
|
+
background:
|
|
123
|
+
linear-gradient(135deg, rgba(18, 31, 61, 0.98), rgba(22, 20, 42, 0.98)),
|
|
124
|
+
var(--bg-secondary);
|
|
125
|
+
box-shadow: 0 28px 90px rgba(0, 0, 0, 0.45);
|
|
126
|
+
color: var(--text-primary);
|
|
127
|
+
font-family: var(--font-sans);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.af-gateway-signin h2 {
|
|
131
|
+
margin: 0;
|
|
132
|
+
font-size: var(--font-size-xl);
|
|
133
|
+
line-height: 1.25;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.af-gateway-signin p {
|
|
137
|
+
margin: 14px 0 0;
|
|
138
|
+
color: var(--text-secondary);
|
|
139
|
+
font-size: var(--font-size-base);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.af-gateway-signin input {
|
|
143
|
+
width: 100%;
|
|
144
|
+
min-height: 40px;
|
|
145
|
+
border: 1px solid rgba(96, 165, 250, 0.34);
|
|
146
|
+
border-radius: var(--radius-sm);
|
|
147
|
+
background: rgba(9, 14, 29, 0.76);
|
|
148
|
+
color: var(--text-primary);
|
|
149
|
+
padding: 9px 11px;
|
|
150
|
+
font: inherit;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.af-gateway-signin input:focus {
|
|
154
|
+
outline: 2px solid rgba(0, 210, 255, 0.65);
|
|
155
|
+
outline-offset: 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.af-gateway-signin input[type="checkbox"] {
|
|
159
|
+
width: auto;
|
|
160
|
+
min-height: auto;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.af-gateway-signin button {
|
|
164
|
+
border: 0;
|
|
165
|
+
border-radius: var(--radius-sm);
|
|
166
|
+
min-height: 38px;
|
|
167
|
+
padding: 8px 14px;
|
|
168
|
+
color: #fff;
|
|
169
|
+
font: inherit;
|
|
170
|
+
font-weight: 800;
|
|
171
|
+
cursor: pointer;
|
|
172
|
+
white-space: nowrap;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.af-gateway-signin button:disabled {
|
|
176
|
+
opacity: 0.55;
|
|
177
|
+
cursor: not-allowed;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.af-gateway-signin__hero {
|
|
181
|
+
display: flex;
|
|
182
|
+
justify-content: space-between;
|
|
183
|
+
gap: 24px;
|
|
184
|
+
margin-bottom: 22px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.af-gateway-signin__kicker {
|
|
188
|
+
margin-bottom: 8px;
|
|
189
|
+
color: rgba(0, 210, 255, 0.86);
|
|
190
|
+
font-size: var(--font-size-xs);
|
|
191
|
+
font-weight: 800;
|
|
192
|
+
letter-spacing: 0.14em;
|
|
193
|
+
text-transform: uppercase;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.af-gateway-signin__mark {
|
|
197
|
+
width: 72px;
|
|
198
|
+
height: 72px;
|
|
199
|
+
display: grid;
|
|
200
|
+
place-items: center;
|
|
201
|
+
flex: 0 0 auto;
|
|
202
|
+
border-radius: 24px;
|
|
203
|
+
border: 1px solid rgba(0, 210, 255, 0.24);
|
|
204
|
+
background: linear-gradient(135deg, rgba(0, 210, 255, 0.18), rgba(233, 69, 96, 0.22));
|
|
205
|
+
color: rgba(255, 255, 255, 0.86);
|
|
206
|
+
font-size: 32px;
|
|
207
|
+
font-weight: 900;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.af-gateway-signin__status-row {
|
|
211
|
+
display: flex;
|
|
212
|
+
align-items: center;
|
|
213
|
+
gap: 10px;
|
|
214
|
+
flex-wrap: wrap;
|
|
215
|
+
margin-bottom: 18px;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.af-gateway-signin__status {
|
|
219
|
+
display: inline-flex;
|
|
220
|
+
align-items: center;
|
|
221
|
+
min-height: 26px;
|
|
222
|
+
padding: 4px 12px;
|
|
223
|
+
border-radius: 999px;
|
|
224
|
+
font-size: var(--font-size-xs);
|
|
225
|
+
font-weight: 800;
|
|
226
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
227
|
+
background: rgba(255, 255, 255, 0.06);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.af-gateway-signin__status--ok {
|
|
231
|
+
color: rgba(120, 255, 190, 0.95);
|
|
232
|
+
border-color: rgba(39, 174, 96, 0.36);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.af-gateway-signin__status--warn {
|
|
236
|
+
color: rgba(255, 210, 120, 0.95);
|
|
237
|
+
border-color: rgba(243, 156, 18, 0.36);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.af-gateway-signin__status--err {
|
|
241
|
+
color: rgba(255, 115, 135, 0.95);
|
|
242
|
+
border-color: rgba(233, 69, 96, 0.42);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.af-gateway-signin__source {
|
|
246
|
+
color: var(--text-muted);
|
|
247
|
+
font-size: var(--font-size-sm);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.af-gateway-signin__form {
|
|
251
|
+
display: grid;
|
|
252
|
+
grid-template-columns: 150px minmax(0, 1fr);
|
|
253
|
+
gap: 12px;
|
|
254
|
+
align-items: center;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.af-gateway-signin__label {
|
|
258
|
+
margin: 0;
|
|
259
|
+
color: var(--text-secondary);
|
|
260
|
+
font-size: var(--font-size-xs);
|
|
261
|
+
font-weight: 800;
|
|
262
|
+
letter-spacing: 0.04em;
|
|
263
|
+
text-transform: uppercase;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.af-gateway-signin__token-input {
|
|
267
|
+
display: flex;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: 8px;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.af-gateway-signin__token-input input {
|
|
273
|
+
flex: 1;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.af-gateway-signin__checkbox {
|
|
277
|
+
display: flex;
|
|
278
|
+
align-items: center;
|
|
279
|
+
gap: 10px;
|
|
280
|
+
margin: 0;
|
|
281
|
+
color: var(--text-secondary);
|
|
282
|
+
font-weight: 700;
|
|
283
|
+
text-transform: none;
|
|
284
|
+
letter-spacing: 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.af-gateway-signin__message {
|
|
288
|
+
margin-top: 14px;
|
|
289
|
+
overflow-wrap: anywhere;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.af-gateway-signin__message--error {
|
|
293
|
+
color: rgba(255, 156, 175, 0.95);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.af-gateway-signin__actions {
|
|
297
|
+
display: flex;
|
|
298
|
+
justify-content: flex-end;
|
|
299
|
+
gap: 10px;
|
|
300
|
+
margin-top: 20px;
|
|
301
|
+
flex-wrap: wrap;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.af-gateway-signin__primary {
|
|
305
|
+
background: var(--accent);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.af-gateway-signin__secondary {
|
|
309
|
+
background: var(--bg-tertiary);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
@media (max-width: 680px) {
|
|
313
|
+
.af-gateway-signin {
|
|
314
|
+
padding: 18px;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.af-gateway-signin__hero {
|
|
318
|
+
gap: 16px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.af-gateway-signin__mark {
|
|
322
|
+
width: 56px;
|
|
323
|
+
height: 56px;
|
|
324
|
+
border-radius: 18px;
|
|
325
|
+
font-size: 26px;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.af-gateway-signin__form {
|
|
329
|
+
grid-template-columns: 1fr;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
115
333
|
:root.theme-light,
|
|
116
334
|
:root.theme-solarized-light,
|
|
117
335
|
:root.theme-catppuccin-latte,
|
|
@@ -201,6 +419,255 @@
|
|
|
201
419
|
--border-accent: rgba(136, 192, 208, 0.55);
|
|
202
420
|
}
|
|
203
421
|
|
|
422
|
+
/* Tool policy editor (allowlist + approve/ask) */
|
|
423
|
+
.af-tool-policy {
|
|
424
|
+
display: flex;
|
|
425
|
+
flex-direction: column;
|
|
426
|
+
gap: 12px;
|
|
427
|
+
padding: 16px;
|
|
428
|
+
border-radius: var(--radius-lg);
|
|
429
|
+
border: 1px solid var(--ui-border-1);
|
|
430
|
+
background: var(--ui-surface-1);
|
|
431
|
+
box-shadow: var(--ui-shadow-1);
|
|
432
|
+
color: var(--text-primary);
|
|
433
|
+
font-family: var(--font-sans);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.af-tool-policy__header {
|
|
437
|
+
display: flex;
|
|
438
|
+
flex-direction: column;
|
|
439
|
+
gap: 6px;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.af-tool-policy__title {
|
|
443
|
+
font-size: var(--font-size-xs);
|
|
444
|
+
font-weight: 700;
|
|
445
|
+
letter-spacing: 0.12em;
|
|
446
|
+
color: var(--accent);
|
|
447
|
+
text-transform: uppercase;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.af-tool-policy__subtitle {
|
|
451
|
+
font-size: var(--font-size-sm);
|
|
452
|
+
color: var(--text-secondary);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.af-tool-policy__mode {
|
|
456
|
+
display: grid;
|
|
457
|
+
grid-template-columns: auto auto 1fr;
|
|
458
|
+
gap: 6px 10px;
|
|
459
|
+
align-items: center;
|
|
460
|
+
padding: 8px 10px;
|
|
461
|
+
border-radius: var(--radius-md);
|
|
462
|
+
border: 1px solid var(--ui-border-1);
|
|
463
|
+
background: var(--ui-overlay-bg);
|
|
464
|
+
font-size: var(--font-size-xs);
|
|
465
|
+
font-weight: 600;
|
|
466
|
+
color: var(--text-primary);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.af-tool-policy__mode-badge {
|
|
470
|
+
text-transform: uppercase;
|
|
471
|
+
letter-spacing: 0.08em;
|
|
472
|
+
font-size: var(--font-size-xxs);
|
|
473
|
+
color: var(--text-muted);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.af-tool-policy__mode-value {
|
|
477
|
+
font-weight: 800;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.af-tool-policy__mode-detail {
|
|
481
|
+
grid-column: 1 / -1;
|
|
482
|
+
font-size: var(--font-size-xs);
|
|
483
|
+
font-weight: 500;
|
|
484
|
+
color: var(--text-secondary);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.af-tool-policy__mode.is-safe {
|
|
488
|
+
border-color: color-mix(in srgb, var(--accent) 50%, transparent);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.af-tool-policy__mode.is-warn {
|
|
492
|
+
border-color: color-mix(in srgb, #f59e0b 50%, transparent);
|
|
493
|
+
background: color-mix(in srgb, #f59e0b 12%, var(--ui-overlay-bg));
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.af-tool-policy__mode.is-danger {
|
|
497
|
+
border-color: color-mix(in srgb, #ef4444 55%, transparent);
|
|
498
|
+
background: color-mix(in srgb, #ef4444 14%, var(--ui-overlay-bg));
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.af-tool-policy__mode.is-info {
|
|
502
|
+
border-color: color-mix(in srgb, #38bdf8 50%, transparent);
|
|
503
|
+
background: color-mix(in srgb, #38bdf8 12%, var(--ui-overlay-bg));
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.af-tool-policy__note {
|
|
507
|
+
font-size: var(--font-size-xs);
|
|
508
|
+
color: var(--text-muted);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.af-tool-policy__controls {
|
|
512
|
+
display: grid;
|
|
513
|
+
grid-template-columns: minmax(180px, 1fr) auto auto;
|
|
514
|
+
gap: 10px;
|
|
515
|
+
align-items: center;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.af-tool-policy__segmented {
|
|
519
|
+
display: inline-flex;
|
|
520
|
+
background: var(--ui-overlay-bg);
|
|
521
|
+
border: 1px solid var(--ui-overlay-border);
|
|
522
|
+
border-radius: var(--radius-lg);
|
|
523
|
+
padding: 2px;
|
|
524
|
+
gap: 2px;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.af-tool-policy__seg-btn {
|
|
528
|
+
border: none;
|
|
529
|
+
background: transparent;
|
|
530
|
+
color: var(--text-secondary);
|
|
531
|
+
padding: 6px 12px;
|
|
532
|
+
font-size: var(--font-size-sm);
|
|
533
|
+
font-weight: 600;
|
|
534
|
+
border-radius: var(--radius-md);
|
|
535
|
+
cursor: pointer;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.af-tool-policy__seg-btn.is-active {
|
|
539
|
+
background: var(--ui-surface-2);
|
|
540
|
+
color: var(--text-primary);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.af-tool-policy__seg-btn:disabled {
|
|
544
|
+
cursor: not-allowed;
|
|
545
|
+
opacity: 0.6;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.af-tool-policy__count {
|
|
549
|
+
padding: 6px 12px;
|
|
550
|
+
border-radius: var(--radius-lg);
|
|
551
|
+
border: 1px solid var(--ui-border-1);
|
|
552
|
+
background: var(--ui-overlay-bg);
|
|
553
|
+
color: var(--text-secondary);
|
|
554
|
+
font-size: var(--font-size-xs);
|
|
555
|
+
font-weight: 600;
|
|
556
|
+
text-align: center;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.af-tool-policy__bulk {
|
|
560
|
+
display: inline-flex;
|
|
561
|
+
gap: 6px;
|
|
562
|
+
justify-self: end;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.af-tool-policy__bulk button {
|
|
566
|
+
border: 1px solid var(--ui-border-1);
|
|
567
|
+
background: var(--ui-overlay-bg);
|
|
568
|
+
color: var(--text-secondary);
|
|
569
|
+
border-radius: var(--radius-md);
|
|
570
|
+
padding: 6px 10px;
|
|
571
|
+
font-size: var(--font-size-xs);
|
|
572
|
+
font-weight: 600;
|
|
573
|
+
cursor: pointer;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
.af-tool-policy__bulk button:disabled {
|
|
577
|
+
cursor: not-allowed;
|
|
578
|
+
opacity: 0.5;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
.af-tool-policy__filter input {
|
|
582
|
+
width: 100%;
|
|
583
|
+
border-radius: var(--radius-md);
|
|
584
|
+
border: 1px solid var(--ui-border-1);
|
|
585
|
+
background: var(--ui-overlay-bg);
|
|
586
|
+
color: var(--text-primary);
|
|
587
|
+
padding: 8px 10px;
|
|
588
|
+
font-size: var(--font-size-sm);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
.af-tool-policy__list {
|
|
592
|
+
display: flex;
|
|
593
|
+
flex-direction: column;
|
|
594
|
+
gap: 10px;
|
|
595
|
+
max-height: 420px;
|
|
596
|
+
overflow: auto;
|
|
597
|
+
padding-right: 4px;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.af-tool-row {
|
|
601
|
+
display: grid;
|
|
602
|
+
grid-template-columns: 24px 1fr auto;
|
|
603
|
+
gap: 10px;
|
|
604
|
+
align-items: flex-start;
|
|
605
|
+
padding: 10px 12px;
|
|
606
|
+
border-radius: var(--radius-md);
|
|
607
|
+
border: 1px solid var(--ui-border-1);
|
|
608
|
+
background: var(--ui-surface-2);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.af-tool-row.is-enabled {
|
|
612
|
+
border-color: var(--accent-border);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.af-tool-row__check input {
|
|
616
|
+
width: 16px;
|
|
617
|
+
height: 16px;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.af-tool-row__title {
|
|
621
|
+
display: flex;
|
|
622
|
+
align-items: center;
|
|
623
|
+
gap: 8px;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.af-tool-row__name {
|
|
627
|
+
font-weight: 700;
|
|
628
|
+
font-size: var(--font-size-sm);
|
|
629
|
+
color: var(--text-primary);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.af-tool-row__badge {
|
|
633
|
+
padding: 2px 8px;
|
|
634
|
+
border-radius: var(--radius-md);
|
|
635
|
+
border: 1px solid var(--ui-chip-border);
|
|
636
|
+
background: var(--ui-chip-bg);
|
|
637
|
+
color: var(--ui-chip-text);
|
|
638
|
+
font-size: var(--font-size-xxs);
|
|
639
|
+
text-transform: uppercase;
|
|
640
|
+
letter-spacing: 0.08em;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.af-tool-row__desc {
|
|
644
|
+
font-size: var(--font-size-xs);
|
|
645
|
+
color: var(--text-secondary);
|
|
646
|
+
margin-top: 4px;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.af-tool-row__hint {
|
|
650
|
+
font-size: var(--font-size-xxs);
|
|
651
|
+
color: var(--text-muted);
|
|
652
|
+
margin-top: 4px;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.af-tool-row__approval select {
|
|
656
|
+
border-radius: var(--radius-md);
|
|
657
|
+
border: 1px solid var(--ui-border-1);
|
|
658
|
+
background: var(--ui-overlay-bg);
|
|
659
|
+
color: var(--text-primary);
|
|
660
|
+
padding: 6px 8px;
|
|
661
|
+
font-size: var(--font-size-xs);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.af-tool-policy__empty {
|
|
665
|
+
padding: 18px;
|
|
666
|
+
text-align: center;
|
|
667
|
+
color: var(--text-muted);
|
|
668
|
+
font-size: var(--font-size-sm);
|
|
669
|
+
}
|
|
670
|
+
|
|
204
671
|
:root.theme-dracula {
|
|
205
672
|
--bg-primary: #282a36;
|
|
206
673
|
--bg-secondary: #343746;
|
|
@@ -885,6 +1352,13 @@
|
|
|
885
1352
|
font-size: var(--font-size-base);
|
|
886
1353
|
}
|
|
887
1354
|
|
|
1355
|
+
.af-select-custom-error {
|
|
1356
|
+
margin-top: 6px;
|
|
1357
|
+
color: var(--accent);
|
|
1358
|
+
font-size: var(--font-size-xs);
|
|
1359
|
+
line-height: 1.35;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
888
1362
|
.af-select-options {
|
|
889
1363
|
max-height: 340px;
|
|
890
1364
|
overflow: auto;
|
|
@@ -926,13 +1400,37 @@
|
|
|
926
1400
|
background: var(--ui-surface-2, rgba(255, 255, 255, 0.06));
|
|
927
1401
|
}
|
|
928
1402
|
|
|
1403
|
+
.af-select-option--disabled {
|
|
1404
|
+
cursor: not-allowed;
|
|
1405
|
+
color: var(--text-muted);
|
|
1406
|
+
opacity: 0.58;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
.af-select-option--disabled.af-select-option--highlighted {
|
|
1410
|
+
background: var(--ui-surface-1, rgba(255, 255, 255, 0.04));
|
|
1411
|
+
}
|
|
1412
|
+
|
|
929
1413
|
.af-select-option-label {
|
|
1414
|
+
display: flex;
|
|
1415
|
+
flex-direction: column;
|
|
1416
|
+
gap: 2px;
|
|
930
1417
|
flex: 1;
|
|
1418
|
+
min-width: 0;
|
|
1419
|
+
overflow: hidden;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
.af-select-option-label > span {
|
|
931
1423
|
overflow: hidden;
|
|
932
1424
|
text-overflow: ellipsis;
|
|
933
1425
|
white-space: nowrap;
|
|
934
1426
|
}
|
|
935
1427
|
|
|
1428
|
+
.af-select-option-reason {
|
|
1429
|
+
color: var(--text-muted);
|
|
1430
|
+
font-size: var(--font-size-xs);
|
|
1431
|
+
line-height: 1.25;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
936
1434
|
.af-select-check {
|
|
937
1435
|
color: var(--accent);
|
|
938
1436
|
font-weight: 700;
|