Open TrueNAS inline details by default

This commit is contained in:
rcourtman
2026-05-21 16:57:10 +01:00
parent 2e5e54d598
commit 1794a83002
4 changed files with 79 additions and 23 deletions
@@ -20,6 +20,7 @@ interface ResourceDetailDrawerProps {
onClose?: () => void;
presentation?: ResourceDetailDrawerPresentation;
resolveResourceLabel?: (resourceId: string) => string | null | undefined;
initialShowTrueNASDetails?: boolean;
}
const TabAvailabilityNotice: Component<{ message: string }> = (props) => (
@@ -48,6 +49,7 @@ const DrawerContent: Component<ResourceDetailDrawerProps> = (props) => {
resource: props.resource,
presentation: presentation(),
resolveResourceLabel: props.resolveResourceLabel,
initialShowTrueNASDetails: props.initialShowTrueNASDetails,
});
const headingId = () => `resource-detail-drawer-heading-${props.resource.id}`;
@@ -270,6 +272,7 @@ export const ResourceDetailDrawer: Component<ResourceDetailDrawerProps> = (props
onClose={props.onClose}
presentation={props.presentation}
resolveResourceLabel={props.resolveResourceLabel}
initialShowTrueNASDetails={props.initialShowTrueNASDetails}
/>
);
};
@@ -152,6 +152,46 @@ describe('ResourceDetailDrawer TrueNAS details', () => {
expect(section.getByText('/mnt/tank/apps/nextcloud -> /data')).toBeInTheDocument();
});
it('can open native TrueNAS detail immediately for inline platform rows', () => {
const resource = baseResource({
id: 'truenas-app-1',
type: 'app-container',
displayName: 'nextcloud',
truenas: {
app: {
name: 'nextcloud',
state: 'RUNNING',
humanVersion: '29.0.0',
containerCount: 2,
upgradeAvailable: true,
imageUpdatesAvailable: false,
usedPorts: [
{
containerPort: 443,
protocol: 'tcp',
hostPorts: [{ hostIp: '0.0.0.0', hostPort: 30443 }],
},
],
volumes: [{ source: '/mnt/tank/apps/nextcloud', destination: '/data' }],
},
},
});
const { getByRole, getByTestId } = render(() => (
<ResourceDetailDrawer
resource={resource}
presentation="table-row"
initialShowTrueNASDetails
/>
));
expect(getByRole('button', { name: 'Hide TrueNAS' })).toBeInTheDocument();
const section = within(getByTestId('resource-truenas-details-section'));
expect(section.getByText('App')).toBeInTheDocument();
expect(section.getByText('0.0.0.0:30443 -> 443/tcp')).toBeInTheDocument();
expect(section.getByText('/mnt/tank/apps/nextcloud -> /data')).toBeInTheDocument();
});
it('renders native TrueNAS share detail from SMB and NFS inventory', () => {
const resource = baseResource({
id: 'truenas-share-1',
@@ -12,6 +12,7 @@ export interface UseResourceDetailDrawerStateOptions {
resource: Resource;
resolveResourceLabel?: (resourceId: string) => string | null | undefined;
presentation?: ResourceDetailDrawerPresentation;
initialShowTrueNASDetails?: boolean;
}
export const useResourceDetailDrawerState = (options: UseResourceDetailDrawerStateOptions) => {
@@ -27,7 +28,9 @@ export const useResourceDetailDrawerState = (options: UseResourceDetailDrawerSta
const [showHostDetails, setShowHostDetails] = createSignal(false);
const [showServiceDetails, setShowServiceDetails] = createSignal(false);
const [showVMwareDetails, setShowVMwareDetails] = createSignal(false);
const [showTrueNASDetails, setShowTrueNASDetails] = createSignal(false);
const [showTrueNASDetails, setShowTrueNASDetails] = createSignal(
options.initialShowTrueNASDetails === true,
);
const [showPbsJobDetail, setShowPbsJobDetail] = createSignal(false);
const [showPmgMailFlowDetail, setShowPmgMailFlowDetail] = createSignal(false);
const [k8sDeploymentsPrefillNamespace, setK8sDeploymentsPrefillNamespace] = createSignal('');
@@ -63,33 +63,43 @@ export function createPlatformResourceLabelResolver(resources: () => readonly Re
};
}
const hasNativeTrueNASDetails = (resource: Resource): boolean =>
Boolean(resource.truenas?.app || resource.truenas?.share || resource.truenas?.vm);
export const PlatformResourceDetailTableRow: Component<{
resource: Resource;
open: boolean;
detailRowId: string;
colSpan: number;
resolveResourceLabel?: (resourceId: string) => string | null | undefined;
initialShowTrueNASDetails?: boolean;
onClose?: () => void;
}> = (props) => (
<Show when={props.open}>
<TableRow
data-inline-detail-for={props.resource.id}
data-inline-platform-resource-detail-for={props.resource.id}
>
<TableCell
id={props.detailRowId}
colspan={props.colSpan}
class="border-b border-border bg-surface-alt p-0"
}> = (props) => {
const initialShowTrueNASDetails = () =>
props.initialShowTrueNASDetails ?? hasNativeTrueNASDetails(props.resource);
return (
<Show when={props.open}>
<TableRow
data-inline-detail-for={props.resource.id}
data-inline-platform-resource-detail-for={props.resource.id}
>
<div class="px-2 py-3 sm:px-4 sm:py-4" onClick={(event) => event.stopPropagation()}>
<ResourceDetailDrawer
resource={props.resource}
presentation="table-row"
resolveResourceLabel={props.resolveResourceLabel}
onClose={props.onClose}
/>
</div>
</TableCell>
</TableRow>
</Show>
);
<TableCell
id={props.detailRowId}
colspan={props.colSpan}
class="border-b border-border bg-surface-alt p-0"
>
<div class="px-2 py-3 sm:px-4 sm:py-4" onClick={(event) => event.stopPropagation()}>
<ResourceDetailDrawer
resource={props.resource}
presentation="table-row"
resolveResourceLabel={props.resolveResourceLabel}
initialShowTrueNASDetails={initialShowTrueNASDetails()}
onClose={props.onClose}
/>
</div>
</TableCell>
</TableRow>
</Show>
);
};