Restructure UX and seed a fully simulated organisation
Rework the dashboard, environment topology view, header navigation, and status rendering, and standardise selects on a shadcn-vue component. Replace the thin database seeder with a SimulatedEnvironmentSeeder that builds a fully wired, mostly-running organisation (ACTIVE server fleet, managed + GHCR registries, Gitea source provider, ClipBin app with production/staging environments, services, slices, endpoints, managed variables, build artifacts, and a completed/in-progress/failed operations history) so the new UI renders against realistic data.
This commit is contained in:
91
resources/js/components/StatusIndicator.vue
Normal file
91
resources/js/components/StatusIndicator.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
status?: string | null;
|
||||
label?: string;
|
||||
size?: "sm" | "md";
|
||||
}>(),
|
||||
{
|
||||
status: "unknown",
|
||||
size: "sm",
|
||||
},
|
||||
);
|
||||
|
||||
type Tone = "positive" | "negative" | "pending" | "neutral";
|
||||
|
||||
const tones: Record<string, Tone> = {
|
||||
active: "positive",
|
||||
running: "positive",
|
||||
succeeded: "positive",
|
||||
success: "positive",
|
||||
completed: "positive",
|
||||
ready: "positive",
|
||||
verified: "positive",
|
||||
enabled: "positive",
|
||||
healthy: "positive",
|
||||
stopped: "negative",
|
||||
failed: "negative",
|
||||
error: "negative",
|
||||
errored: "negative",
|
||||
unhealthy: "negative",
|
||||
cancelled: "negative",
|
||||
installing: "pending",
|
||||
pending: "pending",
|
||||
"in-progress": "pending",
|
||||
building: "pending",
|
||||
planning: "pending",
|
||||
deploying: "pending",
|
||||
provisioning: "pending",
|
||||
queued: "pending",
|
||||
};
|
||||
|
||||
const normalised = computed(() => (props.status ?? "unknown").toString().toLowerCase().trim());
|
||||
|
||||
const tone = computed<Tone>(() => tones[normalised.value] ?? "neutral");
|
||||
|
||||
const label = computed(
|
||||
() =>
|
||||
props.label ??
|
||||
(props.status ?? "unknown").toString().replaceAll("-", " ").replaceAll("_", " "),
|
||||
);
|
||||
|
||||
const dotClasses = computed(() => {
|
||||
switch (tone.value) {
|
||||
case "positive":
|
||||
return "bg-green-500";
|
||||
case "negative":
|
||||
return "bg-red-500";
|
||||
case "pending":
|
||||
return "bg-amber-500 animate-pulse";
|
||||
default:
|
||||
return "bg-zinc-400 dark:bg-zinc-500";
|
||||
}
|
||||
});
|
||||
|
||||
const textClasses = computed(() => {
|
||||
switch (tone.value) {
|
||||
case "positive":
|
||||
return "text-green-700 dark:text-green-400";
|
||||
case "negative":
|
||||
return "text-red-700 dark:text-red-400";
|
||||
case "pending":
|
||||
return "text-amber-700 dark:text-amber-400";
|
||||
default:
|
||||
return "text-muted-foreground";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="inline-flex items-center gap-1.5">
|
||||
<span
|
||||
class="inline-block rounded-full"
|
||||
:class="[dotClasses, size === 'md' ? 'size-2' : 'size-1.5']"
|
||||
/>
|
||||
<span class="capitalize" :class="[textClasses, size === 'md' ? 'text-sm' : 'text-xs']">{{
|
||||
label
|
||||
}}</span>
|
||||
</span>
|
||||
</template>
|
||||
Reference in New Issue
Block a user