Switch ProLayout to top layout with a custom horizontal HeaderMenu
(dropdowns for grouped items) and relocate the user/help/version actions
into the header right area.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Footer vendor label unified to "MesaStack" across all locales.
- Remove footer Help button; keep version as plain text (no click).
- Remove top-right GitHub star widget (delete unused github-star.tsx);
keep version as plain text (no click), retain upgrade "New" badge.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Applied via scripts/rebrand across UI labels, page title, and all
locale strings (en/zh/ja/ru/tr). Functional references untouched:
npm package, URLs, paths, JS identifiers, GPUSTACK_ constants, and the
X-GPUStack-Model header. The backend-contract startsWith string in
llmodels/hooks keeps "GPUStack server" to stay matchable. Logo images
intentionally left unchanged for now.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the standalone "GPUStack" brand word with a target brand
(default MesaStack) across user-facing text. Word-boundary + case-
sensitive matching deliberately skips functional references: lowercase
gpustack (npm pkg/URLs/paths/k8s ns), ALL-CAPS GPUSTACK_ constants,
JS identifiers (getGPUStackPlugin etc.), and X-* HTTP headers. A
line-level skip list protects backend-contract strings matched at
runtime (e.g. the model-file-not-found startsWith check).
Re-run on each new v<version>-lofyer branch after syncing upstream.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Describe the upstream->private mirror chain, the v<version>-lofyer branch
naming for appearance customizations, and how to run scripts/sync-github.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fetch all branches and tags from upstream GitHub and force-push them to
the 192.168.0.23 private origin (full mirror). Supports DRY_RUN and an
opt-in PRUNE_BRANCHES for true mirroring.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- breakdown sub-tables now send all active filters (route/user/api_key), matching the trend chart
- summary tab filters the token trend by user and unions user options from both meta APIs (deduped by id)
- stabilize the filters reference so meta load no longer retriggers a second fetch on mount
After build-publish uploads the UI tarball to COS, dispatch a
repository_dispatch event (ui-built) to gpustack/gpustack so the
backend repack picks up the new UI.
Skipped for tag pushes — release tags drive the backend pack via
its own tag trigger. Requires a DISPATCH_PAT secret with
actions:write on gpustack/gpustack.
The Instances-tab Instance Type column passed isCpu ? cpuOnlyLabel : undefined.
For a GPU row with vram but a missing/zero gpu_count, undefined let
renderInstanceType fall back to "CPU Only" (acceleratable=false). Pass
instanceTypeSeriesLabel(row) directly — consistent with the Instance Types
column and robust to that edge. (PR #1245 review)
buildTrendSeries overwrote a (label, bucket) value on collision. Should two
backend groups ever map to the same display label, their values must add up
rather than letting the last write win. Accumulate instead.
Instance Types are grouped by actual shape now, so each row/series is one
concrete type. Label them accordingly via a shared instanceTypeSeriesLabel,
used by both the table column and the trend legend so they read identically:
GPU shows "<product> x <cards>", CPU shows "CPU Only · N vCPU · M GB" (the
instance's real size, not the bare "CPU Only" + hover tooltip). The Instances
tab also uses the per-instance cpu/mem totals, so a 3c6g instance of a 1c2g
flavor reads 3c6g instead of 1c2g. flatten carries cpu_milli/memory_mib/
gpu_count from the breakdown dimensions.
The CreateOrgScopeField slot only renders a "Global" choice when the
host form passes ``allowGlobal: true``. Without it, an admin in the
"All Orgs" view sees only Personal + every org in the dropdown — and
the form's submit injects an ``X-Organization-Id`` header for every
choice, pinning the new key to a tenant. The matching backend change
(api_keys.owner_principal_id nullable) only kicks in when no header
is sent.
Pass ``allowGlobal: true`` (default-selects Global for admin) plus
``globalLabelId: 'scope.global'`` so the dropdown option reads as
plain "Global" — matching the existing tag / column labels for the
same concept elsewhere in the UI, instead of the longer
inference-backend "shared with all organizations" copy.
Relax the ListItem type so ``owner_principal_id`` may be ``null`` —
the OrganizationCell / OwnerScopeTag renderers already render the
"Global" placeholder for null/undefined; the type was the only thing
still claiming the column was always present.
- Add "Dynamic add-item form fields" guidance to CLAUDE.md (pick
component by field schema: LabelSelector / ListInput / MetadataList)
- Fold StatusTag status-display recipe into create-crud-page skill
- Remove DESIGN.md (content migrated to the above)
flattenItem receives the unmapped frontend dimension; the instance-type
grouping is 'gpu_type' (mapped to backend 'instance_type' via GROUP_BY_MAP),
so the previous 'instance_type' check never matched and the trend legend kept
showing the raw flavor slug. Check 'gpu_type'. (PR #1240 review)
The grouped-trend legend used the raw group key, which for instance_type is
the flavor slug (e.g. gpustack--generic-ln-x64-40c-160g--nvidia-a100-80g-4d).
Prefer the enriched product name so the chart legend matches the GPU Instances
list (#5700); falls back to the slug for legacy rows without dimension data.
Trend charts and breakdown exports need the complete date series. The old
perPage=10000 workaround (and the missing page param on the token trend,
which fell back to perPage=20) dropped low-traffic — often most recent —
buckets, leaving gaps in the charts (#5690).
Send page=-1 (the backend's no-pagination sentinel) for the token trend,
the storage/instances trend charts and table exports, the resource export
dialog, and the summary-tab date trends.
The backend now advertises the active external auth provider on
``/auth/config`` as a single ``external_auth: {type, login_url} | null``
field (replacing the per-provider ``is_oidc`` / ``is_saml`` booleans).
This is the API needed to add CAS without per-provider UI conditionals.
Wire the login UI accordingly:
- ``useSSOAuth`` exposes a single ``loginWithExternalAuth()`` action and
``options.external_auth`` carrying the provider info; the OIDC- and
SAML-specific exports are gone.
- ``LoginForm`` renders one SSO button whenever ``external_auth`` is
set, navigating to ``login_url``. New providers (CAS, future LDAP /
Azure AD / …) need zero UI changes — only a backend route.
- ``LocalUserForm`` and ``LoginKit`` type definitions drop the
per-provider booleans.