feat: port the demo redesign with Manage and Settings tabs

This commit is contained in:
LukeGus committed 2026-10-05 16:23:21 -05:00
1 parent f8151cb885
commit 35c954b79a
128 files changed
+13262 -8143

No files matched your search

+4
View File
@@ -159,6 +159,7 @@ export function createPluginApp(
mobilePrimary: item.mobilePrimary,
electronOnly: item.electronOnly,
separatorAfter: item.separatorAfter ?? true,
group: item.group,
hidden: item.hidden,
after: item.after,
order: item.order,
@@ -392,6 +393,7 @@ export function createPluginApp(
titleKey: key(card.titleKey),
defaultHeight: card.defaultHeight,
defaultPanel: card.defaultPanel,
frame: card.frame,
component: scoped(
card.component as unknown as ComponentType<DashboardCardRenderProps>,
),
@@ -546,6 +548,8 @@ export function createPluginApp(
onReady: (listener) => track(tabsApi.onReady(listener)),
},
confirm: (options) => shell.confirm!(options),
desktop: {
available: isElectron(),
remoteServerUrl,
+63 -1
View File
@@ -194,7 +194,6 @@ export {
ManagerSearch,
type ManagerCardError,
} from "@/components/manager-card";
export { useConfirmation } from "@/hooks/use-confirmation";
export { useAdaptivePolling } from "@/hooks/use-adaptive-polling";
// Homepage widget pieces, for plugins that register a widget.
export { WidgetTitle } from "@/lib/widget-title";
@@ -276,3 +275,66 @@ export { getDeviceId } from "@/lib/device-id";
// A host that is never saved, for connecting to an address straight away.
export { createQuickConnectHost } from "@/sidebar/quick-connect-host";
// The panel kit every tab and sidebar panel is built from.
export {
BackButton,
Facts,
GroupHeading,
PANEL,
PanelSearch,
PanelShell,
Segmented,
ViewToggle,
type PanelDensity,
type PanelViewMode,
} from "@/components/panel-layout";
export {
DataView,
type DataColumn,
type GridColumns,
} from "@/components/data-view";
export { TabStrip, type TabStripItem } from "@/components/tab-strip";
export { CardMasonry } from "@/components/card-masonry";
export { Meter, UsagePair } from "@/components/meter";
export { usageBarColor, usageColor } from "@/lib/usage-color";
export {
Field,
FieldPair,
NumberField,
Repeater,
SecretField,
SelectField,
SwitchRow,
TagInput,
TextAreaField,
TextField,
} from "@/components/form-fields";
// Views and questions drawn over the panel, tab or pane that asked, instead
// of modals over the whole app.
export {
InlineView,
PanePrompt,
SurfaceScope,
useConfirm,
useSurfaceKind,
type ConfirmOptions,
type EditingWidth,
type SurfaceKind,
} from "@/components/surface/surface-scope";
export {
PROMPT_BUTTON,
PROMPT_DESTRUCTIVE_BUTTON,
PROMPT_PRIMARY_BUTTON,
} from "@/components/surface/prompt-styles";
// One connection lifecycle: connecting, failed with retry and a log, dropped,
// or unavailable.
export {
ConnectionGate,
useConnectionGate,
type ConnectionGateController,
type ConnectionGateProps,
} from "@/components/connection/ConnectionGate";
export { type ConnectionUnavailable } from "@/components/connection/ConnectionScreen";
+8
View File
@@ -116,6 +116,14 @@ export const shell: TabShellCallbacks = {
openHostEditor: (...args) => callbacks?.openHostEditor?.(...args),
saveQuickConnect: (...args) =>
callbacks?.saveQuickConnect?.(...args) ?? Promise.resolve(),
confirm: (options) =>
callbacks?.confirm
? callbacks.confirm(options)
: Promise.resolve(
window.confirm(
[options.title, options.description].filter(Boolean).join(" "),
),
),
};
export const tabsApi = {
+2 -1
View File
@@ -22,6 +22,7 @@ import type {
import i18n from "@/i18n/i18n";
import type { PluginSummary } from "@/api/plugins-api";
import { ThemeProvider } from "@/components/theme-provider";
import { SurfaceScope } from "@/components/surface/surface-scope";
import { setPermissionsForTesting } from "@/hooks/use-permissions";
import {
getTabType,
@@ -98,7 +99,7 @@ function recordingShell(calls: ShellCall[]): TabShellCallbacks {
function wrap(element: ReactElement): HTMLElement {
return render(
<ThemeProvider defaultTheme="dark" storageKey="termix-test-theme">
{element}
<SurfaceScope className="h-full">{element}</SurfaceScope>
</ThemeProvider>,
).container;
}