@ddtcorex/dsh-maestro-config 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +213 -36
- package/lib/types/client/MaestroSettings.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client/MaestroSettings.tsx +223 -37
package/lib/client.js
CHANGED
|
@@ -2176,6 +2176,18 @@ var t = {
|
|
|
2176
2176
|
shadowLv3: "var(--dsw-shadow-lv3)",
|
|
2177
2177
|
scrollbarL2: "var(--dsw-alias-scrollbar-bg-l2)"
|
|
2178
2178
|
};
|
|
2179
|
+
var TAB_ICON_PATHS = {
|
|
2180
|
+
globe: "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20M2 12h20M12 2a15 15 0 0 1 4 10 15 15 0 0 1-4 10 15 15 0 0 1-4-10A15 15 0 0 1 12 2z",
|
|
2181
|
+
git: "M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5 0-1.2-.4-2.3-1-3 0-1 0-2 0-3s-1 0-2 1a11 11 0 0 0-6 0c-1-1-2-1-2-1 0 1 0 2 0 3-.6.7-1 1.8-1 3 0 3.5 3 5.5 6 5.5-.4.3-.7.7-.9 1.2-.2.5-.3 1-.3 1.5V22",
|
|
2182
|
+
search: "M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-3.5-3.5",
|
|
2183
|
+
shield: "M12 2l7 4v5c0 5-3.5 7.5-7 9-3.5-1.5-7-4-7-9V6l7-4z",
|
|
2184
|
+
ban: "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM4 12h16",
|
|
2185
|
+
cpu: "M5 12H2a2 2 0 0 1 2-2h2M12 5V2a2 2 0 0 1 2 2v2M19 12h2a2 2 0 0 1-2 2h-2M12 19v2a2 2 0 0 1-2-2v-2M8 8h8v8H8z",
|
|
2186
|
+
bell: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 0 1-3.4 0"
|
|
2187
|
+
};
|
|
2188
|
+
function TabIcon({ name, size = 14 }) {
|
|
2189
|
+
return (0, import_react.createElement)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", style: { flex: "none" } }, (0, import_react.createElement)("path", { d: TAB_ICON_PATHS[name] }));
|
|
2190
|
+
}
|
|
2179
2191
|
function Button({
|
|
2180
2192
|
variant = "ghost",
|
|
2181
2193
|
size = "md",
|
|
@@ -2520,14 +2532,15 @@ function ReviewModelSelector({
|
|
|
2520
2532
|
position: "absolute",
|
|
2521
2533
|
top: "calc(100% + 8px)",
|
|
2522
2534
|
left: "0",
|
|
2523
|
-
minWidth: "300px",
|
|
2524
|
-
maxWidth: "360px",
|
|
2535
|
+
minWidth: "min(300px, calc(100vw - 32px))",
|
|
2536
|
+
maxWidth: "min(360px, calc(100vw - 24px))",
|
|
2525
2537
|
background: t.bgLayer2,
|
|
2526
2538
|
border: `1px solid ${t.borderL2}`,
|
|
2527
2539
|
borderRadius: "12px",
|
|
2528
2540
|
boxShadow: t.shadowLv3,
|
|
2529
2541
|
zIndex: "20",
|
|
2530
|
-
padding: "6px"
|
|
2542
|
+
padding: "6px",
|
|
2543
|
+
boxSizing: "border-box"
|
|
2531
2544
|
};
|
|
2532
2545
|
const rowStyle2 = {
|
|
2533
2546
|
width: "100%",
|
|
@@ -2551,7 +2564,7 @@ function ReviewModelSelector({
|
|
|
2551
2564
|
const modelLabel = selectedProvider === "" ? "Select model" : value?.model ?? "Select model";
|
|
2552
2565
|
return (0, import_react.createElement)(
|
|
2553
2566
|
"div",
|
|
2554
|
-
{ ref: rootRef, "data-maestro-trigger-wrap": "", style: { position: "relative", display: "inline-block", maxWidth: "100%" } },
|
|
2567
|
+
{ ref: rootRef, "data-maestro-trigger-wrap": "", style: { position: "relative", display: "inline-block", maxWidth: "100%", minWidth: 0, boxSizing: "border-box" } },
|
|
2555
2568
|
label ? (0, import_react.createElement)("span", { style: fieldLabelStyle }, label) : null,
|
|
2556
2569
|
(0, import_react.createElement)(
|
|
2557
2570
|
"button",
|
|
@@ -2570,8 +2583,10 @@ function ReviewModelSelector({
|
|
|
2570
2583
|
alignItems: "center",
|
|
2571
2584
|
gap: 8,
|
|
2572
2585
|
cursor: "pointer",
|
|
2573
|
-
maxWidth:
|
|
2574
|
-
|
|
2586
|
+
maxWidth: "min(320px, 100%)",
|
|
2587
|
+
minWidth: 0,
|
|
2588
|
+
whiteSpace: "nowrap",
|
|
2589
|
+
boxSizing: "border-box"
|
|
2575
2590
|
},
|
|
2576
2591
|
onClick: () => {
|
|
2577
2592
|
setOpen((v) => !v);
|
|
@@ -2977,6 +2992,143 @@ function NamedTunnelSetupNote() {
|
|
|
2977
2992
|
(0, import_react.createElement)("ol", { style: { margin: "4px 0", paddingLeft: 20, fontSize: 12, color: t.labelSecondary, lineHeight: "18px" } }, (0, import_react.createElement)("li", null, "cloudflared tunnel login"), (0, import_react.createElement)("li", null, "cloudflared tunnel create dsh-maestro-webhook"), (0, import_react.createElement)("li", null, "cloudflared tunnel route dns dsh-maestro-webhook <your-hostname>"), (0, import_react.createElement)("li", null, "Paste the printed Tunnel ID, credentials file path and hostname below."))
|
|
2978
2993
|
);
|
|
2979
2994
|
}
|
|
2995
|
+
function PlaceholderMappingsEditor({ rows, onChange }) {
|
|
2996
|
+
const updateRow = (index, field, value) => {
|
|
2997
|
+
onChange(rows.map((row, i) => i === index ? { ...row, [field]: value } : row));
|
|
2998
|
+
};
|
|
2999
|
+
const removeRow = (index) => onChange(rows.filter((_, i) => i !== index));
|
|
3000
|
+
const addRow = () => onChange([...rows, { pattern: "", suggestion: "" }]);
|
|
3001
|
+
return (0, import_react.createElement)(
|
|
3002
|
+
"div",
|
|
3003
|
+
{ "data-maestro-placeholders": "", style: { display: "flex", flexDirection: "column", gap: 12, paddingTop: 8 } },
|
|
3004
|
+
// Header — count + primary Add (stacks on mobile via CSS)
|
|
3005
|
+
(0, import_react.createElement)(
|
|
3006
|
+
"div",
|
|
3007
|
+
{ "data-maestro-placeholders-header": "", style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12, padding: "4px 0" } },
|
|
3008
|
+
(0, import_react.createElement)(
|
|
3009
|
+
"div",
|
|
3010
|
+
{ style: { flex: 1, minWidth: 0 } },
|
|
3011
|
+
(0, import_react.createElement)("div", { style: { fontSize: 14, fontWeight: 600, color: t.labelPrimary, lineHeight: "20px" } }, `Placeholder mappings \u2014 ${rows.length} mapped`),
|
|
3012
|
+
(0, import_react.createElement)("div", { style: { fontSize: 12, color: t.labelSecondary, lineHeight: "16px", marginTop: 2 } }, "Blocked pattern \u2192 placeholder suggestion, one mapping per row")
|
|
3013
|
+
),
|
|
3014
|
+
(0, import_react.createElement)(Button, { variant: "primary", size: "md", onClick: addRow, "data-maestro-placeholders-add": "" }, "+ Add mapping")
|
|
3015
|
+
),
|
|
3016
|
+
rows.length === 0 ? (0, import_react.createElement)(
|
|
3017
|
+
"div",
|
|
3018
|
+
{
|
|
3019
|
+
"data-maestro-placeholders-empty": "",
|
|
3020
|
+
style: {
|
|
3021
|
+
display: "flex",
|
|
3022
|
+
flexDirection: "column",
|
|
3023
|
+
alignItems: "center",
|
|
3024
|
+
gap: 10,
|
|
3025
|
+
padding: "20px 16px",
|
|
3026
|
+
borderRadius: 12,
|
|
3027
|
+
border: `1px dashed ${t.borderL2}`,
|
|
3028
|
+
background: "transparent",
|
|
3029
|
+
textAlign: "center"
|
|
3030
|
+
}
|
|
3031
|
+
},
|
|
3032
|
+
(0, import_react.createElement)("div", { style: { fontSize: 13, color: t.labelSecondary, lineHeight: "18px" } }, "No placeholder mappings yet \u2014 add your first mapping"),
|
|
3033
|
+
(0, import_react.createElement)(Button, { variant: "outline", size: "md", onClick: addRow }, "+ Add mapping")
|
|
3034
|
+
) : (0, import_react.createElement)(
|
|
3035
|
+
"div",
|
|
3036
|
+
{ "data-maestro-placeholders-list": "", style: { display: "flex", flexDirection: "column", gap: 12 } },
|
|
3037
|
+
...rows.map(
|
|
3038
|
+
(row, i) => (0, import_react.createElement)(
|
|
3039
|
+
"div",
|
|
3040
|
+
{
|
|
3041
|
+
key: i,
|
|
3042
|
+
"data-maestro-mapping-card": "",
|
|
3043
|
+
style: {
|
|
3044
|
+
display: "flex",
|
|
3045
|
+
flexDirection: "column",
|
|
3046
|
+
gap: 12,
|
|
3047
|
+
padding: 12,
|
|
3048
|
+
borderRadius: 12,
|
|
3049
|
+
border: `1px solid ${t.borderL2}`,
|
|
3050
|
+
background: t.bgLayer1,
|
|
3051
|
+
boxSizing: "border-box"
|
|
3052
|
+
}
|
|
3053
|
+
},
|
|
3054
|
+
// Card header: index badge + preview + X (same as Review's project card header)
|
|
3055
|
+
(0, import_react.createElement)(
|
|
3056
|
+
"div",
|
|
3057
|
+
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 } },
|
|
3058
|
+
(0, import_react.createElement)(
|
|
3059
|
+
"div",
|
|
3060
|
+
{ style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0, flex: 1 } },
|
|
3061
|
+
(0, import_react.createElement)(
|
|
3062
|
+
"span",
|
|
3063
|
+
{
|
|
3064
|
+
style: {
|
|
3065
|
+
flex: "none",
|
|
3066
|
+
width: 24,
|
|
3067
|
+
height: 24,
|
|
3068
|
+
borderRadius: 12,
|
|
3069
|
+
background: "var(--dsw-alias-bg-module-platform, #F5F6F7)",
|
|
3070
|
+
display: "inline-flex",
|
|
3071
|
+
alignItems: "center",
|
|
3072
|
+
justifyContent: "center",
|
|
3073
|
+
fontSize: 11,
|
|
3074
|
+
fontWeight: 600,
|
|
3075
|
+
color: t.labelSecondary
|
|
3076
|
+
}
|
|
3077
|
+
},
|
|
3078
|
+
String(i + 1)
|
|
3079
|
+
),
|
|
3080
|
+
(0, import_react.createElement)(
|
|
3081
|
+
"span",
|
|
3082
|
+
{
|
|
3083
|
+
style: {
|
|
3084
|
+
fontSize: 12,
|
|
3085
|
+
fontFamily: "ui-monospace, monospace",
|
|
3086
|
+
color: row.pattern ? t.labelPrimary : t.labelTertiary,
|
|
3087
|
+
overflow: "hidden",
|
|
3088
|
+
textOverflow: "ellipsis",
|
|
3089
|
+
whiteSpace: "nowrap",
|
|
3090
|
+
minWidth: 0
|
|
3091
|
+
}
|
|
3092
|
+
},
|
|
3093
|
+
row.pattern ? row.suggestion ? `${row.pattern} \u2192 ${row.suggestion}` : `${row.pattern} \u2192 \u2026` : "New mapping"
|
|
3094
|
+
)
|
|
3095
|
+
),
|
|
3096
|
+
(0, import_react.createElement)(Button, { variant: "outline", size: "sm", onClick: () => removeRow(i), "aria-label": `Remove mapping ${i + 1}`, title: "Remove mapping" }, "\u2715")
|
|
3097
|
+
),
|
|
3098
|
+
// Fields grid — 2-col desktop, 1-col mobile (same as Review's project grid)
|
|
3099
|
+
(0, import_react.createElement)(
|
|
3100
|
+
"div",
|
|
3101
|
+
{ "data-maestro-mapping-grid": "", style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 } },
|
|
3102
|
+
(0, import_react.createElement)(
|
|
3103
|
+
"label",
|
|
3104
|
+
{ style: fieldLabelStyle, "data-maestro-field": "" },
|
|
3105
|
+
"Blocked pattern",
|
|
3106
|
+
(0, import_react.createElement)(FieldInput, {
|
|
3107
|
+
value: row.pattern,
|
|
3108
|
+
placeholder: "example-project",
|
|
3109
|
+
onChange: (e) => updateRow(i, "pattern", e.target.value),
|
|
3110
|
+
"aria-label": `Blocked pattern ${i + 1}`,
|
|
3111
|
+
style: { width: "100%" }
|
|
3112
|
+
})
|
|
3113
|
+
),
|
|
3114
|
+
(0, import_react.createElement)(
|
|
3115
|
+
"label",
|
|
3116
|
+
{ style: fieldLabelStyle, "data-maestro-field": "" },
|
|
3117
|
+
"Placeholder",
|
|
3118
|
+
(0, import_react.createElement)(FieldInput, {
|
|
3119
|
+
value: row.suggestion,
|
|
3120
|
+
placeholder: "my-project",
|
|
3121
|
+
onChange: (e) => updateRow(i, "suggestion", e.target.value),
|
|
3122
|
+
"aria-label": `Placeholder suggestion ${i + 1}`,
|
|
3123
|
+
style: { width: "100%" }
|
|
3124
|
+
})
|
|
3125
|
+
)
|
|
3126
|
+
)
|
|
3127
|
+
)
|
|
3128
|
+
)
|
|
3129
|
+
)
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
2980
3132
|
function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
2981
3133
|
const [status, setStatus] = (0, import_react.useState)(null);
|
|
2982
3134
|
const [proxyStatus, setProxyStatus] = (0, import_react.useState)(null);
|
|
@@ -2991,34 +3143,49 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
2991
3143
|
const [showLanPin, setShowLanPin] = (0, import_react.useState)(false);
|
|
2992
3144
|
const [guard, setGuard] = (0, import_react.useState)({});
|
|
2993
3145
|
const [patternsText, setPatternsText] = (0, import_react.useState)("");
|
|
2994
|
-
const [
|
|
3146
|
+
const [placeholderRows, setPlaceholderRows] = (0, import_react.useState)([]);
|
|
2995
3147
|
const [supervisorCfg, setSupervisorCfg] = (0, import_react.useState)({});
|
|
2996
3148
|
const [notifierCfg, setNotifierCfg] = (0, import_react.useState)({});
|
|
2997
3149
|
const [activeTab, setActiveTab] = (0, import_react.useState)("tunnel");
|
|
2998
3150
|
(0, import_react.useEffect)(() => {
|
|
2999
3151
|
const css = `
|
|
3000
|
-
/*
|
|
3001
|
-
[data-maestro-
|
|
3152
|
+
/* Model override dropdown \u2014 prevent right-edge overlap */
|
|
3153
|
+
[data-maestro-control] [data-maestro-menu] { left:auto !important; right:0 !important; }
|
|
3154
|
+
[data-maestro-project-card] [data-maestro-menu] { left:auto !important; right:0 !important; }
|
|
3155
|
+
[data-maestro-trigger-wrap] { min-width:0; }
|
|
3156
|
+
/* Maestro nested tabs \u2014 unified with dsh-maestro-jobs (maestro-design pill bar) */
|
|
3157
|
+
[data-maestro-tabs] { display:flex; gap:6px; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain; touch-action:pan-x; padding:2px 2px 8px; margin:0 -2px 4px; border-bottom:1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.08)); }
|
|
3002
3158
|
[data-maestro-tabs]::-webkit-scrollbar { display:none; width:0; height:0; }
|
|
3003
|
-
[data-maestro-tab] { flex:none;
|
|
3004
|
-
[data-maestro-tab][data-active="true"] { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); border-color:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); color:var(--dsw-alias-label-primary); }
|
|
3159
|
+
[data-maestro-tab] { flex:none; min-width:fit-content; min-height:40px; padding:0 14px; border-radius:999px; border:1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.12)); background:transparent; color:var(--dsw-alias-label-secondary); font-size:13px; line-height:20px; font-weight:500; font-family:inherit; white-space:nowrap; display:inline-flex; align-items:center; justify-content:center; gap:6px; cursor:pointer; -webkit-tap-highlight-color:transparent; transition: background 150ms ease, color 150ms ease, border-color 150ms ease; touch-action:manipulation; }
|
|
3160
|
+
[data-maestro-tab][data-active="true"] { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); border-color:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); color:var(--dsw-alias-label-primary); font-weight:600; }
|
|
3005
3161
|
[data-maestro-tab]:hover { background:var(--dsw-alias-interactive-bg-hover, rgba(0,0,0,.06)); }
|
|
3006
3162
|
[data-maestro-tab][data-active="true"]:hover { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); }
|
|
3007
3163
|
[data-maestro-tab]:focus-visible { outline:2px solid var(--dsw-alias-state-business-primary, #4f6ef7); outline-offset:1px; }
|
|
3164
|
+
[data-maestro-tab]:active { transform: scale(.97); }
|
|
3008
3165
|
[data-maestro-panel] { width:100%; min-width:0; box-sizing:border-box; }
|
|
3009
3166
|
/* label/input overlap fix: flex column gap + full width */
|
|
3010
3167
|
[data-maestro-panel] label { gap:6px !important; }
|
|
3011
3168
|
[data-maestro-row]:last-child { border-bottom:none !important; }
|
|
3012
3169
|
[data-maestro-panel] label > span { width:100% !important; box-sizing:border-box !important; }
|
|
3170
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3171
|
+
[data-maestro-tab] { transition: none !important; }
|
|
3172
|
+
[data-maestro-tab]:active { transform: none !important; }
|
|
3173
|
+
}
|
|
3013
3174
|
@media (max-width: 640px) {
|
|
3014
3175
|
[data-maestro-settings-card] { max-width:100% !important; gap:6px !important; padding:0 2px !important; }
|
|
3015
|
-
[data-maestro-tabs] { gap:6px !important; padding:
|
|
3016
|
-
[data-maestro-tab] { height:
|
|
3017
|
-
|
|
3018
|
-
[data-maestro-
|
|
3176
|
+
[data-maestro-tabs] { gap:6px !important; padding:2px 2px 8px !important; margin:0 -2px 8px !important; }
|
|
3177
|
+
[data-maestro-tab] { min-height:40px !important; height:auto !important; padding:0 12px !important; font-size:13px !important; }
|
|
3178
|
+
/* Placeholder mappings \u2014 card design unified with Review project cards (header X, grid fields) */
|
|
3179
|
+
[data-maestro-placeholders-header] { flex-direction: column !important; align-items: stretch !important; }
|
|
3180
|
+
[data-maestro-placeholders-header] [data-maestro-placeholders-add] { width: 100% !important; justify-content: center !important; }
|
|
3181
|
+
[data-maestro-placeholders-list] { gap: 12px !important; }
|
|
3182
|
+
[data-maestro-mapping-card] { padding:10px !important; }
|
|
3183
|
+
[data-maestro-mapping-grid] { grid-template-columns:1fr !important; gap:12px !important; }
|
|
3019
3184
|
[data-maestro-qr-row] { flex-direction:column !important; align-items:flex-start !important; }
|
|
3020
3185
|
[data-maestro-trigger-wrap] { max-width:100% !important; }
|
|
3021
3186
|
[data-maestro-menu] { min-width:0 !important; max-width:calc(100vw - 32px) !important; left:0 !important; right:auto !important; }
|
|
3187
|
+
[data-maestro-control] [data-maestro-menu] { left:0 !important; right:auto !important; }
|
|
3188
|
+
[data-maestro-project-card] [data-maestro-menu] { left:0 !important; right:auto !important; }
|
|
3022
3189
|
[data-maestro-panel] label { gap:8px !important; }
|
|
3023
3190
|
div[data-maestro-row] { flex-direction:column !important; align-items:stretch !important; padding:12px 0 !important; }
|
|
3024
3191
|
[data-maestro-row-text] { padding-right:0 !important; }
|
|
@@ -3031,7 +3198,7 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3031
3198
|
[data-maestro-project-profile-row] > label { flex:1 1 100% !important; width:100% !important; }
|
|
3032
3199
|
}
|
|
3033
3200
|
@media (max-width: 390px) {
|
|
3034
|
-
[data-maestro-tab] { height:
|
|
3201
|
+
[data-maestro-tab] { min-height:38px !important; height:auto !important; padding:0 10px !important; font-size:12px !important; }
|
|
3035
3202
|
}
|
|
3036
3203
|
`;
|
|
3037
3204
|
const tag = document.createElement("style");
|
|
@@ -3083,15 +3250,13 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3083
3250
|
setError(e.message ?? String(e));
|
|
3084
3251
|
}
|
|
3085
3252
|
};
|
|
3086
|
-
const commitPlaceholders = async () => {
|
|
3253
|
+
const commitPlaceholders = async (rows) => {
|
|
3087
3254
|
setError(null);
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
if (
|
|
3092
|
-
|
|
3093
|
-
setError(`placeholders JSON invalid: ${e.message ?? String(e)}`);
|
|
3094
|
-
return;
|
|
3255
|
+
const obj = {};
|
|
3256
|
+
for (const row of rows) {
|
|
3257
|
+
const pattern = (row.pattern ?? "").trim();
|
|
3258
|
+
if (!pattern) continue;
|
|
3259
|
+
obj[pattern] = (row.suggestion ?? "").trim();
|
|
3095
3260
|
}
|
|
3096
3261
|
try {
|
|
3097
3262
|
await cfgSet("guardBlacklist", { placeholders: obj });
|
|
@@ -3148,7 +3313,7 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3148
3313
|
const pats = Array.isArray(bl?.patterns) ? bl.patterns : [];
|
|
3149
3314
|
const ph = bl?.placeholders && typeof bl.placeholders === "object" ? bl.placeholders : {};
|
|
3150
3315
|
setPatternsText(pats.join("\n"));
|
|
3151
|
-
|
|
3316
|
+
setPlaceholderRows(Object.entries(ph).map(([pattern, suggestion]) => ({ pattern, suggestion: String(suggestion) })));
|
|
3152
3317
|
setSupervisorCfg(sup ?? {});
|
|
3153
3318
|
setNotifierCfg(not ?? {});
|
|
3154
3319
|
}).catch(() => {
|
|
@@ -3265,13 +3430,13 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3265
3430
|
}
|
|
3266
3431
|
};
|
|
3267
3432
|
const TABS = [
|
|
3268
|
-
{ id: "tunnel", label: "Tunnel" },
|
|
3269
|
-
{ id: "gitlab", label: "GitLab" },
|
|
3270
|
-
{ id: "review", label: "Review" },
|
|
3271
|
-
{ id: "guard", label: "Guard" },
|
|
3272
|
-
{ id: "blacklist", label: "Blacklist" },
|
|
3273
|
-
{ id: "supervisor", label: "Supervisor" },
|
|
3274
|
-
{ id: "notifier", label: "Notifier" }
|
|
3433
|
+
{ id: "tunnel", label: "Tunnel", icon: "globe" },
|
|
3434
|
+
{ id: "gitlab", label: "GitLab", icon: "git" },
|
|
3435
|
+
{ id: "review", label: "Review", icon: "search" },
|
|
3436
|
+
{ id: "guard", label: "Guard", icon: "shield" },
|
|
3437
|
+
{ id: "blacklist", label: "Blacklist", icon: "ban" },
|
|
3438
|
+
{ id: "supervisor", label: "Supervisor", icon: "cpu" },
|
|
3439
|
+
{ id: "notifier", label: "Notifier", icon: "bell" }
|
|
3275
3440
|
];
|
|
3276
3441
|
const tabContents = {
|
|
3277
3442
|
tunnel: (0, import_react.createElement)(
|
|
@@ -3335,11 +3500,17 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3335
3500
|
"div",
|
|
3336
3501
|
{ style: { ...rowStyle, flexDirection: "column", alignItems: "stretch", gap: 8, borderBottom: "none" } },
|
|
3337
3502
|
(0, import_react.createElement)("div", { style: rowTitleStyle }, "Placeholder mappings"),
|
|
3338
|
-
(0, import_react.createElement)("div", { style: rowDescStyle }, "
|
|
3339
|
-
(0, import_react.createElement)(
|
|
3503
|
+
(0, import_react.createElement)("div", { style: rowDescStyle }, "Blocked pattern \u2192 placeholder suggestion. One mapping per row \u2014 no JSON needed."),
|
|
3504
|
+
(0, import_react.createElement)(PlaceholderMappingsEditor, {
|
|
3505
|
+
rows: placeholderRows,
|
|
3506
|
+
onChange: (rows) => {
|
|
3507
|
+
setPlaceholderRows(rows);
|
|
3508
|
+
commitPlaceholders(rows);
|
|
3509
|
+
}
|
|
3510
|
+
}),
|
|
3340
3511
|
(0, import_react.createElement)("div", { style: { marginTop: 8 } }, (0, import_react.createElement)(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
3341
3512
|
commitBlacklistPatterns(patternsText);
|
|
3342
|
-
commitPlaceholders();
|
|
3513
|
+
commitPlaceholders(placeholderRows);
|
|
3343
3514
|
} }, "Save Blacklist"))
|
|
3344
3515
|
)
|
|
3345
3516
|
),
|
|
@@ -3388,7 +3559,13 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3388
3559
|
(0, import_react.createElement)(
|
|
3389
3560
|
"div",
|
|
3390
3561
|
{ "data-maestro-tabs": "", role: "tablist", "aria-label": "Maestro settings sections" },
|
|
3391
|
-
...TABS.map((tab) => (0, import_react.createElement)("button", { key: tab.id, "data-maestro-tab": "", "data-active": String(activeTab === tab.id), role: "tab", "aria-selected": activeTab === tab.id, onClick: () =>
|
|
3562
|
+
...TABS.map((tab) => (0, import_react.createElement)("button", { key: tab.id, "data-maestro-tab": "", "data-active": String(activeTab === tab.id), role: "tab", "aria-selected": activeTab === tab.id, onClick: (e) => {
|
|
3563
|
+
setActiveTab(tab.id);
|
|
3564
|
+
try {
|
|
3565
|
+
e.currentTarget.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
|
|
3566
|
+
} catch {
|
|
3567
|
+
}
|
|
3568
|
+
} }, (0, import_react.createElement)(TabIcon, { name: tab.icon }), tab.label))
|
|
3392
3569
|
),
|
|
3393
3570
|
(0, import_react.createElement)("div", { "data-maestro-panel": activeTab, style: { display: "flex", flexDirection: "column", gap: 10, minWidth: 0 } }, tabContents[activeTab]),
|
|
3394
3571
|
error ? (0, import_react.createElement)("p", { style: { color: t.stateError, fontSize: 12, margin: "8px 0 0", padding: "8px 10px", borderRadius: 8, background: "color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent)", border: `1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent)` } }, error) : null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MaestroSettings.d.ts","sourceRoot":"","sources":["../../../src/client/MaestroSettings.tsx"],"names":[],"mappings":"AACA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"MaestroSettings.d.ts","sourceRoot":"","sources":["../../../src/client/MaestroSettings.tsx"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAisCH,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE;IAAE,OAAO,EAAE,GAAG,CAAC;IAAC,aAAa,CAAC,EAAE,GAAG,CAAA;CAAE;;;;;;;;;mBAkZmE,GAAG;;gBAoBzK"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ddtcorex/dsh-maestro-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Maestro Config — shared settings service for the dsh-maestro-* suite over the single namespaced store (~/.dsh/maestro/settings.json)",
|
|
6
6
|
"type": "module",
|
|
@@ -37,6 +37,26 @@ const t = {
|
|
|
37
37
|
scrollbarL2: 'var(--dsw-alias-scrollbar-bg-l2)',
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Nested pill tabs — unified with dsh-maestro-jobs (maestro-design: Minimalism & Swiss)
|
|
42
|
+
// Shared geometry: 40px min-height (44px jobs → 40px unified, touch-friendly ≥24px WCAG),
|
|
43
|
+
// 14px icon + 13px label gap 6, pill 999, border-l1, #EBEEF2 active, hover, focus ring.
|
|
44
|
+
// Icons: lucide-style 14px SVG, stroke 1.8, currentColor.
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
type TabIcon = 'globe' | 'git' | 'search' | 'shield' | 'ban' | 'cpu' | 'bell'
|
|
47
|
+
const TAB_ICON_PATHS: Record<TabIcon, string> = {
|
|
48
|
+
globe: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20M2 12h20M12 2a15 15 0 0 1 4 10 15 15 0 0 1-4 10 15 15 0 0 1-4-10A15 15 0 0 1 12 2z',
|
|
49
|
+
git: 'M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5 0-1.2-.4-2.3-1-3 0-1 0-2 0-3s-1 0-2 1a11 11 0 0 0-6 0c-1-1-2-1-2-1 0 1 0 2 0 3-.6.7-1 1.8-1 3 0 3.5 3 5.5 6 5.5-.4.3-.7.7-.9 1.2-.2.5-.3 1-.3 1.5V22',
|
|
50
|
+
search: 'M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-3.5-3.5',
|
|
51
|
+
shield: 'M12 2l7 4v5c0 5-3.5 7.5-7 9-3.5-1.5-7-4-7-9V6l7-4z',
|
|
52
|
+
ban: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM4 12h16',
|
|
53
|
+
cpu: 'M5 12H2a2 2 0 0 1 2-2h2M12 5V2a2 2 0 0 1 2 2v2M19 12h2a2 2 0 0 1-2 2h-2M12 19v2a2 2 0 0 1-2-2v-2M8 8h8v8H8z',
|
|
54
|
+
bell: 'M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 0 1-3.4 0',
|
|
55
|
+
}
|
|
56
|
+
function TabIcon({ name, size = 14 }: { name: TabIcon; size?: number }) {
|
|
57
|
+
return h('svg', { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': 'true', style: { flex: 'none' } }, h('path', { d: TAB_ICON_PATHS[name] }))
|
|
58
|
+
}
|
|
59
|
+
|
|
40
60
|
// ---------------------------------------------------------------------------
|
|
41
61
|
// Lightweight DSH primitive mirrors (geometry + tokens identical to host)
|
|
42
62
|
// Usage is identical to @deepseek-ai/dsh-client-ui-primitives at runtime.
|
|
@@ -533,14 +553,15 @@ function ReviewModelSelector({
|
|
|
533
553
|
position: 'absolute',
|
|
534
554
|
top: 'calc(100% + 8px)',
|
|
535
555
|
left: '0',
|
|
536
|
-
minWidth: '300px',
|
|
537
|
-
maxWidth: '360px',
|
|
556
|
+
minWidth: 'min(300px, calc(100vw - 32px))',
|
|
557
|
+
maxWidth: 'min(360px, calc(100vw - 24px))',
|
|
538
558
|
background: t.bgLayer2 as string,
|
|
539
559
|
border: `1px solid ${t.borderL2}`,
|
|
540
560
|
borderRadius: '12px',
|
|
541
561
|
boxShadow: t.shadowLv3 as string,
|
|
542
562
|
zIndex: '20',
|
|
543
563
|
padding: '6px',
|
|
564
|
+
boxSizing: 'border-box' as string,
|
|
544
565
|
}
|
|
545
566
|
const rowStyle: Record<string, any> = {
|
|
546
567
|
width: '100%',
|
|
@@ -567,7 +588,7 @@ function ReviewModelSelector({
|
|
|
567
588
|
const modelLabel = selectedProvider === '' ? 'Select model' : (value?.model ?? 'Select model')
|
|
568
589
|
return h(
|
|
569
590
|
'div',
|
|
570
|
-
{ ref: rootRef as any, 'data-maestro-trigger-wrap': '', style: { position: 'relative', display: 'inline-block', maxWidth: '100%' } },
|
|
591
|
+
{ ref: rootRef as any, 'data-maestro-trigger-wrap': '', style: { position: 'relative', display: 'inline-block', maxWidth: '100%', minWidth: 0, boxSizing: 'border-box' as string } },
|
|
571
592
|
label ? h('span', { style: fieldLabelStyle }, label) : null,
|
|
572
593
|
h(
|
|
573
594
|
'button',
|
|
@@ -586,8 +607,10 @@ function ReviewModelSelector({
|
|
|
586
607
|
alignItems: 'center',
|
|
587
608
|
gap: 8,
|
|
588
609
|
cursor: 'pointer',
|
|
589
|
-
maxWidth:
|
|
610
|
+
maxWidth: 'min(320px, 100%)',
|
|
611
|
+
minWidth: 0,
|
|
590
612
|
whiteSpace: 'nowrap',
|
|
613
|
+
boxSizing: 'border-box' as string,
|
|
591
614
|
},
|
|
592
615
|
onClick: () => {
|
|
593
616
|
setOpen((v) => !v)
|
|
@@ -1054,6 +1077,150 @@ function NamedTunnelSetupNote() {
|
|
|
1054
1077
|
)
|
|
1055
1078
|
}
|
|
1056
1079
|
|
|
1080
|
+
// ---------------------------------------------------------------------------
|
|
1081
|
+
// PlaceholderMappingsEditor — row-based "blocked pattern → suggestion" mappings
|
|
1082
|
+
// (same interaction as ProjectMappingsEditor; no JSON editing for users)
|
|
1083
|
+
// ---------------------------------------------------------------------------
|
|
1084
|
+
function PlaceholderMappingsEditor({ rows, onChange }: { rows: { pattern: string; suggestion: string }[]; onChange: (rows: { pattern: string; suggestion: string }[]) => void }) {
|
|
1085
|
+
const updateRow = (index: number, field: 'pattern' | 'suggestion', value: string) => {
|
|
1086
|
+
onChange(rows.map((row, i) => (i === index ? { ...row, [field]: value } : row)))
|
|
1087
|
+
}
|
|
1088
|
+
const removeRow = (index: number) => onChange(rows.filter((_, i) => i !== index))
|
|
1089
|
+
const addRow = () => onChange([...rows, { pattern: '', suggestion: '' }])
|
|
1090
|
+
return h(
|
|
1091
|
+
'div',
|
|
1092
|
+
{ 'data-maestro-placeholders': '', style: { display: 'flex', flexDirection: 'column', gap: 12, paddingTop: 8 } },
|
|
1093
|
+
// Header — count + primary Add (stacks on mobile via CSS)
|
|
1094
|
+
h(
|
|
1095
|
+
'div',
|
|
1096
|
+
{ 'data-maestro-placeholders-header': '', style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, padding: '4px 0' } },
|
|
1097
|
+
h(
|
|
1098
|
+
'div',
|
|
1099
|
+
{ style: { flex: 1, minWidth: 0 } },
|
|
1100
|
+
h('div', { style: { fontSize: 14, fontWeight: 600, color: t.labelPrimary as string, lineHeight: '20px' } }, `Placeholder mappings — ${rows.length} mapped`),
|
|
1101
|
+
h('div', { style: { fontSize: 12, color: t.labelSecondary as string, lineHeight: '16px', marginTop: 2 } }, 'Blocked pattern → placeholder suggestion, one mapping per row'),
|
|
1102
|
+
),
|
|
1103
|
+
h(Button as any, { variant: 'primary', size: 'md', onClick: addRow, 'data-maestro-placeholders-add': '' }, '+ Add mapping'),
|
|
1104
|
+
),
|
|
1105
|
+
rows.length === 0
|
|
1106
|
+
? h(
|
|
1107
|
+
'div',
|
|
1108
|
+
{
|
|
1109
|
+
'data-maestro-placeholders-empty': '',
|
|
1110
|
+
style: {
|
|
1111
|
+
display: 'flex',
|
|
1112
|
+
flexDirection: 'column',
|
|
1113
|
+
alignItems: 'center',
|
|
1114
|
+
gap: 10,
|
|
1115
|
+
padding: '20px 16px',
|
|
1116
|
+
borderRadius: 12,
|
|
1117
|
+
border: `1px dashed ${t.borderL2}`,
|
|
1118
|
+
background: 'transparent',
|
|
1119
|
+
textAlign: 'center' as const,
|
|
1120
|
+
},
|
|
1121
|
+
},
|
|
1122
|
+
h('div', { style: { fontSize: 13, color: t.labelSecondary as string, lineHeight: '18px' } }, 'No placeholder mappings yet — add your first mapping'),
|
|
1123
|
+
h(Button as any, { variant: 'outline', size: 'md', onClick: addRow }, '+ Add mapping'),
|
|
1124
|
+
)
|
|
1125
|
+
: h(
|
|
1126
|
+
'div',
|
|
1127
|
+
{ 'data-maestro-placeholders-list': '', style: { display: 'flex', flexDirection: 'column', gap: 12 } },
|
|
1128
|
+
...rows.map((row, i) =>
|
|
1129
|
+
h(
|
|
1130
|
+
'div',
|
|
1131
|
+
{
|
|
1132
|
+
key: i,
|
|
1133
|
+
'data-maestro-mapping-card': '',
|
|
1134
|
+
style: {
|
|
1135
|
+
display: 'flex',
|
|
1136
|
+
flexDirection: 'column',
|
|
1137
|
+
gap: 12,
|
|
1138
|
+
padding: 12,
|
|
1139
|
+
borderRadius: 12,
|
|
1140
|
+
border: `1px solid ${t.borderL2}`,
|
|
1141
|
+
background: t.bgLayer1 as string,
|
|
1142
|
+
boxSizing: 'border-box' as const,
|
|
1143
|
+
},
|
|
1144
|
+
},
|
|
1145
|
+
// Card header: index badge + preview + X (same as Review's project card header)
|
|
1146
|
+
h(
|
|
1147
|
+
'div',
|
|
1148
|
+
{ style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 } },
|
|
1149
|
+
h(
|
|
1150
|
+
'div',
|
|
1151
|
+
{ style: { display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flex: 1 } },
|
|
1152
|
+
h(
|
|
1153
|
+
'span',
|
|
1154
|
+
{
|
|
1155
|
+
style: {
|
|
1156
|
+
flex: 'none',
|
|
1157
|
+
width: 24,
|
|
1158
|
+
height: 24,
|
|
1159
|
+
borderRadius: 12,
|
|
1160
|
+
background: 'var(--dsw-alias-bg-module-platform, #F5F6F7)',
|
|
1161
|
+
display: 'inline-flex',
|
|
1162
|
+
alignItems: 'center',
|
|
1163
|
+
justifyContent: 'center',
|
|
1164
|
+
fontSize: 11,
|
|
1165
|
+
fontWeight: 600,
|
|
1166
|
+
color: t.labelSecondary as string,
|
|
1167
|
+
},
|
|
1168
|
+
},
|
|
1169
|
+
String(i + 1),
|
|
1170
|
+
),
|
|
1171
|
+
h(
|
|
1172
|
+
'span',
|
|
1173
|
+
{
|
|
1174
|
+
style: {
|
|
1175
|
+
fontSize: 12,
|
|
1176
|
+
fontFamily: 'ui-monospace, monospace',
|
|
1177
|
+
color: row.pattern ? (t.labelPrimary as string) : (t.labelTertiary as string),
|
|
1178
|
+
overflow: 'hidden',
|
|
1179
|
+
textOverflow: 'ellipsis',
|
|
1180
|
+
whiteSpace: 'nowrap',
|
|
1181
|
+
minWidth: 0,
|
|
1182
|
+
},
|
|
1183
|
+
},
|
|
1184
|
+
row.pattern ? (row.suggestion ? `${row.pattern} → ${row.suggestion}` : `${row.pattern} → …`) : 'New mapping',
|
|
1185
|
+
),
|
|
1186
|
+
),
|
|
1187
|
+
h(Button as any, { variant: 'outline', size: 'sm', onClick: () => removeRow(i), 'aria-label': `Remove mapping ${i + 1}`, title: 'Remove mapping' }, '✕'),
|
|
1188
|
+
),
|
|
1189
|
+
// Fields grid — 2-col desktop, 1-col mobile (same as Review's project grid)
|
|
1190
|
+
h(
|
|
1191
|
+
'div',
|
|
1192
|
+
{ 'data-maestro-mapping-grid': '', style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 } },
|
|
1193
|
+
h(
|
|
1194
|
+
'label',
|
|
1195
|
+
{ style: fieldLabelStyle, 'data-maestro-field': '' },
|
|
1196
|
+
'Blocked pattern',
|
|
1197
|
+
h(FieldInput as any, {
|
|
1198
|
+
value: row.pattern,
|
|
1199
|
+
placeholder: 'example-project',
|
|
1200
|
+
onChange: (e: any) => updateRow(i, 'pattern', e.target.value),
|
|
1201
|
+
'aria-label': `Blocked pattern ${i + 1}`,
|
|
1202
|
+
style: { width: '100%' } as any,
|
|
1203
|
+
}),
|
|
1204
|
+
),
|
|
1205
|
+
h(
|
|
1206
|
+
'label',
|
|
1207
|
+
{ style: fieldLabelStyle, 'data-maestro-field': '' },
|
|
1208
|
+
'Placeholder',
|
|
1209
|
+
h(FieldInput as any, {
|
|
1210
|
+
value: row.suggestion,
|
|
1211
|
+
placeholder: 'my-project',
|
|
1212
|
+
onChange: (e: any) => updateRow(i, 'suggestion', e.target.value),
|
|
1213
|
+
'aria-label': `Placeholder suggestion ${i + 1}`,
|
|
1214
|
+
style: { width: '100%' } as any,
|
|
1215
|
+
}),
|
|
1216
|
+
),
|
|
1217
|
+
),
|
|
1218
|
+
),
|
|
1219
|
+
),
|
|
1220
|
+
),
|
|
1221
|
+
)
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1057
1224
|
// ---------------------------------------------------------------------------
|
|
1058
1225
|
// Main — DSH-native grouped settings (DisclosureRow per domain)
|
|
1059
1226
|
// ---------------------------------------------------------------------------
|
|
@@ -1071,35 +1238,50 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1071
1238
|
const [showLanPin, setShowLanPin] = useState(false)
|
|
1072
1239
|
const [guard, setGuard] = useState<any>({})
|
|
1073
1240
|
const [patternsText, setPatternsText] = useState('')
|
|
1074
|
-
const [
|
|
1241
|
+
const [placeholderRows, setPlaceholderRows] = useState<{ pattern: string; suggestion: string }[]>([])
|
|
1075
1242
|
const [supervisorCfg, setSupervisorCfg] = useState<any>({})
|
|
1076
1243
|
const [notifierCfg, setNotifierCfg] = useState<any>({})
|
|
1077
1244
|
const [activeTab, setActiveTab] = useState('tunnel')
|
|
1078
1245
|
// Mobile: inject responsive overrides once (mirrors dsh-maestro-mobile settings-sheet pill pattern + market catsWrap)
|
|
1079
1246
|
useEffect(() => {
|
|
1080
1247
|
const css = `
|
|
1081
|
-
/*
|
|
1082
|
-
[data-maestro-
|
|
1248
|
+
/* Model override dropdown — prevent right-edge overlap */
|
|
1249
|
+
[data-maestro-control] [data-maestro-menu] { left:auto !important; right:0 !important; }
|
|
1250
|
+
[data-maestro-project-card] [data-maestro-menu] { left:auto !important; right:0 !important; }
|
|
1251
|
+
[data-maestro-trigger-wrap] { min-width:0; }
|
|
1252
|
+
/* Maestro nested tabs — unified with dsh-maestro-jobs (maestro-design pill bar) */
|
|
1253
|
+
[data-maestro-tabs] { display:flex; gap:6px; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain; touch-action:pan-x; padding:2px 2px 8px; margin:0 -2px 4px; border-bottom:1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.08)); }
|
|
1083
1254
|
[data-maestro-tabs]::-webkit-scrollbar { display:none; width:0; height:0; }
|
|
1084
|
-
[data-maestro-tab] { flex:none;
|
|
1085
|
-
[data-maestro-tab][data-active="true"] { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); border-color:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); color:var(--dsw-alias-label-primary); }
|
|
1255
|
+
[data-maestro-tab] { flex:none; min-width:fit-content; min-height:40px; padding:0 14px; border-radius:999px; border:1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.12)); background:transparent; color:var(--dsw-alias-label-secondary); font-size:13px; line-height:20px; font-weight:500; font-family:inherit; white-space:nowrap; display:inline-flex; align-items:center; justify-content:center; gap:6px; cursor:pointer; -webkit-tap-highlight-color:transparent; transition: background 150ms ease, color 150ms ease, border-color 150ms ease; touch-action:manipulation; }
|
|
1256
|
+
[data-maestro-tab][data-active="true"] { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); border-color:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); color:var(--dsw-alias-label-primary); font-weight:600; }
|
|
1086
1257
|
[data-maestro-tab]:hover { background:var(--dsw-alias-interactive-bg-hover, rgba(0,0,0,.06)); }
|
|
1087
1258
|
[data-maestro-tab][data-active="true"]:hover { background:var(--dsw-specific-sidebar-nav-item-active, #EBEEF2); }
|
|
1088
1259
|
[data-maestro-tab]:focus-visible { outline:2px solid var(--dsw-alias-state-business-primary, #4f6ef7); outline-offset:1px; }
|
|
1260
|
+
[data-maestro-tab]:active { transform: scale(.97); }
|
|
1089
1261
|
[data-maestro-panel] { width:100%; min-width:0; box-sizing:border-box; }
|
|
1090
1262
|
/* label/input overlap fix: flex column gap + full width */
|
|
1091
1263
|
[data-maestro-panel] label { gap:6px !important; }
|
|
1092
1264
|
[data-maestro-row]:last-child { border-bottom:none !important; }
|
|
1093
1265
|
[data-maestro-panel] label > span { width:100% !important; box-sizing:border-box !important; }
|
|
1266
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1267
|
+
[data-maestro-tab] { transition: none !important; }
|
|
1268
|
+
[data-maestro-tab]:active { transform: none !important; }
|
|
1269
|
+
}
|
|
1094
1270
|
@media (max-width: 640px) {
|
|
1095
1271
|
[data-maestro-settings-card] { max-width:100% !important; gap:6px !important; padding:0 2px !important; }
|
|
1096
|
-
[data-maestro-tabs] { gap:6px !important; padding:
|
|
1097
|
-
[data-maestro-tab] { height:
|
|
1098
|
-
|
|
1099
|
-
[data-maestro-
|
|
1272
|
+
[data-maestro-tabs] { gap:6px !important; padding:2px 2px 8px !important; margin:0 -2px 8px !important; }
|
|
1273
|
+
[data-maestro-tab] { min-height:40px !important; height:auto !important; padding:0 12px !important; font-size:13px !important; }
|
|
1274
|
+
/* Placeholder mappings — card design unified with Review project cards (header X, grid fields) */
|
|
1275
|
+
[data-maestro-placeholders-header] { flex-direction: column !important; align-items: stretch !important; }
|
|
1276
|
+
[data-maestro-placeholders-header] [data-maestro-placeholders-add] { width: 100% !important; justify-content: center !important; }
|
|
1277
|
+
[data-maestro-placeholders-list] { gap: 12px !important; }
|
|
1278
|
+
[data-maestro-mapping-card] { padding:10px !important; }
|
|
1279
|
+
[data-maestro-mapping-grid] { grid-template-columns:1fr !important; gap:12px !important; }
|
|
1100
1280
|
[data-maestro-qr-row] { flex-direction:column !important; align-items:flex-start !important; }
|
|
1101
1281
|
[data-maestro-trigger-wrap] { max-width:100% !important; }
|
|
1102
1282
|
[data-maestro-menu] { min-width:0 !important; max-width:calc(100vw - 32px) !important; left:0 !important; right:auto !important; }
|
|
1283
|
+
[data-maestro-control] [data-maestro-menu] { left:0 !important; right:auto !important; }
|
|
1284
|
+
[data-maestro-project-card] [data-maestro-menu] { left:0 !important; right:auto !important; }
|
|
1103
1285
|
[data-maestro-panel] label { gap:8px !important; }
|
|
1104
1286
|
div[data-maestro-row] { flex-direction:column !important; align-items:stretch !important; padding:12px 0 !important; }
|
|
1105
1287
|
[data-maestro-row-text] { padding-right:0 !important; }
|
|
@@ -1112,7 +1294,7 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1112
1294
|
[data-maestro-project-profile-row] > label { flex:1 1 100% !important; width:100% !important; }
|
|
1113
1295
|
}
|
|
1114
1296
|
@media (max-width: 390px) {
|
|
1115
|
-
[data-maestro-tab] { height:
|
|
1297
|
+
[data-maestro-tab] { min-height:38px !important; height:auto !important; padding:0 10px !important; font-size:12px !important; }
|
|
1116
1298
|
}
|
|
1117
1299
|
`
|
|
1118
1300
|
const tag = document.createElement('style')
|
|
@@ -1165,15 +1347,13 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1165
1347
|
setError(e.message ?? String(e))
|
|
1166
1348
|
}
|
|
1167
1349
|
}
|
|
1168
|
-
const commitPlaceholders = async () => {
|
|
1350
|
+
const commitPlaceholders = async (rows: { pattern: string; suggestion: string }[]) => {
|
|
1169
1351
|
setError(null)
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
if (
|
|
1174
|
-
|
|
1175
|
-
setError(`placeholders JSON invalid: ${e.message ?? String(e)}`)
|
|
1176
|
-
return
|
|
1352
|
+
const obj: Record<string, string> = {}
|
|
1353
|
+
for (const row of rows) {
|
|
1354
|
+
const pattern = (row.pattern ?? '').trim()
|
|
1355
|
+
if (!pattern) continue
|
|
1356
|
+
obj[pattern] = (row.suggestion ?? '').trim()
|
|
1177
1357
|
}
|
|
1178
1358
|
try {
|
|
1179
1359
|
await cfgSet('guardBlacklist', { placeholders: obj })
|
|
@@ -1231,7 +1411,7 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1231
1411
|
const pats = Array.isArray((bl as any)?.patterns) ? (bl as any).patterns : []
|
|
1232
1412
|
const ph = (bl as any)?.placeholders && typeof (bl as any).placeholders === 'object' ? (bl as any).placeholders : {}
|
|
1233
1413
|
setPatternsText(pats.join('\n'))
|
|
1234
|
-
|
|
1414
|
+
setPlaceholderRows(Object.entries(ph).map(([pattern, suggestion]) => ({ pattern, suggestion: String(suggestion) })))
|
|
1235
1415
|
setSupervisorCfg(sup ?? {})
|
|
1236
1416
|
setNotifierCfg(not ?? {})
|
|
1237
1417
|
})
|
|
@@ -1349,16 +1529,16 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1349
1529
|
}
|
|
1350
1530
|
}
|
|
1351
1531
|
|
|
1352
|
-
// Nested tabs
|
|
1353
|
-
const TABS = [
|
|
1354
|
-
{ id: 'tunnel', label: 'Tunnel' },
|
|
1355
|
-
{ id: 'gitlab', label: 'GitLab' },
|
|
1356
|
-
{ id: 'review', label: 'Review' },
|
|
1357
|
-
{ id: 'guard', label: 'Guard' },
|
|
1358
|
-
{ id: 'blacklist', label: 'Blacklist' },
|
|
1359
|
-
{ id: 'supervisor', label: 'Supervisor' },
|
|
1360
|
-
{ id: 'notifier', label: 'Notifier' },
|
|
1361
|
-
]
|
|
1532
|
+
// Nested tabs — unified pill bar with icons (maestro-design, matches dsh-maestro-jobs)
|
|
1533
|
+
const TABS: Array<{ id: string; label: string; icon: TabIcon }> = [
|
|
1534
|
+
{ id: 'tunnel', label: 'Tunnel', icon: 'globe' },
|
|
1535
|
+
{ id: 'gitlab', label: 'GitLab', icon: 'git' },
|
|
1536
|
+
{ id: 'review', label: 'Review', icon: 'search' },
|
|
1537
|
+
{ id: 'guard', label: 'Guard', icon: 'shield' },
|
|
1538
|
+
{ id: 'blacklist', label: 'Blacklist', icon: 'ban' },
|
|
1539
|
+
{ id: 'supervisor', label: 'Supervisor', icon: 'cpu' },
|
|
1540
|
+
{ id: 'notifier', label: 'Notifier', icon: 'bell' },
|
|
1541
|
+
]
|
|
1362
1542
|
|
|
1363
1543
|
const tabContents: Record<string, unknown> = {
|
|
1364
1544
|
tunnel: h(
|
|
@@ -1416,9 +1596,15 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1416
1596
|
),
|
|
1417
1597
|
h('div', { style: { ...rowStyle, flexDirection:'column', alignItems:'stretch', gap: 8, borderBottom:'none' } as any },
|
|
1418
1598
|
h('div', { style: rowTitleStyle }, 'Placeholder mappings'),
|
|
1419
|
-
h('div', { style: rowDescStyle }, '
|
|
1420
|
-
h(
|
|
1421
|
-
|
|
1599
|
+
h('div', { style: rowDescStyle }, 'Blocked pattern → placeholder suggestion. One mapping per row — no JSON needed.'),
|
|
1600
|
+
h(PlaceholderMappingsEditor as any, {
|
|
1601
|
+
rows: placeholderRows,
|
|
1602
|
+
onChange: (rows: any) => {
|
|
1603
|
+
setPlaceholderRows(rows)
|
|
1604
|
+
commitPlaceholders(rows)
|
|
1605
|
+
},
|
|
1606
|
+
}),
|
|
1607
|
+
h('div', { style: { marginTop: 8 } }, h(Button as any, { variant: 'outline', size: 'sm', onClick: () => { commitBlacklistPatterns(patternsText); commitPlaceholders(placeholderRows) } }, 'Save Blacklist')),
|
|
1422
1608
|
),
|
|
1423
1609
|
),
|
|
1424
1610
|
supervisor: h(
|
|
@@ -1455,7 +1641,7 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1455
1641
|
),
|
|
1456
1642
|
h('style', {}, '[data-maestro-logo]{background:#0A84FF !important; background-color:#0A84FF !important; color:#fff !important;}'),
|
|
1457
1643
|
h('div', { 'data-maestro-tabs': '', role:'tablist', 'aria-label':'Maestro settings sections' },
|
|
1458
|
-
...TABS.map(tab => h('button', { key: tab.id, 'data-maestro-tab':'', 'data-active': String(activeTab===tab.id), role:'tab', 'aria-selected': activeTab===tab.id, onClick: () => setActiveTab(tab.id) }, tab.label))
|
|
1644
|
+
...TABS.map(tab => h('button', { key: tab.id, 'data-maestro-tab':'', 'data-active': String(activeTab===tab.id), role:'tab', 'aria-selected': activeTab===tab.id, onClick: (e: any) => { setActiveTab(tab.id); try { e.currentTarget.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }) } catch {} } }, h(TabIcon as any, { name: tab.icon }), tab.label))
|
|
1459
1645
|
),
|
|
1460
1646
|
h('div', { 'data-maestro-panel': activeTab, style: { display:'flex', flexDirection:'column', gap:10, minWidth:0 } }, tabContents[activeTab] as any),
|
|
1461
1647
|
error ? h('p', { style: { color: t.stateError as string, fontSize: 12, margin: '8px 0 0', padding: '8px 10px', borderRadius: 8, background: 'color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent)', border: `1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent)` } }, error) : null,
|