mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-09 16:00:59 +00:00
Remove 103 unused frontend exports
Dead-code sweep. Named exports flagged unused by ts-prune and confirmed unreferenced by adversarial cross-file verification, removed via a TypeScript compiler-API codemod (whole-declaration removal by name). tsc --noEmit over the full project including all test files, and npm run lint (eslint + theme + canonical-platform audits), both pass. 54 candidates deferred for safety: 1 false positive caught by the type-check (WizardState is imported by SetupCompletionPanel.tsx), ~20 files whose export removal orphans secondary imports/helpers (needs a follow-up cascading pass), and 2 multi-declarator statements.
This commit is contained in:
parent
faefe6edc8
commit
62cff03210
60 changed files with 7 additions and 527 deletions
|
|
@ -556,20 +556,6 @@ export interface StepResult {
|
|||
run_at: string;
|
||||
}
|
||||
|
||||
export interface RemediationExecution {
|
||||
id: string;
|
||||
plan_id: string;
|
||||
status: 'pending' | 'approved' | 'running' | 'completed' | 'failed' | 'rolled_back';
|
||||
approved_by?: string;
|
||||
approved_at?: string;
|
||||
started_at?: string;
|
||||
completed_at?: string;
|
||||
current_step: number;
|
||||
step_results?: StepResult[];
|
||||
error?: string;
|
||||
rollback_error?: string;
|
||||
}
|
||||
|
||||
// Compatibility response shape for older execution endpoints.
|
||||
export interface RemediationExecutionResult {
|
||||
execution_id: string;
|
||||
|
|
|
|||
|
|
@ -16,29 +16,6 @@ import {
|
|||
parseOptionalAPIResponseOrNull,
|
||||
} from './responseUtils';
|
||||
|
||||
export interface RemovedDockerHost {
|
||||
id: string;
|
||||
hostname?: string;
|
||||
displayName?: string;
|
||||
removedAt: number;
|
||||
}
|
||||
|
||||
export interface RemovedHostAgent {
|
||||
id: string;
|
||||
hostname?: string;
|
||||
displayName?: string;
|
||||
linkedVmId?: string;
|
||||
linkedContainerId?: string;
|
||||
removedAt: number;
|
||||
}
|
||||
|
||||
export interface RemovedKubernetesCluster {
|
||||
id: string;
|
||||
name?: string;
|
||||
displayName?: string;
|
||||
removedAt: number;
|
||||
}
|
||||
|
||||
async function deleteResource<T extends object>(
|
||||
url: string,
|
||||
parseErrorMessage: string,
|
||||
|
|
|
|||
|
|
@ -201,14 +201,6 @@ export function apiErrorCode(error: unknown): string | null {
|
|||
return trimmedOptionalString((error as APIErrorLike).code);
|
||||
}
|
||||
|
||||
export function apiErrorDetail(error: unknown): string | null {
|
||||
if (!error || typeof error !== 'object') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return trimmedOptionalString((error as APIErrorLike).detail);
|
||||
}
|
||||
|
||||
export function apiErrorDetails(error: unknown): Record<string, string> | null {
|
||||
if (!error || typeof error !== 'object') {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -359,5 +359,3 @@ export const formatInteger = (value?: number): string => {
|
|||
if (value === undefined || value === null || Number.isNaN(value)) return '—';
|
||||
return new Intl.NumberFormat().format(Math.round(value));
|
||||
};
|
||||
|
||||
export const ALIAS_COLLAPSE_THRESHOLD = 4;
|
||||
|
|
|
|||
|
|
@ -490,7 +490,3 @@ export const useResourceDetailDrawerDerivedState = (
|
|||
tabs,
|
||||
};
|
||||
};
|
||||
|
||||
export type ResourceDetailDrawerDerivedState = ReturnType<
|
||||
typeof useResourceDetailDrawerDerivedState
|
||||
>;
|
||||
|
|
|
|||
|
|
@ -95,7 +95,3 @@ export const useResourceDetailDrawerDockerActionsState = (
|
|||
queueDockerUpdateAll,
|
||||
};
|
||||
};
|
||||
|
||||
export type UseResourceDetailDrawerDockerActionsStateResult = ReturnType<
|
||||
typeof useResourceDetailDrawerDockerActionsState
|
||||
>;
|
||||
|
|
|
|||
|
|
@ -234,7 +234,3 @@ export const useResourceDetailDrawerHistoryState = (
|
|||
refetchHistoryFacets,
|
||||
};
|
||||
};
|
||||
|
||||
export type ResourceDetailDrawerHistoryState = ReturnType<
|
||||
typeof useResourceDetailDrawerHistoryState
|
||||
>;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,3 @@ export function useUnifiedResourceTableViewportSync(
|
|||
setHostBodyRef,
|
||||
};
|
||||
}
|
||||
|
||||
export type UnifiedResourceTableViewportSync = ReturnType<
|
||||
typeof useUnifiedResourceTableViewportSync
|
||||
>;
|
||||
|
|
|
|||
|
|
@ -216,16 +216,3 @@ export function isModelProviderConfigured(
|
|||
const provider = getProviderFromModelId(modelId);
|
||||
return isAIProviderConfigured(provider, settings);
|
||||
}
|
||||
|
||||
export function groupModelsByProvider(models: AIAvailableModel[]): Map<string, AIAvailableModel[]> {
|
||||
const grouped = new Map<string, AIAvailableModel[]>();
|
||||
|
||||
for (const model of models) {
|
||||
const provider = getProviderFromModelId(model.id);
|
||||
const existing = grouped.get(provider) || [];
|
||||
existing.push(model);
|
||||
grouped.set(provider, existing);
|
||||
}
|
||||
|
||||
return grouped;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,34 +48,6 @@ export const matchConfiguredNodeToResource = (
|
|||
});
|
||||
};
|
||||
|
||||
export const collectConfiguredInfrastructureHosts = (nodes: NodeConfigWithStatus[]) => {
|
||||
const configuredHosts = new Set<string>();
|
||||
const clusterMemberIPs = new Set<string>();
|
||||
|
||||
nodes.forEach((node) => {
|
||||
const cleanedHost = node.host.replace(/^https?:\/\//, '').replace(/:\d+$/, '');
|
||||
configuredHosts.add(cleanedHost.toLowerCase());
|
||||
|
||||
if (!('isCluster' in node) || !node.isCluster || !('clusterEndpoints' in node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
node.clusterEndpoints?.forEach((endpoint: ClusterEndpoint) => {
|
||||
if (endpoint.ip) {
|
||||
clusterMemberIPs.add(endpoint.ip.toLowerCase());
|
||||
}
|
||||
if (endpoint.host) {
|
||||
clusterMemberIPs.add(endpoint.host.toLowerCase());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
clusterMemberIPs,
|
||||
configuredHosts,
|
||||
};
|
||||
};
|
||||
|
||||
const createRepresentedDiscoveryHosts = (): RepresentedDiscoveryHosts => ({
|
||||
pve: new Set<string>(),
|
||||
pbs: new Set<string>(),
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ import type { DiscoverySettingsFormProps } from './discoverySettingsModel';
|
|||
import type { TrueNASSettingsPanelState } from './useTrueNASSettingsPanelState';
|
||||
import type { VMwareSettingsPanelState } from './useVMwareSettingsPanelState';
|
||||
|
||||
export type DiscoveryMode = 'auto' | 'custom';
|
||||
|
||||
export interface InfrastructurePlatformSettingsProps {
|
||||
selectedAgent: Accessor<NodeType>;
|
||||
onSelectAgent: (agent: NodeType) => void;
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
export type { ReportingResourceType } from '@/utils/reportingResourceTypes';
|
||||
export { toReportingResourceType } from '@/utils/reportingResourceTypes';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,3 @@
|
|||
export {
|
||||
DEFAULT_SETTINGS_TAB,
|
||||
agentKeyFromPlatformType,
|
||||
deriveTabFromPath,
|
||||
deriveTabFromQuery,
|
||||
isRetiredSettingsCompatibilityPath,
|
||||
isRouteableSettingsPath,
|
||||
resolveCanonicalSettingsPath,
|
||||
settingsAgentLabel,
|
||||
settingsAgentNodeLabel,
|
||||
settingsAgentPlatformType,
|
||||
settingsTabPath,
|
||||
type AgentKey,
|
||||
type ProxmoxPlatformType,
|
||||
type SettingsTab,
|
||||
} from './settingsNavigationModel';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
export type {
|
||||
SettingsHeaderMeta,
|
||||
SettingsHeaderMetaMap,
|
||||
SettingsNavGroup,
|
||||
SettingsNavGroupId,
|
||||
SettingsNavItem,
|
||||
SettingsTab,
|
||||
} from './settingsNavigationModel';
|
||||
|
|
|
|||
|
|
@ -559,5 +559,3 @@ Pulse prepares the first-host install token from setup so you can move straight
|
|||
tokenName,
|
||||
};
|
||||
};
|
||||
|
||||
export type InfrastructureInstallState = ReturnType<typeof useInfrastructureInstallState>;
|
||||
|
|
|
|||
|
|
@ -6,12 +6,6 @@ import { useInfrastructureDiscoveryRuntimeState } from './useInfrastructureDisco
|
|||
import { useTrueNASSettingsPanelState } from './useTrueNASSettingsPanelState';
|
||||
import { useVMwareSettingsPanelState } from './useVMwareSettingsPanelState';
|
||||
|
||||
export type {
|
||||
DiscoveryScanStatus,
|
||||
DiscoveredServer,
|
||||
NodeType,
|
||||
} from './infrastructureSettingsModel';
|
||||
|
||||
type InfrastructureEventBus = {
|
||||
on<T extends EventType>(event: T, handler: (data?: EventDataMap[T]) => void): () => void;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
export { SetupWizard } from './SetupWizard';
|
||||
export { StepIndicator } from './StepIndicator';
|
||||
export type { WizardState, WizardStep } from './SetupWizard';
|
||||
export type { WizardState, } from './SetupWizard';
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ export const WORKLOAD_TABLE_HISTORY_RANGE_LABELS: Record<WorkloadTableMetricHist
|
|||
'7d': '7d',
|
||||
};
|
||||
export const WORKLOAD_TABLE_HISTORY_DEFAULT_RANGE: WorkloadTableMetricHistoryRange = '1h';
|
||||
export const WORKLOAD_TABLE_HISTORY_RANGE = WORKLOAD_TABLE_HISTORY_DEFAULT_RANGE;
|
||||
export const WORKLOAD_TABLE_HISTORY_MAX_POINTS = 72;
|
||||
export const WORKLOAD_TABLE_HISTORY_POLL_MS = 30_000;
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ export const DEFAULT_WORKLOADS_SORT_KEY: WorkloadsSortKey = 'type';
|
|||
export const DEFAULT_WORKLOADS_SORT_DIRECTION = 'asc';
|
||||
export const DEFAULT_WORKLOADS_VIEW_MODE: ViewMode = 'all';
|
||||
export const DEFAULT_WORKLOADS_STATUS_MODE: WorkloadsStatusMode = 'all';
|
||||
export const DEFAULT_WORKLOADS_GROUPING_MODE: WorkloadsGroupingMode = 'grouped';
|
||||
export const DEFAULT_WORKLOADS_METRIC_DISPLAY_MODE: WorkloadsMetricDisplayMode = 'bars';
|
||||
|
||||
export const countActiveWorkloadsFilters = (
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ export { InvestigationSection } from './InvestigationSection';
|
|||
export { InvestigationMessages } from './InvestigationMessages';
|
||||
export { RemediationStatus } from './RemediationStatus';
|
||||
export { RunToolCallTrace } from './RunToolCallTrace';
|
||||
export { PatrolStatusBar } from './PatrolStatusBar';
|
||||
export { RunHistoryEntry } from './RunHistoryEntry';
|
||||
export { RunHistoryPanel } from './RunHistoryPanel';
|
||||
export { CountdownTimer } from './CountdownTimer';
|
||||
|
|
|
|||
|
|
@ -3,16 +3,13 @@ export { FilterChip } from './FilterChip';
|
|||
export { AddFilterMenu } from './AddFilterMenu';
|
||||
export { SavedViewsMenu } from './SavedViewsMenu';
|
||||
export { useSavedViews } from './useSavedViews';
|
||||
export type { SavedView, UseSavedViewsResult } from './useSavedViews';
|
||||
export type { SavedView, } from './useSavedViews';
|
||||
export {
|
||||
clearFilter,
|
||||
formatFilterChipValue,
|
||||
isFilterSet,
|
||||
} from './filterCatalog';
|
||||
export type {
|
||||
FilterBarProps,
|
||||
FilterBarSearch,
|
||||
FilterDef,
|
||||
FilterGroupKey,
|
||||
FilterSelectOption,
|
||||
} from './filterCatalog';
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { useFilterButtonGroupState } from './useFilterButtonGroupState';
|
|||
|
||||
export type {
|
||||
FilterButtonGroupProps,
|
||||
FilterButtonGroupVariant,
|
||||
FilterOption,
|
||||
} from './filterButtonGroupModel';
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from './pulseDataGridModel';
|
||||
import { usePulseDataGridState } from './usePulseDataGridState';
|
||||
|
||||
export type { PulseDataGridProps, TableColumn } from './pulseDataGridModel';
|
||||
export type { PulseDataGridProps, } from './pulseDataGridModel';
|
||||
|
||||
/**
|
||||
* A standardized, responsive datagrid component for Pulse.
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@ import { type SearchFieldProps } from './searchFieldModel';
|
|||
import { useSearchFieldState } from './useSearchFieldState';
|
||||
|
||||
export type {
|
||||
SearchFieldFocusEvent,
|
||||
SearchFieldKeyboardEvent,
|
||||
SearchFieldMouseEvent,
|
||||
SearchFieldProps,
|
||||
} from './searchFieldModel';
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
import { type SearchInputProps } from './searchInputModel';
|
||||
import { useSearchInputState } from './useSearchInputState';
|
||||
|
||||
export type { SearchInputKeyboardEvent, SearchInputProps } from './searchInputModel';
|
||||
export type { SearchInputProps } from './searchInputModel';
|
||||
|
||||
export const SearchInput: Component<SearchInputProps> = (props) => {
|
||||
const search = useSearchInputState(props);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from './searchTipsPopoverModel';
|
||||
import { useSearchTipsPopoverState } from './useSearchTipsPopoverState';
|
||||
|
||||
export type { SearchTip, SearchTipsPopoverProps } from './searchTipsPopoverModel';
|
||||
export type { SearchTipsPopoverProps } from './searchTipsPopoverModel';
|
||||
|
||||
export const SearchTipsPopover: Component<SearchTipsPopoverProps> = (props) => {
|
||||
const triggerVariant = () => getSearchTipsPopoverTriggerVariant(props.triggerVariant);
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ import { useSelectionCardGroupState } from './useSelectionCardGroupState';
|
|||
|
||||
export type {
|
||||
SelectionCardGroupProps,
|
||||
SelectionCardGroupVariant,
|
||||
SelectionCardOption,
|
||||
SelectionCardTone,
|
||||
} from './selectionCardGroupModel';
|
||||
|
||||
export function SelectionCardGroup<T extends string | number>(props: SelectionCardGroupProps<T>) {
|
||||
|
|
|
|||
|
|
@ -153,85 +153,3 @@ export const ResponsiveMetricCell: Component<ResponsiveMetricCellProps> = (props
|
|||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simpler metric text component for when you just want colored percentage
|
||||
* without the MetricBar complexity
|
||||
*/
|
||||
export const MetricText: Component<{
|
||||
value: number;
|
||||
type: 'cpu' | 'memory' | 'disk';
|
||||
label?: string;
|
||||
class?: string;
|
||||
thresholds?: MetricDisplayThresholds | null;
|
||||
}> = (props) => {
|
||||
const displayLabel = createMemo(() => props.label ?? formatPercent(props.value));
|
||||
const colorClass = createMemo(() => metricTextClass(props.value, props.type, props.thresholds));
|
||||
|
||||
return (
|
||||
<span class={`text-xs text-center ${colorClass()} ${props.class || ''}`}>
|
||||
<Show when={!props.label} fallback={displayLabel()}>
|
||||
<AnimatedNumber value={props.value} format={formatPercent} />
|
||||
</Show>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Metric cell with explicit mobile/desktop rendering
|
||||
* Use this when you need full control over what renders in each mode
|
||||
*/
|
||||
export const DualMetricCell: Component<{
|
||||
value: number;
|
||||
type: 'cpu' | 'memory' | 'disk';
|
||||
label?: string;
|
||||
sublabel?: string;
|
||||
resourceId?: string;
|
||||
isRunning?: boolean;
|
||||
showMobile: boolean;
|
||||
mobileContent?: JSX.Element;
|
||||
desktopContent?: JSX.Element;
|
||||
fallback?: JSX.Element;
|
||||
class?: string;
|
||||
thresholds?: MetricDisplayThresholds | null;
|
||||
}> = (props) => {
|
||||
const displayLabel = createMemo(() => props.label ?? formatPercent(props.value));
|
||||
const colorClass = createMemo(() => metricTextClass(props.value, props.type, props.thresholds));
|
||||
const isRunning = () => props.isRunning !== false;
|
||||
|
||||
const defaultFallback = (
|
||||
<div class="h-4 flex items-center justify-center">
|
||||
<span class="text-xs text-muted" aria-hidden="true">—</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
const defaultMobileContent = (
|
||||
<div class={`text-xs text-center ${colorClass()}`}>
|
||||
<Show when={!props.label} fallback={displayLabel()}>
|
||||
<AnimatedNumber value={props.value} format={formatPercent} />
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
|
||||
const defaultDesktopContent = (
|
||||
<MetricBar
|
||||
value={props.value}
|
||||
label={displayLabel()}
|
||||
animatedLabelValue={props.label ? undefined : props.value}
|
||||
sublabel={props.sublabel}
|
||||
type={props.type}
|
||||
resourceId={props.resourceId}
|
||||
thresholds={props.thresholds}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Show when={isRunning()} fallback={props.fallback ?? defaultFallback}>
|
||||
<div class={props.class}>
|
||||
<Show when={props.showMobile} fallback={props.desktopContent ?? defaultDesktopContent}>
|
||||
{props.mobileContent ?? defaultMobileContent}
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export const SUMMARY_CHART_SLOT_CLASS = 'h-[136px] sm:h-[150px]';
|
||||
|
||||
export const SUMMARY_CHART_SLOT_COMPACT_CLASS = 'h-[108px] sm:h-[120px]';
|
||||
export const SUMMARY_CHART_PLOT_AREA_CLASS = 'h-[120px] sm:h-[134px]';
|
||||
|
|
|
|||
|
|
@ -8,6 +8,3 @@ export const SUMMARY_TIME_RANGE_LABEL: Record<SummaryTimeRange, string> = {
|
|||
'24h': '24h',
|
||||
'7d': '7d',
|
||||
};
|
||||
|
||||
export const isSummaryTimeRange = (value: string): value is SummaryTimeRange =>
|
||||
(SUMMARY_TIME_RANGES as readonly string[]).includes(value);
|
||||
|
|
|
|||
|
|
@ -73,5 +73,3 @@ export function useCommandPaletteState(props: CommandPaletteModalProps) {
|
|||
setQuery,
|
||||
};
|
||||
}
|
||||
|
||||
export type CommandPaletteState = ReturnType<typeof useCommandPaletteState>;
|
||||
|
|
|
|||
|
|
@ -126,5 +126,3 @@ export function useContainerUpdateButtonState(props: UpdateButtonProps) {
|
|||
shouldHideButton,
|
||||
};
|
||||
}
|
||||
|
||||
export type ContainerUpdateButtonState = ReturnType<typeof useContainerUpdateButtonState>;
|
||||
|
|
|
|||
|
|
@ -98,5 +98,3 @@ export function useHelpIconState(props: HelpIconProps) {
|
|||
toggleOpen,
|
||||
};
|
||||
}
|
||||
|
||||
export type HelpIconState = ReturnType<typeof useHelpIconState>;
|
||||
|
|
|
|||
|
|
@ -80,5 +80,3 @@ export function useMobileNavBarState(props: MobileNavBarProps) {
|
|||
showLeftFade,
|
||||
};
|
||||
}
|
||||
|
||||
export type MobileNavBarState = ReturnType<typeof useMobileNavBarState>;
|
||||
|
|
|
|||
|
|
@ -211,5 +211,3 @@ export function useWebInterfaceUrlFieldState(props: WebInterfaceUrlFieldProps) {
|
|||
urlValue,
|
||||
};
|
||||
}
|
||||
|
||||
export type WebInterfaceUrlFieldState = ReturnType<typeof useWebInterfaceUrlFieldState>;
|
||||
|
|
|
|||
|
|
@ -124,16 +124,6 @@ export const getGuestOverrideIdentity = (
|
|||
};
|
||||
};
|
||||
|
||||
export const canonicalGuestOverrideResourceId = (
|
||||
resource: GuestOverrideResourceLike,
|
||||
): string | undefined => {
|
||||
const identity = getGuestOverrideIdentity(resource);
|
||||
if (!identity) {
|
||||
return undefined;
|
||||
}
|
||||
return `${identity.instance}:${identity.node}:${identity.vmid}`;
|
||||
};
|
||||
|
||||
export const guestOverrideStorageId = (resource: GuestOverrideResourceLike): string => {
|
||||
const identity = getGuestOverrideIdentity(resource);
|
||||
if (!identity) {
|
||||
|
|
|
|||
|
|
@ -40,17 +40,3 @@ export const stripStateKeys = (
|
|||
delete (next as Record<string, unknown>).poweredOffSeverity;
|
||||
return next;
|
||||
};
|
||||
|
||||
export const removeOverrideState = (
|
||||
overrides: Override[],
|
||||
rawOverridesConfig: Record<string, RawOverrideConfig>,
|
||||
resourceId: string,
|
||||
) => {
|
||||
const nextRawConfig = { ...rawOverridesConfig };
|
||||
delete nextRawConfig[resourceId];
|
||||
|
||||
return {
|
||||
nextOverrides: overrides.filter((override) => override.id !== resourceId),
|
||||
nextRawConfig,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -81,14 +81,6 @@ export const getStoragePoolTableColumns = (
|
|||
colClassName: 'hidden xl:table-column xl:w-[11%]',
|
||||
},
|
||||
];
|
||||
|
||||
export const STORAGE_CONTROLS_NODE_SELECT_CLASS =
|
||||
'px-2 py-1 text-xs border border-border rounded-md bg-surface text-base-content focus:ring-2 focus:ring-blue-500 focus:border-blue-500';
|
||||
|
||||
export const STORAGE_CONTROLS_NODE_DIVIDER_CLASS = 'h-5 w-px bg-surface-hover hidden sm:block';
|
||||
|
||||
export const STORAGE_CONTENT_CARD_HEADER_CLASS =
|
||||
'border-b border-border bg-surface-hover px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-muted';
|
||||
export const STORAGE_CONTENT_CARD_BODY_CLASS = 'p-2';
|
||||
|
||||
export const STORAGE_POOLS_EMPTY_STATE_CLASS = 'p-6 text-sm text-muted';
|
||||
|
|
|
|||
|
|
@ -854,18 +854,6 @@ const matchesTrueNASStorageSearch = (resource: Resource, search: string): boolea
|
|||
return haystack.includes(needle);
|
||||
};
|
||||
|
||||
export function filterTrueNASStorageResources(
|
||||
resources: Resource[],
|
||||
search: string,
|
||||
status: TrueNASStorageStatusFilter,
|
||||
): Resource[] {
|
||||
return resources.filter((resource) => {
|
||||
if (!matchesTrueNASStorageSearch(resource, search)) return false;
|
||||
if (status === 'all') return true;
|
||||
return mapTrueNASStorageStatus(resource) === status;
|
||||
});
|
||||
}
|
||||
|
||||
const resourceIncidentLabel = (resource: Resource, incident: ResourceIncident): string => {
|
||||
const label = asTrimmedString(resource.incidentLabel);
|
||||
if (label) return label;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ export const TRUENAS_DEFAULT_TAB = 'overview';
|
|||
export const VMWARE_PATH = '/vmware';
|
||||
export const VMWARE_DEFAULT_TAB = 'overview';
|
||||
export const PMG_THRESHOLDS_PATH = '/alerts/thresholds/mail-gateway';
|
||||
export const ALERTS_OVERVIEW_PATH = '/alerts/overview';
|
||||
export const PATROL_PATH = '/patrol';
|
||||
|
||||
export const STORAGE_QUERY_PARAMS = {
|
||||
|
|
|
|||
|
|
@ -191,18 +191,6 @@ export interface AIConversationMessage {
|
|||
content: string;
|
||||
}
|
||||
|
||||
// AI Execute request/response types
|
||||
export interface AIExecuteRequest {
|
||||
prompt: string;
|
||||
target_type?: string; // "agent", "system-container", "vm", etc.
|
||||
target_id?: string;
|
||||
context?: Record<string, unknown>;
|
||||
history?: AIConversationMessage[]; // Previous conversation messages
|
||||
finding_id?: string; // If fixing a patrol finding, the ID to resolve on success
|
||||
model?: string; // Override model for this request (user selection in chat)
|
||||
use_case?: 'chat' | 'patrol'; // Optional server-side routing/model selection
|
||||
}
|
||||
|
||||
// Tool execution info
|
||||
export interface AIToolExecution {
|
||||
name: string; // "run_command", "read_file"
|
||||
|
|
@ -387,15 +375,6 @@ export interface AIChatMessage {
|
|||
toolCalls?: AIChatToolCall[];
|
||||
}
|
||||
|
||||
export interface AIChatSession {
|
||||
id: string;
|
||||
username: string;
|
||||
title: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
messages: AIChatMessage[];
|
||||
}
|
||||
|
||||
// Summary returned by list endpoint (no messages)
|
||||
export interface AIChatSessionHandoffResource {
|
||||
id?: string;
|
||||
|
|
|
|||
|
|
@ -63,30 +63,6 @@ export interface ConnectedInfrastructureItem {
|
|||
surfaces: ConnectedInfrastructureSurface[];
|
||||
}
|
||||
|
||||
export interface KubernetesCluster {
|
||||
id: string;
|
||||
agentId: string;
|
||||
name?: string;
|
||||
displayName?: string;
|
||||
customDisplayName?: string;
|
||||
server?: string;
|
||||
context?: string;
|
||||
version?: string;
|
||||
status: string;
|
||||
lastSeen: number;
|
||||
intervalSeconds: number;
|
||||
agentVersion?: string;
|
||||
tokenId?: string;
|
||||
tokenName?: string;
|
||||
tokenHint?: string;
|
||||
tokenLastUsedAt?: number;
|
||||
hidden?: boolean;
|
||||
pendingUninstall?: boolean;
|
||||
nodes?: KubernetesNode[];
|
||||
pods?: KubernetesPod[];
|
||||
deployments?: KubernetesDeployment[];
|
||||
}
|
||||
|
||||
export interface KubernetesNode {
|
||||
uid: string;
|
||||
name: string;
|
||||
|
|
@ -1068,11 +1044,6 @@ export interface PhysicalDisk {
|
|||
smartAttributes?: SMARTAttributes;
|
||||
}
|
||||
|
||||
/** Returns the best resource ID for disk metrics queries (serial preferred, WWN fallback). */
|
||||
export function diskResourceId(disk: PhysicalDisk): string | null {
|
||||
return disk.serial || disk.wwn || null;
|
||||
}
|
||||
|
||||
export interface CPUInfo {
|
||||
model: string;
|
||||
cores: number;
|
||||
|
|
@ -1259,7 +1230,3 @@ export type WSMessage =
|
|||
scanning?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
// Utility types
|
||||
export type Status = 'running' | 'stopped' | 'paused' | 'unknown';
|
||||
export type GuestType = 'vm' | 'system-container';
|
||||
|
|
|
|||
|
|
@ -87,15 +87,6 @@ export interface NodesConfig {
|
|||
pbsInstances: PBSNodeConfig[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete configuration structure
|
||||
*/
|
||||
export interface PulseConfig {
|
||||
auth: Partial<AuthConfig>; // From .env
|
||||
system: SystemConfig; // From system.json
|
||||
nodes: NodesConfig; // From nodes.enc
|
||||
}
|
||||
|
||||
/**
|
||||
* API response for security status
|
||||
*/
|
||||
|
|
@ -180,47 +171,3 @@ export interface SSOProviderInfo {
|
|||
iconUrl?: string;
|
||||
loginUrl: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* First-run setup request
|
||||
*/
|
||||
export interface SetupRequest {
|
||||
username: string;
|
||||
password: string;
|
||||
apiToken?: string;
|
||||
enableNotifications?: boolean;
|
||||
darkMode?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guards for configuration validation
|
||||
*/
|
||||
export const isValidUpdateChannel = (value: string): value is UpdateChannel => {
|
||||
return value === 'stable' || value === 'rc';
|
||||
};
|
||||
|
||||
export const isValidTimeFormat = (value: string): boolean => {
|
||||
return /^([01]\d|2[0-3]):([0-5]\d)$/.test(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Default values for configuration
|
||||
*/
|
||||
export const DEFAULT_CONFIG: {
|
||||
system: SystemConfig;
|
||||
} = {
|
||||
system: {
|
||||
connectionTimeout: 60,
|
||||
autoUpdateEnabled: false,
|
||||
updateChannel: 'stable',
|
||||
autoUpdateCheckInterval: 24,
|
||||
autoUpdateTime: '03:00',
|
||||
backupPollingEnabled: true,
|
||||
backupPollingInterval: 0,
|
||||
temperatureMonitoringEnabled: true,
|
||||
telemetryEnabled: true,
|
||||
sshPort: 22,
|
||||
allowedOrigins: '',
|
||||
frontendPort: 7655,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -162,10 +162,6 @@ export interface UpdateNotesRequest {
|
|||
user_secrets?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface UpdateSettingsRequest {
|
||||
max_discovery_age_days?: number; // Days before rediscovery (default 30)
|
||||
}
|
||||
|
||||
// AI provider information for discovery transparency
|
||||
export interface AIProviderInfo {
|
||||
provider: string; // e.g., "anthropic", "openai", "ollama"
|
||||
|
|
|
|||
|
|
@ -104,18 +104,3 @@ export type NodeConfigWithStatus = NodeConfig & {
|
|||
hasToken?: boolean;
|
||||
status: 'connected' | 'disconnected' | 'offline' | 'error' | 'pending';
|
||||
};
|
||||
|
||||
export interface NodesResponse {
|
||||
pve_instances: PVENodeConfig[];
|
||||
pbs_instances: PBSNodeConfig[];
|
||||
pmg_instances?: PMGNodeConfig[];
|
||||
}
|
||||
|
||||
export interface NodeUpdateRequest {
|
||||
node: NodeConfig;
|
||||
}
|
||||
|
||||
export interface NodeDeleteResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,10 +137,6 @@ export interface RecoveryPointsSeriesBucket {
|
|||
remote: number;
|
||||
}
|
||||
|
||||
export interface RecoveryPointsSeriesResponse {
|
||||
data: RecoveryPointsSeriesBucket[];
|
||||
}
|
||||
|
||||
export interface RecoveryPointsFacets {
|
||||
clusters?: string[];
|
||||
nodesAgents?: string[];
|
||||
|
|
@ -150,7 +146,3 @@ export interface RecoveryPointsFacets {
|
|||
hasVerification?: boolean;
|
||||
hasEntityId?: boolean;
|
||||
}
|
||||
|
||||
export interface RecoveryPointsFacetsResponse {
|
||||
data: RecoveryPointsFacets;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,8 +196,6 @@ export const requiresGovernedResourceDisplay = (policy?: ResourcePolicy | null):
|
|||
if (!policy) return false;
|
||||
return policy.routing.scope === 'local-only' || (policy.routing.redact?.length ?? 0) > 0;
|
||||
};
|
||||
|
||||
export type ResourceApprovalLevel = 'none' | 'dry_run_only' | 'admin' | 'mfa';
|
||||
export type ResourceChangeConfidence = 'high' | 'medium' | 'low';
|
||||
export type ResourceChangeKind =
|
||||
| 'state_transition'
|
||||
|
|
|
|||
|
|
@ -342,23 +342,6 @@ export const getFindingSeverityCompactLabel = (
|
|||
severity: UnifiedFinding['severity'] | string,
|
||||
): string => FINDING_SEVERITY_COMPACT_LABELS[severity] || String(severity).toUpperCase();
|
||||
|
||||
export const getFindingCompactBadgePresentation = (
|
||||
finding: Pick<UnifiedFinding, 'severity' | 'resourceId' | 'resourceName' | 'title'>,
|
||||
): FindingCompactBadgePresentation => {
|
||||
if (isPatrolRuntimeFinding(finding)) {
|
||||
const severityPresentation = getFindingSeverityPresentation(finding);
|
||||
return {
|
||||
label: severityPresentation.label,
|
||||
badgeClasses: severityPresentation.badgeClasses,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
label: getFindingSeverityCompactLabel(finding.severity),
|
||||
badgeClasses: getFindingSeverityBadgeClasses(finding.severity),
|
||||
};
|
||||
};
|
||||
|
||||
export const isPatrolRuntimeFinding = (
|
||||
finding: Pick<UnifiedFinding, 'resourceId' | 'resourceName' | 'title'>,
|
||||
): boolean => {
|
||||
|
|
@ -617,25 +600,6 @@ export const doesFindingNeedAttention = (
|
|||
);
|
||||
};
|
||||
|
||||
// True when the finding has an investigation outcome indicating that some
|
||||
// remediation step has run against it — anything past "fix queued." For these
|
||||
// states, Verify fix is a meaningful action; for fix_queued (still awaiting
|
||||
// approval) and earlier states there is nothing applied yet to verify, and
|
||||
// for fix_failed the fix didn't complete so verification doesn't apply.
|
||||
export const findingHasAppliedFix = (
|
||||
finding: Pick<UnifiedFinding, 'investigationOutcome'>,
|
||||
): boolean => {
|
||||
switch (finding.investigationOutcome) {
|
||||
case 'fix_executed':
|
||||
case 'fix_verified':
|
||||
case 'fix_verification_failed':
|
||||
case 'fix_verification_unknown':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getFindingLoopStateBadgeClasses = (loopState: string): string =>
|
||||
FINDING_LOOP_STATE_CLASSES[loopState] || DEFAULT_LOOP_STATE_CLASSES;
|
||||
|
||||
|
|
|
|||
|
|
@ -190,10 +190,6 @@ export function getAlertConfigDiscardLabel(isReloading: boolean) {
|
|||
return isReloading ? ALERT_CONFIG_DISCARDING_LABEL : ALERT_CONFIG_DISCARD_LABEL;
|
||||
}
|
||||
|
||||
export function getAlertConfigSwarmGapValidationError() {
|
||||
return ALERT_CONFIG_SWARM_GAP_VALIDATION;
|
||||
}
|
||||
|
||||
export function getAlertConfigQuietHourSuppressOptions() {
|
||||
return ALERT_CONFIG_QUIET_HOUR_SUPPRESS_OPTIONS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,17 +275,6 @@ export function getAlertWebhookUrlPlaceholder(urlPattern?: string) {
|
|||
return urlPattern || ALERT_WEBHOOK_URL_PLACEHOLDER;
|
||||
}
|
||||
|
||||
export function getAlertWebhookMentionPlaceholder(service: string) {
|
||||
return (
|
||||
ALERT_WEBHOOK_SERVICE_PRESENTATION[service as AlertWebhookService]?.mentionPlaceholder ||
|
||||
ALERT_WEBHOOK_MENTION_FALLBACK_PLACEHOLDER
|
||||
);
|
||||
}
|
||||
|
||||
export function getAlertWebhookMentionHelp(service: string) {
|
||||
return ALERT_WEBHOOK_SERVICE_PRESENTATION[service as AlertWebhookService]?.mentionHelp || '';
|
||||
}
|
||||
|
||||
export function getAlertWebhookSummaryLabel(enabledCount: number, totalCount: number) {
|
||||
return `${enabledCount} of ${totalCount} webhooks enabled`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,10 +146,6 @@ export function parseCloudTier(value?: string | null): CloudTierKey {
|
|||
}
|
||||
}
|
||||
|
||||
export function getCloudPlanForTier(value?: string | null): CloudPlanDefinition {
|
||||
return CLOUD_PLAN_BY_TIER[parseCloudTier(value)];
|
||||
}
|
||||
|
||||
export function getCloudPlanPricePresentation(
|
||||
plan: CloudPlanDefinition,
|
||||
): CloudPlanPricePresentation {
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ export interface HostedCommercialModelInput {
|
|||
guestUsage: number;
|
||||
renewsOrExpires: string;
|
||||
}
|
||||
|
||||
export const SELF_HOSTED_NOT_METERED_LABEL = 'Not metered';
|
||||
export const LIFETIME_DAYS_REMAINING_LABEL = 'Permanent';
|
||||
|
||||
const asUnlimitedLimit = (value?: number) =>
|
||||
|
|
|
|||
|
|
@ -307,14 +307,6 @@ export function readInfrastructureSummaryCache(
|
|||
}
|
||||
}
|
||||
|
||||
export function hasFreshInfrastructureSummaryCache(
|
||||
range: TimeRange,
|
||||
maxAgeMs: number = INFRA_SUMMARY_CACHE_MAX_AGE_MS,
|
||||
metrics?: readonly InfrastructureSummaryMetric[] | null,
|
||||
): boolean {
|
||||
return readInfrastructureSummaryCache(range, maxAgeMs, undefined, metrics) !== null;
|
||||
}
|
||||
|
||||
const inFlightFetches = new Map<string, Promise<InfrastructureSummaryFetchResult>>();
|
||||
let infraSummaryFetchSeq = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -60,10 +60,6 @@ export interface LicenseInlineNotice {
|
|||
body: string;
|
||||
}
|
||||
|
||||
export interface LicenseActionNotice extends LicenseInlineNotice {
|
||||
actionLabel: string;
|
||||
}
|
||||
|
||||
export interface BillingAdminOrganizationBadge {
|
||||
label: string;
|
||||
badgeClass: string;
|
||||
|
|
|
|||
|
|
@ -758,13 +758,3 @@ export function getContainerRuntimeBadgeForRuntime(runtime?: string | null): Res
|
|||
title: `Runtime: ${label}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function getContainerRuntimeBadge(
|
||||
platformType?: PlatformType,
|
||||
platformData?: Record<string, unknown> | null,
|
||||
): ResourceBadge | null {
|
||||
if (platformType !== 'docker' || !platformData) return null;
|
||||
|
||||
const docker = (platformData as { docker?: { runtime?: string } } | undefined)?.docker;
|
||||
return getContainerRuntimeBadgeForRuntime(docker?.runtime);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,9 +163,3 @@ export const buildStorageSourceOptionsFromKeys = (
|
|||
const orderedKeys = orderStorageSourceKeys(keys).filter((key) => key !== 'all');
|
||||
return [ALL_STORAGE_SOURCE_OPTION, ...orderedKeys.map((key) => getStorageSourceOption(key))];
|
||||
};
|
||||
|
||||
export const DEFAULT_STORAGE_SOURCE_OPTIONS: StorageSourceOption[] =
|
||||
buildStorageSourceOptionsFromKeys(['proxmox-pve', 'proxmox-pbs', 'ceph', 'truenas']);
|
||||
|
||||
export const buildStorageSourceOptions = (storageList: Storage[]): StorageSourceOption[] =>
|
||||
buildStorageSourceOptionsFromKeys(storageList.map((storage) => resolveStorageSourceKey(storage)));
|
||||
|
|
|
|||
|
|
@ -48,11 +48,6 @@ export function fetchStorageSummaryAndCache(
|
|||
return request;
|
||||
}
|
||||
|
||||
export function __resetStorageSummaryCacheForTests(): void {
|
||||
inMemoryCache.clear();
|
||||
inFlightFetches.clear();
|
||||
}
|
||||
|
||||
const unsubscribeStorageOrgSwitch = eventBus.on('org_switched', () => {
|
||||
inMemoryCache.clear();
|
||||
inFlightFetches.clear();
|
||||
|
|
|
|||
|
|
@ -39,12 +39,6 @@ export function getUnifiedAgentLastSeenLabel(
|
|||
return row.lastSeen ? formatRelativeTime(row.lastSeen) : '—';
|
||||
}
|
||||
|
||||
export function getMonitoringStoppedEmptyState(hasFilters: boolean): string {
|
||||
return hasFilters
|
||||
? 'No monitoring-stopped items match the current filters.'
|
||||
: 'No infrastructure currently has monitoring stopped.';
|
||||
}
|
||||
|
||||
export function getUnifiedAgentStopMonitoringUnavailableMessage(): string {
|
||||
return 'No host identifiers are available to stop monitoring.';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ export interface UnifiedAgentLookupStatusPresentation {
|
|||
}
|
||||
|
||||
export const MONITORING_STOPPED_STATUS_LABEL = 'Monitoring stopped';
|
||||
export const ALLOW_RECONNECT_LABEL = 'Allow reconnect';
|
||||
|
||||
export function getUnifiedAgentStatusPresentation(
|
||||
state: UnifiedAgentMonitoringState,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { normalizeOrgScope } from '@/utils/orgScope';
|
|||
import { eventBus } from '@/stores/events';
|
||||
|
||||
export const WORKLOADS_SUMMARY_CACHE_VERSION = 6;
|
||||
export const WORKLOAD_CHART_DEFAULT_POINT_LIMIT = 180;
|
||||
|
||||
const WORKLOADS_SUMMARY_CACHE_PREFIX = 'pulse.workloadsSummaryCharts.';
|
||||
const WORKLOADS_SUMMARY_CACHE_MAX_AGE_MS = 5 * 60_000;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue