48 Commits
Author SHA1 Message Date
Tosone b6effe29ef build(deps): bump aws-sdk, x/net and web dependencies
Update the AWS S3 storage dependency chain, golang.org/x/net and the
web frontend routing/icon packages to their latest patch releases,
picking up the upstream bug fixes for the S3 client used by the storage
backend, the HTTP/2 stack, and the router/icon bundles shipped in the
web UI.

Go direct upgrades:
- github.com/aws/aws-sdk-go-v2 v1.47.4 -> v1.47.5
- github.com/aws/aws-sdk-go-v2/config v1.33.11 -> v1.33.12
- github.com/aws/aws-sdk-go-v2/service/s3 v1.114.5 -> v1.114.6
- github.com/aws/smithy-go v1.28.6 -> v1.28.7
- golang.org/x/net v0.61.0 -> v0.62.0

Go transitive bumps pulled in by the SDK release:
- aws-sdk-go-v2/credentials v1.20.11 -> v1.20.12
- aws-sdk-go-v2/feature/ec2/imds v1.20.4 -> v1.20.5
- aws-sdk-go-v2/aws/protocol/eventstream v1.7.24 -> v1.7.25
- aws-sdk-go-v2/internal/configsources v1.5.7 -> v1.5.8
- aws-sdk-go-v2/internal/endpoints/v2 v2.8.7 -> v2.8.8
- aws-sdk-go-v2/internal/v4a v1.5.7 -> v1.5.8
- aws-sdk-go-v2/service/internal/accept-encoding v1.13.22 -> v1.13.23
- aws-sdk-go-v2/service/internal/checksum v1.11.8 -> v1.11.9
- aws-sdk-go-v2/service/internal/presigned-url v1.14.7 -> v1.14.8
- aws-sdk-go-v2/service/internal/s3shared v1.20.7 -> v1.20.8
- aws-sdk-go-v2/service/signin v1.11.0 -> v1.12.0
- aws-sdk-go-v2/service/sso v1.38.5 -> v1.39.0
- aws-sdk-go-v2/service/ssooidc v1.43.5 -> v1.44.0
- aws-sdk-go-v2/service/sts v1.51.5 -> v1.51.6

Web upgrades:
- lucide-react ^1.62.0 -> ^1.63.0
- react-router-dom ^7.18.4 -> ^7.18.5

Verification:
- go mod tidy
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go vet -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- bun run lint (web)
- bun run build (web)
2026-10-28 17:02:46 +08:00
Tosone 3a21e24d1a feat(web): show the run log in a dialog with a stop action
View log navigated away to a separate log page. Open the log of the run in a
dialog next to the run list instead, with Stop (for a running build) and Close
at the bottom. The tag cell and the action menu both open the dialog, Rerun now
refreshes the list instead of following the new run, and the terminal lives in
a reusable component that refits itself when the dialog is resized.

Verification:
- bun run build
- bun run lint
- Opened a finished run in a headless browser: the dialog shows the stored log
  and only Close.
- Opened a running run: the log streams, the footer has Stop, and clicking it
  disables the button.
2026-10-28 16:48:43 +08:00
Tosone 3b28beb913 fix(web): type builder runner ids as strings
The builder runner API returns UUID strings for the runner and builder ids, but
the interfaces declared them as numbers and the duration chart sample followed.

Verification:
- bun run build
- bun run lint
2026-10-28 16:48:39 +08:00
Tosone fe54c8f4a6 fix(web): wrap long runner status messages without growing the page
The status message tooltip was a single nowrap line, so long build errors
spread far beyond the table. It was also absolutely positioned without
offsets, so its hidden box escaped the scroll container and extended the
document height, which pushed the run list pagination away from the bottom of
the window.

Give it a max width, allow wrapping and break long tokens, and position it
fixed so the hidden element stays out of the scrollable overflow.

Verification:
- bun run build
- bun run lint
- Opened the v0.1 error in a headless browser: the message wraps to 6 lines
  within 448px; with a 500px tall viewport the document no longer scrolls and
  the pagination stays at the bottom.
2026-10-28 16:16:01 +08:00
Tosone 8b316363c1 feat(web): start builds from the dialog and add a run actions menu
Creating a build followed the new run's log page, which threw away the overview
the user came from. Close the dialog and refresh the run list instead, so the
new run shows up in place.

Replace the plain Rerun/Stop action text with a dropdown offering the run log
and, depending on the status, Rerun or Stop.

Verification:
- bun run build
- bun run lint
- Clicked Build then Create in a headless browser: the dialog closes, the URL
  stays the same and the list refreshes; the action menu lists View log and
  Rerun for a finished run.
2026-10-28 16:15:55 +08:00
Tosone 6258800bb6 feat(web): confirm tag copies inside the tag card
Clicking the tag name or the image reference showed a floating "Copied"
tooltip above the trigger, which was hard to read and wide. Show the
confirmation where the copy happened instead: next to the tag name, or inside
the image reference block on its right side, for 1.6 seconds.

The reference block now shows just the image reference (no docker pull/helm
pull verb) and uses a narrower width. The page level tooltip element and its
ids are gone.

Verification:
- bun run build
- bun run lint
- Clicked both copy targets in a headless browser: the inline "Copied" marker
  appears and disappears while the page keeps the same URL.
2026-10-28 16:15:48 +08:00
Tosone 20fe7fa4b0 fix(web): tolerate artifacts without config or sbom on the tag list
The tag list parsed config_raw, sbom and vulnerability results with JSON.parse
without guarding the empty strings the API returns for artifacts that carry no
config (raw blobs, for example), which crashed the page with "Unexpected end of
JSON input". It also passed an undefined distro name into the distro helpers,
which called trim() on it.

Parse the encoded artifact fields through a helper that falls back on empty or
invalid JSON, guard the manifest fields read by skipManifest, tolerate a null
artifact list, and make the distro helpers return an empty name instead of
throwing.

Verification:
- bun run build
- bun run lint
- Opened the affected tag list in a headless browser: the row renders with "-"
  for OS/ARCH and 0 C/H/M/L instead of crashing.
2026-10-28 16:15:43 +08:00
Tosone bf467f299e fix(web): match the build dialog inputs to the design system
The build dialog used hand written inputs and textarea with legacy styles and
swapped error classes plus an inline icon for validation. Use the shared
Input, Textarea and Label components and drive the error state with
aria-invalid, so the dialog follows the same look as the rest of the forms.

Verification:
- bun run build
- bun run lint
- Opened the dialog in a headless browser and checked the invalid state.
2026-10-28 15:05:52 +08:00
Tosone dfb808f38a feat(web): explain the cron expression and tag template fields
Add an info tooltip to the cron expression and the OCI tag template field:
the first documents the five-field cron format and the time zone it is
evaluated in, the second lists the Go template variable and the sprig helpers
the builder renders it with. Both inputs use the shared Input component now.

Verification:
- bun run build
- bun run lint
2026-10-28 15:05:49 +08:00
Tosone d6b9909a28 feat(web): search and sort the builder code repository picker
The picker only offered the first page of repositories sorted by name. Turn
it into a searchable popover that queries the provider list endpoint with the
typed name, so repositories past the first page stay reachable, and ask for
the most recently pushed repository first. The repository and branch pickers
now take half a row each, below the provider and organization.

Verification:
- bun run build
- bun run lint
- Opened the builder page and confirmed the picker filters while typing.
2026-10-28 15:05:44 +08:00
Tosone 4bb14f69ae feat(web): only accept access tokens as source code credentials
Listing code repositories goes through the provider API and only a token
credential can authenticate those calls, so the source code credential dialog
no longer offers SSH keys or username and password. Drop the credential type
select, the fields it switched between, and the translations they needed.

Verification:
- bun run build
- bun run lint
2026-10-28 15:05:37 +08:00
Tosone fb8667ca2a fix(web): only highlight the hovered command item
cmdk always renders data-selected (true or false) on its items, while the
data-selected variant is an attribute presence selector, so every command
item matched the highlight styles. Use the exact-value variant so only the
hovered or keyboard selected item is highlighted.

Verification:
- bun run build
- bun run lint
2026-10-28 15:05:31 +08:00
Tosone 42600b95f5 feat(web): chart the build duration of a repository builder
Show how long the recent builds took above the run list: the chart reads the
last 100 runs of the builder, plots the elapsed time of the finished ones and
marks the latest duration in the header. It is drawn as plain svg so no chart
dependency is needed, and hovering a point shows the tag, the duration and
the time of that build.

Verification:
- bunx tsc --noEmit
- bun run lint
- bun run build
2026-10-28 11:09:38 +08:00
Tosone 14a7952ea6 fix(web): stop the builder page from rewriting its URL on back
The page listened to popstate and called navigate(backTo) with an empty
`back_to`, and react-router resolves an empty path to the current pathname
with an empty search, pushing a new entry. Pressing back therefore stayed on
the builder page and dropped every query parameter. The mount effect that
re-pushed the current query had the same problem: it added a duplicate
history entry.

Drop both; `back_to` is still used by the Cancel button, and the browser back
button now undoes the navigation that opened the page.

Verification:
- bunx tsc --noEmit
- bun run lint
- bun run build
2026-10-28 11:09:38 +08:00
Tosone e5032fb087 feat(web): merge the builder and runs tabs of a repository
A repository exposed two tabs that only differed by whether a builder was
configured: "Builder" opened the setup form and "Runs" opened the build
list. Merge them into one "Builder" tab: it shows the setup form while the
repository has no builder and the run list once a builder exists.

- add RepositoryTabs, the tab bar shared by the repository pages
- add pages/Builder/index.tsx, which picks the setup form or the run list
  from the repository builder and swaps to the run list after a save
- render the setup form inside the repository chrome when embedded
- point the configure/update/back links at the merged route and keep
  /repository/runners as an alias for existing bookmarks

Verification:
- bunx tsc --noEmit
- bun run lint
- bun run build
2026-10-28 11:09:37 +08:00
Tosone 833597b871 refactor(web): drop the builder shortcut from the namespace menu
The builder belongs to a repository, so the namespace level entry between
the members and the daemon task sections duplicated the repository tab.
Remove the section entry, its daemon gate and the builder specific link,
and stop mapping the builder route to the removed section.

Verification:
- bunx tsc --noEmit
- bun run lint
- bun run build
2026-10-28 11:09:37 +08:00
Tosone 2b47c02f4e refactor(web): import lodash helpers from lodash-es
The web app only uses `size` and `orderBy`, and `lodash` is the CommonJS
build that the bundler cannot tree-shake. Import the helpers by name from
`lodash-es` instead, drop `lodash` and declare `@types/lodash-es` (it was
only reachable through bytemd before).

Verification:
- bunx tsc --noEmit
- bun run lint
- bun run build
2026-10-28 11:09:37 +08:00
Tosone fb4ae986d1 build(deps): bump go and web dependencies
Update Go modules and web packages to their latest available patch and
minor releases.

Go:
- github.com/aws/aws-sdk-go-v2 v1.47.3 -> v1.47.4
- github.com/aws/aws-sdk-go-v2/config v1.33.9 -> v1.33.11
- github.com/aws/aws-sdk-go-v2/service/s3 v1.114.3 -> v1.114.5
- github.com/aws/smithy-go v1.28.5 -> v1.28.6
- github.com/go-redsync/redsync/v4 v4.18.0 -> v4.18.1
- github.com/tencentyun/cos-go-sdk-v5 v0.7.75 -> v0.7.76
- transitive: aws-sdk-go-v2 internals, eventstream, credentials, sso,
  ssooidc, sts and signin

Web:
- @base-ui/react 1.8.0 -> 1.9.0
- @tanstack/react-query 5.104.1 -> 5.105.0
- axios 1.20.0 -> 1.21.0
- cron-parser 5.10.1 -> 5.10.2
- human-format 1.2.1 -> 1.4.0
- lucide-react 1.52.0 -> 1.62.0
- react / react-dom 19.3.0 -> 19.3.1
- shadcn 4.21.3 -> 4.23.0
- zod 4.6.5 -> 4.6.7
- zustand 5.0.15 -> 5.0.16
- @types/node 26.6.4 -> 26.6.5
- autoprefixer 10.6.1 -> 10.6.2
- oxlint 1.87.0 -> 1.90.0
- postcss 8.5.29 -> 8.5.32
- postcss-import 17.0.0 -> 17.0.1
- vite 8.3.3 -> 8.3.5

Verification:
- go mod tidy
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go vet -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- bun run lint
- bun run build
2026-10-27 22:55:34 +08:00
Tosone a1051f53c2 feat(web): show the provider push time in the code repository list
The list offered an Oci Repo Count column nobody acted on, an action column
whose only entry opened the setup builder — reachable from the repository
tabs now — and a timestamp that read as nine hours old because the API sends
UTC wall-clock strings and dayjs parsed them as local time.

- replace the count and action columns with the last update time, rendered
  through RelativeTime so the timezone is handled once
- sort by pushed_at descending and page twenty at a time, with the page size
  as a constant instead of the global settings value
- drop the forced 100rem page width: the app layout already sizes the content
  column, so the pages overflowed it and their justify-between rows pushed
  the actions past the right edge
- give the sync button the same gutter as the namespace page's create button,
  and let the pagination component own its container

Verification:
- cd web && npx tsc --noEmit
- cd web && npx oxlint
- cd web && npx vite build
2026-10-27 22:47:50 +08:00
Tosone 64e4de5702 feat(web): rework the setup builder form
The form mixed three interaction styles: popovers with a cmdk search list,
plain selects and hand-styled inputs. Picking a provider could leave two
options looking highlighted, an empty list opened an empty popup that
rendered as a thin grey line, and several fields had no dark mode support.

Make every picker a Select and calm the form down:

- provider, organization, repository and branch — plus the cron and merge
  branch pickers — are Selects now; the popup is only rendered when there is
  something to choose, and the branch pickers refresh their list when opened
  because branches are no longer synced
- provider options show their display name, an unavailable provider disables
  the organization and repository pickers, and its hint opens the credential
  dialog in place instead of navigating away
- the OCI repository picker lists the repository name without the namespace
  prefix, the way the repository is referred to elsewhere
- the section descriptions move into info tooltips next to the headings
- clone depth uses the shared input, round-trips through
  code_repository_clone_depth, clamps to a non-negative integer and explains
  that 0 clones the full history
- the self-managed repository block uses the shared inputs, keeps the token
  masked and gives the fields room to breathe
- CommandItem gets a pointer cursor, which fixes every cmdk list, and the
  setup page drops the forced 100rem width that pushed it past the viewport

Verification:
- cd web && npx tsc --noEmit
- cd web && npx oxlint
- cd web && npx vite build
2026-10-27 22:47:47 +08:00
Tosone 7039914b3a feat(web): add a builder tab on repository pages and drop duplicate navigation
The repository pages carried their own tab strip, and the sidebar repeated
the same entries under the repository node, so the same navigation existed
in two places and neither was complete: the Setup builder page was only
reachable from the code repository list, which no longer links to it.

- add /namespaces/:namespace/repository/builder rendering the setup builder,
  and turn the repository tabs into Summary | Builder | Runs | Tag list; the
  former "Builder" tab, the runner list, becomes "Runs"
- remove the repository level from the sidebar: its entries are the page
  tabs now, and "Repository list" stays highlighted while browsing into a
  repository
- drop NamespaceTabs, the duplicate header strip on the namespace pages
- resolve entity ids as opaque UUID strings: interface fields are strings
  now and the pages that parsed ids with parseInt stopped truncating them
  (a UUIDv7 starts with "1a1...", so parseInt returned 1)
- add useNamespaceId: a page opened without ?namespace_id — a bookmark or a
  hand written URL — looks the id up from the namespace in the route instead
  of requesting /namespaces/null or /namespaces//
- the tag page: title is Tags, its search box matches the namespace one, and
  it skips the request while the namespace is unresolved

Verification:
- cd web && npx tsc --noEmit
- cd web && npx oxlint
- cd web && npx vite build
2026-10-27 22:47:33 +08:00
Tosone ef9fa992fc fix(web): widen the credential type select so options are not clipped
The credential dialog used a w-fit trigger, so the popup inherited the width
of the currently selected label ("Access token"), and the explicit min-w-0
on the popup removed the 9rem floor that select-content normally keeps. The
longest option, "Username and password", was therefore clipped by the
popup's overflow-x-hidden.

Let the trigger span the dialog and keep the default min width of the popup.

Verification:
- cd web && npx tsc --noEmit
- cd web && npx oxlint
- cd web && npx vite build
2026-10-27 21:30:35 +08:00
Tosone ce7d1c6b6e feat(web): manage code repository credentials from settings
The code repository entry sat next to namespaces even though it holds no
content: it only configures the source builds clone from. Its provider
submenu came from the OAuth2 login flags, so turning OAuth off left an
empty menu entry and a blank page, and there was no way to supply an access
token at all.

- move the entry into the Settings group and drop the provider submenu; the
  providers are now cards on the page, so listing them twice only added a
  third level
- rebuild /coderepos as one card per provider showing the linked account,
  the credential type and the last sync result, with actions to add or
  update a credential, resync, clear it, or open the repository list
- add CredentialDialog for the token, SSH key and username/password types,
  with the OAuth binding offered as an alternative that still needs a token
  for syncing
- read the sync state of /coderepos/{provider} from the providers response
  instead of issuing a second request, and point the builder setup provider
  combobox at the credential settings when nothing is configured
- extend ICodeRepositoryProviderItem with the new fields and add the
  zh-CN/en-US strings

Verification:
- cd web && npx tsc --noEmit
- cd web && npx oxlint
- cd web && npx vite build
2026-10-27 21:07:53 +08:00
Tosone 10269798be refactor(web): migrate legacy accent colors to design tokens
The legacy pages still used scattered Tailwind colors (purple, blue,
indigo) as interactive accents, so the app drifted away from the single
neutral `--primary` accent of the design system. Replace them with tokens:

- purple primary buttons -> bg-primary / text-primary-foreground
- gray secondary buttons -> bg-secondary
- indigo active tabs -> border-primary / text-foreground
- purple and indigo focus rings -> focus:ring-ring
- blue switches -> peer-checked:bg-primary, with the knob switched to
  primary-foreground while checked so it stays visible in dark mode
- blue checkboxes -> accent-primary
- blue links and the Dockerfile editor selection -> text-primary and
  selection:bg-foreground

Verification:
- cd web && npx oxlint
- cd web && bun run build
2026-10-11 09:31:17 +08:00
Tosone 3e4f4c8564 fix(web): use the background token for page shells
The legacy page shells hardcoded `bg-white` without a dark variant, so
the whole page rendered white in dark mode. Use the `bg-background`
token, matching the pages that were already migrated.

Verification:
- cd web && npx oxlint
- cd web && bun run build
2026-10-11 09:31:09 +08:00
Tosone ffe28bb78e refactor(api): rename UserStatus Deactive to Inactive
"Deactive" is not a valid English word; the standard antonym of "Active"
is "Inactive". Restore the enum value, regenerate the go-enum output,
update the CLI test expectation, sync the generated swagger enum and
x-enum-varnames, and fix the web UI request payload and label.

Note: persisted rows and API clients using the old "Deactive" value must
switch to "Inactive"; no data migration is included.

Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go vet -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/api/enums/... ./cmd/cli/...
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/validators/...
2026-10-07 20:56:24 +08:00
Tosone 00735de3b1 feat(web): use Nunito as the primary font
Load Nunito (variable, normal and italic) from Fontsource and put it
first in the `--font-sans` stack, keeping Geist as a fallback so
characters missing from Nunito still render.

Also bump the sidebar `sigma` wordmark from `text-sm` to `text-lg` so
the wordmark reads more clearly next to the 32px logo mark.

Verification:
- bun run lint
- bun run build
2026-10-06 23:28:43 +08:00
Tosone 7c2c45884a build(deps): bump go and web dependencies
Update Go modules and web packages to their latest available versions.

Go:
- github.com/go-git/go-git/v6 v6.0.0-alpha.5 -> v6.0.0-beta.1
- github.com/redis/go-redis/v9 and redisotel v9.22.0 -> v9.23.0
- github.com/tidwall/gjson v1.19.0 -> v1.20.0
- turso.tech/database/tursogo v0.8.1 -> v0.8.2
- transitive: go-billy/v6 beta.1, ProtonMail/go-crypto 1.5.2,
  pjbgf/sha1cd 0.7.0, go.uber.org/atomic 1.12.0

Web:
- @fontsource-variable/nunito 5.3.0 (new)
- @vitejs/plugin-react 5.2.0 -> 6.1.2
- @tanstack/react-query 5.104.0 -> 5.104.1
- cron-parser 4.9.0 -> 5.10.1
- lucide-react 1.49.0 -> 1.52.0
- shadcn 4.21.1 -> 4.21.3
- vite 8.3.2 -> 8.3.3
- oxlint 1.86.0 -> 1.87.0
- postcss 8.5.28 -> 8.5.29
- postcss-import 16.2.0 -> 17.0.0
- postcss-nesting 13.0.2 -> 14.0.3
- @types/node 25.9.9 -> 26.6.4

Adapt to the cron-parser v5 API, where the default `parseExpression`
export was replaced by the named `CronExpressionParser.parse`.

Verification:
- go mod tidy
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go vet -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- bun run lint
- bun run build
2026-10-06 23:28:41 +08:00
Tosone 14df8a87d4 style(web): sort imports into third-party and local groups
Reorder imports across web/src into two blocks separated by a blank line:
third-party packages first, then this repository's @/ and relative modules,
each sorted alphabetically. Document the convention in AGENTS.md.

Verification:
- web: `npx tsc --noEmit`, `npx oxlint`, `npx vite build`
2026-10-04 19:59:27 +08:00
Tosone 4cbddc95ab style(web): organize code repository imports 2026-10-04 16:35:32 +08:00
Tosone 2a61be0cbf fix(web): keep namespace form select popups at trigger width
Drop the shared minimum popup width on the create and update namespace
visibility and size-limit unit selects so each popup matches its trigger.

Verification:
- web: `npx tsc --noEmit`, `npx oxlint`, `npx vite build`
2026-10-04 16:35:32 +08:00
Tosone f4ccd565f6 feat(web): add icons to daemon task actions
Add a SquarePen icon for Update and a Play icon for Run in the four GC
action menus, and tidy the page formatting.

Verification:
- web: `npx tsc --noEmit`, `npx oxlint`, `npx vite build`
2026-10-04 16:35:23 +08:00
Tosone ce781cdff7 feat(web): manage user status and role in settings
- right align the namespace count and status columns, and rename the
  namespace header to "Namespace count"
- render last login and created at with RelativeTime
- replace the inline update button with a centered three-dot menu whose
  Deactive action calls PUT /users/{id} to deactivate the user
- drop the status field from the update dialog, disable the role select
  for the signed in user, and omit role/status when updating self

Verification:
- web: `npx tsc --noEmit`, `npx oxlint`, `npx vite build`
2026-10-04 16:35:17 +08:00
Tosone bbd7308153 fix(web): refine select and dropdown menu interactions
Open select popups below the trigger instead of covering it, show a
pointer cursor on select options, give options more vertical room, and
use a not-allowed cursor for disabled selects and menu items.

Verification:
- web: `npx tsc --noEmit`, `npx oxlint`, `npx vite build`
2026-10-04 16:35:11 +08:00
Tosone b8ef92eba1 feat(web): restructure sidebar menu and polish user list
Rebuild the sidebar menu as a context-driven hierarchy so every
collapsible group has real children:

- add a Home entry and list namespaces under Namespaces, merging the
  former hot-namespace group; the active namespace is always shown and
  expanded even when it is not hot
- nest the namespace sections (summary, repositories, members, daemon
  tasks, webhooks) and the active repository sections (summary, tags,
  builder) under the current branch, using SidebarMenuSub so children
  share a vertical guide line
- expose the enabled code repository providers (github, gitlab) under
  Code Repository and fall back to a plain link when none is enabled
- drive expansion and highlighting from the route only, highlighting the
  selected leaf instead of its container rows
- add a Base UI collapsible primitive, align the sidebar menu metrics
  with the content lists (h-9/text-sm items, h-8 sub items, sidebar-accent
  active state), use a neutral gray for the sidebar text both when idle
  and selected, and drop the unused --sidebar-active token
- add the menu.allNamespaces message

Also polish the settings user list: un-bold the header and username, show
last login and created at with RelativeTime, and replace the inline update
button with a centered three-dot dropdown.

Verification:
- web: `npx tsc --noEmit`
- web: `npx oxlint`
- web: `npx vite build`
2026-10-04 12:03:21 +08:00
Tosone e7df1342b5 refactor(web): modernize namespace page and use @ import alias
Reformat the page, switch relative imports to the @ alias, replace the
inline update/delete buttons with a dropdown row-actions menu, and use
exponentiation for the TiB/GiB/MiB size conversion.

Verification:
- cd web && bunx tsc --noEmit
- cd web && bun run lint
2026-10-03 00:33:57 +08:00
Tosone 95c6006fa1 fix(web): use exponentiation for size unit conversions
JavaScript bitwise shifts operate on 32-bit integers, so `1 << 40` evaluates
to `1 << 8` (256) instead of 1 TiB, corrupting TiB size limits and the
calcUnit TiB branch. Replace the shifts with exponentiation.

Verification:
- cd web && bunx tsc --noEmit
- cd web && bun run lint
2026-10-03 00:27:26 +08:00
Tosone 217cec5829 build(deps): bump go and web dependencies
- Update go.mod/go.sum (grype, syft, aws-sdk-go-v2, distribution,
  gin contrib, validator and others).
- Update web/package.json and web/bun.lock (shikijs, react-router-dom,
  lucide-react, oxlint, esbuild, vite and others).
- Ignore the local `.delta/` directory in .gitignore.
2026-10-02 23:36:56 +08:00
Tosone dbd9601947 refactor(web): unify namespace UI and modernize tables, tabs and dialogs
- Add a shared NamespaceTabs component and use underline tabs across the
  namespace summary, repository, member, daemon task and webhook pages.
- Redesign the pagination footer with theme tokens and a page indicator,
  and give previous/next proper pointer and disabled states.
- Align the daemon task and webhook table headers with the namespace list
  style, drop bold text, and use a muted header color.
- Convert the namespace member list to the shadcn Table component and
  match the search/create toolbar height.
- Modernize the webhook create dialog (Input, Label, Switch, two-column
  events) and unify button and input styles.
- Make the namespace summary markdown editor fill the available height.
- Stay silent on 404/empty responses for the namespace summary, member
  and webhook requests instead of showing an error toast.
- Add standard `appearance` declarations and update deprecated Tailwind
  classes to clear editor warnings.

Verification: bunx tsc --noEmit; bunx oxlint; bun run build (web)
2026-10-02 23:34:29 +08:00
Tosone 3b99c1d305 chore(web): enable react/perf lint rules and resolve every finding
Turn on the react, react-hooks, suspicious and perf rule sets in oxlint and
fix the 2665 diagnostics they report instead of muting the rules:

- validation/limit state is derived during render instead of being synced
  in an effect (namespace/repository/tag limits, size limit + unit,
  username/email/password checks in Menu, Users, Webhook and Member)
- refetch triggers are gone: mutation handlers now call the memoized fetcher
  directly (Namespace list and members, Menu token timer) instead of bumping
  a `refresh` state that only existed to re-run an effect
- data fetchers (fetchNamespace/fetchTags/fetchRepository/fetchWebhook/
  fetchMembers/logout) are memoized with useCallback and their effects use
  correct dependency arrays; the async profile seeding uses an override state
  instead of an effect
- fix 39 shadowed variables (resp/err/*ListData/configData/requestUrl/...),
  use stable list keys instead of array indexes, hoist `cutDigest` to module
  scope and memoize the ToggleGroup context value
- replace the ported HTML5 email pattern with a zod based `isEmail` helper
  (zod 4, `z.email()`), dropping the control-character regex
- use-mobile seeds its state lazily and Shiki derives the highlighted html
  with useMemo

.oxlintrc.json pins the setup: plugins react/typescript/unicorn/oxc,
correctness as error, suspicious/perf as warn, `_`-prefixed names ignored by
no-unused-vars, and react-in-jsx-scope off because the app uses the React 19
automatic JSX runtime (that rule only applies to React < 17).

Verification: web: `bun run lint` (0 warnings, 0 errors, no
oxlint-disable directives left in src); `tsc --noEmit`; `vite build`;
unused-import scan reports 0.
2026-09-17 16:13:02 +08:00
Tosone 8bb35e880b chore(web): clear oxlint warnings and pin its configuration
Fix the diagnostics that oxlint reports on the codebase instead of
silencing the rules:

- unused event parameters (41): `onClick={e => ...}` -> `onClick={() => ...}`
  and `.catch(err => ...)` -> `.catch(() => ...)` where the argument was
  never used
- unused state members: keep only the half that is used
  (`const [sortOrder] = useState(...)`, `const [, setUserObj] = ...`), and
  drop the sort state in CodeRepository/List that was fully unused
- unused props/locals: drop `index` from TableItem/TableItemDropdown (plus
  interface and call sites), `namespace`/`repository` from Tag TableItem,
  two dead `const user = ...` in Login/Callback and the unused `u` URL in
  Webhook/List, along with the imports that became unused (IUserSelf, IOrder)
- one-line effects (10): `useEffect(() => { cond && setX() }, [dep])` ->
  explicit `if (cond) { setX(); }`
- utils/index.ts: keep the HTML5 email pattern as-is with a scoped
  `oxlint-disable-next-line no-control-regex` and a reason

Add .oxlintrc.json to pin the setup: correctness rules are errors,
no-unused-vars ignores `_`-prefixed names, browser/es2024 globals,
dist/node_modules/public ignored. The rule set matches the previous
defaults, so nothing is disabled to hide a warning.

Verification: web: `bun run lint` (0 warnings, 0 errors); `tsc --noEmit`;
`vite build`; unused-import scan reports 0.
2026-09-17 15:40:19 +08:00
Tosone 3ca56e7b67 refactor(web): replace @headlessui/react with shadcn components
Swap every headlessui usage for the shadcn/base-ui components that are
already bundled in the app, then drop the dependency:

- menus (8): Menu/MenuButton/MenuItems/MenuItem + Transition -> DropdownMenu;
  role checks that guarded the original clicks are preserved as
  DropdownMenuItem `disabled`
- dialogs (14): Dialog/DialogPanel/DialogTitle + Transition* -> Dialog,
  DialogContent, DialogTitle, DialogDescription, DialogFooter and Button
- listboxes (6): Listbox -> Select; the multiple-selection one becomes a
  DropdownMenu with DropdownMenuCheckboxItem
- comboboxes (9): Combobox -> Popover + Command, wiring the existing search
  state into CommandInput and keeping shouldFilter={false} for server-side
  search
- remove @headlessui/react from package.json/bun.lock

Also included:
- drop imports that became unused (Table/Button in Builder/RunnerList,
  Separator, useSidebar, dayjs, Link/useParams, Check/ChevronsUpDown and the
  leftover shadcn imports in the webhook pages)
- replace Tailwind v4 arbitrary sizes that have spacing-scale equivalents
  (w-[350px] -> w-87.5, h-[36px] -> h-9, after:top-[2px] -> after:top-0.5, ...);
  h-[18.4px] is intentionally kept since 4.6 is not a multiple of 0.25
- fix the webhook log delete-confirm label (was "Resend")
- add oxlint with `lint` and `lint:fix` scripts

Verification: web: `tsc --noEmit`; `vite build`; `oxlint` (0 errors,
72 pre-existing warnings); scripted scan reports 0 unused imports and no
remaining @headlessui imports.
2026-09-17 15:31:21 +08:00
Tosone 959b2f2ee6 feat(web): polish layout, sidebar, tables and utils
Follow up the shadcn/ui migration with a round of layout and UX fixes:

- layout: unify the horizontal padding of the page header, page toolbars,
  table headers/cells and pagination on `px-4`, so titles, search boxes and
  the first/last table columns share one left/right baseline while the table
  itself stays full width.
- sidebar: stop the SidebarProvider wrapper (`w-full`) from squeezing the
  page content, enlarge the menu rows, lighten the active background through
  a new `--sidebar-active` token, drop the bold active label, and always show
  a pointer cursor for buttons and menu items.
- user menu: fold API docs, theme and language into the bottom dropdown,
  persist username/email on login, callback and token refresh, fall back to
  "sigma" when no username is known, and expose a Login entry for guests.
- tables: replace the row action dropdown with inline update/delete icon
  buttons (delete in red), right align the Action column, only render sort
  arrows for the active sort, keep namespace/repository names readable on
  hover, and render created/updated columns as relative times.
- components: add `RelativeTime` (dayjs relativeTime + tooltip) and the
  `Field`/`FieldLabel` primitives, rebuild the login page on top of them,
  and bump the shared button/input/select/toggle/tabs presets to h-9.
- home: lay the summary cards out in a responsive grid instead of a fixed
  1600px wide row that overflowed the viewport.
- utils: merge the short helper modules into `utils/index.ts` (trimHTTP,
  calcUnit, Regex, Tooltip) and `utils/request.ts` (axios interceptors plus
  token refresh), leaving only index/request/distros.

Verification:
- `npx tsc --noEmit`
- `npx vite build`
2026-09-16 22:41:24 +08:00
Tosone a7c816494a feat(auth): add login rate limit configuration
Add login failure rate limiting with per-username tracking, supporting both delay-based throttling and lockout via configurable backend.
Update all sample configs, Helm templates, and documentation to include the new auth loginRateLimit settings.

Verification:
All config files, Helm charts, and docs are updated to match the new configuration schema.
2026-09-13 15:26:25 +08:00
Tosone d2470bb310 build(deps): bump Go and web dependencies
Update direct and indirect Go module versions, including aws-sdk-go-v2,
goose, ClickHouse, Azure SDK and golang.org/x/exp, and refresh the web
toolchain (react 19.3, vite 8.3, typescript 7, shadcn, tailwind).

Switch the web Vite `@` alias from `__dirname` to `import.meta.dirname`
to align with the ESM config runtime.

Verification: not run (dependency-only change).
2026-09-12 17:16:41 +08:00
Tosone d847d3b27d refactor(web): migrate to shadcn/ui and update tooling stack
Complete migration from legacy React toastify/headlessui to shadcn/ui components, update Tailwind CSS setup, add path aliases, and replace old icon libraries with lucide-react. Also update dependencies to modern versions and clean up unused files and styles.
2026-08-24 11:39:02 +08:00
Tosone c118f1872c chore: upgrade to go 1.27 and update dependencies
Update go version from 1.26 to 1.27 across all workflows, dockerfile, and project configs. Switch uuid usage to stdlib package instead of external google/uuid. Bump traefik, bun, and various golang/x dependencies versions. Clean up unused direct uuid dependency.

Verification:
go test ./pkg/utils/uuid/...
2026-08-20 14:28:59 +08:00
Tosone c4ecfa80d9 chore: initial commit 2026-08-01 20:32:49 +08:00