mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
feat: port the demo redesign with Manage and Settings tabs
This commit is contained in:
1 parent
f8151cb885
commit
35c954b79a
128 files changed
+13262
-8143
No files matched your search
@@ -34,6 +34,7 @@ const ALLOWED = [
|
||||
"AlertDialogTitle",
|
||||
"AlertDialogTrigger",
|
||||
"AlertTitle",
|
||||
"BackButton",
|
||||
"Badge",
|
||||
"BarSeries",
|
||||
"BarSeriesItem",
|
||||
@@ -48,17 +49,25 @@ const ALLOWED = [
|
||||
"CardFooter",
|
||||
"CardGridCanvas",
|
||||
"CardHeader",
|
||||
"CardMasonry",
|
||||
"CardTitle",
|
||||
"Checkbox",
|
||||
"ColumnCountStepper",
|
||||
"ComponentSlot",
|
||||
"ConfirmOptions",
|
||||
"ConnectionGate",
|
||||
"ConnectionGateController",
|
||||
"ConnectionGateProps",
|
||||
"ConnectionLogPanel",
|
||||
"ConnectionLogProvider",
|
||||
"ConnectionOrigin",
|
||||
"ConnectionScreen",
|
||||
"ConnectionStage",
|
||||
"ConnectionStatus",
|
||||
"ConnectionUnavailable",
|
||||
"CustomKeybinding",
|
||||
"DataColumn",
|
||||
"DataView",
|
||||
"Dialog",
|
||||
"DialogClose",
|
||||
"DialogContent",
|
||||
@@ -84,20 +93,27 @@ const ALLOWED = [
|
||||
"DropdownMenuSubContent",
|
||||
"DropdownMenuSubTrigger",
|
||||
"DropdownMenuTrigger",
|
||||
"EditingWidth",
|
||||
"EmptyState",
|
||||
"FOLDER_COLORS",
|
||||
"Facts",
|
||||
"FakeSwitch",
|
||||
"Field",
|
||||
"FieldPair",
|
||||
"FullScreenAppPhase",
|
||||
"FullScreenAppWrapper",
|
||||
"GridCardCatalogEntry",
|
||||
"GridColSpan",
|
||||
"GridColumns",
|
||||
"GridLayout",
|
||||
"GridSlot",
|
||||
"GroupHeading",
|
||||
"HostDefaultBadge",
|
||||
"HostDefaultField",
|
||||
"HostFeatureFields",
|
||||
"HostFeatureFieldsProps",
|
||||
"HostKeyVerificationDialog",
|
||||
"InlineView",
|
||||
"Input",
|
||||
"Kbd",
|
||||
"KbdKey",
|
||||
@@ -114,8 +130,19 @@ const ALLOWED = [
|
||||
"ManagerCardError",
|
||||
"ManagerCardShell",
|
||||
"ManagerSearch",
|
||||
"Meter",
|
||||
"MetricCard",
|
||||
"MiniStat",
|
||||
"NumberField",
|
||||
"PANEL",
|
||||
"PanePrompt",
|
||||
"PROMPT_BUTTON",
|
||||
"PROMPT_DESTRUCTIVE_BUTTON",
|
||||
"PROMPT_PRIMARY_BUTTON",
|
||||
"PanelDensity",
|
||||
"PanelSearch",
|
||||
"PanelShell",
|
||||
"PanelViewMode",
|
||||
"PassphraseDialog",
|
||||
"PasswordInput",
|
||||
"PluginComponent",
|
||||
@@ -127,14 +154,18 @@ const ALLOWED = [
|
||||
"RadialGauge",
|
||||
"RadialGaugeProps",
|
||||
"RecentActivityItem",
|
||||
"Repeater",
|
||||
"RobustClipboardProvider",
|
||||
"SSHAuthDialog",
|
||||
"ScrollArea",
|
||||
"ScrollBar",
|
||||
"SecretField",
|
||||
"SectionCard",
|
||||
"Segmented",
|
||||
"Select",
|
||||
"Select2",
|
||||
"SelectContent",
|
||||
"SelectField",
|
||||
"SelectGroup",
|
||||
"SelectItem",
|
||||
"SelectLabel",
|
||||
@@ -158,8 +189,16 @@ const ALLOWED = [
|
||||
"Sparkline",
|
||||
"SparklineProps",
|
||||
"StatRow",
|
||||
"SurfaceKind",
|
||||
"SurfaceScope",
|
||||
"Switch",
|
||||
"SwitchRow",
|
||||
"TOTPDialog",
|
||||
"TabStrip",
|
||||
"TabStripItem",
|
||||
"TagInput",
|
||||
"TextAreaField",
|
||||
"TextField",
|
||||
"Textarea",
|
||||
"TextareaProps",
|
||||
"Tooltip",
|
||||
@@ -167,7 +206,9 @@ const ALLOWED = [
|
||||
"TooltipProvider",
|
||||
"TooltipTrigger",
|
||||
"UptimeInfo",
|
||||
"UsagePair",
|
||||
"VersionInfo",
|
||||
"ViewToggle",
|
||||
"WebSocketConnectionTarget",
|
||||
"WidgetTitle",
|
||||
"buildOriginWsUrl",
|
||||
@@ -198,13 +239,17 @@ const ALLOWED = [
|
||||
"runAdaptiveBackgroundTask",
|
||||
"runAdaptivePolling",
|
||||
"runVisibleInterval",
|
||||
"usageBarColor",
|
||||
"usageColor",
|
||||
"useAdaptivePolling",
|
||||
"useAppTheme",
|
||||
"useConfirmation",
|
||||
"useConfirm",
|
||||
"useConnectionGate",
|
||||
"useConnectionLog",
|
||||
"useIsDefaultsEditor",
|
||||
"useIsMobile",
|
||||
"useOptionalConnectionLog",
|
||||
"useSurfaceKind",
|
||||
"useTabs",
|
||||
"useTabsSafe",
|
||||
];
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Builds src/ui/settings/settings-search-index.ts: the i18n keys each core
|
||||
* settings section shows, so the Settings search can match on any label in
|
||||
* a section without mounting it. Run it after changing a settings section.
|
||||
*
|
||||
* --check fails when the committed file is out of date.
|
||||
*/
|
||||
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
const ROOT = path.resolve(__dirname, "..");
|
||||
const SIDEBAR = path.join(ROOT, "src", "ui", "sidebar");
|
||||
const OUT = path.join(
|
||||
ROOT,
|
||||
"src",
|
||||
"ui",
|
||||
"settings",
|
||||
"settings-search-index.ts",
|
||||
);
|
||||
|
||||
function keysIn(text) {
|
||||
return [
|
||||
...new Set([...text.matchAll(/\bt\(\s*"([\w.-]+)"/g)].map((m) => m[1])),
|
||||
];
|
||||
}
|
||||
|
||||
function read(file) {
|
||||
return fs.readFileSync(path.join(SIDEBAR, file), "utf8");
|
||||
}
|
||||
|
||||
/** The body of one exported or local function, by name. */
|
||||
function functionBody(source, name) {
|
||||
const start = source.search(new RegExp(`function ${name}\\b`));
|
||||
if (start < 0) throw new Error(`No function ${name}`);
|
||||
const next = source.slice(start + 1).search(/\n(export )?function \w+/);
|
||||
return next < 0 ? source.slice(start) : source.slice(start, start + 1 + next);
|
||||
}
|
||||
|
||||
/** Profile sections, split on their AccordionSection ids. */
|
||||
function profileSections() {
|
||||
const source = read("UserProfilePanel.tsx");
|
||||
const lines = source.split("\n");
|
||||
const starts = [];
|
||||
lines.forEach((line, i) => {
|
||||
if (/^\s{6}<AccordionSection\b/.test(line)) starts.push(i);
|
||||
});
|
||||
const out = {};
|
||||
starts.forEach((start, k) => {
|
||||
const end = k + 1 < starts.length ? starts[k + 1] : lines.length;
|
||||
const chunk = lines.slice(start, end).join("\n");
|
||||
const id = (chunk.match(/\bid="([^"]+)"/) || [])[1];
|
||||
if (id) out[id] = keysIn(chunk);
|
||||
});
|
||||
out.interface = [
|
||||
...new Set([
|
||||
...(out.interface ?? []),
|
||||
...keysIn(read("InterfacePresetSettings.tsx")),
|
||||
]),
|
||||
];
|
||||
out.security = [
|
||||
...new Set([
|
||||
...(out.security ?? []),
|
||||
...keysIn(read("AuthEnrollmentSections.tsx")),
|
||||
...keysIn(functionBody(source, "PasswordChangeSection")),
|
||||
]),
|
||||
];
|
||||
out["api-keys"] = [
|
||||
...new Set([
|
||||
...(out["api-keys"] ?? []),
|
||||
...keysIn(functionBody(source, "NewApiKeyDialog")),
|
||||
]),
|
||||
];
|
||||
out.keybindings = keysIn(
|
||||
fs.readFileSync(
|
||||
path.join(ROOT, "src", "ui", "settings", "KeybindingsSettings.tsx"),
|
||||
"utf8",
|
||||
),
|
||||
);
|
||||
return out;
|
||||
}
|
||||
|
||||
function adminSections() {
|
||||
const settings = read("AdminSettingsSections.tsx");
|
||||
const management = read("AdminManagementSections.tsx");
|
||||
return {
|
||||
"admin-general": keysIn(
|
||||
functionBody(settings, "AdminGeneralSettingsSection"),
|
||||
),
|
||||
"admin-users": [
|
||||
...new Set([
|
||||
...keysIn(functionBody(management, "AdminUsersSection")),
|
||||
...keysIn(read("AdminUserDialogs.tsx")),
|
||||
]),
|
||||
],
|
||||
"admin-sessions": keysIn(functionBody(management, "AdminSessionsSection")),
|
||||
"admin-roles": keysIn(functionBody(management, "AdminRolesSection")),
|
||||
"admin-host-defaults": [
|
||||
...new Set([
|
||||
...keysIn(functionBody(settings, "AdminHostDefaultsSection")),
|
||||
...keysIn(read("AdminHostTags.tsx")),
|
||||
]),
|
||||
],
|
||||
"admin-branding": keysIn(read("AdminBrandingSection.tsx")),
|
||||
"admin-database": keysIn(functionBody(settings, "AdminDatabaseSection")),
|
||||
"admin-ssl": keysIn(functionBody(settings, "AdminSSLSection")),
|
||||
"admin-api-keys": keysIn(read("AdminApiKeysSection.tsx")),
|
||||
"admin-audit-log": keysIn(read("AdminAuditLogSection.tsx")),
|
||||
};
|
||||
}
|
||||
|
||||
function render() {
|
||||
const index = { ...profileSections(), ...adminSections() };
|
||||
const body = Object.entries(index)
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
.map(
|
||||
([id, keys]) =>
|
||||
` ${JSON.stringify(id)}: [\n${keys
|
||||
.sort()
|
||||
.map((key) => ` ${JSON.stringify(key)},`)
|
||||
.join("\n")}\n ],`,
|
||||
)
|
||||
.join("\n");
|
||||
return `// Generated by scripts/generate-settings-search-index.cjs. Do not edit.\n\n/** The i18n keys each core settings section shows, for search. */\nexport const SETTINGS_SEARCH_INDEX: Record<string, string[]> = {\n${body}\n};\n`;
|
||||
}
|
||||
|
||||
const next = render();
|
||||
if (process.argv.includes("--check")) {
|
||||
const current = fs.existsSync(OUT) ? fs.readFileSync(OUT, "utf8") : "";
|
||||
if (current !== next) {
|
||||
console.error(
|
||||
"src/ui/settings/settings-search-index.ts is out of date. Run: node scripts/generate-settings-search-index.cjs",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
fs.writeFileSync(OUT, next);
|
||||
console.log(`Wrote ${path.relative(ROOT, OUT)}`);
|
||||
}
|
||||
Reference in new issue
Block a user