From 3504764fe883e7ea21993694bea113b326c2cf5c Mon Sep 17 00:00:00 2001
From: Maya
Date: Sat, 6 Sep 2025 17:58:06 -0400
Subject: [PATCH] services frontend getting there
---
.../features/discovery/DiscoveryStatus.svelte | 12 -
.../features/nodes/components/NodeCard.svelte | 17 +-
.../NodeEditModal/Details/DetailsForm.svelte | 37 +-
.../NodeEditModal/NodeEditor.svelte | 39 +-
.../Services/ServicesConfigPanel.svelte | 595 ++++++++++--------
.../Services/ServicesForm.svelte | 293 ++++-----
src/lib/features/nodes/store.ts | 32 +-
src/lib/features/nodes/types/base.ts | 14 +-
src/lib/features/services/types/base.ts | 53 ++
src/lib/shared/components/data/Tag.svelte | 9 +-
.../components/forms/DynamicField.svelte | 263 --------
.../components/forms/JsonContainer.svelte | 107 ----
.../components/forms/ListConfigEditor.svelte | 2 +
.../components/forms/ListManager.svelte | 2 +
.../components/forms/ListSelectItem.svelte | 26 +-
.../shared/components/forms/RichSelect.svelte | 84 ++-
src/lib/shared/stores/registry.ts | 19 +-
17 files changed, 650 insertions(+), 954 deletions(-)
create mode 100644 src/lib/features/services/types/base.ts
delete mode 100644 src/lib/shared/components/forms/DynamicField.svelte
delete mode 100644 src/lib/shared/components/forms/JsonContainer.svelte
diff --git a/src/lib/features/discovery/DiscoveryStatus.svelte b/src/lib/features/discovery/DiscoveryStatus.svelte
index f2786fdb..6d80daf6 100644
--- a/src/lib/features/discovery/DiscoveryStatus.svelte
+++ b/src/lib/features/discovery/DiscoveryStatus.svelte
@@ -7,7 +7,6 @@
import { getDaemonDiscoveryState } from '../daemons/store';
import RichSelect from '$lib/shared/components/forms/RichSelect.svelte';
import { getNodeTargetString } from "../nodes/store";
- import { nodeStatuses } from '$lib/shared/stores/registry';
import DaemonDiscoveryStatus from './DaemonDiscoveryStatus.svelte';
import { type TagProps } from '$lib/shared/components/data/types';
import { get } from 'svelte/store';
@@ -15,9 +14,6 @@
let selectedDaemonId: string | null = null;
$: discoveryData = getDaemonDiscoveryState(selectedDaemonId, get(sessions));
$: selectedDaemon = $daemons.find(daemon => daemon.id == selectedDaemonId);
- $: selectedNode = $nodes.find(node => node.id == selectedDaemon?.node_id);
- $: nodeStyle = nodeStatuses.getColor(selectedNode?.status || null);
-
// Auto-select daemon logic: prioritize daemon with active session, fallback to first daemon
$: if (!selectedDaemonId && $daemons.length > 0) {
@@ -50,17 +46,9 @@
value: d.id,
label: node?.name || `Daemon ${d.id.substring(0, 8)}`,
description: node ? `on ${getNodeTargetString(node?.target)}` : `Daemon ${d.id.substring(0, 8)}`,
- status: node?.status
}
})}
getOptionId={(option) => option.value}
- getOptionTags={(option): TagProps[] => {
- return [{
- label: option.status,
- bgColor: nodeStyle.bg,
- textColor: nodeStyle.text
- }]
- }}
onSelect={handleDaemonSelect} />
{/if}
diff --git a/src/lib/features/nodes/components/NodeCard.svelte b/src/lib/features/nodes/components/NodeCard.svelte
index 38a14184..d892503b 100644
--- a/src/lib/features/nodes/components/NodeCard.svelte
+++ b/src/lib/features/nodes/components/NodeCard.svelte
@@ -2,12 +2,12 @@
import { Edit, Radar, Trash2 } from 'lucide-svelte';
import { getNodeTargetString } from '../store';
import type { Node } from '../types/base';
- import { capabilities, nodeStatuses, nodeTypes } from '$lib/shared/stores/registry';
import GenericCard from '$lib/shared/components/data/GenericCard.svelte';
import type { Daemon } from '$lib/features/daemons/types/base';
import { getDaemonDiscoveryState } from '$lib/features/daemons/store';
import DaemonDiscoveryStatus from '$lib/features/discovery/DaemonDiscoveryStatus.svelte';
import { sessions } from '$lib/features/discovery/store';
+ import { services } from '$lib/shared/stores/registry';
export let node: Node;
export let daemon: Daemon | null;
@@ -26,12 +26,8 @@
// Build card data
$: cardData = {
title: node.name,
- subtitle: nodeTypes.getDisplay(node.node_type),
- status: node.monitoring_interval == 0 ? 'Monitoring Disabled' : nodeStatuses.getDisplay(node.status || null),
- statusColor: node.monitoring_interval == 0 ? 'text-gray-400' : nodeStatuses.getColor(node.status || null).text,
- icon: nodeTypes.getIconComponent(node.node_type),
iconColor: 'text-blue-400',
-
+ icon: services.getIconComponent(node.services[0].type),
sections: connectionInfo ? [{
label: 'Connection',
value: connectionInfo
@@ -39,12 +35,11 @@
lists: [
{
- label: 'Capabilities',
- items: node.capabilities.map(cap => {
- const [capId, capInfo] = Object.entries(cap)[0];
+ label: 'Services',
+ items: node.services.map(cap => {
return ({
- id: capId,
- label: capabilities.getDisplay(capId),
+ id: cap.type,
+ label: services.getDisplay(cap.type),
bgColor: 'bg-purple-900/30',
color: 'text-purple-300'
})
diff --git a/src/lib/features/nodes/components/NodeEditModal/Details/DetailsForm.svelte b/src/lib/features/nodes/components/NodeEditModal/Details/DetailsForm.svelte
index 9b024377..ca38d94f 100644
--- a/src/lib/features/nodes/components/NodeEditModal/Details/DetailsForm.svelte
+++ b/src/lib/features/nodes/components/NodeEditModal/Details/DetailsForm.svelte
@@ -5,33 +5,28 @@
import { required } from 'svelte-forms/validators';
import type { Node } from '$lib/features/nodes/types/base';
import { maxLength, validNodeType } from '$lib/shared/components/forms/validators';
- import { nodeTargets, nodeTypes } from '$lib/shared/stores/registry';
+ import { nodeTargets } from '$lib/shared/stores/registry';
export let form: any;
export let formData: Node;
- export let isEditing: boolean = false;
// Create form fields with validation
const name = field('name', formData.name, [required(), maxLength(100)]);
const description = field('description', formData.description || '', [maxLength(500)]);
- const nodeType = field('node_type', formData.node_type, [validNodeType(isEditing)]);
const hostname = field('hostname', formData.hostname || '');
// Add fields to form
onMount(() => {
form.name = name
form.description = description
- form.nodeType = nodeType
form.hostname = hostname
});
// Update formData when field values change
$: formData.name = $name.value;
$: formData.description = $description.value;
- $: formData.node_type = $nodeType.value;
$: formData.hostname = $hostname.value;
- $: nodeTypeOptions = nodeTypes.getItems().map(t => {return {value:t.id, label: t.display_name}});
$: targetTypeOptions = nodeTargets.getItems().map(t => {return {value:t.id, label: t.display_name, description: t.description, icon: t.icon}});
// Initialize target if needed
@@ -91,36 +86,6 @@
-
-
-
-
- {#if $nodeType.errors.length > 0}
-
-
-
{$nodeType.errors[0]}
-
- {/if}
-
- Classification for this node type
-
-
-
@@ -204,12 +205,11 @@
- {:else if activeTab === 'capabilities'}
+ {:else if activeTab === 'services'}
{#if !isEditing}
@@ -221,10 +221,9 @@
{/if}
-
diff --git a/src/lib/features/nodes/components/NodeEditModal/Services/ServicesConfigPanel.svelte b/src/lib/features/nodes/components/NodeEditModal/Services/ServicesConfigPanel.svelte
index 11001d6a..1589affb 100644
--- a/src/lib/features/nodes/components/NodeEditModal/Services/ServicesConfigPanel.svelte
+++ b/src/lib/features/nodes/components/NodeEditModal/Services/ServicesConfigPanel.svelte
@@ -1,326 +1,365 @@
-{#if !capability || !schema}
-
-
-
No capability selected
-
Select a capability from the list to configure it
-
-
-{:else}
- {@const config = getCapabilityConfig(capability)}
-
-
-
-
- {#if schema.capability_info.icon}
- {@const iconStyle = createStyle(schema.capability_info.color, schema.capability_info.icon)}
-
- {/if}
-
- {schema.capability_info.display_name}
-
+{#if service && serviceMetadata}
+
+
+
+
+
{serviceMetadata.display_name}
+
+
+
{serviceMetadata.description}
+
- {#if schema.capability_info.description}
-
{schema.capability_info.description}
- {/if}
-
-
-
-
- {#if !getCapabilityConfig(capability).system_assigned && capabilityNameField}
+
+
+
+
+
+ {#if serviceNameField}
-
{/if}
-
-
- {#if schema.capability_fields.length > 0}
-
-
Configuration
-
- {#each schema.capability_fields as field}
- capabilityConfig[field.id] = value}
- />
- {/each}
-
+
+
+ {#if confirmedField}
+
+
+
+ Service Confirmed
+
+
+ Mark as confirmed if you've verified this service is actually running
+
{/if}
-
-
-
+
+
+
Ports
+
+
+
+ {#if service.ports.length === 0}
+
+ No ports configured. Click "Add Port" to add one.
+
+ {:else}
+
+ {#each service.ports as port, index}
+
+
+
+
Port Number
+
handlePortNumberChange(index, e)}
+ class="w-full px-2 py-1 text-sm bg-gray-700 border border-gray-600 rounded text-white focus:ring-2 focus:ring-blue-500"
+ />
-
-
- {#if isExpanded}
-
-
- {#each section.test_fields as field}
- updateTestConfig(sectionIndex, field.id, value)}
- disabled={!testConfig?.enabled}
- />
- {/each}
-
+
+
+
+
- {/each}
-
-
- {/if} -->
-
-
- {#if schema.warnings.length > 0}
-
-
Warnings
-
- {#each schema.warnings as warning}
-
{warning.message}
- {/each}
-
+
+ {/each}
{/if}
-
- {#if schema.errors.length > 0}
-
-
Errors
-
- {#each schema.errors as error}
-
{error.message}
- {/each}
-
+
+
+
+
+
+
Endpoints
+
+
+
+ {#if service.endpoints.length === 0}
+
+ No endpoints configured. Click "Add Endpoint" to add one.
+
+ {:else}
+
+ {#each service.endpoints as endpoint, index}
+
+
+
+
Path
+
handleEndpointPathChange(index, e)}
+ placeholder="/api/health"
+ class="w-full px-2 py-1 text-sm bg-gray-700 border border-gray-600 rounded text-white focus:ring-2 focus:ring-blue-500"
+ />
+
+
+
+
+
+
+ {/each}
{/if}
+{:else}
+
+
+
No service selected
+
Select a service from the list to configure it
+
+
{/if}
\ No newline at end of file
diff --git a/src/lib/features/nodes/components/NodeEditModal/Services/ServicesForm.svelte b/src/lib/features/nodes/components/NodeEditModal/Services/ServicesForm.svelte
index 5b5ea041..b754dcea 100644
--- a/src/lib/features/nodes/components/NodeEditModal/Services/ServicesForm.svelte
+++ b/src/lib/features/nodes/components/NodeEditModal/Services/ServicesForm.svelte
@@ -1,183 +1,186 @@
!getCapabilityConfig(selected).system_assigned}
- emptyMessage="No capabilities configured. Add one to get started."
+ allowReorder={true}
+ placeholder="Select service type to add..."
{getOptionId}
{getOptionLabel}
{getOptionDescription}
{getOptionIcon}
{getOptionIconColor}
+ {getOptionTags}
+ {getOptionCategory}
{getItemId}
{getItemLabel}
{getItemDescription}
{getItemIcon}
{getItemIconColor}
+ {getItemTags}
- onAdd={handleAddCapability}
- onChange={handleCapabilityChange}
+ onAdd={handleAddService}
+ onRemove={handleRemoveService}
+ onChange={handleServiceChange}
>
- onChange(updatedCapability)}
+ service={selectedItem}
+ onChange={(updatedService) => onChange(updatedService)}
/>
\ No newline at end of file
diff --git a/src/lib/features/nodes/store.ts b/src/lib/features/nodes/store.ts
index 1a80d612..bbad213a 100644
--- a/src/lib/features/nodes/store.ts
+++ b/src/lib/features/nodes/store.ts
@@ -1,11 +1,9 @@
import { writable } from 'svelte/store';
import type { Node } from "./types/base";
import { api } from '../../shared/utils/api';
-import { createPoller, type Poller } from '../../shared/utils/polling';
import type { NodeTarget } from './types/targets';
-import { pushError, pushInfo, pushWarning } from '$lib/shared/stores/feedback';
+import { pushInfo, pushWarning } from '$lib/shared/stores/feedback';
import { utcTimeZoneSentinel, uuidv4Sentinel } from '$lib/shared/utils/formatting';
-import { testTypes } from '$lib/shared/stores/registry';
export const nodes = writable
([]);
export const polling = writable(false);
@@ -57,14 +55,14 @@ export async function createNode(data: Node) {
interface UpdateNodeResponse {
node: Node,
- capability_test_changes: Record,
+ // capability_test_changes: Record,
subnet_changes: NodeSubnetRelationshipChange
}
-interface NodeCapabilityTestChange {
- newly_compatible: string[],
- incompatible: string[]
-}
+// interface NodeCapabilityTestChange {
+// newly_compatible: string[],
+// incompatible: string[]
+// }
interface NodeSubnetRelationshipChange {
new_gateway: Subnet[],
@@ -80,12 +78,12 @@ export async function updateNode(data: Node) {
(updatedNodeResponse, current) => {
const updatedNode = updatedNodeResponse.node;
- Object.keys(updatedNodeResponse.capability_test_changes).forEach(cap => {
- let incompatible = updatedNodeResponse.capability_test_changes[cap].incompatible.map(i => testTypes.getDisplay(i))
- let newly_compatible = updatedNodeResponse.capability_test_changes[cap].newly_compatible.map(n => testTypes.getDisplay(n))
- incompatible.length > 0 ? pushWarning(`The following tests are no longer compatible with node "${updatedNode.name}" and have been removed: ${incompatible.join(", ")}`) : null
- newly_compatible.length > 0 ? pushInfo(`The following tests are now compatible with node "${updatedNode.name}" and have been added: ${newly_compatible.join(", ")}`) : null
- })
+ // Object.keys(updatedNodeResponse.capability_test_changes).forEach(cap => {
+ // let incompatible = updatedNodeResponse.capability_test_changes[cap].incompatible.map(i => testTypes.getDisplay(i))
+ // let newly_compatible = updatedNodeResponse.capability_test_changes[cap].newly_compatible.map(n => testTypes.getDisplay(n))
+ // incompatible.length > 0 ? pushWarning(`The following tests are no longer compatible with node "${updatedNode.name}" and have been removed: ${incompatible.join(", ")}`) : null
+ // newly_compatible.length > 0 ? pushInfo(`The following tests are now compatible with node "${updatedNode.name}" and have been added: ${newly_compatible.join(", ")}`) : null
+ // })
if (updatedNodeResponse.subnet_changes.new_dns_resolver.length > 0) {
pushInfo(`The following subnets now have node "${updatedNode.name}" set as a DNS resolver: ${
@@ -133,7 +131,6 @@ export function createEmptyNodeFormData(): Node {
created_at: utcTimeZoneSentinel,
updated_at: utcTimeZoneSentinel,
name: '',
- status: 'Unknown',
description: '',
hostname: '',
target: {
@@ -142,14 +139,11 @@ export function createEmptyNodeFormData(): Node {
ip: '',
},
},
- node_type: 'UnknownDevice',
- capabilities: [],
+ services: [],
subnets: [],
- monitoring_interval: 10,
last_seen: utcTimeZoneSentinel,
node_groups: [],
discovery_status: 'Manual',
- dns_resolver_node_id: uuidv4Sentinel
};
}
diff --git a/src/lib/features/nodes/types/base.ts b/src/lib/features/nodes/types/base.ts
index 77e5cfa4..48f109f4 100644
--- a/src/lib/features/nodes/types/base.ts
+++ b/src/lib/features/nodes/types/base.ts
@@ -1,12 +1,6 @@
-import type { Capability } from "$lib/features/capabilities/types/base";
+import type { Service } from "$lib/features/services/types/base";
import type { NodeTarget } from "./targets";
-export interface NodeContext {
- node_id?: string;
- node_type: string;
- capabilities: Capability[];
- target: any;
-}
export interface Node {
id: string;
created_at: string;
@@ -16,15 +10,11 @@ export interface Node {
description: string;
hostname: string;
target: NodeTarget;
- node_type: string;
- capabilities: Capability[];
+ services: Service[];
subnets: NodeSubnetMembership[];
- monitoring_interval: number;
node_groups: string[];
discovery_status: string;
- status: string;
- dns_resolver_node_id: string;
}
export type NodeCapability = {
diff --git a/src/lib/features/services/types/base.ts b/src/lib/features/services/types/base.ts
new file mode 100644
index 00000000..7357d72d
--- /dev/null
+++ b/src/lib/features/services/types/base.ts
@@ -0,0 +1,53 @@
+// Frontend Service interface that matches the backend Service enum with serde(tag = "type")
+
+export interface Port {
+ number: number;
+ udp: boolean;
+ tcp: boolean;
+}
+
+export interface Endpoint {
+ url?: string;
+ method?: string;
+ protocol?: string;
+ ip?: string;
+ port?: Port;
+ path?: string;
+}
+
+export interface Service {
+ // Service type (automatically added by serde tag)
+ type: string;
+
+ // Common fields shared by all service variants
+ confirmed: boolean;
+ name: string;
+ ports: Port[];
+ endpoints: Endpoint[];
+
+ // Optional daemon_id for NetvisorDaemon services
+ daemon_id?: string;
+}
+
+// Helper functions for working with services and the TypeRegistry
+export function createDefaultService(serviceType: string, serviceName?: string, defaultPorts?: Port[], defaultEndpoints?: Endpoint[]): Service {
+ return {
+ type: serviceType,
+ confirmed: false,
+ name: serviceName || serviceType,
+ ports: defaultPorts ? [...defaultPorts] : [],
+ endpoints: defaultEndpoints ? [...defaultEndpoints] : []
+ };
+}
+
+export function getServiceDisplayName(service: Service): string {
+ return service.name || service.type;
+}
+
+export function formatServicePorts(ports: Port[]): string {
+ if (!ports || ports.length === 0) return "No ports";
+
+ return ports.map(p =>
+ `${p.number}${p.tcp && p.udp ? '/tcp+udp' : p.tcp ? '/tcp' : '/udp'}`
+ ).join(', ');
+}
\ No newline at end of file
diff --git a/src/lib/shared/components/data/Tag.svelte b/src/lib/shared/components/data/Tag.svelte
index 9676cc7f..a71fbd89 100644
--- a/src/lib/shared/components/data/Tag.svelte
+++ b/src/lib/shared/components/data/Tag.svelte
@@ -1,13 +1,12 @@
-
-{#if formField}
-
-{/if}
\ No newline at end of file
diff --git a/src/lib/shared/components/forms/JsonContainer.svelte b/src/lib/shared/components/forms/JsonContainer.svelte
deleted file mode 100644
index 9e537d0f..00000000
--- a/src/lib/shared/components/forms/JsonContainer.svelte
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
-
-
- {#if showCopyButton}
-
- {/if}
-
-
-
- {#if isExpanded}
-
-
-
-
-
- {jsonLines} lines • {prettyJson.length} characters
- JSON
-
-
- {/if}
-
\ No newline at end of file
diff --git a/src/lib/shared/components/forms/ListConfigEditor.svelte b/src/lib/shared/components/forms/ListConfigEditor.svelte
index a85333f4..0e41f124 100644
--- a/src/lib/shared/components/forms/ListConfigEditor.svelte
+++ b/src/lib/shared/components/forms/ListConfigEditor.svelte
@@ -33,6 +33,7 @@
export let getOptionIconColor: (option: TOption) => string = () => '';
export let getOptionTags: (option: TOption) => TagProps[] = () => [];
export let getOptionIsDisabled: (option: TOption) => boolean = () => false;
+ export let getOptionCategory: (item: any) => string | null = (item) => null;
// Display functions for items (list)
export let getItemId: (item: TItem) => string;
@@ -134,6 +135,7 @@
getOptionIconColor={getOptionIconColor}
getOptionTags={getOptionTags}
getOptionIsDisabled={getOptionIsDisabled}
+ {getOptionCategory}
getItemId={getItemId}
getItemLabel={getItemLabel}
diff --git a/src/lib/shared/components/forms/ListManager.svelte b/src/lib/shared/components/forms/ListManager.svelte
index 945dac22..f84a3b62 100644
--- a/src/lib/shared/components/forms/ListManager.svelte
+++ b/src/lib/shared/components/forms/ListManager.svelte
@@ -29,6 +29,7 @@
export let getOptionLabel: (item: V) => string | null = (item) => null
export let getOptionDescription: (item: V) => string | null = (item) => null
export let getOptionIsDisabled: (item: V) => boolean = (item) => false
+ export let getOptionCategory: (item: any) => string | null = (item) => null;
// Items
export let items: T[] = [];
@@ -158,6 +159,7 @@
{getOptionDescription}
{getOptionTags}
{getOptionIsDisabled}
+ {getOptionCategory}
/>
diff --git a/src/lib/shared/components/forms/ListSelectItem.svelte b/src/lib/shared/components/forms/ListSelectItem.svelte
index 28978f4e..770e4d76 100644
--- a/src/lib/shared/components/forms/ListSelectItem.svelte
+++ b/src/lib/shared/components/forms/ListSelectItem.svelte
@@ -27,20 +27,22 @@
-
{getLabel(item)}
+
+ {getLabel(item)}
+
+ {#if getTags}
+ {@const tags = getTags(item)}
+ {#each tags as tag}
+
+ {/each}
+ {/if}
+
{#if getDescription}
{getDescription(item)}
{/if}
-
-
- {#if getTags}
- {@const tags = getTags(item)}
- {#each tags as tag}
-
- {/each}
- {/if}
\ No newline at end of file
diff --git a/src/lib/shared/components/forms/RichSelect.svelte b/src/lib/shared/components/forms/RichSelect.svelte
index 00351aa5..9f28bd03 100644
--- a/src/lib/shared/components/forms/RichSelect.svelte
+++ b/src/lib/shared/components/forms/RichSelect.svelte
@@ -20,6 +20,7 @@
export let getOptionLabel: (item: any) => string | null = (item) => null
export let getOptionDescription: (item: any) => string | null = (item) => null
export let getOptionIsDisabled: (item: any) => boolean = (item) => false
+ export let getOptionCategory: (item: any) => string | null = (item) => null;
export let showDescriptionUnderDropdown: boolean = false;
@@ -28,6 +29,32 @@
$: selectedItem = options.find(i => getOptionId(i) === selectedValue);
+ // Group options by category when getOptionCategory is provided
+ $: groupedOptions = (() => {
+ if (!getOptionCategory) {
+ return [{ category: null, options: options }];
+ }
+
+ const groups = new Map
();
+
+ options.forEach(option => {
+ const category = getOptionCategory(option);
+ if (!groups.has(category)) {
+ groups.set(category, []);
+ }
+ groups.get(category)!.push(option);
+ });
+
+ // Sort categories alphabetically, with null category first
+ const sortedEntries = Array.from(groups.entries()).sort(([a], [b]) => {
+ if (a === null) return -1;
+ if (b === null) return 1;
+ return a.localeCompare(b);
+ });
+
+ return sortedEntries.map(([category, options]) => ({ category, options }));
+ })();
+
function handleSelect(value: string) {
try {
const item = options.find(i => getOptionId(i) === value);
@@ -115,28 +142,41 @@
{#if isOpen && !disabled}
- {#each options as option}
-
+ {#each groupedOptions as group, groupIndex}
+
+ {#if group.category !== null}
+
+ {group.category}
+
+ {/if}
+
+
+ {#each group.options as option, optionIndex}
+ {@const isLastInGroup = optionIndex === group.options.length - 1}
+ {@const isLastGroup = groupIndex === groupedOptions.length - 1}
+
+ {/each}
{/each}
{/if}
diff --git a/src/lib/shared/stores/registry.ts b/src/lib/shared/stores/registry.ts
index 8bd5bc12..628bea14 100644
--- a/src/lib/shared/stores/registry.ts
+++ b/src/lib/shared/stores/registry.ts
@@ -14,13 +14,8 @@ export interface TypeMetadata {
}
export interface TypeRegistry {
- test_types: TypeMetadata[];
- node_types: TypeMetadata[];
- capabilities: TypeMetadata[];
- criticality_levels: TypeMetadata[];
- node_statuses: TypeMetadata[];
+ services: TypeMetadata[];
node_targets: TypeMetadata[];
- diagnostic_statuses: TypeMetadata[];
}
export const registry = writable();
@@ -53,6 +48,11 @@ function createRegistryHelpers(category: T) {
const $registry = get(registry);
return $registry?.[category]?.find(item => item.id === id)?.icon || 'help-circle';
},
+
+ getCategory: (id: string | null) => {
+ const $registry = get(registry);
+ return $registry?.[category]?.find(item => item.id === id)?.category || "";
+ },
getColor: (id: string | null): ColorStyle => {
const $registry = get(registry);
@@ -86,13 +86,8 @@ function createRegistryHelpers(category: T) {
}
// Create all the helpers
-export const testTypes = createRegistryHelpers('test_types');
-export const nodeTypes = createRegistryHelpers('node_types');
-export const capabilities = createRegistryHelpers('capabilities');
-export const criticalityLevels = createRegistryHelpers('criticality_levels');
-export const nodeStatuses = createRegistryHelpers('node_statuses');
+export const services = createRegistryHelpers('services');
export const nodeTargets = createRegistryHelpers('node_targets');
-export const diagnosticStatuses = createRegistryHelpers('diagnostic_statuses');
export async function getRegistry() {
const result = await api.request(