feat(ui): Design refresh with dark mode, assistant, and global search by nfebe · Pull Request #74 · flatrun/ui · GitHub
Skip to content

feat(ui): Design refresh with dark mode, assistant, and global search#74

Merged
nfebe merged 4 commits into
mainfrom
feat/design-refresh-foundation
Jun 28, 2026
Merged

feat(ui): Design refresh with dark mode, assistant, and global search#74
nfebe merged 4 commits into
mainfrom
feat/design-refresh-foundation

Conversation

@nfebe

@nfebe nfebe commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

A design pass over the panel that clears long-standing UI debt: three competing icon sets, an unused PrimeVue dependency, no dark mode, and actions that ran silently. First of the Albacore UI passes; per-screen polish and modal consolidation come later.

Foundation. A semantic token layer drives a persisted light/dark theme (defaulting to the OS preference), iconography is unified on one offline Iconify set behind an <Icon> wrapper, and the unused PrimeVue dependency is gone. The shell, modals, cards, tables, and swept screens use the tokens, so they follow the theme.

Shell and search. Refreshed sidebar and header with a theme toggle, and a global command palette (Ctrl/Cmd+K) that searches deployments, containers, images, volumes, and networks alongside every page.

Assistant. The header button becomes a floating launcher; the chat moves into a right-hand slide-over with sample prompts, a history view, and file-upload UI. File and log viewers open the assistant inline beside the content, passing what is on screen as context.

Per-action feedback. Single start, stop, restart, and rebuild actions show a spinner on the affected control and toast success or failure, instead of running silently.

Two caveats: file uploads in the chat are UI-only for now, and the history view shows placeholder entries until the persistence API lands. Dark mode covers the shell, shared components, and modals; a few bespoke screens still need their own pass.

nfebe added 4 commits June 28, 2026 23:24
Replace the unused PrimeVue dependency and ad-hoc colours with a semantic
design-token layer that supports a persisted light and dark theme, and
consolidate iconography onto a single offline Iconify set. Existing screens,
modals, and cards were migrated to the tokens so they adapt to the theme.
Refresh the sidebar and header to the new design language with a light and
dark toggle, and add a global command palette reachable with Ctrl or Cmd+K
that searches deployments, containers, images, volumes, and networks as well
as every page.
Replace the header AI button with a floating launcher and move the chat into
a right-hand slide-over with sample prompts, a history view, and file-upload
affordances. File and log viewers can now open the assistant inline beside
the content, passing what is on screen as context.
Single start, stop, restart, and rebuild actions ran silently in the
background. Each now shows a per-action spinner, disables only the affected
control while it runs, and reports success or failure with a toast.
@sourceant

sourceant Bot commented Jun 28, 2026

Copy link
Copy Markdown

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review complete. See the overview comment for a summary.

@@ -0,0 +1,34 @@
import { ref } from "vue";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current state uses a Set<string> which is not reactive in the way Vue expects if you assign to it using busy.value = new Set(...) without careful tracking. While functional here because of complete re-assignment, consider using a reactive(new Set()) or simply an object map Record<string, boolean> for better performance and standard Vue reactivity patterns.

Suggested change
import { ref } from "vue";
import { reactive } from "vue";
import { useNotificationsStore } from "@/stores/notifications";
export function useActionRunner() {
const busy = reactive<Record<string, boolean>>({});
const notifications = useNotificationsStore();
const isBusy = (key: string) => !!busy[key];
async function run(
key: string,
fn: () => Promise<unknown>,
opts: { success?: string; error?: string } = {},
): Promise<void> {
if (busy[key]) return;
busy[key] = true;
try {
await fn();
if (opts.success) notifications.success(opts.success);
} catch (e) {
const detail = e instanceof Error ? e.message : "";
notifications.error(opts.error ?? "Action failed", detail);
} finally {
delete busy[key];
}
}
return { isBusy, run };
}

activeIndex.value = 0;
});

const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check for Mac platforms using navigator.platform is deprecated. While it works for now, it's better to use the modern navigator.userAgentData if available, or check navigator.userAgent as a fallback.

Suggested change
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
const isMac = typeof navigator !== "undefined" && (/Mac|iPhone|iPad/.test(navigator.userAgent) || navigator.platform.includes('Mac'));

const entitiesLoaded = ref(false);
const entitiesLoading = ref(false);

async function loadEntities() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function fetches from multiple APIs concurrently. Since this is called on every focus of the search input, it might create unnecessary load. Consider debouncing the load or implementing a basic TTL cache if the entity list doesn't change frequently.

Suggested change

@nfebe nfebe merged commit 53aa637 into main Jun 28, 2026
5 checks passed
@nfebe nfebe deleted the feat/design-refresh-foundation branch June 28, 2026 22:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant