Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,21 @@ describe('HealthDetails', () => {
exists: true,
},
},
diskSpace2: {
status: 'UP',
details: {
total: 1024,
free: 2048,
threshold: 4096,
exists: false,
},
},
},
};

render(HealthDetails, {
props: {
name: 'Name',
health: healthMock,
},
});
Expand All @@ -67,6 +77,34 @@ describe('HealthDetails', () => {
).toHaveTextContent(status);
},
);

it('should format diskSpace details correctly', async () => {
const diskSpaceInfo = await screen.findByRole('definition', {
name: 'diskSpace2',
});

// Assert pretty-printed numbers via pretty-bytes and other primitive values
const dsi = within(diskSpaceInfo);
// total: 994662584320 bytes -> 995 GB (rounded)
expect(
await dsi.findByRole('definition', { name: 'total' }),
).toHaveTextContent('1.02 kB');

// free: 300063879168 bytes -> 300 GB (rounded)
expect(
await dsi.findByRole('definition', { name: 'free' }),
).toHaveTextContent('2.05 kB');

// threshold: 10485760 bytes -> 10 MB
expect(
await dsi.findByRole('definition', { name: 'threshold' }),
).toHaveTextContent('4.1 kB');

// exists: boolean unchanged
expect(
await dsi.findByRole('definition', { name: 'exists' }),
).toHaveTextContent('false');
});
});

describe('Health .components', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,42 @@
class="px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
:class="{ 'bg-white': index % 2 === 0, 'bg-gray-50': index % 2 !== 0 }"
>
<dt
:id="'health-detail__' + name"
class="text-sm font-medium text-gray-500"
>
<dt :id="`health-${id}__${name}`" class="text-sm font-medium text-gray-500">
{{ name }}
</dt>
<dd
class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2"
:aria-labelledby="'health-detail__' + name"
:aria-labelledby="`health-${id}__` + name"
>
<sba-status-badge v-if="health.status" :status="health.status" />

<dl v-if="details && details.length > 0" class="grid grid-cols-2 mt-2">
<template v-for="detail in details" :key="detail.name">
<dt class="font-medium" v-text="detail.name" />
<dt
class="font-medium"
:id="`health-detail-${id}__${detail.name}`"
v-text="detail.name"
/>
<dd
v-if="name === 'diskSpace' && typeof detail.value === 'number'"
v-if="
name.toLowerCase().startsWith('diskspace') &&
typeof detail.value === 'number'
"
:aria-labelledby="`health-detail-${id}__${detail.name}`"
v-text="prettyBytes(detail.value)"
/>
<dd v-else-if="typeof detail.value === 'object'">
<dd
v-else-if="typeof detail.value === 'object'"
:aria-labelledby="`health-detail-${id}__${detail.name}`"
>
<pre
class="break-words whitespace-pre-wrap"
v-text="toJson(detail.value)"
v-text="JSON.stringify(detail.value)"
/>
</dd>
<dd
v-else
:aria-labelledby="`health-detail-${id}__${detail.name}`"
class="break-words whitespace-pre-wrap"
v-text="detail.value"
/>
Expand All @@ -63,52 +72,41 @@
/>
</template>

<script>
<script lang="ts" setup>
import prettyBytes from 'pretty-bytes';
import { computed, useId } from 'vue';

const id = useId();

const isChildHealth = (value) => {
return value !== null && typeof value === 'object' && 'status' in value;
};

export default {
name: 'HealthDetails',
props: {
name: {
type: String,
required: true,
},
health: {
type: Object,
required: true,
},
index: {
type: Number,
default: 0,
},
},
computed: {
details() {
if (this.health.details || this.health.components) {
return Object.entries(this.health.details || this.health.components)
.filter(([, value]) => !isChildHealth(value))
.map(([name, value]) => ({ name, value }));
}
return [];
},
childHealth() {
if (this.health.details || this.health.components) {
return Object.entries(this.health.details || this.health.components)
.filter(([, value]) => isChildHealth(value))
.map(([name, value]) => ({ name, value }));
}
return [];
},
},
methods: {
prettyBytes,
toJson(obj) {
return JSON.stringify(obj, null, 2);
},
},
};
const {
health,
name,
index = 0,
} = defineProps<{
name: string;
health: Record<string, any>;
index?: number;
}>();

const details = computed(() => {
if (health.details || health.components) {
return Object.entries(health.details || health.components)
.filter(([, value]) => !isChildHealth(value))
.map(([name, value]) => ({ name, value }));
}
return [];
});

const childHealth = computed(() => {
if (health.details || health.components) {
return Object.entries(health.details || health.components)
.filter(([, value]) => isChildHealth(value))
.map(([name, value]) => ({ name, value }));
}
return [];
});
</script>