mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 08:09:22 +00:00
Co-authored-by: ktx-riya <riya.kukadiya@kiara.tech> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
144 lines
6.1 KiB
Vue
144 lines
6.1 KiB
Vue
<!-- Copyright 2026 OpenObserve Inc.
|
|
|
|
TEMPORARY review page for the empty-state system. Reachable at
|
|
/empty-state-demo. Each card renders a real OEmptyState preset exactly as it
|
|
would appear in the app. Remove this file + its route once approved.
|
|
-->
|
|
<template>
|
|
<div :class="['es-demo-page', { dark: localDark, '[color-scheme:dark]': localDark }]">
|
|
<div class="p-8 flex flex-col gap-8 bg-surface-base min-h-screen">
|
|
<div class="flex items-start justify-between gap-4 flex-wrap">
|
|
<div>
|
|
<h1 class="text-2xl font-semibold text-text-primary">
|
|
Empty states — full set for review
|
|
</h1>
|
|
<p class="text-sm text-text-secondary mt-1 max-w-2xl">
|
|
Every preset below is a real
|
|
<code class="text-text-primary"><OEmptyState></code> with its
|
|
production copy, illustration, and action. Each detailed scene has its
|
|
own character micro-animation and pauses under OS "reduce motion".
|
|
Nothing is wired into real pages yet.
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<OButton
|
|
variant="outline"
|
|
size="sm"
|
|
icon-left="filter-list"
|
|
@click="filteredPreview = !filteredPreview"
|
|
>
|
|
{{ filteredPreview ? "First-run state" : "Filtered state" }}
|
|
</OButton>
|
|
<OButton variant="outline" size="sm" icon-left="dark-mode" @click="localDark = !localDark">
|
|
{{ localDark ? "Light preview" : "Dark preview" }}
|
|
</OButton>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 xl:grid-cols-2 gap-6">
|
|
<section v-for="p in presets" :key="p.preset" class="flex flex-col gap-2">
|
|
<div class="flex items-baseline gap-2">
|
|
<span class="text-xs font-semibold uppercase tracking-wider text-text-secondary">
|
|
{{ p.label }}
|
|
</span>
|
|
<code class="text-[0.7rem] text-text-disabled">preset="{{ p.preset }}"</code>
|
|
</div>
|
|
<div class="rounded-xl border border-border-default h-110 overflow-hidden">
|
|
<OEmptyState
|
|
:preset="p.preset"
|
|
size="hero"
|
|
:filtered="filteredPreview"
|
|
@action="onAction(p.preset)"
|
|
@secondary-action="onAction(p.preset + ':secondary')"
|
|
/>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div>
|
|
<h2 class="text-lg font-semibold text-text-primary mb-1">
|
|
Character — optional, only where it adds value
|
|
</h2>
|
|
<p class="text-sm text-text-secondary mb-3 max-w-2xl">
|
|
The illustration is just a named choice, so a scene can opt into a
|
|
character (e.g. a prominent first-run hero) while everything else stays
|
|
object-only. Same component, <code class="text-text-primary">illustration="explorer"</code>.
|
|
</p>
|
|
<div class="rounded-xl border border-border-default h-110 overflow-hidden">
|
|
<OEmptyState
|
|
size="hero"
|
|
variant="create"
|
|
illustration="explorer"
|
|
title="We couldn't find any data"
|
|
description="Nothing matches yet — try a different stream, widen the time range, or create something new."
|
|
action-label="Clear filters"
|
|
action-icon="filter-list"
|
|
@action="onAction('explorer')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h2 class="text-lg font-semibold text-text-primary mb-3">
|
|
Sizes — the same system at block & inline scale
|
|
</h2>
|
|
<div class="grid grid-cols-1 xl:grid-cols-2 gap-6">
|
|
<section class="flex flex-col gap-2">
|
|
<span class="text-xs font-semibold uppercase tracking-wider text-text-secondary">
|
|
size="block" (inside a card / dashboard panel)
|
|
</span>
|
|
<div class="rounded-xl border border-border-default overflow-hidden">
|
|
<OEmptyState preset="no-search-results" size="block" @action="onAction('block')" />
|
|
</div>
|
|
</section>
|
|
<section class="flex flex-col gap-2">
|
|
<span class="text-xs font-semibold uppercase tracking-wider text-text-secondary">
|
|
size="inline" (table body / dropdown)
|
|
</span>
|
|
<div class="rounded-xl border border-border-default overflow-hidden">
|
|
<OEmptyState preset="no-search-results" size="inline" @action="onAction('inline')" />
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from "vue";
|
|
|
|
import { OEmptyState, type EmptyStatePresetName } from "@/lib/core/EmptyState";
|
|
import OButton from "@/lib/core/Button/OButton.vue";
|
|
|
|
// local dark-mode preview wrapper so reviewers can flip themes without changing
|
|
// their global setting (mirrors the app's `.dark` class on a scoped root).
|
|
const localDark = ref(false);
|
|
// toggles the filtered/search "no results" state for every preset below
|
|
const filteredPreview = ref(false);
|
|
|
|
const presets: { preset: EmptyStatePresetName; label: string }[] = [
|
|
{ preset: "no-search-results", label: "No search results" },
|
|
{ preset: "no-logs", label: "No logs in range" },
|
|
{ preset: "no-dashboards", label: "No dashboards (first run)" },
|
|
{ preset: "no-pipelines", label: "No pipelines (first run)" },
|
|
{ preset: "no-functions", label: "No functions (first run)" },
|
|
{ preset: "no-streams", label: "No data ingested" },
|
|
{ preset: "no-alerts", label: "No alerts (create / define)" },
|
|
{ preset: "no-incidents", label: "No incidents (all caught up)" },
|
|
{ preset: "load-error", label: "Failed to load" },
|
|
{ preset: "no-data", label: "Generic — no data (NoData fallback)" },
|
|
{ preset: "no-traces", label: "No traces" },
|
|
{ preset: "no-search-history", label: "No search history" },
|
|
{ preset: "no-users", label: "No users" },
|
|
{ preset: "no-reports", label: "No reports" },
|
|
{ preset: "no-queries", label: "No running queries" },
|
|
{ preset: "no-service-accounts", label: "No service accounts" },
|
|
{ preset: "no-invitations", label: "No invitations" },
|
|
];
|
|
|
|
const onAction = (which: string) => {
|
|
|
|
};
|
|
</script>
|