-
-
Notifications
You must be signed in to change notification settings - Fork 21
feat(apps): per-app versioning + Updates UI surface (#89 P1) #967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ import { TaosAppsSection } from "./TaosAppsSection"; | |
| import { useIsMobile } from "@/hooks/use-is-mobile"; | ||
| import { MobileStore } from "./MobileStore"; | ||
| import { AppIcon, StoreCover } from "./AppIcon"; | ||
| import { getApp } from "@/registry/app-registry"; | ||
| import { StudiosView } from "./StudiosView"; | ||
|
|
||
| /* ------------------------------------------------------------------ | ||
|
|
@@ -841,6 +842,7 @@ export function StoreApp({ windowId: _windowId }: { windowId: string }) { | |
| const [selectedDevices, setSelectedDevices] = useState<string[]>([]); | ||
| const [selectedBackends, setSelectedBackends] = useState<string[]>([]); | ||
| const [compatMap, setCompatMap] = useState<Map<string, ResolveResponse>>(new Map()); | ||
| const [optionalCatalog, setOptionalCatalog] = useState<Array<{ id: string; version: string; installed: boolean; update_available: boolean }>>([]); | ||
|
|
||
| const userId = typeof window !== "undefined" ? window.localStorage.getItem("taos.user.id") || "anon" : "anon"; | ||
| const profileId = typeof window !== "undefined" ? window.localStorage.getItem("taos.profile.id") || "default" : "default"; | ||
|
|
@@ -928,6 +930,7 @@ export function StoreApp({ windowId: _windowId }: { windowId: string }) { | |
| fetchLatestFrameworks().then(setLatest).catch(() => {}); | ||
| fetch("/api/agents").then((r) => r.ok ? r.json() : []).then((j) => setAgentList(Array.isArray(j) ? j : (j?.agents ?? []))).catch(() => {}); | ||
| fetch("/api/cluster/install-targets", { headers: { Accept: "application/json" } }).then((r) => r.ok ? r.json() : null).then((data) => { if (Array.isArray(data)) setInstallTargets(data); }).catch(() => {}); | ||
| fetch("/api/apps/optional/catalog", { headers: { Accept: "application/json" } }).then((r) => r.ok ? r.json() : null).then((data) => { if (data?.apps) setOptionalCatalog(data.apps); }).catch(() => {}); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WARNING: Optional catalog is fetched only on mount Optional app install/remove emits
|
||
| refreshInstalled(); | ||
| }, [refreshInstalled]); | ||
|
|
||
|
|
@@ -1148,16 +1151,40 @@ export function StoreApp({ windowId: _windowId }: { windowId: string }) { | |
| <p className="text-[12px] text-shell-text-tertiary mt-0.5">{filtered.length} apps</p> | ||
| </div> | ||
| </div> | ||
| {activeNav === "updates" && (() => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WARNING: Optional app updates ignore the Updates tab search When
|
||
| const updatableOptional = optionalCatalog.filter((e) => e.installed && e.update_available); | ||
| if (updatableOptional.length === 0) return null; | ||
| return ( | ||
| <div className="mb-4"> | ||
| <h3 className="text-[13px] font-semibold text-shell-text mb-2">taOS Apps</h3> | ||
| <div className="flex flex-col gap-1"> | ||
| {updatableOptional.map((entry) => { | ||
| const meta = getApp(entry.id); | ||
| return ( | ||
| <div key={entry.id} className="flex items-center gap-3 px-3 py-2.5 rounded-xl bg-shell-surface border border-shell-border"> | ||
| <span className="text-[12.5px] font-medium text-shell-text">{meta?.name ?? entry.id}</span> | ||
| <span className="font-mono text-[10px] text-shell-text-tertiary">{entry.version}</span> | ||
| <span className="text-[9px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded bg-shell-surface-active text-shell-text-tertiary border border-shell-border-strong">Core</span> | ||
| <span className="ml-auto text-[11px] text-amber-300/80">Included in next system update</span> | ||
| </div> | ||
| ); | ||
| })} | ||
| </div> | ||
| </div> | ||
| ); | ||
| })()} | ||
| {searching && filtered.length === 0 ? ( | ||
| <div className="flex flex-col items-center justify-center h-40 text-shell-text-tertiary text-sm gap-2"> | ||
| <Package className="w-8 h-8" /> | ||
| <span>No matches for “{search.trim()}”</span> | ||
| </div> | ||
| ) : activeNav === "updates" && filtered.length === 0 ? ( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WARNING: Optional app updates are hidden when normal store updates exist This branch only renders when
|
||
| <div className="flex flex-col items-center justify-center h-40 text-shell-text-tertiary text-sm gap-2"> | ||
| <Package className="w-8 h-8" /> | ||
| <span>You’re all up to date</span> | ||
| </div> | ||
| optionalCatalog.some((e) => e.installed && e.update_available) ? null : ( | ||
| <div className="flex flex-col items-center justify-center h-40 text-shell-text-tertiary text-sm gap-2"> | ||
| <Package className="w-8 h-8" /> | ||
| <span>You’re all up to date</span> | ||
| </div> | ||
| ) | ||
| ) : activeNav === "installed" && filtered.length === 0 ? ( | ||
| <div className="flex flex-col items-center justify-center h-40 text-shell-text-tertiary text-sm gap-2"> | ||
| <Package className="w-8 h-8" /> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SUGGESTION: Backend/frontend optional app metadata can drift
The comment says
getAppcovers every optional app, but that guarantee lives outside this component. If the backend allowlist gains an optional app that is missing from the frontend registry, this will still render raw ids and generic icons viameta?.name ?? entry.id/meta?.icon ?? "package".Consider keeping the backend allowlist and frontend registry synchronized through shared metadata or a startup/config validation check so this fallback is not silently relied on.
Reply with
@kilocode-bot fix itto have Kilo Code address this issue.