diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..50a4477 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +postgres +.idea +docker-compose.yml +atlas.hcl +autoglue +config.yaml +.env \ No newline at end of file diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..1e41f3c --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,101 @@ +name: Docker Publish + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +on: + push: + branches: [ "main" ] + # Publish semver tags as releases. + tags: [ 'v*.*.*' ] + pull_request: + branches: [ "main" ] + +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: ${{ github.repository }} + + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + # This is used to complete the identity challenge + # with sigstore/fulcio when running outside of PRs. + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + # Install the cosign tool except on PR + # https://github.com/sigstore/cosign-installer + - name: Install cosign + if: github.event_name != 'pull_request' + uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0 + with: + cosign-release: 'v2.2.4' + + # Set up BuildKit Docker container builder to be able to build + # multi-platform images and export cache + # https://github.com/docker/setup-buildx-action + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=tag + type=ref,event=branch + type=raw,value=latest + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + platforms: linux/amd64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + # Sign the resulting Docker image digest except on PRs. + # This will only write to the public Rekor transparency log when the Docker + # repository is public to avoid leaking data. If you would like to publish + # transparency data even for private images, pass --force to cosign below. + # https://github.com/sigstore/cosign + - name: Sign the published Docker image + if: ${{ github.event_name != 'pull_request' }} + env: + # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + TAGS: ${{ steps.meta.outputs.tags }} + DIGEST: ${{ steps.build-and-push.outputs.digest }} + # This step uses the identity token to provision an ephemeral certificate + # against the sigstore community Fulcio instance. + run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..074673f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +################################# +# Builder: Go + Node in one +################################# +FROM golang:1.25-alpine AS builder + +RUN apk add --no-cache \ + git ca-certificates tzdata \ + build-base \ + nodejs npm + +RUN npm i -g yarn pnpm + +WORKDIR /src + +COPY . . +RUN make swagger && make build + + +################################# +# Runtime +################################# +FROM alpine:3.20 + +RUN apk add --no-cache ca-certificates tzdata \ + && addgroup -S app && adduser -S app -G app + +WORKDIR /app +COPY --from=builder /src/autoglue /app/autoglue + +ENV PORT=8080 +EXPOSE 8080 +USER app + +HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ + CMD wget -qO- "http://127.0.0.1:${PORT}/api/healthz" || exit 1 + +ENTRYPOINT ["/app/autoglue"] \ No newline at end of file diff --git a/autoglue b/autoglue deleted file mode 100755 index c658036..0000000 Binary files a/autoglue and /dev/null differ diff --git a/cmd/cli/serve.go b/cmd/cli/serve.go index f18004c..710c9c6 100644 --- a/cmd/cli/serve.go +++ b/cmd/cli/serve.go @@ -30,8 +30,9 @@ var serveCmd = &cobra.Command{ Long: "Start the server", Run: func(cmd *cobra.Command, args []string) { db.Connect() + gdb := db.DB - jobs, err := bg.NewJobs() + jobs, err := bg.NewJobs(gdb) if err != nil { log.Fatalf("failed to init background jobs: %v", err) } @@ -44,23 +45,27 @@ var serveCmd = &cobra.Command{ }() defer jobs.Stop() - // Enqueue one job immediately - /* - id := uuid.NewString() - if _, err := jobs.Enqueue(context.Background(), id, "bootstrap_bastion", bg.BastionBootstrapArgs{}); err != nil { - log.Fatalf("[enqueue] failed (job_id=%s): %v", id, err) + { + // schedule next 03:30 local time + now := time.Now() + next := time.Date(now.Year(), now.Month(), now.Day(), 3, 30, 0, 0, now.Location()) + if !next.After(now) { + next = next.Add(24 * time.Hour) } - log.Printf("[enqueue] queued (job_id=%s)", id) - // Verify the row exists - if got, err := jobs.Client.Get(context.Background(), id); err != nil { - log.Fatalf("[verify] Get failed (job_id=%s): %v", id, err) - } else if j, ok := got.(*job.Job); ok { - log.Printf("[verify] Get ok (job_id=%s, status=%s)", j.ID, j.Status) - } else { - log.Printf("[verify] Get ok (job_id=%s) but unexpected type %T", id, got) + _, err := jobs.Enqueue( + context.Background(), + uuid.NewString(), + "archer_cleanup", + bg.CleanupArgs{RetainDays: 7, Table: "jobs"}, + archer.WithScheduleTime(next), + archer.WithMaxRetries(1), + ) + if err != nil { + log.Printf("failed to enqueue archer_cleanup: %v", err) } - */ + } + // Periodic scheduler schedCtx, schedCancel := context.WithCancel(context.Background()) defer schedCancel() diff --git a/docker-compose.yml b/docker-compose.yml index b2f5929..0f2b239 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,17 @@ services: - # autoglue: - # image: ghcr.io/glueops/autoglue:latest - # build: - # context: . - # dockerfile: Dockerfile - # ports: - # - 8080:8080 - # expose: - # - 8080 - # env_file: .env - # environment: - # AUTOGLUE_DATABASE_DSN: postgres://autoglue:autoglue@postgres:5432/autoglue - # AUTOGLUE_BIND_ADDRESS: 0.0.0.0 - # depends_on: - # - postgres + autoglue: + # image: ghcr.io/glueops/autoglue:latest + build: . + ports: + - 8080:8080 + expose: + - 8080 + env_file: .env + environment: + AUTOGLUE_DATABASE_DSN: postgres://$DB_USER:$DB_PASSWORD@postgres:5432/$DB_NAME + AUTOGLUE_BIND_ADDRESS: 0.0.0.0 + depends_on: + - postgres postgres: build: diff --git a/docs/docs.go b/docs/docs.go index f1b0e94..075d9ea 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2223,6 +2223,360 @@ const docTemplate = `{ } } }, + "/api/v1/jobs/active": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Currently running jobs (limit default 100)", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Active jobs", + "parameters": [ + { + "type": "integer", + "default": 100, + "description": "Max rows", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/jobs.JobListItem" + } + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/enqueue": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Schedules a job on a queue with optional args/schedule", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Manually enqueue a job", + "parameters": [ + { + "description": "Enqueue request", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/jobs.EnqueueReq" + } + } + ], + "responses": { + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/jobs.EnqueueResp" + } + }, + "400": { + "description": "bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/failures": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Failed jobs ordered by most recent (limit default 100)", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Recent failures", + "parameters": [ + { + "type": "integer", + "default": 100, + "description": "Max rows", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/jobs.JobListItem" + } + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/kpi": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Aggregated counters across all queues", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Jobs KPI", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/jobs.KPI" + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/queues": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Counts and avg duration per queue (last 24h)", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Per-queue rollups", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/jobs.QueueRollup" + } + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/{id}/cancel": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Cancels running or scheduled jobs", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Cancel a job", + "parameters": [ + { + "type": "string", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "no content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "404": { + "description": "not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/{id}/retry": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Calls Archer ScheduleNow on the job id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Retry a job immediately", + "parameters": [ + { + "type": "string", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "no content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "404": { + "description": "not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, "/api/v1/labels": { "get": { "security": [ @@ -6335,6 +6689,110 @@ const docTemplate = `{ } } }, + "jobs.EnqueueReq": { + "type": "object" + }, + "jobs.EnqueueResp": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "jobs.JobListItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "last_error": { + "type": "string" + }, + "max_retry": { + "type": "integer" + }, + "queue_name": { + "type": "string" + }, + "retry_count": { + "type": "integer" + }, + "scheduled_at": { + "type": "string" + }, + "started_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "jobs.KPI": { + "type": "object", + "properties": { + "dueNow": { + "type": "integer", + "format": "int64" + }, + "failed24h": { + "type": "integer", + "format": "int64" + }, + "retryable": { + "type": "integer", + "format": "int64" + }, + "runningNow": { + "type": "integer", + "format": "int64" + }, + "scheduledFuture": { + "type": "integer", + "format": "int64" + }, + "succeeded24h": { + "type": "integer", + "format": "int64" + } + } + }, + "jobs.QueueRollup": { + "type": "object", + "properties": { + "avgDurationSecs": { + "type": "number", + "format": "float64" + }, + "failed24h": { + "type": "integer", + "format": "int64" + }, + "queueName": { + "type": "string" + }, + "queuedDue": { + "type": "integer", + "format": "int64" + }, + "queuedFuture": { + "type": "integer", + "format": "int64" + }, + "running": { + "type": "integer", + "format": "int64" + }, + "success24h": { + "type": "integer", + "format": "int64" + } + } + }, "labels.addLabelToPoolRequest": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 52006d2..e259f76 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2219,6 +2219,360 @@ } } }, + "/api/v1/jobs/active": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Currently running jobs (limit default 100)", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Active jobs", + "parameters": [ + { + "type": "integer", + "default": 100, + "description": "Max rows", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/jobs.JobListItem" + } + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/enqueue": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Schedules a job on a queue with optional args/schedule", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Manually enqueue a job", + "parameters": [ + { + "description": "Enqueue request", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/jobs.EnqueueReq" + } + } + ], + "responses": { + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/jobs.EnqueueResp" + } + }, + "400": { + "description": "bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/failures": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Failed jobs ordered by most recent (limit default 100)", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Recent failures", + "parameters": [ + { + "type": "integer", + "default": 100, + "description": "Max rows", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/jobs.JobListItem" + } + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/kpi": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Aggregated counters across all queues", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Jobs KPI", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/jobs.KPI" + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/queues": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Counts and avg duration per queue (last 24h)", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Per-queue rollups", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/jobs.QueueRollup" + } + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/{id}/cancel": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Cancels running or scheduled jobs", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Cancel a job", + "parameters": [ + { + "type": "string", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "no content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "404": { + "description": "not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v1/jobs/{id}/retry": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Calls Archer ScheduleNow on the job id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Retry a job immediately", + "parameters": [ + { + "type": "string", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "no content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "bad request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "unauthorized", + "schema": { + "type": "string" + } + }, + "404": { + "description": "not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "internal error", + "schema": { + "type": "string" + } + } + } + } + }, "/api/v1/labels": { "get": { "security": [ @@ -6331,6 +6685,110 @@ } } }, + "jobs.EnqueueReq": { + "type": "object" + }, + "jobs.EnqueueResp": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "jobs.JobListItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "last_error": { + "type": "string" + }, + "max_retry": { + "type": "integer" + }, + "queue_name": { + "type": "string" + }, + "retry_count": { + "type": "integer" + }, + "scheduled_at": { + "type": "string" + }, + "started_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "jobs.KPI": { + "type": "object", + "properties": { + "dueNow": { + "type": "integer", + "format": "int64" + }, + "failed24h": { + "type": "integer", + "format": "int64" + }, + "retryable": { + "type": "integer", + "format": "int64" + }, + "runningNow": { + "type": "integer", + "format": "int64" + }, + "scheduledFuture": { + "type": "integer", + "format": "int64" + }, + "succeeded24h": { + "type": "integer", + "format": "int64" + } + } + }, + "jobs.QueueRollup": { + "type": "object", + "properties": { + "avgDurationSecs": { + "type": "number", + "format": "float64" + }, + "failed24h": { + "type": "integer", + "format": "int64" + }, + "queueName": { + "type": "string" + }, + "queuedDue": { + "type": "integer", + "format": "int64" + }, + "queuedFuture": { + "type": "integer", + "format": "int64" + }, + "running": { + "type": "integer", + "format": "int64" + }, + "success24h": { + "type": "integer", + "format": "int64" + } + } + }, "labels.addLabelToPoolRequest": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index d698377..4685ac8 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -337,6 +337,78 @@ definitions: status: type: string type: object + jobs.EnqueueReq: + type: object + jobs.EnqueueResp: + properties: + id: + type: string + type: object + jobs.JobListItem: + properties: + id: + type: string + last_error: + type: string + max_retry: + type: integer + queue_name: + type: string + retry_count: + type: integer + scheduled_at: + type: string + started_at: + type: string + status: + type: string + updated_at: + type: string + type: object + jobs.KPI: + properties: + dueNow: + format: int64 + type: integer + failed24h: + format: int64 + type: integer + retryable: + format: int64 + type: integer + runningNow: + format: int64 + type: integer + scheduledFuture: + format: int64 + type: integer + succeeded24h: + format: int64 + type: integer + type: object + jobs.QueueRollup: + properties: + avgDurationSecs: + format: float64 + type: number + failed24h: + format: int64 + type: integer + queueName: + type: string + queuedDue: + format: int64 + type: integer + queuedFuture: + format: int64 + type: integer + running: + format: int64 + type: integer + success24h: + format: int64 + type: integer + type: object labels.addLabelToPoolRequest: properties: node_pool_ids: @@ -2191,6 +2263,230 @@ paths: summary: Detach one node pool from a cluster (org scoped) tags: - clusters + /api/v1/jobs/{id}/cancel: + post: + consumes: + - application/json + description: Cancels running or scheduled jobs + parameters: + - description: Job ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "204": + description: no content + schema: + type: string + "400": + description: bad request + schema: + type: string + "401": + description: unauthorized + schema: + type: string + "404": + description: not found + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: Cancel a job + tags: + - jobs + /api/v1/jobs/{id}/retry: + post: + consumes: + - application/json + description: Calls Archer ScheduleNow on the job id + parameters: + - description: Job ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "204": + description: no content + schema: + type: string + "400": + description: bad request + schema: + type: string + "401": + description: unauthorized + schema: + type: string + "404": + description: not found + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: Retry a job immediately + tags: + - jobs + /api/v1/jobs/active: + get: + description: Currently running jobs (limit default 100) + parameters: + - default: 100 + description: Max rows + in: query + name: limit + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/jobs.JobListItem' + type: array + "401": + description: unauthorized + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: Active jobs + tags: + - jobs + /api/v1/jobs/enqueue: + post: + consumes: + - application/json + description: Schedules a job on a queue with optional args/schedule + parameters: + - description: Enqueue request + in: body + name: payload + required: true + schema: + $ref: '#/definitions/jobs.EnqueueReq' + produces: + - application/json + responses: + "202": + description: Accepted + schema: + $ref: '#/definitions/jobs.EnqueueResp' + "400": + description: bad request + schema: + type: string + "401": + description: unauthorized + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: Manually enqueue a job + tags: + - jobs + /api/v1/jobs/failures: + get: + description: Failed jobs ordered by most recent (limit default 100) + parameters: + - default: 100 + description: Max rows + in: query + name: limit + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/jobs.JobListItem' + type: array + "401": + description: unauthorized + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: Recent failures + tags: + - jobs + /api/v1/jobs/kpi: + get: + description: Aggregated counters across all queues + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/jobs.KPI' + "401": + description: unauthorized + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: Jobs KPI + tags: + - jobs + /api/v1/jobs/queues: + get: + description: Counts and avg duration per queue (last 24h) + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/jobs.QueueRollup' + type: array + "401": + description: unauthorized + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: Per-queue rollups + tags: + - jobs /api/v1/labels: get: consumes: diff --git a/go.mod b/go.mod index a3ae65b..722e1e1 100644 --- a/go.mod +++ b/go.mod @@ -11,29 +11,29 @@ require ( github.com/google/uuid v1.6.0 github.com/joho/godotenv v1.5.1 github.com/spf13/cobra v1.10.1 - github.com/spf13/viper v1.20.1 + github.com/spf13/viper v1.21.0 github.com/swaggo/http-swagger/v2 v2.0.2 github.com/swaggo/swag v1.16.6 - github.com/wneessen/go-mail v0.6.2 - golang.org/x/crypto v0.41.0 - golang.org/x/text v0.28.0 + github.com/wneessen/go-mail v0.7.0 + golang.org/x/crypto v0.42.0 + golang.org/x/text v0.29.0 gopkg.in/yaml.v3 v3.0.1 - gorm.io/datatypes v1.2.6 + gorm.io/datatypes v1.2.7 gorm.io/driver/postgres v1.6.0 - gorm.io/gorm v1.30.2 + gorm.io/gorm v1.31.0 ) require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/spec v0.20.6 // indirect github.com/go-openapi/swag v0.19.15 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -46,21 +46,20 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mailru/easyjson v0.7.6 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect - github.com/sagikazarmark/locafero v0.7.0 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.12.0 // indirect - github.com/spf13/cast v1.7.1 // indirect - github.com/spf13/pflag v1.0.9 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/swaggo/files/v2 v2.0.0 // indirect - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.9.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.27.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect golang.org/x/tools v0.36.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gorm.io/driver/mysql v1.5.6 // indirect diff --git a/go.sum b/go.sum index c1cbd21..248e838 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/earthboundkid/versioninfo/v2 v2.24.1 h1:SJTMHaoUx3GzjjnUO1QzP3ZXK6Ee/ github.com/earthboundkid/versioninfo/v2 v2.24.1/go.mod h1:VcWEooDEuyUJnMfbdTh0uFN4cfEIg+kHMuWB2CDCLjw= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE= @@ -35,8 +35,8 @@ github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= @@ -45,7 +45,6 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0kt github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -81,41 +80,42 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= -github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= -github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= @@ -124,89 +124,24 @@ github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSy github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ= github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI= github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= -github.com/wneessen/go-mail v0.6.2 h1:c6V7c8D2mz868z9WJ+8zDKtUyLfZ1++uAZmo2GRFji8= -github.com/wneessen/go-mail v0.6.2/go.mod h1:L/PYjPK3/2ZlNb2/FjEBIn9n1rUWjW+Toy531oVmeb4= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= -go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +github.com/wneessen/go-mail v0.7.0 h1:/Wmgd5AVjp5PA+Ken5EFfr+QR83gmqHli9HcAhh0vnU= +github.com/wneessen/go-mail v0.7.0/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -219,16 +154,16 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/datatypes v1.2.6 h1:KafLdXvFUhzNeL2ncm03Gl3eTLONQfNKZ+wJ+9Y4Nck= -gorm.io/datatypes v1.2.6/go.mod h1:M2iO+6S3hhi4nAyYe444Pcb0dcIiOMJ7QHaUXxyiNZY= +gorm.io/datatypes v1.2.7 h1:ww9GAhF1aGXZY3EB3cJPJ7//JiuQo7DlQA7NNlVaTdk= +gorm.io/datatypes v1.2.7/go.mod h1:M2iO+6S3hhi4nAyYe444Pcb0dcIiOMJ7QHaUXxyiNZY= gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= -gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= -gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= +gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= +gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc= gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gorm.io/gorm v1.30.2 h1:f7bevlVoVe4Byu3pmbWPVHnPsLoWaMjEb7/clyr9Ivs= -gorm.io/gorm v1.30.2/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= +gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY= +gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/internal/api/routes.go b/internal/api/routes.go index 9a69902..a6e7ced 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -8,6 +8,7 @@ import ( "github.com/glueops/autoglue/internal/handlers/authn" "github.com/glueops/autoglue/internal/handlers/clusters" "github.com/glueops/autoglue/internal/handlers/health" + "github.com/glueops/autoglue/internal/handlers/jobs" "github.com/glueops/autoglue/internal/handlers/labels" "github.com/glueops/autoglue/internal/handlers/nodepools" "github.com/glueops/autoglue/internal/handlers/orgs" @@ -36,6 +37,17 @@ func RegisterRoutes(r chi.Router) { ad.Delete("/users/{userId}", authn.AdminDeleteUser) }) + v1.Route("/jobs", func(j chi.Router) { + j.Use(authMW) + j.Get("/kpi", jobs.GetKPI) + j.Get("/queues", jobs.GetQueues) + j.Get("/active", jobs.GetActive) + j.Get("/failures", jobs.GetFailures) + j.Post("/{id}/retry", jobs.RetryNow) + j.Post("/{id}/cancel", jobs.Cancel) + j.Post("/{id}/enqueue", jobs.Enqueue) + }) + v1.Route("/auth", func(a chi.Router) { a.Post("/login", authn.Login) a.Post("/register", authn.Register) diff --git a/internal/bg/bg.go b/internal/bg/bg.go index ba7d155..f54d720 100644 --- a/internal/bg/bg.go +++ b/internal/bg/bg.go @@ -1,4 +1,3 @@ -// internal/bg/bg.go package bg import ( @@ -11,10 +10,13 @@ import ( "github.com/dyaksa/archer" "github.com/spf13/viper" + "gorm.io/gorm" ) type Jobs struct{ Client *archer.Client } +var BgJobs *Jobs + func archerOptionsFromDSN(dsn string) (*archer.Options, error) { u, err := url.Parse(dsn) if err != nil { @@ -40,7 +42,7 @@ func archerOptionsFromDSN(dsn string) (*archer.Options, error) { }, nil } -func NewJobs() (*Jobs, error) { +func NewJobs(gdb *gorm.DB) (*Jobs, error) { opts, err := archerOptionsFromDSN(viper.GetString("database.dsn")) if err != nil { return nil, err @@ -54,6 +56,10 @@ func NewJobs() (*Jobs, error) { if timeoutSec <= 0 { timeoutSec = 60 } + retainDays := viper.GetInt("archer.cleanup_retain_days") + if retainDays <= 0 { + retainDays = 7 + } // LOG what we’re connecting to (sanitized) so you can confirm DB/host log.Printf("[archer] addr=%s db=%s user=%s ssl=%s", opts.Addr, opts.DBName, opts.User, opts.SSL) @@ -74,7 +80,15 @@ func NewJobs() (*Jobs, error) { archer.WithTimeout(time.Duration(timeoutSec)*time.Second), ) - return &Jobs{Client: c}, nil + jobs := &Jobs{Client: c} + + c.Register( + "archer_cleanup", + CleanupWorker(gdb, jobs, retainDays), + archer.WithInstances(1), + archer.WithTimeout(5*time.Minute), + ) + return jobs, nil } func (j *Jobs) Start() error { return j.Client.Start() } diff --git a/internal/bg/cleanup.go b/internal/bg/cleanup.go new file mode 100644 index 0000000..2387b82 --- /dev/null +++ b/internal/bg/cleanup.go @@ -0,0 +1,53 @@ +package bg + +import ( + "context" + "time" + + "github.com/dyaksa/archer" + "github.com/dyaksa/archer/job" + "github.com/google/uuid" + "gorm.io/gorm" +) + +type CleanupArgs struct { + RetainDays int `json:"retain_days"` + Table string `json:"table"` +} + +type JobRow struct { + ID string `gorm:"primaryKey"` + Status string + UpdatedAt time.Time +} + +func (JobRow) TableName() string { return "jobs" } + +func CleanupWorker(gdb *gorm.DB, jobs *Jobs, retainDays int) archer.WorkerFn { + return func(ctx context.Context, j job.Job) (any, error) { + if err := CleanupJobs(gdb, retainDays); err != nil { + return nil, err + } + + // schedule tomorrow 03:30 + next := time.Now().Truncate(24 * time.Hour).Add(24 * time.Hour).Add(3*time.Hour + 30*time.Minute) + + _, _ = jobs.Enqueue( + ctx, + uuid.NewString(), + "archer_cleanup", + CleanupArgs{RetainDays: retainDays, Table: "jobs"}, + archer.WithScheduleTime(next), + archer.WithMaxRetries(1), + ) + return nil, nil + } +} + +func CleanupJobs(db *gorm.DB, retainDays int) error { + cutoff := time.Now().AddDate(0, 0, -retainDays) + return db. + Where("status IN ?", []string{"success", "failed", "cancelled"}). + Where("updated_at < ?", cutoff). + Delete(&JobRow{}).Error +} diff --git a/internal/handlers/jobs/jobs.go b/internal/handlers/jobs/jobs.go new file mode 100644 index 0000000..b25dd9b --- /dev/null +++ b/internal/handlers/jobs/jobs.go @@ -0,0 +1,293 @@ +package jobs + +import ( + "encoding/json" + "net/http" + "strconv" + "time" + + "github.com/dyaksa/archer" + "github.com/glueops/autoglue/internal/bg" + "github.com/glueops/autoglue/internal/db" + "github.com/glueops/autoglue/internal/db/models" + "github.com/glueops/autoglue/internal/middleware" + "github.com/glueops/autoglue/internal/response" + "github.com/go-chi/chi/v5" + "github.com/google/uuid" +) + +type JobListItem struct { + ID string `json:"id"` + QueueName string `json:"queue_name"` + Status string `json:"status"` + RetryCount int `json:"retry_count"` + MaxRetry int `json:"max_retry"` + ScheduledAt time.Time `json:"scheduled_at"` + StartedAt *time.Time `json:"started_at,omitempty"` + UpdatedAt time.Time `json:"updated_at"` + LastError *string `json:"last_error,omitempty"` +} + +type EnqueueReq struct { + Queue string `json:"queue"` + Args json.RawMessage `json:"args"` // keep raw and pass through to Archer + MaxRetries *int `json:"max_retries,omitempty"` + ScheduleAt *time.Time `json:"schedule_at,omitempty"` +} + +type EnqueueResp struct { + ID string `json:"id"` +} + +func parseLimit(r *http.Request, def int) int { + if s := r.URL.Query().Get("limit"); s != "" { + if n, err := strconv.Atoi(s); err == nil && n > 0 && n <= 1000 { + return n + } + } + return def +} + +func isNotFoundErr(err error) bool { + if err == nil { + return false + } + msg := err.Error() + return msg == "job not found" || msg == "no rows in result set" +} + +// ---------------------- READ ENDPOINTS ---------------------- + +// GetKPI godoc +// @Summary Jobs KPI +// @Description Aggregated counters across all queues +// @Tags jobs +// @Security BearerAuth +// @Produce json +// @Success 200 {object} jobs.KPI +// @Failure 401 {string} string "unauthorized" +// @Failure 500 {string} string "internal error" +// @Router /api/v1/jobs/kpi [get] +func GetKPI(w http.ResponseWriter, r *http.Request) { + if middleware.GetAuthContext(r) == nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + k, err := LoadKPI(db.DB) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _ = response.JSON(w, http.StatusOK, k) +} + +// GetQueues godoc +// @Summary Per-queue rollups +// @Description Counts and avg duration per queue (last 24h) +// @Tags jobs +// @Security BearerAuth +// @Produce json +// @Success 200 {array} jobs.QueueRollup +// @Failure 401 {string} string "unauthorized" +// @Failure 500 {string} string "internal error" +// @Router /api/v1/jobs/queues [get] +func GetQueues(w http.ResponseWriter, r *http.Request) { + if middleware.GetAuthContext(r) == nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + rows, err := LoadPerQueue(db.DB) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _ = response.JSON(w, http.StatusOK, rows) +} + +// GetActive godoc +// @Summary Active jobs +// @Description Currently running jobs (limit default 100) +// @Tags jobs +// @Security BearerAuth +// @Produce json +// @Param limit query int false "Max rows" default(100) +// @Success 200 {array} jobs.JobListItem +// @Failure 401 {string} string "unauthorized" +// @Failure 500 {string} string "internal error" +// @Router /api/v1/jobs/active [get] +func GetActive(w http.ResponseWriter, r *http.Request) { + if middleware.GetAuthContext(r) == nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + limit := parseLimit(r, 100) + + var rows []JobListItem + err := db.DB.Model(&models.Job{}). + Select("id, queue_name, status, retry_count, max_retry, scheduled_at, started_at, updated_at, last_error"). + Where("status = ?", "running"). + Order("started_at DESC NULLS LAST, updated_at DESC"). + Limit(limit). + Scan(&rows).Error + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _ = response.JSON(w, http.StatusOK, rows) +} + +// GetFailures godoc +// @Summary Recent failures +// @Description Failed jobs ordered by most recent (limit default 100) +// @Tags jobs +// @Security BearerAuth +// @Produce json +// @Param limit query int false "Max rows" default(100) +// @Success 200 {array} jobs.JobListItem +// @Failure 401 {string} string "unauthorized" +// @Failure 500 {string} string "internal error" +// @Router /api/v1/jobs/failures [get] +func GetFailures(w http.ResponseWriter, r *http.Request) { + if middleware.GetAuthContext(r) == nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + limit := parseLimit(r, 100) + + var rows []JobListItem + err := db.DB.Model(&models.Job{}). + Select("id, queue_name, status, retry_count, max_retry, scheduled_at, started_at, updated_at, last_error"). + Where("status = ?", "failed"). + Order("updated_at DESC"). + Limit(limit). + Scan(&rows).Error + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _ = response.JSON(w, http.StatusOK, rows) +} + +// ---------------------- MUTATION ENDPOINTS ---------------------- + +// RetryNow godoc +// @Summary Retry a job immediately +// @Description Calls Archer ScheduleNow on the job id +// @Tags jobs +// @Security BearerAuth +// @Accept json +// @Produce json +// @Param id path string true "Job ID" +// @Success 204 {string} string "no content" +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "unauthorized" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "internal error" +// @Router /api/v1/jobs/{id}/retry [post] +func RetryNow(w http.ResponseWriter, r *http.Request) { + if middleware.GetAuthContext(r) == nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + id := chi.URLParam(r, "id") + if id == "" { + http.Error(w, "missing id", http.StatusBadRequest) + return + } + // archer.ScheduleNow returns (any, error); if the id is unknown, expect an error you can surface as 404 + if _, err := bg.BgJobs.Client.ScheduleNow(r.Context(), id); err != nil { + status := http.StatusInternalServerError + // (Optional) map error text if Archer returns a recognizable "not found" + if isNotFoundErr(err) { + status = http.StatusNotFound + } + http.Error(w, err.Error(), status) + return + } + response.NoContent(w) +} + +// Cancel godoc +// @Summary Cancel a job +// @Description Cancels running or scheduled jobs +// @Tags jobs +// @Security BearerAuth +// @Accept json +// @Produce json +// @Param id path string true "Job ID" +// @Success 204 {string} string "no content" +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "unauthorized" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "internal error" +// @Router /api/v1/jobs/{id}/cancel [post] +func Cancel(w http.ResponseWriter, r *http.Request) { + if middleware.GetAuthContext(r) == nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + id := chi.URLParam(r, "id") + if id == "" { + http.Error(w, "missing id", http.StatusBadRequest) + return + } + if _, err := bg.BgJobs.Client.Cancel(r.Context(), id); err != nil { + status := http.StatusInternalServerError + if isNotFoundErr(err) { + status = http.StatusNotFound + } + http.Error(w, err.Error(), status) + return + } + response.NoContent(w) +} + +// Enqueue godoc +// @Summary Manually enqueue a job +// @Description Schedules a job on a queue with optional args/schedule +// @Tags jobs +// @Security BearerAuth +// @Accept json +// @Produce json +// @Param payload body jobs.EnqueueReq true "Enqueue request" +// @Success 202 {object} jobs.EnqueueResp +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "unauthorized" +// @Failure 500 {string} string "internal error" +// @Router /api/v1/jobs/enqueue [post] +func Enqueue(w http.ResponseWriter, r *http.Request) { + if middleware.GetAuthContext(r) == nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + var req EnqueueReq + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid json: "+err.Error(), http.StatusBadRequest) + return + } + if req.Queue == "" { + http.Error(w, "queue is required", http.StatusBadRequest) + return + } + + id := uuid.NewString() + opts := []archer.FnOptions{} + if req.MaxRetries != nil { + opts = append(opts, archer.WithMaxRetries(*req.MaxRetries)) + } + if req.ScheduleAt != nil { + opts = append(opts, archer.WithScheduleTime(*req.ScheduleAt)) + } + + if _, err := bg.BgJobs.Client.Schedule(r.Context(), id, req.Queue, req.Args, opts...); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + _ = response.JSON(w, http.StatusAccepted, EnqueueResp{ID: id}) +} diff --git a/internal/handlers/jobs/kpi.go b/internal/handlers/jobs/kpi.go new file mode 100644 index 0000000..4afe134 --- /dev/null +++ b/internal/handlers/jobs/kpi.go @@ -0,0 +1,66 @@ +package jobs + +import ( + "time" + + "github.com/glueops/autoglue/internal/db/models" + "gorm.io/gorm" +) + +type KPI struct { + RunningNow int64 + DueNow int64 + ScheduledFuture int64 + Succeeded24h int64 + Failed24h int64 + Retryable int64 +} + +func LoadKPI(db *gorm.DB) (KPI, error) { + var k KPI + now := time.Now() + dayAgo := now.Add(-24 * time.Hour) + + if err := db.Model(&models.Job{}). + Where("status = ?", "running"). + Count(&k.RunningNow).Error; err != nil { + return k, err + } + + if err := db.Model(&models.Job{}). + Where("status IN ?", []string{"queued", "scheduled", "pending"}). + Where("scheduled_at > ?", now). + Count(&k.ScheduledFuture).Error; err != nil { + return k, err + } + + if err := db.Model(&models.Job{}). + Where("status IN ?", []string{"queued", "scheduled", "pending"}). + Where("scheduled_at <= ?", now). + Count(&k.DueNow).Error; err != nil { + return k, err + } + + if err := db.Model(&models.Job{}). + Where("status = ?", "success"). + Where("updated_at >= ?", dayAgo). + Count(&k.Succeeded24h).Error; err != nil { + return k, err + } + + if err := db.Model(&models.Job{}). + Where("status = ?", "failed"). + Where("updated_at >= ?", dayAgo). + Count(&k.Failed24h).Error; err != nil { + return k, err + } + + if err := db.Model(&models.Job{}). + Where("status = ?", "failed"). + Where("retry_count < max_retry"). + Count(&k.Retryable).Error; err != nil { + return k, err + } + + return k, nil +} diff --git a/internal/handlers/jobs/queue.go b/internal/handlers/jobs/queue.go new file mode 100644 index 0000000..c8583f8 --- /dev/null +++ b/internal/handlers/jobs/queue.go @@ -0,0 +1,64 @@ +package jobs + +import ( + "time" + + "github.com/glueops/autoglue/internal/db/models" + "gorm.io/gorm" +) + +type QueueRollup struct { + QueueName string + Running int64 + QueuedDue int64 + QueuedFuture int64 + Success24h int64 + Failed24h int64 + AvgDurationSecs float64 +} + +func LoadPerQueue(db *gorm.DB) ([]QueueRollup, error) { + var queues []string + if err := db.Model(&models.Job{}).Distinct().Pluck("queue_name", &queues).Error; err != nil { + return nil, err + } + + now := time.Now() + dayAgo := now.Add(-24 * time.Hour) + out := make([]QueueRollup, 0, len(queues)) + + for _, q := range queues { + var rr, qd, qf, s24, f24 int64 + var avgDur *float64 + + _ = db.Model(&models.Job{}).Where("queue_name = ? AND status = 'running'", q).Count(&rr).Error + _ = db.Model(&models.Job{}).Where("queue_name = ? AND status IN ('queued','scheduled','pending') AND scheduled_at <= ?", q, now).Count(&qd).Error + _ = db.Model(&models.Job{}).Where("queue_name = ? AND status IN ('queued','scheduled','pending') AND scheduled_at > ?", q, now).Count(&qf).Error + _ = db.Model(&models.Job{}).Where("queue_name = ? AND status = 'success' AND updated_at >= ?", q, dayAgo).Count(&s24).Error + _ = db.Model(&models.Job{}).Where("queue_name = ? AND status = 'failed' AND updated_at >= ?", q, dayAgo).Count(&f24).Error + + _ = db. + Model(&models.Job{}). + Select("AVG(EXTRACT(EPOCH FROM (updated_at - started_at)))"). + Where("queue_name = ? AND status = 'success' AND started_at IS NOT NULL AND updated_at >= ?", q, dayAgo). + Scan(&avgDur).Error + + out = append(out, QueueRollup{ + QueueName: q, + Running: rr, + QueuedDue: qd, + QueuedFuture: qf, + Success24h: s24, + Failed24h: f24, + AvgDurationSecs: coalesceF64(avgDur, 0), + }) + } + return out, nil +} + +func coalesceF64(p *float64, d float64) float64 { + if p == nil { + return d + } + return *p +} diff --git a/internal/ui/dist/assets/icons-DQ1I1M7X.js b/internal/ui/dist/assets/icons-B5E6SSBo.js similarity index 55% rename from internal/ui/dist/assets/icons-DQ1I1M7X.js rename to internal/ui/dist/assets/icons-B5E6SSBo.js index 15edc62..9a297f6 100644 --- a/internal/ui/dist/assets/icons-DQ1I1M7X.js +++ b/internal/ui/dist/assets/icons-B5E6SSBo.js @@ -1,186 +1,206 @@ -import{r as d,R as s}from"./vendor-DvippHRz.js";/** +import{r as i,R as s}from"./vendor-DvippHRz.js";/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const w=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),b=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,a,c)=>c?c.toUpperCase():a.toLowerCase()),k=e=>{const t=b(e);return t.charAt(0).toUpperCase()+t.slice(1)},v=(...e)=>e.filter((t,a,c)=>!!t&&t.trim()!==""&&c.indexOf(t)===a).join(" ").trim(),z=e=>{for(const t in e)if(t.startsWith("aria-")||t==="role"||t==="title")return!0};/** + */const w=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),b=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,a,c)=>c?c.toUpperCase():a.toLowerCase()),u=e=>{const t=b(e);return t.charAt(0).toUpperCase()+t.slice(1)},M=(...e)=>e.filter((t,a,c)=>!!t&&t.trim()!==""&&c.indexOf(t)===a).join(" ").trim(),z=e=>{for(const t in e)if(t.startsWith("aria-")||t==="role"||t==="title")return!0};/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */var j={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** + */var C={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const N=d.forwardRef(({color:e="currentColor",size:t=24,strokeWidth:a=2,absoluteStrokeWidth:c,className:o="",children:r,iconNode:p,...i},h)=>d.createElement("svg",{ref:h,...j,width:t,height:t,stroke:e,strokeWidth:c?Number(a)*24/Number(t):a,className:v("lucide",o),...!r&&!z(i)&&{"aria-hidden":"true"},...i},[...p.map(([g,x])=>d.createElement(g,x)),...Array.isArray(r)?r:[r]]));/** + */const j=i.forwardRef(({color:e="currentColor",size:t=24,strokeWidth:a=2,absoluteStrokeWidth:c,className:n="",children:r,iconNode:p,...d},h)=>i.createElement("svg",{ref:h,...C,width:t,height:t,stroke:e,strokeWidth:c?Number(a)*24/Number(t):a,className:M("lucide",n),...!r&&!z(d)&&{"aria-hidden":"true"},...d},[...p.map(([g,x])=>i.createElement(g,x)),...Array.isArray(r)?r:[r]]));/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const n=(e,t)=>{const a=d.forwardRef(({className:c,...o},r)=>d.createElement(N,{ref:r,iconNode:t,className:v(`lucide-${w(k(e))}`,`lucide-${e}`,c),...o}));return a.displayName=k(e),a};/** + */const o=(e,t)=>{const a=i.forwardRef(({className:c,...n},r)=>i.createElement(j,{ref:r,iconNode:t,className:M(`lucide-${w(u(e))}`,`lucide-${e}`,c),...n}));return a.displayName=u(e),a};/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const C=[["path",{d:"M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z",key:"lc1i9w"}],["path",{d:"m7 16.5-4.74-2.85",key:"1o9zyk"}],["path",{d:"m7 16.5 5-3",key:"va8pkn"}],["path",{d:"M7 16.5v5.17",key:"jnp8gn"}],["path",{d:"M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z",key:"8zsnat"}],["path",{d:"m17 16.5-5-3",key:"8arw3v"}],["path",{d:"m17 16.5 4.74-2.85",key:"8rfmw"}],["path",{d:"M17 16.5v5.17",key:"k6z78m"}],["path",{d:"M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z",key:"1xygjf"}],["path",{d:"M12 8 7.26 5.15",key:"1vbdud"}],["path",{d:"m12 8 4.74-2.85",key:"3rx089"}],["path",{d:"M12 13.5V8",key:"1io7kd"}]],u1=n("boxes",C);/** + */const N=[["path",{d:"M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z",key:"3c2336"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],f1=o("badge-check",N);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const $=[["path",{d:"m10.852 14.772-.383.923",key:"11vil6"}],["path",{d:"m10.852 9.228-.383-.923",key:"1fjppe"}],["path",{d:"m13.148 14.772.382.924",key:"je3va1"}],["path",{d:"m13.531 8.305-.383.923",key:"18epck"}],["path",{d:"m14.772 10.852.923-.383",key:"k9m8cz"}],["path",{d:"m14.772 13.148.923.383",key:"1xvhww"}],["path",{d:"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 0 0-5.63-1.446 3 3 0 0 0-.368 1.571 4 4 0 0 0-2.525 5.771",key:"jcbbz1"}],["path",{d:"M17.998 5.125a4 4 0 0 1 2.525 5.771",key:"1kkn7e"}],["path",{d:"M19.505 10.294a4 4 0 0 1-1.5 7.706",key:"18bmuc"}],["path",{d:"M4.032 17.483A4 4 0 0 0 11.464 20c.18-.311.892-.311 1.072 0a4 4 0 0 0 7.432-2.516",key:"uozx0d"}],["path",{d:"M4.5 10.291A4 4 0 0 0 6 18",key:"whdemb"}],["path",{d:"M6.002 5.125a3 3 0 0 0 .4 1.375",key:"1kqy2g"}],["path",{d:"m9.228 10.852-.923-.383",key:"1wtb30"}],["path",{d:"m9.228 13.148-.923.383",key:"1a830x"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],m1=n("brain-cog",$);/** + */const $=[["path",{d:"M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z",key:"lc1i9w"}],["path",{d:"m7 16.5-4.74-2.85",key:"1o9zyk"}],["path",{d:"m7 16.5 5-3",key:"va8pkn"}],["path",{d:"M7 16.5v5.17",key:"jnp8gn"}],["path",{d:"M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z",key:"8zsnat"}],["path",{d:"m17 16.5-5-3",key:"8arw3v"}],["path",{d:"m17 16.5 4.74-2.85",key:"8rfmw"}],["path",{d:"M17 16.5v5.17",key:"k6z78m"}],["path",{d:"M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z",key:"1xygjf"}],["path",{d:"M12 8 7.26 5.15",key:"1vbdud"}],["path",{d:"m12 8 4.74-2.85",key:"3rx089"}],["path",{d:"M12 13.5V8",key:"1io7kd"}]],_1=o("boxes",$);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const O=[["path",{d:"M12 10h.01",key:"1nrarc"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M12 6h.01",key:"1vi96p"}],["path",{d:"M16 10h.01",key:"1m94wz"}],["path",{d:"M16 14h.01",key:"1gbofw"}],["path",{d:"M16 6h.01",key:"1x0f13"}],["path",{d:"M8 10h.01",key:"19clt8"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M8 6h.01",key:"1dz90k"}],["path",{d:"M9 22v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3",key:"cabbwy"}],["rect",{x:"4",y:"2",width:"16",height:"20",rx:"2",key:"1uxh74"}]],v1=n("building",O);/** + */const O=[["path",{d:"m10.852 14.772-.383.923",key:"11vil6"}],["path",{d:"m10.852 9.228-.383-.923",key:"1fjppe"}],["path",{d:"m13.148 14.772.382.924",key:"je3va1"}],["path",{d:"m13.531 8.305-.383.923",key:"18epck"}],["path",{d:"m14.772 10.852.923-.383",key:"k9m8cz"}],["path",{d:"m14.772 13.148.923.383",key:"1xvhww"}],["path",{d:"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 0 0-5.63-1.446 3 3 0 0 0-.368 1.571 4 4 0 0 0-2.525 5.771",key:"jcbbz1"}],["path",{d:"M17.998 5.125a4 4 0 0 1 2.525 5.771",key:"1kkn7e"}],["path",{d:"M19.505 10.294a4 4 0 0 1-1.5 7.706",key:"18bmuc"}],["path",{d:"M4.032 17.483A4 4 0 0 0 11.464 20c.18-.311.892-.311 1.072 0a4 4 0 0 0 7.432-2.516",key:"uozx0d"}],["path",{d:"M4.5 10.291A4 4 0 0 0 6 18",key:"whdemb"}],["path",{d:"M6.002 5.125a3 3 0 0 0 .4 1.375",key:"1kqy2g"}],["path",{d:"m9.228 10.852-.923-.383",key:"1wtb30"}],["path",{d:"m9.228 13.148-.923.383",key:"1a830x"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],g1=o("brain-cog",O);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const P=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],f1=n("check",P);/** + */const L=[["path",{d:"M12 10h.01",key:"1nrarc"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M12 6h.01",key:"1vi96p"}],["path",{d:"M16 10h.01",key:"1m94wz"}],["path",{d:"M16 14h.01",key:"1gbofw"}],["path",{d:"M16 6h.01",key:"1x0f13"}],["path",{d:"M8 10h.01",key:"19clt8"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M8 6h.01",key:"1dz90k"}],["path",{d:"M9 22v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3",key:"cabbwy"}],["rect",{x:"4",y:"2",width:"16",height:"20",rx:"2",key:"1uxh74"}]],x1=o("building",L);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const q=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],M1=n("chevron-down",q);/** + */const q=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],w1=o("check",q);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const A=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],_1=n("chevron-up",A);/** + */const P=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],b1=o("chevron-down",P);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const L=[["path",{d:"M12 13v8l-4-4",key:"1f5nwf"}],["path",{d:"m12 21 4-4",key:"1lfcce"}],["path",{d:"M4.393 15.269A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.436 8.284",key:"ui1hmy"}]],g1=n("cloud-download",L);/** + */const A=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],z1=o("chevron-up",A);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const V=[["path",{d:"M15.536 11.293a1 1 0 0 0 0 1.414l2.376 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z",key:"1uwlt4"}],["path",{d:"M2.297 11.293a1 1 0 0 0 0 1.414l2.377 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414L6.088 8.916a1 1 0 0 0-1.414 0z",key:"10291m"}],["path",{d:"M8.916 17.912a1 1 0 0 0 0 1.415l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.415l-2.377-2.376a1 1 0 0 0-1.414 0z",key:"1tqoq1"}],["path",{d:"M8.916 4.674a1 1 0 0 0 0 1.414l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z",key:"1x6lto"}]],x1=n("component",V);/** + */const V=[["path",{d:"M22 2 2 22",key:"y4kqgn"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],C1=o("circle-slash-2",V);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const E=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],w1=n("copy",E);/** + */const H=[["path",{d:"M12 13v8l-4-4",key:"1f5nwf"}],["path",{d:"m12 21 4-4",key:"1lfcce"}],["path",{d:"M4.393 15.269A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.436 8.284",key:"ui1hmy"}]],j1=o("cloud-download",H);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const H=[["path",{d:"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v6",key:"rc0qvx"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["circle",{cx:"4",cy:"16",r:"2",key:"1ehqvc"}],["path",{d:"m10 10-4.5 4.5",key:"7fwrp6"}],["path",{d:"m9 11 1 1",key:"wa6s5q"}]],b1=n("file-key-2",H);/** + */const S=[["path",{d:"M15.536 11.293a1 1 0 0 0 0 1.414l2.376 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z",key:"1uwlt4"}],["path",{d:"M2.297 11.293a1 1 0 0 0 0 1.414l2.377 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414L6.088 8.916a1 1 0 0 0-1.414 0z",key:"10291m"}],["path",{d:"M8.916 17.912a1 1 0 0 0 0 1.415l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.415l-2.377-2.376a1 1 0 0 0-1.414 0z",key:"1tqoq1"}],["path",{d:"M8.916 4.674a1 1 0 0 0 0 1.414l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z",key:"1x6lto"}]],N1=o("component",S);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const S=[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"1d0kgt"}]],z1=n("house",S);/** + */const E=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],$1=o("copy",E);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const B=[["path",{d:"m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4",key:"g0fldk"}],["path",{d:"m21 2-9.6 9.6",key:"1j0ho8"}],["circle",{cx:"7.5",cy:"15.5",r:"5.5",key:"yqb3hr"}]],j1=n("key",B);/** + */const B=[["path",{d:"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v6",key:"rc0qvx"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["circle",{cx:"4",cy:"16",r:"2",key:"1ehqvc"}],["path",{d:"m10 10-4.5 4.5",key:"7fwrp6"}],["path",{d:"m9 11 1 1",key:"wa6s5q"}]],O1=o("file-key-2",B);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const U=[["path",{d:"M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z",key:"1pdavp"}],["path",{d:"M20.054 15.987H3.946",key:"14rxg9"}]],N1=n("laptop",U);/** + */const U=[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"1d0kgt"}]],L1=o("house",U);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const D=[["path",{d:"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",key:"1cjeqo"}],["path",{d:"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",key:"19qd67"}]],C1=n("link",D);/** + */const R=[["path",{d:"m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4",key:"g0fldk"}],["path",{d:"m21 2-9.6 9.6",key:"1j0ho8"}],["circle",{cx:"7.5",cy:"15.5",r:"5.5",key:"yqb3hr"}]],q1=o("key",R);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const R=[["rect",{x:"3",y:"5",width:"6",height:"6",rx:"1",key:"1defrl"}],["path",{d:"m3 17 2 2 4-4",key:"1jhpwq"}],["path",{d:"M13 6h8",key:"15sg57"}],["path",{d:"M13 12h8",key:"h98zly"}],["path",{d:"M13 18h8",key:"oe0vm4"}]],$1=n("list-todo",R);/** + */const Z=[["path",{d:"M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z",key:"1pdavp"}],["path",{d:"M20.054 15.987H3.946",key:"14rxg9"}]],P1=o("laptop",Z);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const I=[["circle",{cx:"12",cy:"16",r:"1",key:"1au0dj"}],["rect",{x:"3",y:"10",width:"18",height:"12",rx:"2",key:"6s8ecr"}],["path",{d:"M7 10V7a5 5 0 0 1 10 0v3",key:"1pqi11"}]],O1=n("lock-keyhole",I);/** + */const D=[["path",{d:"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",key:"1cjeqo"}],["path",{d:"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",key:"19qd67"}]],A1=o("link",D);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const K=[["path",{d:"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",key:"kfwtm"}]],P1=n("moon",K);/** + */const T=[["rect",{x:"3",y:"5",width:"6",height:"6",rx:"1",key:"1defrl"}],["path",{d:"m3 17 2 2 4-4",key:"1jhpwq"}],["path",{d:"M13 6h8",key:"15sg57"}],["path",{d:"M13 12h8",key:"h98zly"}],["path",{d:"M13 18h8",key:"oe0vm4"}]],V1=o("list-todo",T);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const T=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]],q1=n("pencil",T);/** + */const W=[["circle",{cx:"12",cy:"16",r:"1",key:"1au0dj"}],["rect",{x:"3",y:"10",width:"18",height:"12",rx:"2",key:"6s8ecr"}],["path",{d:"M7 10V7a5 5 0 0 1 10 0v3",key:"1pqi11"}]],H1=o("lock-keyhole",W);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const W=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]],A1=n("plus",W);/** + */const I=[["path",{d:"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",key:"kfwtm"}]],S1=o("moon",I);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Z=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],L1=n("refresh-cw",Z);/** + */const K=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]],E1=o("pencil",K);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const F=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],V1=n("search",F);/** + */const G=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]],B1=o("plus",G);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const G=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],E1=n("server",G);/** + */const F=[["path",{d:"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"14sxne"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16",key:"1hlbsb"}],["path",{d:"M16 16h5v5",key:"ccwih5"}]],U1=o("refresh-ccw",F);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const X=[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],H1=n("settings",X);/** + */const X=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],R1=o("refresh-cw",X);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const J=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],S1=n("shield-check",J);/** + */const J=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],Z1=o("search",J);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Q=[["path",{d:"M3 3h.01",key:"159qn6"}],["path",{d:"M7 5h.01",key:"1hq22a"}],["path",{d:"M11 7h.01",key:"1osv80"}],["path",{d:"M3 7h.01",key:"1xzrh3"}],["path",{d:"M7 9h.01",key:"19b3jx"}],["path",{d:"M3 11h.01",key:"1eifu7"}],["rect",{width:"4",height:"4",x:"15",y:"5",key:"mri9e4"}],["path",{d:"m19 9 2 2v10c0 .6-.4 1-1 1h-6c-.6 0-1-.4-1-1V11l2-2",key:"aib6hk"}],["path",{d:"m13 14 8-2",key:"1d7bmk"}],["path",{d:"m13 19 8-2",key:"1y2vml"}]],B1=n("spray-can",Q);/** + */const Q=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],D1=o("server",Q);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Y=[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]],U1=n("sun",Y);/** + */const Y=[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],T1=o("settings",Y);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const e1=[["path",{d:"M13.172 2a2 2 0 0 1 1.414.586l6.71 6.71a2.4 2.4 0 0 1 0 3.408l-4.592 4.592a2.4 2.4 0 0 1-3.408 0l-6.71-6.71A2 2 0 0 1 6 9.172V3a1 1 0 0 1 1-1z",key:"16rjxf"}],["path",{d:"M2 7v6.172a2 2 0 0 0 .586 1.414l6.71 6.71a2.4 2.4 0 0 0 3.191.193",key:"178nd4"}],["circle",{cx:"10.5",cy:"6.5",r:".5",fill:"currentColor",key:"12ikhr"}]],D1=n("tags",e1);/** + */const e1=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],W1=o("shield-check",e1);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const t1=[["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],R1=n("trash",t1);/** + */const t1=[["path",{d:"M3 3h.01",key:"159qn6"}],["path",{d:"M7 5h.01",key:"1hq22a"}],["path",{d:"M11 7h.01",key:"1osv80"}],["path",{d:"M3 7h.01",key:"1xzrh3"}],["path",{d:"M7 9h.01",key:"19b3jx"}],["path",{d:"M3 11h.01",key:"1eifu7"}],["rect",{width:"4",height:"4",x:"15",y:"5",key:"mri9e4"}],["path",{d:"m19 9 2 2v10c0 .6-.4 1-1 1h-6c-.6 0-1-.4-1-1V11l2-2",key:"aib6hk"}],["path",{d:"m13 14 8-2",key:"1d7bmk"}],["path",{d:"m13 19 8-2",key:"1y2vml"}]],I1=o("spray-can",t1);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const a1=[["path",{d:"m18.84 12.25 1.72-1.71h-.02a5.004 5.004 0 0 0-.12-7.07 5.006 5.006 0 0 0-6.95 0l-1.72 1.71",key:"yqzxt4"}],["path",{d:"m5.17 11.75-1.71 1.71a5.004 5.004 0 0 0 .12 7.07 5.006 5.006 0 0 0 6.95 0l1.71-1.71",key:"4qinb0"}],["line",{x1:"8",x2:"8",y1:"2",y2:"5",key:"1041cp"}],["line",{x1:"2",x2:"5",y1:"8",y2:"8",key:"14m1p5"}],["line",{x1:"16",x2:"16",y1:"19",y2:"22",key:"rzdirn"}],["line",{x1:"19",x2:"22",y1:"16",y2:"16",key:"ox905f"}]],I1=n("unlink",a1);/** + */const a1=[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]],K1=o("sun",a1);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const c1=[["path",{d:"M2 21a8 8 0 0 1 13.292-6",key:"bjp14o"}],["circle",{cx:"10",cy:"8",r:"5",key:"o932ke"}],["path",{d:"M19 16v6",key:"tddt3s"}],["path",{d:"M22 19h-6",key:"vcuq98"}]],K1=n("user-round-plus",c1);/** + */const c1=[["path",{d:"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z",key:"vktsd0"}],["circle",{cx:"7.5",cy:"7.5",r:".5",fill:"currentColor",key:"kqv944"}]],G1=o("tag",c1);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const n1=[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]],T1=n("user",n1);/** + */const o1=[["path",{d:"M13.172 2a2 2 0 0 1 1.414.586l6.71 6.71a2.4 2.4 0 0 1 0 3.408l-4.592 4.592a2.4 2.4 0 0 1-3.408 0l-6.71-6.71A2 2 0 0 1 6 9.172V3a1 1 0 0 1 1-1z",key:"16rjxf"}],["path",{d:"M2 7v6.172a2 2 0 0 0 .586 1.414l6.71 6.71a2.4 2.4 0 0 0 3.191.193",key:"178nd4"}],["circle",{cx:"10.5",cy:"6.5",r:".5",fill:"currentColor",key:"12ikhr"}]],F1=o("tags",o1);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const o1=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],W1=n("users",o1);/** + */const n1=[["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],X1=o("trash",n1);/** * @license lucide-react v0.542.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const r1=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],Z1=n("x",r1);var f={color:void 0,size:void 0,className:void 0,style:void 0,attr:void 0},u=s.createContext&&s.createContext(f),h1=["attr","size","title"];function s1(e,t){if(e==null)return{};var a=i1(e,t),c,o;if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0)&&Object.prototype.propertyIsEnumerable.call(e,c)&&(a[c]=e[c])}return a}function i1(e,t){if(e==null)return{};var a={};for(var c in e)if(Object.prototype.hasOwnProperty.call(e,c)){if(t.indexOf(c)>=0)continue;a[c]=e[c]}return a}function y(){return y=Object.assign?Object.assign.bind():function(e){for(var t=1;ts.createElement(t.tag,l({key:a},t.attr),M(t.child)))}function _(e){return t=>s.createElement(p1,y({attr:l({},e.attr)},t),M(e.child))}function p1(e){var t=a=>{var{attr:c,size:o,title:r}=e,p=s1(e,h1),i=o||a.size||"1em",h;return a.className&&(h=a.className),e.className&&(h=(h?h+" ":"")+e.className),s.createElement("svg",y({stroke:"currentColor",fill:"currentColor",strokeWidth:"0"},a.attr,c,p,{className:h,style:l(l({color:e.color||a.color},a.style),e.style),height:i,width:i,xmlns:"http://www.w3.org/2000/svg"}),r&&s.createElement("title",null,r),e.children)};return u!==void 0?s.createElement(u.Consumer,null,a=>t(a)):t(f)}function F1(e){return _({attr:{viewBox:"0 0 1024 1024"},child:[{tag:"path",attr:{d:"M888 680h-54V540H546v-92h238c8.8 0 16-7.2 16-16V168c0-8.8-7.2-16-16-16H240c-8.8 0-16 7.2-16 16v264c0 8.8 7.2 16 16 16h238v92H190v140h-54c-4.4 0-8 3.6-8 8v176c0 4.4 3.6 8 8 8h176c4.4 0 8-3.6 8-8V688c0-4.4-3.6-8-8-8h-54v-72h220v72h-54c-4.4 0-8 3.6-8 8v176c0 4.4 3.6 8 8 8h176c4.4 0 8-3.6 8-8V688c0-4.4-3.6-8-8-8h-54v-72h220v72h-54c-4.4 0-8 3.6-8 8v176c0 4.4 3.6 8 8 8h176c4.4 0 8-3.6 8-8V688c0-4.4-3.6-8-8-8zM256 805.3c0 1.5-1.2 2.7-2.7 2.7h-58.7c-1.5 0-2.7-1.2-2.7-2.7v-58.7c0-1.5 1.2-2.7 2.7-2.7h58.7c1.5 0 2.7 1.2 2.7 2.7v58.7zm288 0c0 1.5-1.2 2.7-2.7 2.7h-58.7c-1.5 0-2.7-1.2-2.7-2.7v-58.7c0-1.5 1.2-2.7 2.7-2.7h58.7c1.5 0 2.7 1.2 2.7 2.7v58.7zM288 384V216h448v168H288zm544 421.3c0 1.5-1.2 2.7-2.7 2.7h-58.7c-1.5 0-2.7-1.2-2.7-2.7v-58.7c0-1.5 1.2-2.7 2.7-2.7h58.7c1.5 0 2.7 1.2 2.7 2.7v58.7zM360 300a40 40 0 1 0 80 0 40 40 0 1 0-80 0z"},child:[]}]})(e)}function G1(e){return _({attr:{viewBox:"0 0 496 512"},child:[{tag:"path",attr:{d:"M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"},child:[]}]})(e)}export{F1 as A,u1 as B,f1 as C,b1 as F,z1 as H,j1 as K,N1 as L,P1 as M,A1 as P,L1 as R,U1 as S,D1 as T,W1 as U,Z1 as X,x1 as a,B1 as b,E1 as c,m1 as d,O1 as e,$1 as f,v1 as g,T1 as h,H1 as i,S1 as j,M1 as k,G1 as l,_1 as m,q1 as n,R1 as o,V1 as p,C1 as q,I1 as r,w1 as s,g1 as t,K1 as u}; + */const r1=[["path",{d:"m18.84 12.25 1.72-1.71h-.02a5.004 5.004 0 0 0-.12-7.07 5.006 5.006 0 0 0-6.95 0l-1.72 1.71",key:"yqzxt4"}],["path",{d:"m5.17 11.75-1.71 1.71a5.004 5.004 0 0 0 .12 7.07 5.006 5.006 0 0 0 6.95 0l1.71-1.71",key:"4qinb0"}],["line",{x1:"8",x2:"8",y1:"2",y2:"5",key:"1041cp"}],["line",{x1:"2",x2:"5",y1:"8",y2:"8",key:"14m1p5"}],["line",{x1:"16",x2:"16",y1:"19",y2:"22",key:"rzdirn"}],["line",{x1:"19",x2:"22",y1:"16",y2:"16",key:"ox905f"}]],J1=o("unlink",r1);/** + * @license lucide-react v0.542.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const h1=[["path",{d:"M2 21a8 8 0 0 1 13.292-6",key:"bjp14o"}],["circle",{cx:"10",cy:"8",r:"5",key:"o932ke"}],["path",{d:"M19 16v6",key:"tddt3s"}],["path",{d:"M22 19h-6",key:"vcuq98"}]],Q1=o("user-round-plus",h1);/** + * @license lucide-react v0.542.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const s1=[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]],Y1=o("user",s1);/** + * @license lucide-react v0.542.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const d1=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],e2=o("users",d1);/** + * @license lucide-react v0.542.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const i1=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],t2=o("x",i1);var f={color:void 0,size:void 0,className:void 0,style:void 0,attr:void 0},m=s.createContext&&s.createContext(f),y1=["attr","size","title"];function l1(e,t){if(e==null)return{};var a=p1(e,t),c,n;if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0)&&Object.prototype.propertyIsEnumerable.call(e,c)&&(a[c]=e[c])}return a}function p1(e,t){if(e==null)return{};var a={};for(var c in e)if(Object.prototype.hasOwnProperty.call(e,c)){if(t.indexOf(c)>=0)continue;a[c]=e[c]}return a}function y(){return y=Object.assign?Object.assign.bind():function(e){for(var t=1;ts.createElement(t.tag,l({key:a},t.attr),_(t.child)))}function k(e){return t=>s.createElement(v1,y({attr:l({},e.attr)},t),_(e.child))}function v1(e){var t=a=>{var{attr:c,size:n,title:r}=e,p=l1(e,y1),d=n||a.size||"1em",h;return a.className&&(h=a.className),e.className&&(h=(h?h+" ":"")+e.className),s.createElement("svg",y({stroke:"currentColor",fill:"currentColor",strokeWidth:"0"},a.attr,c,p,{className:h,style:l(l({color:e.color||a.color},a.style),e.style),height:d,width:d,xmlns:"http://www.w3.org/2000/svg"}),r&&s.createElement("title",null,r),e.children)};return m!==void 0?s.createElement(m.Consumer,null,a=>t(a)):t(f)}function a2(e){return k({attr:{viewBox:"0 0 1024 1024"},child:[{tag:"path",attr:{d:"M888 680h-54V540H546v-92h238c8.8 0 16-7.2 16-16V168c0-8.8-7.2-16-16-16H240c-8.8 0-16 7.2-16 16v264c0 8.8 7.2 16 16 16h238v92H190v140h-54c-4.4 0-8 3.6-8 8v176c0 4.4 3.6 8 8 8h176c4.4 0 8-3.6 8-8V688c0-4.4-3.6-8-8-8h-54v-72h220v72h-54c-4.4 0-8 3.6-8 8v176c0 4.4 3.6 8 8 8h176c4.4 0 8-3.6 8-8V688c0-4.4-3.6-8-8-8h-54v-72h220v72h-54c-4.4 0-8 3.6-8 8v176c0 4.4 3.6 8 8 8h176c4.4 0 8-3.6 8-8V688c0-4.4-3.6-8-8-8zM256 805.3c0 1.5-1.2 2.7-2.7 2.7h-58.7c-1.5 0-2.7-1.2-2.7-2.7v-58.7c0-1.5 1.2-2.7 2.7-2.7h58.7c1.5 0 2.7 1.2 2.7 2.7v58.7zm288 0c0 1.5-1.2 2.7-2.7 2.7h-58.7c-1.5 0-2.7-1.2-2.7-2.7v-58.7c0-1.5 1.2-2.7 2.7-2.7h58.7c1.5 0 2.7 1.2 2.7 2.7v58.7zM288 384V216h448v168H288zm544 421.3c0 1.5-1.2 2.7-2.7 2.7h-58.7c-1.5 0-2.7-1.2-2.7-2.7v-58.7c0-1.5 1.2-2.7 2.7-2.7h58.7c1.5 0 2.7 1.2 2.7 2.7v58.7zM360 300a40 40 0 1 0 80 0 40 40 0 1 0-80 0z"},child:[]}]})(e)}function c2(e){return k({attr:{viewBox:"0 0 24 24"},child:[{tag:"path",attr:{fill:"none",strokeWidth:"2",d:"M3,6 L21,6 L3,6 Z M10,2 L10,4 M14,2 L14,4 M16,12 C18.3736719,13.1826446 20,15.6506255 20,19 L20,23 L4,23 L4,19 C4,15.6457258 5.6310898,13.1754259 8,12 M12,16.5 L12,23 M12,13 C15.3137085,13 18,10.3137085 18,7 C18,3.6862915 15.3137085,1 12,1 C8.6862915,1 6,3.6862915 6,7 C6,10.3137085 8.6862915,13 12,13 Z M8,12 C8,14.209139 9.790861,16 12,16 L12,16 C14.209139,16 16,14.209139 16,12"},child:[]}]})(e)}function o2(e){return k({attr:{viewBox:"0 0 496 512"},child:[{tag:"path",attr:{d:"M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"},child:[]}]})(e)}export{a2 as A,_1 as B,w1 as C,O1 as F,c2 as G,L1 as H,q1 as K,P1 as L,S1 as M,B1 as P,R1 as R,K1 as S,F1 as T,e2 as U,t2 as X,N1 as a,I1 as b,D1 as c,g1 as d,H1 as e,V1 as f,x1 as g,Y1 as h,T1 as i,W1 as j,b1 as k,o2 as l,z1 as m,E1 as n,X1 as o,Z1 as p,A1 as q,J1 as r,U1 as s,G1 as t,f1 as u,C1 as v,$1 as w,j1 as x,Q1 as y}; diff --git a/internal/ui/dist/assets/index--a4aJrTK.css b/internal/ui/dist/assets/index--a4aJrTK.css deleted file mode 100644 index 2aca382..0000000 --- a/internal/ui/dist/assets/index--a4aJrTK.css +++ /dev/null @@ -1 +0,0 @@ -/*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:"";--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-widest:.1em;--leading-tight:1.25;--leading-loose:2;--radius-xs:.125rem;--radius-2xl:1rem;--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){*{outline-color:color-mix(in oklab,var(--ring)50%,transparent)}}body{background-color:var(--background);color:var(--foreground)}}@layer components;@layer utilities{.\@container\/card-header{container:card-header/inline-size}.pointer-events-none{pointer-events:none}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.inset-x-0{inset-inline:calc(var(--spacing)*0)}.inset-y-0{inset-block:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-1\.5{top:calc(var(--spacing)*1.5)}.top-2\.5{top:calc(var(--spacing)*2.5)}.top-3\.5{top:calc(var(--spacing)*3.5)}.top-4{top:calc(var(--spacing)*4)}.top-\[50\%\]{top:50%}.right-0{right:calc(var(--spacing)*0)}.right-1{right:calc(var(--spacing)*1)}.right-2{right:calc(var(--spacing)*2)}.right-3{right:calc(var(--spacing)*3)}.right-4{right:calc(var(--spacing)*4)}.bottom-0{bottom:calc(var(--spacing)*0)}.left-0{left:calc(var(--spacing)*0)}.left-2{left:calc(var(--spacing)*2)}.left-\[50\%\]{left:50%}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-start-2{grid-column-start:2}.row-span-2{grid-row:span 2/span 2}.row-start-1{grid-row-start:1}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.-mx-1{margin-inline:calc(var(--spacing)*-1)}.mx-2{margin-inline:calc(var(--spacing)*2)}.mx-3\.5{margin-inline:calc(var(--spacing)*3.5)}.mx-auto{margin-inline:auto}.my-1{margin-block:calc(var(--spacing)*1)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-auto{margin-top:auto}.mr-2{margin-right:calc(var(--spacing)*2)}.mr-4{margin-right:calc(var(--spacing)*4)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-auto{margin-left:auto}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-row{display:table-row}.aspect-square{aspect-ratio:1}.size-2{width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}.size-2\.5{width:calc(var(--spacing)*2.5);height:calc(var(--spacing)*2.5)}.size-3\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-7{width:calc(var(--spacing)*7);height:calc(var(--spacing)*7)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.h-3{height:calc(var(--spacing)*3)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-12{height:calc(var(--spacing)*12)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.h-svh{height:100svh}.max-h-\(--radix-dropdown-menu-content-available-height\){max-height:var(--radix-dropdown-menu-content-available-height)}.max-h-\(--radix-select-content-available-height\){max-height:var(--radix-select-content-available-height)}.max-h-56{max-height:calc(var(--spacing)*56)}.max-h-64{max-height:calc(var(--spacing)*64)}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-screen{min-height:100vh}.min-h-svh{min-height:100svh}.w-\(--sidebar-width\){width:var(--sidebar-width)}.w-3{width:calc(var(--spacing)*3)}.w-3\/4{width:75%}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-24{width:calc(var(--spacing)*24)}.w-36{width:calc(var(--spacing)*36)}.w-40{width:calc(var(--spacing)*40)}.w-48{width:calc(var(--spacing)*48)}.w-56{width:calc(var(--spacing)*56)}.w-64{width:calc(var(--spacing)*64)}.w-72{width:calc(var(--spacing)*72)}.w-\[120px\]{width:120px}.w-\[160px\]{width:160px}.w-\[180px\]{width:180px}.w-\[200px\]{width:200px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\(--skeleton-width\){max-width:var(--skeleton-width)}.max-w-\[70vw\]{max-width:70vw}.max-w-\[calc\(100\%-2rem\)\]{max-width:calc(100% - 2rem)}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.max-w-xl{max-width:var(--container-xl)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-5{min-width:calc(var(--spacing)*5)}.min-w-\[8rem\]{min-width:8rem}.min-w-\[360px\]{min-width:360px}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.origin-\(--radix-dropdown-menu-content-transform-origin\){transform-origin:var(--radix-dropdown-menu-content-transform-origin)}.origin-\(--radix-select-content-transform-origin\){transform-origin:var(--radix-select-content-transform-origin)}.origin-\(--radix-tooltip-content-transform-origin\){transform-origin:var(--radix-tooltip-content-transform-origin)}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-x-px{--tw-translate-x:-1px;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-px{--tw-translate-x:1px;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-\[-50\%\]{--tw-translate-y:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-\[calc\(-50\%_-_2px\)\]{--tw-translate-y: calc(-50% - 2px) ;translate:var(--tw-translate-x)var(--tw-translate-y)}.rotate-45{rotate:45deg}.animate-in{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.animate-pulse{animation:var(--animate-pulse)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.scroll-my-1{scroll-margin-block:calc(var(--spacing)*1)}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-rows-\[auto_auto\]{grid-template-rows:auto auto}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*2)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-4>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*4)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-x-reverse)))}.self-start{align-self:flex-start}.justify-self-end{justify-self:flex-end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[2px\]{border-radius:2px}.rounded-\[4px\]{border-radius:4px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.rounded-xs{border-radius:var(--radius-xs)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-input{border-color:var(--input)}.border-sidebar-border{border-color:var(--sidebar-border)}.border-transparent{border-color:#0000}.bg-accent{background-color:var(--accent)}.bg-background{background-color:var(--background)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black)50%,transparent)}}.bg-border{background-color:var(--border)}.bg-card{background-color:var(--card)}.bg-destructive{background-color:var(--destructive)}.bg-muted,.bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab,red,red)){.bg-muted\/50{background-color:color-mix(in oklab,var(--muted)50%,transparent)}}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-secondary{background-color:var(--secondary)}.bg-sidebar{background-color:var(--sidebar)}.bg-sidebar-border{background-color:var(--sidebar-border)}.bg-transparent{background-color:#0000}.fill-current{fill:currentColor}.fill-primary{fill:var(--primary)}.p-0{padding:calc(var(--spacing)*0)}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-6{padding-block:calc(var(--spacing)*6)}.py-8{padding-block:calc(var(--spacing)*8)}.py-10{padding-block:calc(var(--spacing)*10)}.pt-4{padding-top:calc(var(--spacing)*4)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-8{padding-right:calc(var(--spacing)*8)}.pl-2{padding-left:calc(var(--spacing)*2)}.pl-8{padding-left:calc(var(--spacing)*8)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-loose{--tw-leading:var(--leading-loose);line-height:var(--leading-loose)}.leading-none{--tw-leading:1;line-height:1}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-balance{text-wrap:balance}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-accent-foreground{color:var(--accent-foreground)}.text-card-foreground{color:var(--card-foreground)}.text-current{color:currentColor}.text-destructive{color:var(--destructive)}.text-foreground{color:var(--foreground)}.text-muted-foreground{color:var(--muted-foreground)}.text-popover-foreground{color:var(--popover-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-red-500{color:var(--color-red-500)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-sidebar-foreground,.text-sidebar-foreground\/70{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab,red,red)){.text-sidebar-foreground\/70{color:color-mix(in oklab,var(--sidebar-foreground)70%,transparent)}}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,)var(--tw-slashed-zero,)var(--tw-numeric-figure,)var(--tw-numeric-spacing,)var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-\[0_0_0_1px_hsl\(var\(--sidebar-border\)\)\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,hsl(var(--sidebar-border)));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-sidebar-ring{--tw-ring-color:var(--sidebar-ring)}.ring-offset-background{--tw-ring-offset-color:var(--background)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,visibility,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[color\,box-shadow\]{transition-property:color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[left\,right\,width\]{transition-property:left,right,width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[margin\,opacity\]{transition-property:margin,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\,height\,padding\]{transition-property:width,height,padding;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-none{transition-property:none}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-linear{--tw-ease:linear;transition-timing-function:linear}.fade-in-0{--tw-enter-opacity:0}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.zoom-in-95{--tw-enter-scale:.95}.group-focus-within\/menu-item\:opacity-100:is(:where(.group\/menu-item):focus-within *){opacity:1}@media (hover:hover){.group-hover\/menu-item\:opacity-100:is(:where(.group\/menu-item):hover *){opacity:1}}.group-has-data-\[sidebar\=menu-action\]\/menu-item\:pr-8:is(:where(.group\/menu-item):has([data-sidebar=menu-action]) *){padding-right:calc(var(--spacing)*8)}.group-data-\[collapsible\=icon\]\:-mt-8:is(:where(.group)[data-collapsible=icon] *){margin-top:calc(var(--spacing)*-8)}.group-data-\[collapsible\=icon\]\:hidden:is(:where(.group)[data-collapsible=icon] *){display:none}.group-data-\[collapsible\=icon\]\:size-8\!:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--spacing)*8)!important;height:calc(var(--spacing)*8)!important}.group-data-\[collapsible\=icon\]\:w-\(--sidebar-width-icon\):is(:where(.group)[data-collapsible=icon] *){width:var(--sidebar-width-icon)}.group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\)\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing)*4)))}.group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\+2px\)\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing)*4)) + 2px)}.group-data-\[collapsible\=icon\]\:overflow-hidden:is(:where(.group)[data-collapsible=icon] *){overflow:hidden}.group-data-\[collapsible\=icon\]\:p-0\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing)*0)!important}.group-data-\[collapsible\=icon\]\:p-2\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing)*2)!important}.group-data-\[collapsible\=icon\]\:opacity-0:is(:where(.group)[data-collapsible=icon] *){opacity:0}.group-data-\[collapsible\=offcanvas\]\:right-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.group)[data-collapsible=offcanvas] *){right:calc(var(--sidebar-width)*-1)}.group-data-\[collapsible\=offcanvas\]\:left-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.group)[data-collapsible=offcanvas] *){left:calc(var(--sidebar-width)*-1)}.group-data-\[collapsible\=offcanvas\]\:w-0:is(:where(.group)[data-collapsible=offcanvas] *){width:calc(var(--spacing)*0)}.group-data-\[collapsible\=offcanvas\]\:translate-x-0:is(:where(.group)[data-collapsible=offcanvas] *){--tw-translate-x:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.group)[data-disabled=true] *){pointer-events:none}.group-data-\[disabled\=true\]\:opacity-50:is(:where(.group)[data-disabled=true] *){opacity:.5}.group-data-\[side\=left\]\:-right-4:is(:where(.group)[data-side=left] *){right:calc(var(--spacing)*-4)}.group-data-\[side\=left\]\:border-r:is(:where(.group)[data-side=left] *){border-right-style:var(--tw-border-style);border-right-width:1px}.group-data-\[side\=right\]\:left-0:is(:where(.group)[data-side=right] *){left:calc(var(--spacing)*0)}.group-data-\[side\=right\]\:rotate-180:is(:where(.group)[data-side=right] *){rotate:180deg}.group-data-\[side\=right\]\:border-l:is(:where(.group)[data-side=right] *){border-left-style:var(--tw-border-style);border-left-width:1px}.group-data-\[state\=open\]\/collapsible\:rotate-180:is(:where(.group\/collapsible)[data-state=open] *){rotate:180deg}.group-data-\[variant\=floating\]\:rounded-lg:is(:where(.group)[data-variant=floating] *){border-radius:var(--radius)}.group-data-\[variant\=floating\]\:border:is(:where(.group)[data-variant=floating] *){border-style:var(--tw-border-style);border-width:1px}.group-data-\[variant\=floating\]\:border-sidebar-border:is(:where(.group)[data-variant=floating] *){border-color:var(--sidebar-border)}.group-data-\[variant\=floating\]\:shadow-sm:is(:where(.group)[data-variant=floating] *){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}@media (hover:hover){.peer-hover\/menu-button\:text-sidebar-accent-foreground:is(:where(.peer\/menu-button):hover~*){color:var(--sidebar-accent-foreground)}}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-50:is(:where(.peer):disabled~*){opacity:.5}.peer-data-\[active\=true\]\/menu-button\:text-sidebar-accent-foreground:is(:where(.peer\/menu-button)[data-active=true]~*){color:var(--sidebar-accent-foreground)}.peer-data-\[size\=default\]\/menu-button\:top-1\.5:is(:where(.peer\/menu-button)[data-size=default]~*){top:calc(var(--spacing)*1.5)}.peer-data-\[size\=lg\]\/menu-button\:top-2\.5:is(:where(.peer\/menu-button)[data-size=lg]~*){top:calc(var(--spacing)*2.5)}.peer-data-\[size\=sm\]\/menu-button\:top-1:is(:where(.peer\/menu-button)[data-size=sm]~*){top:calc(var(--spacing)*1)}.selection\:bg-primary ::selection{background-color:var(--primary)}.selection\:bg-primary::selection{background-color:var(--primary)}.selection\:text-primary-foreground ::selection{color:var(--primary-foreground)}.selection\:text-primary-foreground::selection{color:var(--primary-foreground)}.file\:inline-flex::file-selector-button{display:inline-flex}.file\:h-7::file-selector-button{height:calc(var(--spacing)*7)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:-inset-2:after{content:var(--tw-content);inset:calc(var(--spacing)*-2)}.after\:inset-y-0:after{content:var(--tw-content);inset-block:calc(var(--spacing)*0)}.after\:left-1\/2:after{content:var(--tw-content);left:50%}.after\:w-\[2px\]:after{content:var(--tw-content);width:2px}.group-data-\[collapsible\=offcanvas\]\:after\:left-full:is(:where(.group)[data-collapsible=offcanvas] *):after{content:var(--tw-content);left:100%}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--destructive)90%,transparent)}}.hover\:bg-muted\/50:hover{background-color:var(--muted)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab,var(--muted)50%,transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--primary)90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--secondary)80%,transparent)}}.hover\:bg-sidebar-accent:hover{background-color:var(--sidebar-accent)}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:text-sidebar-accent-foreground:hover{color:var(--sidebar-accent-foreground)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-\[0_0_0_1px_hsl\(var\(--sidebar-accent\)\)\]:hover{--tw-shadow:0 0 0 1px var(--tw-shadow-color,hsl(var(--sidebar-accent)));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:group-data-\[collapsible\=offcanvas\]\:bg-sidebar:hover:is(:where(.group)[data-collapsible=offcanvas] *){background-color:var(--sidebar)}.hover\:after\:bg-sidebar-border:hover:after{content:var(--tw-content);background-color:var(--sidebar-border)}}.focus\:bg-accent:focus{background-color:var(--accent)}.focus\:text-accent-foreground:focus{color:var(--accent-foreground)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-ring:focus{--tw-ring-color:var(--ring)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--ring)50%,transparent)}}.active\:bg-sidebar-accent:active{background-color:var(--sidebar-accent)}.active\:text-sidebar-accent-foreground:active{color:var(--sidebar-accent-foreground)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}:where([data-side=left]) .in-data-\[side\=left\]\:cursor-w-resize{cursor:w-resize}:where([data-side=right]) .in-data-\[side\=right\]\:cursor-e-resize{cursor:e-resize}.has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.has-data-\[variant\=inset\]\:bg-sidebar:has([data-variant=inset]){background-color:var(--sidebar)}.has-\[\>svg\]\:px-2\.5:has(>svg){padding-inline:calc(var(--spacing)*2.5)}.has-\[\>svg\]\:px-3:has(>svg){padding-inline:calc(var(--spacing)*3)}.has-\[\>svg\]\:px-4:has(>svg){padding-inline:calc(var(--spacing)*4)}.aria-disabled\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.data-\[active\=true\]\:bg-sidebar-accent[data-active=true]{background-color:var(--sidebar-accent)}.data-\[active\=true\]\:font-medium[data-active=true]{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.data-\[active\=true\]\:text-sidebar-accent-foreground[data-active=true]{color:var(--sidebar-accent-foreground)}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[error\=true\]\:text-destructive[data-error=true]{color:var(--destructive)}.data-\[inset\]\:pl-8[data-inset]{padding-left:calc(var(--spacing)*8)}.data-\[orientation\=horizontal\]\:h-px[data-orientation=horizontal]{height:1px}.data-\[orientation\=horizontal\]\:w-full[data-orientation=horizontal]{width:100%}.data-\[orientation\=vertical\]\:h-full[data-orientation=vertical]{height:100%}.data-\[orientation\=vertical\]\:w-px[data-orientation=vertical]{width:1px}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:var(--muted-foreground)}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y:calc(var(--spacing)*1);translate:var(--tw-translate-x)var(--tw-translate-y)}.data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y:calc(var(--spacing)*2*-1)}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x:calc(var(--spacing)*-1);translate:var(--tw-translate-x)var(--tw-translate-y)}.data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x:calc(var(--spacing)*2)}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x:calc(var(--spacing)*1);translate:var(--tw-translate-x)var(--tw-translate-y)}.data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x:calc(var(--spacing)*2*-1)}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y:calc(var(--spacing)*-1);translate:var(--tw-translate-x)var(--tw-translate-y)}.data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y:calc(var(--spacing)*2)}.data-\[size\=default\]\:h-9[data-size=default]{height:calc(var(--spacing)*9)}.data-\[size\=sm\]\:h-8[data-size=sm]{height:calc(var(--spacing)*8)}:is(.\*\:data-\[slot\=select-value\]\:line-clamp-1>*)[data-slot=select-value]{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:is(.\*\:data-\[slot\=select-value\]\:flex>*)[data-slot=select-value]{display:flex}:is(.\*\:data-\[slot\=select-value\]\:items-center>*)[data-slot=select-value]{align-items:center}:is(.\*\:data-\[slot\=select-value\]\:gap-2>*)[data-slot=select-value]{gap:calc(var(--spacing)*2)}.data-\[state\=checked\]\:border-primary[data-state=checked]{border-color:var(--primary)}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:var(--primary)}.data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:var(--primary-foreground)}.data-\[state\=closed\]\:animate-out[data-state=closed]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.data-\[state\=closed\]\:duration-300[data-state=closed]{--tw-duration:.3s;transition-duration:.3s}.data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity:0}.data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale:.95}.data-\[state\=closed\]\:slide-out-to-bottom[data-state=closed]{--tw-exit-translate-y:100%}.data-\[state\=closed\]\:slide-out-to-left[data-state=closed]{--tw-exit-translate-x:-100%}.data-\[state\=closed\]\:slide-out-to-right[data-state=closed]{--tw-exit-translate-x:100%}.data-\[state\=closed\]\:slide-out-to-top[data-state=closed]{--tw-exit-translate-y:-100%}.data-\[state\=open\]\:animate-in[data-state=open]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:var(--accent)}.data-\[state\=open\]\:bg-secondary[data-state=open]{background-color:var(--secondary)}.data-\[state\=open\]\:text-accent-foreground[data-state=open]{color:var(--accent-foreground)}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:var(--muted-foreground)}.data-\[state\=open\]\:opacity-100[data-state=open]{opacity:1}.data-\[state\=open\]\:duration-500[data-state=open]{--tw-duration:.5s;transition-duration:.5s}.data-\[state\=open\]\:fade-in-0[data-state=open]{--tw-enter-opacity:0}.data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale:.95}.data-\[state\=open\]\:slide-in-from-bottom[data-state=open]{--tw-enter-translate-y:100%}.data-\[state\=open\]\:slide-in-from-left[data-state=open]{--tw-enter-translate-x:-100%}.data-\[state\=open\]\:slide-in-from-right[data-state=open]{--tw-enter-translate-x:100%}.data-\[state\=open\]\:slide-in-from-top[data-state=open]{--tw-enter-translate-y:-100%}@media (hover:hover){.data-\[state\=open\]\:hover\:bg-sidebar-accent[data-state=open]:hover{background-color:var(--sidebar-accent)}.data-\[state\=open\]\:hover\:text-sidebar-accent-foreground[data-state=open]:hover{color:var(--sidebar-accent-foreground)}}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:var(--muted)}.data-\[variant\=destructive\]\:text-destructive[data-variant=destructive]{color:var(--destructive)}.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:color-mix(in oklab,var(--destructive)10%,transparent)}}.data-\[variant\=destructive\]\:focus\:text-destructive[data-variant=destructive]:focus{color:var(--destructive)}@media (min-width:40rem){.sm\:flex{display:flex}.sm\:max-w-2xl{max-width:var(--container-2xl)}.sm\:max-w-\[480px\]{max-width:480px}.sm\:max-w-\[520px\]{max-width:520px}.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:max-w-md{max-width:var(--container-md)}.sm\:max-w-sm{max-width:var(--container-sm)}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:justify-end{justify-content:flex-end}.sm\:text-left{text-align:left}}@media (min-width:48rem){.md\:block{display:block}.md\:flex{display:flex}.md\:h-24{height:calc(var(--spacing)*24)}.md\:max-w-\[48ch\]{max-width:48ch}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}.md\:gap-2{gap:calc(var(--spacing)*2)}.md\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.md\:px-0{padding-inline:calc(var(--spacing)*0)}.md\:py-0{padding-block:calc(var(--spacing)*0)}.md\:text-left{text-align:left}.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.md\:break-normal{overflow-wrap:normal;word-break:normal}.md\:opacity-0{opacity:0}.md\:peer-data-\[variant\=inset\]\:m-2:is(:where(.peer)[data-variant=inset]~*){margin:calc(var(--spacing)*2)}.md\:peer-data-\[variant\=inset\]\:ml-0:is(:where(.peer)[data-variant=inset]~*){margin-left:calc(var(--spacing)*0)}.md\:peer-data-\[variant\=inset\]\:rounded-xl:is(:where(.peer)[data-variant=inset]~*){border-radius:calc(var(--radius) + 4px)}.md\:peer-data-\[variant\=inset\]\:shadow-sm:is(:where(.peer)[data-variant=inset]~*){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.md\:peer-data-\[variant\=inset\]\:peer-data-\[state\=collapsed\]\:ml-2:is(:where(.peer)[data-variant=inset]~*):is(:where(.peer)[data-state=collapsed]~*){margin-left:calc(var(--spacing)*2)}.md\:after\:hidden:after{content:var(--tw-content);display:none}}@media (min-width:64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}.dark\:border-input:is(.dark *){border-color:var(--input)}.dark\:bg-destructive\/60:is(.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:bg-destructive\/60:is(.dark *){background-color:color-mix(in oklab,var(--destructive)60%,transparent)}}.dark\:bg-input\/30:is(.dark *){background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\:bg-input\/30:is(.dark *){background-color:color-mix(in oklab,var(--input)30%,transparent)}}@media (hover:hover){.dark\:hover\:bg-accent\/50:is(.dark *):hover{background-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-accent\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--accent)50%,transparent)}}.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--input)50%,transparent)}}}.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\:data-\[state\=checked\]\:bg-primary:is(.dark *)[data-state=checked]{background-color:var(--primary)}.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:is(.dark *)[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:is(.dark *)[data-variant=destructive]:focus{background-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\[\&_svg\:not\(\[class\*\=\'text-\'\]\)\]\:text-muted-foreground svg:not([class*=text-]){color:var(--muted-foreground)}.\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:calc(var(--spacing)*0)}.\[\.border-b\]\:pb-6.border-b{padding-bottom:calc(var(--spacing)*6)}.\[\.border-t\]\:pt-6.border-t{padding-top:calc(var(--spacing)*6)}:is(.\*\:\[span\]\:last\:flex>*):is(span):last-child{display:flex}:is(.\*\:\[span\]\:last\:items-center>*):is(span):last-child{align-items:center}:is(.\*\:\[span\]\:last\:gap-2>*):is(span):last-child{gap:calc(var(--spacing)*2)}:is(.data-\[variant\=destructive\]\:\*\:\[svg\]\:\!text-destructive[data-variant=destructive]>*):is(svg){color:var(--destructive)!important}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y:2px;translate:var(--tw-translate-x)var(--tw-translate-y)}.\[\&\>button\]\:hidden>button{display:none}.\[\&\>span\:last-child\]\:truncate>span:last-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\[\&\>svg\]\:pointer-events-none>svg{pointer-events:none}.\[\&\>svg\]\:size-3>svg{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.\[\&\>svg\]\:size-4>svg{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\[\&\>svg\]\:shrink-0>svg{flex-shrink:0}.\[\&\>svg\]\:text-sidebar-accent-foreground>svg{color:var(--sidebar-accent-foreground)}.\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}[data-side=left][data-collapsible=offcanvas] .\[\[data-side\=left\]\[data-collapsible\=offcanvas\]_\&\]\:-right-2{right:calc(var(--spacing)*-2)}[data-side=left][data-state=collapsed] .\[\[data-side\=left\]\[data-state\=collapsed\]_\&\]\:cursor-e-resize{cursor:e-resize}[data-side=right][data-collapsible=offcanvas] .\[\[data-side\=right\]\[data-collapsible\=offcanvas\]_\&\]\:-left-2{left:calc(var(--spacing)*-2)}[data-side=right][data-state=collapsed] .\[\[data-side\=right\]\[data-state\=collapsed\]_\&\]\:cursor-w-resize{cursor:w-resize}@media (hover:hover){a.\[a\&\]\:hover\:bg-accent:hover{background-color:var(--accent)}a.\[a\&\]\:hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){a.\[a\&\]\:hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--destructive)90%,transparent)}}a.\[a\&\]\:hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){a.\[a\&\]\:hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--primary)90%,transparent)}}a.\[a\&\]\:hover\:bg-secondary\/90:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){a.\[a\&\]\:hover\:bg-secondary\/90:hover{background-color:color-mix(in oklab,var(--secondary)90%,transparent)}}a.\[a\&\]\:hover\:text-accent-foreground:hover{color:var(--accent-foreground)}}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}:root{--radius:.625rem;--background:oklch(100% 0 0);--foreground:oklch(14.1% .005 285.823);--card:oklch(100% 0 0);--card-foreground:oklch(14.1% .005 285.823);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.1% .005 285.823);--primary:oklch(21% .006 285.885);--primary-foreground:oklch(98.5% 0 0);--secondary:oklch(96.7% .001 286.375);--secondary-foreground:oklch(21% .006 285.885);--muted:oklch(96.7% .001 286.375);--muted-foreground:oklch(55.2% .016 285.938);--accent:oklch(96.7% .001 286.375);--accent-foreground:oklch(21% .006 285.885);--destructive:oklch(57.7% .245 27.325);--border:oklch(92% .004 286.32);--input:oklch(92% .004 286.32);--ring:oklch(70.5% .015 286.067);--chart-1:oklch(64.6% .222 41.116);--chart-2:oklch(60% .118 184.704);--chart-3:oklch(39.8% .07 227.392);--chart-4:oklch(82.8% .189 84.429);--chart-5:oklch(76.9% .188 70.08);--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.1% .005 285.823);--sidebar-primary:oklch(21% .006 285.885);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(96.7% .001 286.375);--sidebar-accent-foreground:oklch(21% .006 285.885);--sidebar-border:oklch(92% .004 286.32);--sidebar-ring:oklch(70.5% .015 286.067)}.dark{--background:oklch(14.1% .005 285.823);--foreground:oklch(98.5% 0 0);--card:oklch(21% .006 285.885);--card-foreground:oklch(98.5% 0 0);--popover:oklch(21% .006 285.885);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(92% .004 286.32);--primary-foreground:oklch(21% .006 285.885);--secondary:oklch(27.4% .006 286.033);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(27.4% .006 286.033);--muted-foreground:oklch(70.5% .015 286.067);--accent:oklch(27.4% .006 286.033);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.2% .016 285.938);--chart-1:oklch(48.8% .243 264.376);--chart-2:oklch(69.6% .17 162.48);--chart-3:oklch(76.9% .188 70.08);--chart-4:oklch(62.7% .265 303.9);--chart-5:oklch(64.5% .246 16.439);--sidebar:oklch(21% .006 285.885);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(48.8% .243 264.376);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(27.4% .006 286.033);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.2% .016 285.938)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes pulse{50%{opacity:.5}}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0));filter:blur(var(--tw-enter-blur,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,0));filter:blur(var(--tw-exit-blur,0))}} diff --git a/internal/ui/dist/assets/index-CHoyJPs-.css b/internal/ui/dist/assets/index-CHoyJPs-.css new file mode 100644 index 0000000..a27ddb6 --- /dev/null +++ b/internal/ui/dist/assets/index-CHoyJPs-.css @@ -0,0 +1 @@ +/*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:"";--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-300:oklch(80.8% .114 19.571);--color-red-500:oklch(63.7% .237 25.331);--color-red-800:oklch(44.4% .177 26.899);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-900:oklch(20.8% .042 265.755);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-widest:.1em;--leading-tight:1.25;--leading-loose:2;--radius-xs:.125rem;--radius-2xl:1rem;--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){*{outline-color:color-mix(in oklab,var(--ring)50%,transparent)}}body{background-color:var(--background);color:var(--foreground)}}@layer components;@layer utilities{.\@container\/card-header{container:card-header/inline-size}.pointer-events-none{pointer-events:none}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.inset-x-0{inset-inline:calc(var(--spacing)*0)}.inset-y-0{inset-block:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-1\.5{top:calc(var(--spacing)*1.5)}.top-2\.5{top:calc(var(--spacing)*2.5)}.top-3\.5{top:calc(var(--spacing)*3.5)}.top-4{top:calc(var(--spacing)*4)}.top-\[50\%\]{top:50%}.right-0{right:calc(var(--spacing)*0)}.right-1{right:calc(var(--spacing)*1)}.right-2{right:calc(var(--spacing)*2)}.right-3{right:calc(var(--spacing)*3)}.right-4{right:calc(var(--spacing)*4)}.bottom-0{bottom:calc(var(--spacing)*0)}.left-0{left:calc(var(--spacing)*0)}.left-2{left:calc(var(--spacing)*2)}.left-\[50\%\]{left:50%}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-start-2{grid-column-start:2}.row-span-2{grid-row:span 2/span 2}.row-start-1{grid-row-start:1}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.-mx-1{margin-inline:calc(var(--spacing)*-1)}.mx-2{margin-inline:calc(var(--spacing)*2)}.mx-3\.5{margin-inline:calc(var(--spacing)*3.5)}.mx-auto{margin-inline:auto}.my-1{margin-block:calc(var(--spacing)*1)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-auto{margin-top:auto}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-2{margin-right:calc(var(--spacing)*2)}.mr-4{margin-right:calc(var(--spacing)*4)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-auto{margin-left:auto}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-row{display:table-row}.field-sizing-content{field-sizing:content}.aspect-square{aspect-ratio:1}.size-2{width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}.size-2\.5{width:calc(var(--spacing)*2.5);height:calc(var(--spacing)*2.5)}.size-3\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-7{width:calc(var(--spacing)*7);height:calc(var(--spacing)*7)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.h-3{height:calc(var(--spacing)*3)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-12{height:calc(var(--spacing)*12)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.h-svh{height:100svh}.max-h-\(--radix-dropdown-menu-content-available-height\){max-height:var(--radix-dropdown-menu-content-available-height)}.max-h-\(--radix-select-content-available-height\){max-height:var(--radix-select-content-available-height)}.max-h-56{max-height:calc(var(--spacing)*56)}.max-h-64{max-height:calc(var(--spacing)*64)}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-16{min-height:calc(var(--spacing)*16)}.min-h-screen{min-height:100vh}.min-h-svh{min-height:100svh}.w-\(--sidebar-width\){width:var(--sidebar-width)}.w-3{width:calc(var(--spacing)*3)}.w-3\/4{width:75%}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-6{width:calc(var(--spacing)*6)}.w-24{width:calc(var(--spacing)*24)}.w-36{width:calc(var(--spacing)*36)}.w-40{width:calc(var(--spacing)*40)}.w-48{width:calc(var(--spacing)*48)}.w-56{width:calc(var(--spacing)*56)}.w-64{width:calc(var(--spacing)*64)}.w-72{width:calc(var(--spacing)*72)}.w-\[120px\]{width:120px}.w-\[160px\]{width:160px}.w-\[180px\]{width:180px}.w-\[200px\]{width:200px}.w-\[260px\]{width:260px}.w-\[360px\]{width:360px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\(--skeleton-width\){max-width:var(--skeleton-width)}.max-w-\[70vw\]{max-width:70vw}.max-w-\[280px\]{max-width:280px}.max-w-\[calc\(100\%-2rem\)\]{max-width:calc(100% - 2rem)}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.max-w-xl{max-width:var(--container-xl)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-5{min-width:calc(var(--spacing)*5)}.min-w-\[8rem\]{min-width:8rem}.min-w-\[360px\]{min-width:360px}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.min-w-full{min-width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.origin-\(--radix-dropdown-menu-content-transform-origin\){transform-origin:var(--radix-dropdown-menu-content-transform-origin)}.origin-\(--radix-select-content-transform-origin\){transform-origin:var(--radix-select-content-transform-origin)}.origin-\(--radix-tooltip-content-transform-origin\){transform-origin:var(--radix-tooltip-content-transform-origin)}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-x-px{--tw-translate-x:-1px;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-px{--tw-translate-x:1px;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-\[-50\%\]{--tw-translate-y:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-\[calc\(-50\%_-_2px\)\]{--tw-translate-y: calc(-50% - 2px) ;translate:var(--tw-translate-x)var(--tw-translate-y)}.rotate-45{rotate:45deg}.animate-in{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.animate-pulse{animation:var(--animate-pulse)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.scroll-my-1{scroll-margin-block:calc(var(--spacing)*1)}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-rows-\[auto_auto\]{grid-template-rows:auto auto}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*2)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-4>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*4)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-x-reverse)))}.self-start{align-self:flex-start}.justify-self-end{justify-self:flex-end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[2px\]{border-radius:2px}.rounded-\[4px\]{border-radius:4px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.rounded-xs{border-radius:var(--radius-xs)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-input{border-color:var(--input)}.border-red-300{border-color:var(--color-red-300)}.border-sidebar-border{border-color:var(--sidebar-border)}.border-transparent{border-color:#0000}.bg-accent{background-color:var(--accent)}.bg-background{background-color:var(--background)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black)50%,transparent)}}.bg-border{background-color:var(--border)}.bg-card{background-color:var(--card)}.bg-destructive{background-color:var(--destructive)}.bg-muted,.bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab,red,red)){.bg-muted\/50{background-color:color-mix(in oklab,var(--muted)50%,transparent)}}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-red-50{background-color:var(--color-red-50)}.bg-secondary{background-color:var(--secondary)}.bg-sidebar{background-color:var(--sidebar)}.bg-sidebar-border{background-color:var(--sidebar-border)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-transparent{background-color:#0000}.fill-current{fill:currentColor}.fill-primary{fill:var(--primary)}.p-0{padding:calc(var(--spacing)*0)}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-6{padding-block:calc(var(--spacing)*6)}.py-8{padding-block:calc(var(--spacing)*8)}.py-10{padding-block:calc(var(--spacing)*10)}.pt-4{padding-top:calc(var(--spacing)*4)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-8{padding-right:calc(var(--spacing)*8)}.pl-2{padding-left:calc(var(--spacing)*2)}.pl-8{padding-left:calc(var(--spacing)*8)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-loose{--tw-leading:var(--leading-loose);line-height:var(--leading-loose)}.leading-none{--tw-leading:1;line-height:1}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-balance{text-wrap:balance}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-accent-foreground{color:var(--accent-foreground)}.text-card-foreground{color:var(--card-foreground)}.text-current{color:currentColor}.text-destructive{color:var(--destructive)}.text-foreground{color:var(--foreground)}.text-muted-foreground{color:var(--muted-foreground)}.text-popover-foreground{color:var(--popover-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-red-500{color:var(--color-red-500)}.text-red-800{color:var(--color-red-800)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-sidebar-foreground,.text-sidebar-foreground\/70{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab,red,red)){.text-sidebar-foreground\/70{color:color-mix(in oklab,var(--sidebar-foreground)70%,transparent)}}.text-slate-500{color:var(--color-slate-500)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,)var(--tw-slashed-zero,)var(--tw-numeric-figure,)var(--tw-numeric-spacing,)var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-\[0_0_0_1px_hsl\(var\(--sidebar-border\)\)\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,hsl(var(--sidebar-border)));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-sidebar-ring{--tw-ring-color:var(--sidebar-ring)}.ring-offset-background{--tw-ring-offset-color:var(--background)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,visibility,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[color\,box-shadow\]{transition-property:color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[left\,right\,width\]{transition-property:left,right,width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[margin\,opacity\]{transition-property:margin,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\,height\,padding\]{transition-property:width,height,padding;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-none{transition-property:none}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-linear{--tw-ease:linear;transition-timing-function:linear}.fade-in-0{--tw-enter-opacity:0}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.zoom-in-95{--tw-enter-scale:.95}.running{animation-play-state:running}.group-focus-within\/menu-item\:opacity-100:is(:where(.group\/menu-item):focus-within *){opacity:1}@media (hover:hover){.group-hover\/menu-item\:opacity-100:is(:where(.group\/menu-item):hover *){opacity:1}}.group-has-data-\[sidebar\=menu-action\]\/menu-item\:pr-8:is(:where(.group\/menu-item):has([data-sidebar=menu-action]) *){padding-right:calc(var(--spacing)*8)}.group-data-\[collapsible\=icon\]\:-mt-8:is(:where(.group)[data-collapsible=icon] *){margin-top:calc(var(--spacing)*-8)}.group-data-\[collapsible\=icon\]\:hidden:is(:where(.group)[data-collapsible=icon] *){display:none}.group-data-\[collapsible\=icon\]\:size-8\!:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--spacing)*8)!important;height:calc(var(--spacing)*8)!important}.group-data-\[collapsible\=icon\]\:w-\(--sidebar-width-icon\):is(:where(.group)[data-collapsible=icon] *){width:var(--sidebar-width-icon)}.group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\)\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing)*4)))}.group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\+2px\)\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing)*4)) + 2px)}.group-data-\[collapsible\=icon\]\:overflow-hidden:is(:where(.group)[data-collapsible=icon] *){overflow:hidden}.group-data-\[collapsible\=icon\]\:p-0\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing)*0)!important}.group-data-\[collapsible\=icon\]\:p-2\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing)*2)!important}.group-data-\[collapsible\=icon\]\:opacity-0:is(:where(.group)[data-collapsible=icon] *){opacity:0}.group-data-\[collapsible\=offcanvas\]\:right-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.group)[data-collapsible=offcanvas] *){right:calc(var(--sidebar-width)*-1)}.group-data-\[collapsible\=offcanvas\]\:left-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.group)[data-collapsible=offcanvas] *){left:calc(var(--sidebar-width)*-1)}.group-data-\[collapsible\=offcanvas\]\:w-0:is(:where(.group)[data-collapsible=offcanvas] *){width:calc(var(--spacing)*0)}.group-data-\[collapsible\=offcanvas\]\:translate-x-0:is(:where(.group)[data-collapsible=offcanvas] *){--tw-translate-x:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.group)[data-disabled=true] *){pointer-events:none}.group-data-\[disabled\=true\]\:opacity-50:is(:where(.group)[data-disabled=true] *){opacity:.5}.group-data-\[side\=left\]\:-right-4:is(:where(.group)[data-side=left] *){right:calc(var(--spacing)*-4)}.group-data-\[side\=left\]\:border-r:is(:where(.group)[data-side=left] *){border-right-style:var(--tw-border-style);border-right-width:1px}.group-data-\[side\=right\]\:left-0:is(:where(.group)[data-side=right] *){left:calc(var(--spacing)*0)}.group-data-\[side\=right\]\:rotate-180:is(:where(.group)[data-side=right] *){rotate:180deg}.group-data-\[side\=right\]\:border-l:is(:where(.group)[data-side=right] *){border-left-style:var(--tw-border-style);border-left-width:1px}.group-data-\[state\=open\]\/collapsible\:rotate-180:is(:where(.group\/collapsible)[data-state=open] *){rotate:180deg}.group-data-\[variant\=floating\]\:rounded-lg:is(:where(.group)[data-variant=floating] *){border-radius:var(--radius)}.group-data-\[variant\=floating\]\:border:is(:where(.group)[data-variant=floating] *){border-style:var(--tw-border-style);border-width:1px}.group-data-\[variant\=floating\]\:border-sidebar-border:is(:where(.group)[data-variant=floating] *){border-color:var(--sidebar-border)}.group-data-\[variant\=floating\]\:shadow-sm:is(:where(.group)[data-variant=floating] *){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}@media (hover:hover){.peer-hover\/menu-button\:text-sidebar-accent-foreground:is(:where(.peer\/menu-button):hover~*){color:var(--sidebar-accent-foreground)}}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-50:is(:where(.peer):disabled~*){opacity:.5}.peer-data-\[active\=true\]\/menu-button\:text-sidebar-accent-foreground:is(:where(.peer\/menu-button)[data-active=true]~*){color:var(--sidebar-accent-foreground)}.peer-data-\[size\=default\]\/menu-button\:top-1\.5:is(:where(.peer\/menu-button)[data-size=default]~*){top:calc(var(--spacing)*1.5)}.peer-data-\[size\=lg\]\/menu-button\:top-2\.5:is(:where(.peer\/menu-button)[data-size=lg]~*){top:calc(var(--spacing)*2.5)}.peer-data-\[size\=sm\]\/menu-button\:top-1:is(:where(.peer\/menu-button)[data-size=sm]~*){top:calc(var(--spacing)*1)}.selection\:bg-primary ::selection{background-color:var(--primary)}.selection\:bg-primary::selection{background-color:var(--primary)}.selection\:text-primary-foreground ::selection{color:var(--primary-foreground)}.selection\:text-primary-foreground::selection{color:var(--primary-foreground)}.file\:inline-flex::file-selector-button{display:inline-flex}.file\:h-7::file-selector-button{height:calc(var(--spacing)*7)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:-inset-2:after{content:var(--tw-content);inset:calc(var(--spacing)*-2)}.after\:inset-y-0:after{content:var(--tw-content);inset-block:calc(var(--spacing)*0)}.after\:left-1\/2:after{content:var(--tw-content);left:50%}.after\:w-\[2px\]:after{content:var(--tw-content);width:2px}.group-data-\[collapsible\=offcanvas\]\:after\:left-full:is(:where(.group)[data-collapsible=offcanvas] *):after{content:var(--tw-content);left:100%}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--destructive)90%,transparent)}}.hover\:bg-muted\/50:hover{background-color:var(--muted)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab,var(--muted)50%,transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--primary)90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--secondary)80%,transparent)}}.hover\:bg-sidebar-accent:hover{background-color:var(--sidebar-accent)}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:text-sidebar-accent-foreground:hover{color:var(--sidebar-accent-foreground)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-\[0_0_0_1px_hsl\(var\(--sidebar-accent\)\)\]:hover{--tw-shadow:0 0 0 1px var(--tw-shadow-color,hsl(var(--sidebar-accent)));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:group-data-\[collapsible\=offcanvas\]\:bg-sidebar:hover:is(:where(.group)[data-collapsible=offcanvas] *){background-color:var(--sidebar)}.hover\:after\:bg-sidebar-border:hover:after{content:var(--tw-content);background-color:var(--sidebar-border)}}.focus\:bg-accent:focus{background-color:var(--accent)}.focus\:text-accent-foreground:focus{color:var(--accent-foreground)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-ring:focus{--tw-ring-color:var(--ring)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--ring)50%,transparent)}}.active\:bg-sidebar-accent:active{background-color:var(--sidebar-accent)}.active\:text-sidebar-accent-foreground:active{color:var(--sidebar-accent-foreground)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}:where([data-side=left]) .in-data-\[side\=left\]\:cursor-w-resize{cursor:w-resize}:where([data-side=right]) .in-data-\[side\=right\]\:cursor-e-resize{cursor:e-resize}.has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.has-data-\[variant\=inset\]\:bg-sidebar:has([data-variant=inset]){background-color:var(--sidebar)}.has-\[\>svg\]\:px-2\.5:has(>svg){padding-inline:calc(var(--spacing)*2.5)}.has-\[\>svg\]\:px-3:has(>svg){padding-inline:calc(var(--spacing)*3)}.has-\[\>svg\]\:px-4:has(>svg){padding-inline:calc(var(--spacing)*4)}.aria-disabled\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.data-\[active\=true\]\:bg-sidebar-accent[data-active=true]{background-color:var(--sidebar-accent)}.data-\[active\=true\]\:font-medium[data-active=true]{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.data-\[active\=true\]\:text-sidebar-accent-foreground[data-active=true]{color:var(--sidebar-accent-foreground)}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[error\=true\]\:text-destructive[data-error=true]{color:var(--destructive)}.data-\[inset\]\:pl-8[data-inset]{padding-left:calc(var(--spacing)*8)}.data-\[orientation\=horizontal\]\:h-px[data-orientation=horizontal]{height:1px}.data-\[orientation\=horizontal\]\:w-full[data-orientation=horizontal]{width:100%}.data-\[orientation\=vertical\]\:h-full[data-orientation=vertical]{height:100%}.data-\[orientation\=vertical\]\:w-px[data-orientation=vertical]{width:1px}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:var(--muted-foreground)}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y:calc(var(--spacing)*1);translate:var(--tw-translate-x)var(--tw-translate-y)}.data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y:calc(var(--spacing)*2*-1)}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x:calc(var(--spacing)*-1);translate:var(--tw-translate-x)var(--tw-translate-y)}.data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x:calc(var(--spacing)*2)}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x:calc(var(--spacing)*1);translate:var(--tw-translate-x)var(--tw-translate-y)}.data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x:calc(var(--spacing)*2*-1)}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y:calc(var(--spacing)*-1);translate:var(--tw-translate-x)var(--tw-translate-y)}.data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y:calc(var(--spacing)*2)}.data-\[size\=default\]\:h-9[data-size=default]{height:calc(var(--spacing)*9)}.data-\[size\=sm\]\:h-8[data-size=sm]{height:calc(var(--spacing)*8)}:is(.\*\:data-\[slot\=select-value\]\:line-clamp-1>*)[data-slot=select-value]{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:is(.\*\:data-\[slot\=select-value\]\:flex>*)[data-slot=select-value]{display:flex}:is(.\*\:data-\[slot\=select-value\]\:items-center>*)[data-slot=select-value]{align-items:center}:is(.\*\:data-\[slot\=select-value\]\:gap-2>*)[data-slot=select-value]{gap:calc(var(--spacing)*2)}.data-\[state\=checked\]\:border-primary[data-state=checked]{border-color:var(--primary)}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:var(--primary)}.data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:var(--primary-foreground)}.data-\[state\=closed\]\:animate-out[data-state=closed]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.data-\[state\=closed\]\:duration-300[data-state=closed]{--tw-duration:.3s;transition-duration:.3s}.data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity:0}.data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale:.95}.data-\[state\=closed\]\:slide-out-to-bottom[data-state=closed]{--tw-exit-translate-y:100%}.data-\[state\=closed\]\:slide-out-to-left[data-state=closed]{--tw-exit-translate-x:-100%}.data-\[state\=closed\]\:slide-out-to-right[data-state=closed]{--tw-exit-translate-x:100%}.data-\[state\=closed\]\:slide-out-to-top[data-state=closed]{--tw-exit-translate-y:-100%}.data-\[state\=open\]\:animate-in[data-state=open]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:var(--accent)}.data-\[state\=open\]\:bg-secondary[data-state=open]{background-color:var(--secondary)}.data-\[state\=open\]\:text-accent-foreground[data-state=open]{color:var(--accent-foreground)}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:var(--muted-foreground)}.data-\[state\=open\]\:opacity-100[data-state=open]{opacity:1}.data-\[state\=open\]\:duration-500[data-state=open]{--tw-duration:.5s;transition-duration:.5s}.data-\[state\=open\]\:fade-in-0[data-state=open]{--tw-enter-opacity:0}.data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale:.95}.data-\[state\=open\]\:slide-in-from-bottom[data-state=open]{--tw-enter-translate-y:100%}.data-\[state\=open\]\:slide-in-from-left[data-state=open]{--tw-enter-translate-x:-100%}.data-\[state\=open\]\:slide-in-from-right[data-state=open]{--tw-enter-translate-x:100%}.data-\[state\=open\]\:slide-in-from-top[data-state=open]{--tw-enter-translate-y:-100%}@media (hover:hover){.data-\[state\=open\]\:hover\:bg-sidebar-accent[data-state=open]:hover{background-color:var(--sidebar-accent)}.data-\[state\=open\]\:hover\:text-sidebar-accent-foreground[data-state=open]:hover{color:var(--sidebar-accent-foreground)}}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:var(--muted)}.data-\[variant\=destructive\]\:text-destructive[data-variant=destructive]{color:var(--destructive)}.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:color-mix(in oklab,var(--destructive)10%,transparent)}}.data-\[variant\=destructive\]\:focus\:text-destructive[data-variant=destructive]:focus{color:var(--destructive)}@media (min-width:40rem){.sm\:flex{display:flex}.sm\:max-w-2xl{max-width:var(--container-2xl)}.sm\:max-w-\[480px\]{max-width:480px}.sm\:max-w-\[520px\]{max-width:520px}.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:max-w-md{max-width:var(--container-md)}.sm\:max-w-sm{max-width:var(--container-sm)}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:justify-end{justify-content:flex-end}.sm\:text-left{text-align:left}}@media (min-width:48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:block{display:block}.md\:flex{display:flex}.md\:h-24{height:calc(var(--spacing)*24)}.md\:max-w-\[48ch\]{max-width:48ch}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}.md\:justify-end{justify-content:flex-end}.md\:gap-2{gap:calc(var(--spacing)*2)}.md\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.md\:px-0{padding-inline:calc(var(--spacing)*0)}.md\:py-0{padding-block:calc(var(--spacing)*0)}.md\:text-left{text-align:left}.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.md\:break-normal{overflow-wrap:normal;word-break:normal}.md\:opacity-0{opacity:0}.md\:peer-data-\[variant\=inset\]\:m-2:is(:where(.peer)[data-variant=inset]~*){margin:calc(var(--spacing)*2)}.md\:peer-data-\[variant\=inset\]\:ml-0:is(:where(.peer)[data-variant=inset]~*){margin-left:calc(var(--spacing)*0)}.md\:peer-data-\[variant\=inset\]\:rounded-xl:is(:where(.peer)[data-variant=inset]~*){border-radius:calc(var(--radius) + 4px)}.md\:peer-data-\[variant\=inset\]\:shadow-sm:is(:where(.peer)[data-variant=inset]~*){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.md\:peer-data-\[variant\=inset\]\:peer-data-\[state\=collapsed\]\:ml-2:is(:where(.peer)[data-variant=inset]~*):is(:where(.peer)[data-state=collapsed]~*){margin-left:calc(var(--spacing)*2)}.md\:after\:hidden:after{content:var(--tw-content);display:none}}@media (min-width:64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}.dark\:border-input:is(.dark *){border-color:var(--input)}.dark\:bg-destructive\/60:is(.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:bg-destructive\/60:is(.dark *){background-color:color-mix(in oklab,var(--destructive)60%,transparent)}}.dark\:bg-input\/30:is(.dark *){background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\:bg-input\/30:is(.dark *){background-color:color-mix(in oklab,var(--input)30%,transparent)}}@media (hover:hover){.dark\:hover\:bg-accent\/50:is(.dark *):hover{background-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-accent\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--accent)50%,transparent)}}.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--input)50%,transparent)}}}.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\:data-\[state\=checked\]\:bg-primary:is(.dark *)[data-state=checked]{background-color:var(--primary)}.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:is(.dark *)[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:is(.dark *)[data-variant=destructive]:focus{background-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\[\&_svg\:not\(\[class\*\=\'text-\'\]\)\]\:text-muted-foreground svg:not([class*=text-]){color:var(--muted-foreground)}.\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:calc(var(--spacing)*0)}.\[\.border-b\]\:pb-6.border-b{padding-bottom:calc(var(--spacing)*6)}.\[\.border-t\]\:pt-6.border-t{padding-top:calc(var(--spacing)*6)}:is(.\*\:\[span\]\:last\:flex>*):is(span):last-child{display:flex}:is(.\*\:\[span\]\:last\:items-center>*):is(span):last-child{align-items:center}:is(.\*\:\[span\]\:last\:gap-2>*):is(span):last-child{gap:calc(var(--spacing)*2)}:is(.data-\[variant\=destructive\]\:\*\:\[svg\]\:\!text-destructive[data-variant=destructive]>*):is(svg){color:var(--destructive)!important}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y:2px;translate:var(--tw-translate-x)var(--tw-translate-y)}.\[\&\>button\]\:hidden>button{display:none}.\[\&\>span\:last-child\]\:truncate>span:last-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\[\&\>svg\]\:pointer-events-none>svg{pointer-events:none}.\[\&\>svg\]\:size-3>svg{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.\[\&\>svg\]\:size-4>svg{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\[\&\>svg\]\:shrink-0>svg{flex-shrink:0}.\[\&\>svg\]\:text-sidebar-accent-foreground>svg{color:var(--sidebar-accent-foreground)}.\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}[data-side=left][data-collapsible=offcanvas] .\[\[data-side\=left\]\[data-collapsible\=offcanvas\]_\&\]\:-right-2{right:calc(var(--spacing)*-2)}[data-side=left][data-state=collapsed] .\[\[data-side\=left\]\[data-state\=collapsed\]_\&\]\:cursor-e-resize{cursor:e-resize}[data-side=right][data-collapsible=offcanvas] .\[\[data-side\=right\]\[data-collapsible\=offcanvas\]_\&\]\:-left-2{left:calc(var(--spacing)*-2)}[data-side=right][data-state=collapsed] .\[\[data-side\=right\]\[data-state\=collapsed\]_\&\]\:cursor-w-resize{cursor:w-resize}@media (hover:hover){a.\[a\&\]\:hover\:bg-accent:hover{background-color:var(--accent)}a.\[a\&\]\:hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){a.\[a\&\]\:hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--destructive)90%,transparent)}}a.\[a\&\]\:hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){a.\[a\&\]\:hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--primary)90%,transparent)}}a.\[a\&\]\:hover\:bg-secondary\/90:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){a.\[a\&\]\:hover\:bg-secondary\/90:hover{background-color:color-mix(in oklab,var(--secondary)90%,transparent)}}a.\[a\&\]\:hover\:text-accent-foreground:hover{color:var(--accent-foreground)}}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}:root{--radius:.625rem;--background:oklch(100% 0 0);--foreground:oklch(14.1% .005 285.823);--card:oklch(100% 0 0);--card-foreground:oklch(14.1% .005 285.823);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.1% .005 285.823);--primary:oklch(21% .006 285.885);--primary-foreground:oklch(98.5% 0 0);--secondary:oklch(96.7% .001 286.375);--secondary-foreground:oklch(21% .006 285.885);--muted:oklch(96.7% .001 286.375);--muted-foreground:oklch(55.2% .016 285.938);--accent:oklch(96.7% .001 286.375);--accent-foreground:oklch(21% .006 285.885);--destructive:oklch(57.7% .245 27.325);--border:oklch(92% .004 286.32);--input:oklch(92% .004 286.32);--ring:oklch(70.5% .015 286.067);--chart-1:oklch(64.6% .222 41.116);--chart-2:oklch(60% .118 184.704);--chart-3:oklch(39.8% .07 227.392);--chart-4:oklch(82.8% .189 84.429);--chart-5:oklch(76.9% .188 70.08);--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.1% .005 285.823);--sidebar-primary:oklch(21% .006 285.885);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(96.7% .001 286.375);--sidebar-accent-foreground:oklch(21% .006 285.885);--sidebar-border:oklch(92% .004 286.32);--sidebar-ring:oklch(70.5% .015 286.067)}.dark{--background:oklch(14.1% .005 285.823);--foreground:oklch(98.5% 0 0);--card:oklch(21% .006 285.885);--card-foreground:oklch(98.5% 0 0);--popover:oklch(21% .006 285.885);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(92% .004 286.32);--primary-foreground:oklch(21% .006 285.885);--secondary:oklch(27.4% .006 286.033);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(27.4% .006 286.033);--muted-foreground:oklch(70.5% .015 286.067);--accent:oklch(27.4% .006 286.033);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.2% .016 285.938);--chart-1:oklch(48.8% .243 264.376);--chart-2:oklch(69.6% .17 162.48);--chart-3:oklch(76.9% .188 70.08);--chart-4:oklch(62.7% .265 303.9);--chart-5:oklch(64.5% .246 16.439);--sidebar:oklch(21% .006 285.885);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(48.8% .243 264.376);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(27.4% .006 286.033);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.2% .016 285.938)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes pulse{50%{opacity:.5}}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0));filter:blur(var(--tw-enter-blur,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,0));filter:blur(var(--tw-exit-blur,0))}} diff --git a/internal/ui/dist/assets/index-CmZFDWt2.js b/internal/ui/dist/assets/index-CmZFDWt2.js deleted file mode 100644 index 1f1583c..0000000 --- a/internal/ui/dist/assets/index-CmZFDWt2.js +++ /dev/null @@ -1 +0,0 @@ -import{t as Xs,m as Qs,r as c,j as e,n as ss,z as Es,F as Zs,C as et,p as st,q as tt,v as J,w as R,_ as Ne,x as Se,y as at,A as B,B as K,D as O,E as zs,G as ts,T as rt,J as nt,H as it}from"./vendor-DvippHRz.js";import{S as Me,R as lt,a as Os,C as Ls,b as As,T as Ds,D as Ts,P as $s,O as Ms,c as ot,d as dt,e as ct,f as mt,g as ut,A as xt,h as ht,i as jt,j as ft,k as gt,l as pt,m as vt,n as bt,I as wt,o as yt,p as Nt,q as St,r as Ct,s as kt,t as _t,u as It,v as Et,w as zt,x as Ot,y as Lt,z as At,B as Dt,E as Tt,V as $t,F as Mt,G as Pt,H as Ft,J as Rt,K as Vt,L as Ht,M as Ut,N as Bt,Q as Kt,U as Gt}from"./radix-DRmH1vcw.js";import{X as Ps,S as qt,M as Jt,L as Wt,C as Ee,H as Yt,A as Xt,B as Qt,a as Zt,T as ea,b as sa,c as Fs,d as ta,K as aa,F as ra,e as na,f as ia,g as la,U as vs,h as oa,i as da,j as ca,k as as,l as ma,m as ua,P as Pe,n as Je,o as we,p as Rs,R as Vs,q as Ce,r as xa,s as ha,t as ja,u as bs}from"./icons-DQ1I1M7X.js";import{u as We,L as ve,O as rs,N as ns,a as Fe,b as Hs,R as fa,c as T,B as ga}from"./router-CANfZtzM.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const m of document.querySelectorAll('link[rel="modulepreload"]'))n(m);new MutationObserver(m=>{for(const u of m)if(u.type==="childList")for(const g of u.addedNodes)g.tagName==="LINK"&&g.rel==="modulepreload"&&n(g)}).observe(document,{childList:!0,subtree:!0});function a(m){const u={};return m.integrity&&(u.integrity=m.integrity),m.referrerPolicy&&(u.referrerPolicy=m.referrerPolicy),m.crossOrigin==="use-credentials"?u.credentials="include":m.crossOrigin==="anonymous"?u.credentials="omit":u.credentials="same-origin",u}function n(m){if(m.ep)return;m.ep=!0;const u=a(m);fetch(m.href,u)}})();function h(...s){return Xs(Qs(s))}function ws(s){return s.toLowerCase().trim().replace(/['"]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)+/g,"")}const Qe=768;function pa(){const[s,t]=c.useState(void 0);return c.useEffect(()=>{const a=window.matchMedia(`(max-width: ${Qe-1}px)`),n=()=>{t(window.innerWidtha.removeEventListener("change",n)},[]),!!s}const is=ss("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",{variants:{variant:{default:"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",destructive:"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",outline:"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",secondary:"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2 has-[>svg]:px-3",sm:"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",lg:"h-10 rounded-md px-6 has-[>svg]:px-4",icon:"size-9"}},defaultVariants:{variant:"default",size:"default"}});function x({className:s,variant:t,size:a,asChild:n=!1,...m}){const u=n?Me:"button";return e.jsx(u,{"data-slot":"button",className:h(is({variant:t,size:a,className:s})),...m})}function L({className:s,type:t,...a}){return e.jsx("input",{type:t,"data-slot":"input",className:h("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm","focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]","aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",s),...a})}function ze({className:s,orientation:t="horizontal",decorative:a=!0,...n}){return e.jsx(lt,{"data-slot":"separator",decorative:a,orientation:t,className:h("bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",s),...n})}function va({...s}){return e.jsx(Os,{"data-slot":"sheet",...s})}function ba({...s}){return e.jsx($s,{"data-slot":"sheet-portal",...s})}function wa({className:s,...t}){return e.jsx(Ms,{"data-slot":"sheet-overlay",className:h("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",s),...t})}function ya({className:s,children:t,side:a="right",...n}){return e.jsxs(ba,{children:[e.jsx(wa,{}),e.jsxs(Ls,{"data-slot":"sheet-content",className:h("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",a==="right"&&"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",a==="left"&&"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",a==="top"&&"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",a==="bottom"&&"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",s),...n,children:[t,e.jsxs(As,{className:"ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none",children:[e.jsx(Ps,{className:"size-4"}),e.jsx("span",{className:"sr-only",children:"Close"})]})]})]})}function Na({className:s,...t}){return e.jsx("div",{"data-slot":"sheet-header",className:h("flex flex-col gap-1.5 p-4",s),...t})}function Sa({className:s,...t}){return e.jsx(Ds,{"data-slot":"sheet-title",className:h("text-foreground font-semibold",s),...t})}function Ca({className:s,...t}){return e.jsx(Ts,{"data-slot":"sheet-description",className:h("text-muted-foreground text-sm",s),...t})}function fe({className:s,...t}){return e.jsx("div",{"data-slot":"skeleton",className:h("bg-accent animate-pulse rounded-md",s),...t})}function Ye({delayDuration:s=0,...t}){return e.jsx(ot,{"data-slot":"tooltip-provider",delayDuration:s,...t})}function ls({...s}){return e.jsx(Ye,{children:e.jsx(dt,{"data-slot":"tooltip",...s})})}function os({...s}){return e.jsx(ct,{"data-slot":"tooltip-trigger",...s})}function ds({className:s,sideOffset:t=0,children:a,...n}){return e.jsx(mt,{children:e.jsxs(ut,{"data-slot":"tooltip-content",sideOffset:t,className:h("bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",s),...n,children:[a,e.jsx(xt,{className:"bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]"})]})})}const ka="sidebar_state",_a=3600*24*7,Ia="16rem",Ea="18rem",za="3rem",Oa="b",Us=c.createContext(null);function Bs(){const s=c.useContext(Us);if(!s)throw new Error("useSidebar must be used within a SidebarProvider.");return s}function La({defaultOpen:s=!0,open:t,onOpenChange:a,className:n,style:m,children:u,...g}){const j=pa(),[b,f]=c.useState(!1),[k,p]=c.useState(s),_=t??k,I=c.useCallback(o=>{const d=typeof o=="function"?o(_):o;a?a(d):p(d),document.cookie=`${ka}=${d}; path=/; max-age=${_a}`},[a,_]),$=c.useCallback(()=>j?f(o=>!o):I(o=>!o),[j,I,f]);c.useEffect(()=>{const o=d=>{d.key===Oa&&(d.metaKey||d.ctrlKey)&&(d.preventDefault(),$())};return window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[$]);const M=_?"expanded":"collapsed",F=c.useMemo(()=>({state:M,open:_,setOpen:I,isMobile:j,openMobile:b,setOpenMobile:f,toggleSidebar:$}),[M,_,I,j,b,f,$]);return e.jsx(Us.Provider,{value:F,children:e.jsx(Ye,{delayDuration:0,children:e.jsx("div",{"data-slot":"sidebar-wrapper",style:{"--sidebar-width":Ia,"--sidebar-width-icon":za,...m},className:h("group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",n),...g,children:u})})})}function Aa({side:s="left",variant:t="sidebar",collapsible:a="offcanvas",className:n,children:m,...u}){const{isMobile:g,state:j,openMobile:b,setOpenMobile:f}=Bs();return a==="none"?e.jsx("div",{"data-slot":"sidebar",className:h("bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",n),...u,children:m}):g?e.jsx(va,{open:b,onOpenChange:f,...u,children:e.jsxs(ya,{"data-sidebar":"sidebar","data-slot":"sidebar","data-mobile":"true",className:"bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden",style:{"--sidebar-width":Ea},side:s,children:[e.jsxs(Na,{className:"sr-only",children:[e.jsx(Sa,{children:"Sidebar"}),e.jsx(Ca,{children:"Displays the mobile sidebar."})]}),e.jsx("div",{className:"flex h-full w-full flex-col",children:m})]})}):e.jsxs("div",{className:"group peer text-sidebar-foreground hidden md:block","data-state":j,"data-collapsible":j==="collapsed"?a:"","data-variant":t,"data-side":s,"data-slot":"sidebar",children:[e.jsx("div",{"data-slot":"sidebar-gap",className:h("relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear","group-data-[collapsible=offcanvas]:w-0","group-data-[side=right]:rotate-180",t==="floating"||t==="inset"?"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]":"group-data-[collapsible=icon]:w-(--sidebar-width-icon)")}),e.jsx("div",{"data-slot":"sidebar-container",className:h("fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",s==="left"?"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]":"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",t==="floating"||t==="inset"?"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]":"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",n),...u,children:e.jsx("div",{"data-sidebar":"sidebar","data-slot":"sidebar-inner",className:"bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm",children:m})})]})}function Da({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-header","data-sidebar":"header",className:h("flex flex-col gap-2 p-2",s),...t})}function Ta({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-footer","data-sidebar":"footer",className:h("flex flex-col gap-2 p-2",s),...t})}function $a({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-content","data-sidebar":"content",className:h("flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",s),...t})}function Ma({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-group","data-sidebar":"group",className:h("relative flex w-full min-w-0 flex-col p-2",s),...t})}function Pa({className:s,asChild:t=!1,...a}){const n=t?Me:"div";return e.jsx(n,{"data-slot":"sidebar-group-label","data-sidebar":"group-label",className:h("text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0","group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",s),...a})}function Fa({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-group-content","data-sidebar":"group-content",className:h("w-full text-sm",s),...t})}function Ra({className:s,...t}){return e.jsx("ul",{"data-slot":"sidebar-menu","data-sidebar":"menu",className:h("flex w-full min-w-0 flex-col gap-1",s),...t})}function Va({className:s,...t}){return e.jsx("li",{"data-slot":"sidebar-menu-item","data-sidebar":"menu-item",className:h("group/menu-item relative",s),...t})}const Ha=ss("peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",{variants:{variant:{default:"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",outline:"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"},size:{default:"h-8 text-sm",sm:"h-7 text-xs",lg:"h-12 text-sm group-data-[collapsible=icon]:p-0!"}},defaultVariants:{variant:"default",size:"default"}});function Ua({asChild:s=!1,isActive:t=!1,variant:a="default",size:n="default",tooltip:m,className:u,...g}){const j=s?Me:"button",{isMobile:b,state:f}=Bs(),k=e.jsx(j,{"data-slot":"sidebar-menu-button","data-sidebar":"menu-button","data-size":n,"data-active":t,className:h(Ha({variant:a,size:n}),u),...g});return m?(typeof m=="string"&&(m={children:m}),e.jsxs(ls,{children:[e.jsx(os,{asChild:!0,children:k}),e.jsx(ds,{side:"right",align:"center",hidden:f!=="collapsed"||b,...m})]})):k}const Ge="";class Y extends Error{status;body;constructor(t,a,n){super(a),this.status=t,this.body=n}}function Ba(s){const t={};if(!s)return t;if(s instanceof Headers)s.forEach((a,n)=>t[n]=a);else if(Array.isArray(s))for(const[a,n]of s)t[a]=n;else Object.assign(t,s);return t}function Ka(){const s={},t=localStorage.getItem("access_token");return t&&(s.Authorization=`Bearer ${t}`),s}function Ga(){const s=localStorage.getItem("active_org_id");return s?{"X-Org-ID":s}:{}}async function ke(s,t,a,n={}){const u={...{"Content-Type":"application/json"},...n.auth===!1?{}:Ka(),...Ga(),...Ba(n.headers)},g=await fetch(`${Ge}${s}`,{method:t,headers:u,body:a===void 0?void 0:JSON.stringify(a),...n}),b=(g.headers.get("content-type")||"").includes("application/json"),f=b?await g.json().catch(()=>{}):await g.text().catch(()=>"");if(!g.ok){const k=b&&f&&typeof f=="object"&&"error"in f&&f.error||b&&f&&typeof f=="object"&&"message"in f&&f.message||typeof f=="string"&&f||`HTTP ${g.status}`;throw new Y(g.status,String(k),f)}return console.debug("API ->",t,`${Ge}${s}`,u),b?f:void 0}const z={get:(s,t)=>ke(s,"GET",void 0,t),post:(s,t,a)=>ke(s,"POST",t,a),put:(s,t,a)=>ke(s,"PUT",t,a),patch:(s,t,a)=>ke(s,"PATCH",t,a),delete:(s,t)=>ke(s,"DELETE",void 0,t)};function qa(s){return s&&(s.user||s.user_id)}function Ks(s){return qa(s)?.role==="admin"}function Ja(s){return(s?.org_role??"")==="admin"}const ue={isAuthenticated(){return!!localStorage.getItem("access_token")},async login(s,t){const a=await z.post("/api/v1/auth/login",{email:s,password:t});localStorage.setItem("access_token",a.access_token),localStorage.setItem("refresh_token",a.refresh_token)},async register(s,t,a){await z.post("/api/v1/auth/register",{name:s,email:t,password:a})},async me(){return await z.get("/api/v1/auth/me")},async logout(){const s=localStorage.getItem("refresh_token");if(s)try{await z.post("/api/v1/auth/logout",{refresh_token:s})}catch{}localStorage.removeItem("access_token"),localStorage.removeItem("refresh_token")},async forgot(s){await z.post("/api/v1/auth/password/forgot",{email:s})},async reset(s,t){await z.post("/api/v1/auth/password/reset",{token:s,new_password:t})},async verify(s){const t=await fetch(`${Ge}/api/v1/auth/verify?token=${encodeURIComponent(s)}`);if(!t.ok){const a=await t.text();throw new Error(a)}}};function Wa({...s}){return e.jsx(ht,{"data-slot":"collapsible",...s})}function Ya({...s}){return e.jsx(jt,{"data-slot":"collapsible-trigger",...s})}function Xa({...s}){return e.jsx(ft,{"data-slot":"collapsible-content",...s})}function Re({...s}){return e.jsx(gt,{"data-slot":"dropdown-menu",...s})}function Ve({...s}){return e.jsx(pt,{"data-slot":"dropdown-menu-trigger",...s})}function He({className:s,sideOffset:t=4,...a}){return e.jsx(vt,{children:e.jsx(bt,{"data-slot":"dropdown-menu-content",sideOffset:t,className:h("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",s),...a})})}function me({className:s,inset:t,variant:a="default",...n}){return e.jsx(wt,{"data-slot":"dropdown-menu-item","data-inset":t,"data-variant":a,className:h("focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",s),...n})}function Qa(){const{setTheme:s,theme:t}=Es();return e.jsxs(Re,{children:[e.jsx(Ve,{asChild:!0,children:e.jsx(x,{variant:"outline",size:"icon","aria-label":"Toggle theme",children:t==="light"?e.jsx(qt,{className:"h-5 w-5"}):t==="dark"?e.jsx(Jt,{className:"h-5 w-5"}):e.jsx(Wt,{className:"h-5 w-5"})})}),e.jsxs(He,{align:"end",children:[e.jsxs(me,{onClick:()=>s("light"),children:[t==="light"&&e.jsx(Ee,{}),"Light"]}),e.jsxs(me,{onClick:()=>s("dark"),children:[t==="dark"&&e.jsx(Ee,{}),"Dark"]}),e.jsxs(me,{onClick:()=>s("system"),children:[t==="system"&&e.jsx(Ee,{}),"System"]})]})]})}const es="active_org_id",be="active-org-changed",Le="orgs-changed";function je(){return localStorage.getItem(es)}function Oe(s){s?localStorage.setItem(es,s):localStorage.removeItem(es),window.dispatchEvent(new CustomEvent(be,{detail:s}))}function ys(){window.dispatchEvent(new Event(Le))}const Za=()=>{const[s,t]=c.useState([]),[a,n]=c.useState(null);async function m(){try{const j=await z.get("/api/v1/orgs");t(j),!je()&&j.length>0&&(Oe(j[0].id),n(j[0].id))}catch(j){const b=j instanceof Y?j.message:"Failed to load organizations";console.error(b)}}c.useEffect(()=>{n(je()),m();const j=k=>{k.key==="active_org_id"&&n(k.newValue)};window.addEventListener("storage",j);const b=k=>n(k.detail??null),f=()=>void m();return window.addEventListener(be,b),window.addEventListener(Le,f),()=>{window.removeEventListener("storage",j),window.removeEventListener(be,b),window.removeEventListener(Le,f)}},[]);const u=j=>{Oe(j),n(j)},g=s.find(j=>j.id===a)?.name??"Select Org";return e.jsxs(Re,{children:[e.jsx(Ve,{asChild:!0,children:e.jsx(x,{variant:"outline",className:"w-full justify-start",children:g})}),e.jsx(He,{className:"w-48",children:s.length===0?e.jsx(me,{disabled:!0,children:"No organizations"}):s.map(j=>e.jsx(me,{onClick:()=>u(j.id),className:j.id===a?"font-semibold":void 0,children:j.name},j.id))})]})},er=[{label:"Dashboard",icon:Yt,to:"/dashboard"},{label:"Core",icon:ta,items:[{label:"Cluster",to:"/core/clusters",icon:Xt},{label:"Node Pools",icon:Qt,to:"/core/nodepools"},{label:"Annotations",icon:Zt,to:"/core/annotations"},{label:"Labels",icon:ea,to:"/core/labels"},{label:"Taints",icon:sa,to:"/core/taints"},{label:"Servers",icon:Fs,to:"/core/servers"}]},{label:"Security",icon:na,items:[{label:"Keys & Tokens",icon:aa,to:"/security/keys"},{label:"SSH Keys",to:"/security/ssh",icon:ra}]},{label:"Tasks",icon:ia,items:[]},{label:"Settings",icon:da,items:[{label:"Organizations",to:"/settings/orgs",icon:la},{label:"Members",to:"/settings/members",icon:vs},{label:"Profile",to:"/settings/me",icon:oa}]},{label:"Admin",icon:ca,requiresAdmin:!0,items:[{label:"Users",to:"/admin/users",icon:vs,requiresAdmin:!0}]}];function Gs(s,t,a){return s.filter(n=>!(n.requiresAdmin&&!t||n.requiresOrgAdmin&&!a)).map(n=>({...n,items:n.items?Gs(n.items,t,a):void 0})).filter(n=>!n.items||n.items.length>0)}const qs=({item:s})=>{const t=We(),a=s.icon;return s.to?e.jsxs(ve,{to:s.to,className:`hover:bg-accent hover:text-accent-foreground flex items-center space-x-2 rounded-md px-4 py-2 text-sm ${t.pathname===s.to?"bg-accent text-accent-foreground":""}`,children:[e.jsx(a,{className:"mr-4 h-4 w-4"}),s.label]}):s.items?e.jsx(Wa,{defaultOpen:!0,className:"group/collapsible",children:e.jsxs(Ma,{children:[e.jsx(Pa,{asChild:!0,children:e.jsxs(Ya,{children:[e.jsx(a,{className:"mr-4 h-4 w-4"}),s.label,e.jsx(as,{className:"ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180"})]})}),e.jsx(Xa,{children:e.jsx(Fa,{children:e.jsx(Ra,{children:s.items.map((n,m)=>e.jsx(Va,{children:e.jsx(Ua,{asChild:!0,children:e.jsx(qs,{item:n})})},m))})})})]})}):null},sr=()=>{const[s,t]=c.useState(null),[a,n]=c.useState(!0);c.useEffect(()=>{let u=!0;return(async()=>{try{const g=await ue.me();if(!u)return;t(g)}catch{}finally{n(!1)}})(),()=>{u=!1}},[]);const m=c.useMemo(()=>{const u=Ks(s),g=Ja(s);return Gs(er,u,g)},[s]);return a?e.jsx("div",{className:"p-6",children:"Loading…"}):e.jsxs(Aa,{children:[e.jsx(Da,{className:"flex items-center justify-between p-4",children:e.jsx("h1",{className:"text-xl font-bold",children:"AutoGlue"})}),e.jsx($a,{children:m.map((u,g)=>e.jsx(qs,{item:u},g))}),e.jsxs(Ta,{className:"space-y-2 p-4",children:[e.jsx(Za,{}),e.jsx(Qa,{}),e.jsx(x,{onClick:()=>{localStorage.clear(),window.location.reload()},className:"w-full",children:"Logout"})]})]})};function tr(){return e.jsx("footer",{className:"border-t",children:e.jsxs("div",{className:"container flex flex-col items-center justify-between gap-4 py-10 md:h-24 md:flex-row md:py-0",children:[e.jsx("div",{className:"flex flex-col items-center gap-4 px-8 md:flex-row md:gap-2 md:px-0",children:e.jsxs("p",{className:"text-muted-foreground text-center text-sm leading-loose md:text-left",children:["Built for"," ",e.jsx("a",{href:"https://www.glueops.dev/",target:"_blank",rel:"noreferrer",className:"font-medium underline underline-offset-4",children:"GlueOps"}),". The source code is available on"," ",e.jsx("a",{href:"https://github.com/GlueOps/autoglue",target:"_blank",rel:"noreferrer",className:"font-medium underline underline-offset-4",children:"GitHub"}),"."]})}),e.jsx("div",{className:"flex items-center space-x-4",children:e.jsx("a",{href:"https://github.com/GlueOps/autoglue",target:"_blank",rel:"noreferrer",children:e.jsx(ma,{className:"h-5 w-5"})})})]})})}function ar(){return e.jsx("div",{className:"flex h-screen",children:e.jsxs(La,{children:[e.jsx(sr,{}),e.jsxs("div",{className:"flex flex-1 flex-col",children:[e.jsx("main",{className:"flex-1 overflow-auto p-4",children:e.jsx(rs,{})}),e.jsx(tr,{})]})]})})}function rr({children:s}){const t=We();return ue.isAuthenticated()?s?e.jsx(e.Fragment,{children:s}):e.jsx(rs,{}):e.jsx(ns,{to:"/auth/login",state:{from:t},replace:!0})}function nr({children:s}){const[t,a]=c.useState(!0),[n,m]=c.useState(!1),u=We();return c.useEffect(()=>{let g=!0;return(async()=>{try{const j=await ue.me();if(!g)return;m(Ks(j))}catch{if(!g)return;m(!1)}finally{if(a(!1),!g)return}})(),()=>{g=!1}},[]),t?null:n?s?e.jsx(e.Fragment,{children:s}):e.jsx(rs,{}):e.jsx(ns,{to:"/403",replace:!0,state:{from:u}})}function cs({...s}){return e.jsx(yt,{"data-slot":"alert-dialog",...s})}function ms({...s}){return e.jsx(Nt,{"data-slot":"alert-dialog-trigger",...s})}function ir({...s}){return e.jsx(Et,{"data-slot":"alert-dialog-portal",...s})}function lr({className:s,...t}){return e.jsx(zt,{"data-slot":"alert-dialog-overlay",className:h("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",s),...t})}function us({className:s,...t}){return e.jsxs(ir,{children:[e.jsx(lr,{}),e.jsx(St,{"data-slot":"alert-dialog-content",className:h("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",s),...t})]})}function xs({className:s,...t}){return e.jsx("div",{"data-slot":"alert-dialog-header",className:h("flex flex-col gap-2 text-center sm:text-left",s),...t})}function hs({className:s,...t}){return e.jsx("div",{"data-slot":"alert-dialog-footer",className:h("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",s),...t})}function js({className:s,...t}){return e.jsx(Ct,{"data-slot":"alert-dialog-title",className:h("text-lg font-semibold",s),...t})}function fs({className:s,...t}){return e.jsx(kt,{"data-slot":"alert-dialog-description",className:h("text-muted-foreground text-sm",s),...t})}function gs({className:s,...t}){return e.jsx(It,{className:h(is(),s),...t})}function ps({className:s,...t}){return e.jsx(_t,{className:h(is({variant:"outline"}),s),...t})}function oe({className:s,...t}){return e.jsx("div",{"data-slot":"card",className:h("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",s),...t})}function de({className:s,...t}){return e.jsx("div",{"data-slot":"card-header",className:h("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",s),...t})}function he({className:s,...t}){return e.jsx("div",{"data-slot":"card-title",className:h("leading-none font-semibold",s),...t})}function ce({className:s,...t}){return e.jsx("div",{"data-slot":"card-content",className:h("px-6",s),...t})}function Ae({className:s,...t}){return e.jsx("div",{"data-slot":"card-footer",className:h("flex items-center px-6 [.border-t]:pt-6",s),...t})}function ae({...s}){return e.jsx(Os,{"data-slot":"dialog",...s})}function Ue({...s}){return e.jsx(Ot,{"data-slot":"dialog-trigger",...s})}function or({...s}){return e.jsx($s,{"data-slot":"dialog-portal",...s})}function dr({className:s,...t}){return e.jsx(Ms,{"data-slot":"dialog-overlay",className:h("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",s),...t})}function re({className:s,children:t,showCloseButton:a=!0,...n}){return e.jsxs(or,{"data-slot":"dialog-portal",children:[e.jsx(dr,{}),e.jsxs(Ls,{"data-slot":"dialog-content",className:h("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",s),...n,children:[t,a&&e.jsxs(As,{"data-slot":"dialog-close",className:"ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",children:[e.jsx(Ps,{}),e.jsx("span",{className:"sr-only",children:"Close"})]})]})]})}function ne({className:s,...t}){return e.jsx("div",{"data-slot":"dialog-header",className:h("flex flex-col gap-2 text-center sm:text-left",s),...t})}function ie({className:s,...t}){return e.jsx("div",{"data-slot":"dialog-footer",className:h("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",s),...t})}function le({className:s,...t}){return e.jsx(Ds,{"data-slot":"dialog-title",className:h("text-lg leading-none font-semibold",s),...t})}function qe({className:s,...t}){return e.jsx(Ts,{"data-slot":"dialog-description",className:h("text-muted-foreground text-sm",s),...t})}function cr({className:s,...t}){return e.jsx(Lt,{"data-slot":"label",className:h("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",s),...t})}const G=Zs,Js=c.createContext({}),w=({...s})=>e.jsx(Js.Provider,{value:{name:s.name},children:e.jsx(et,{...s})}),Xe=()=>{const s=c.useContext(Js),t=c.useContext(Ws),{getFieldState:a}=st(),n=tt({name:s.name}),m=a(s.name,n);if(!s)throw new Error("useFormField should be used within ");const{id:u}=t;return{id:u,name:s.name,formItemId:`${u}-form-item`,formDescriptionId:`${u}-form-item-description`,formMessageId:`${u}-form-item-message`,...m}},Ws=c.createContext({});function y({className:s,...t}){const a=c.useId();return e.jsx(Ws.Provider,{value:{id:a},children:e.jsx("div",{"data-slot":"form-item",className:h("grid gap-2",s),...t})})}function N({className:s,...t}){const{error:a,formItemId:n}=Xe();return e.jsx(cr,{"data-slot":"form-label","data-error":!!a,className:h("data-[error=true]:text-destructive",s),htmlFor:n,...t})}function C({...s}){const{error:t,formItemId:a,formDescriptionId:n,formMessageId:m}=Xe();return e.jsx(Me,{"data-slot":"form-control",id:a,"aria-describedby":t?`${n} ${m}`:`${n}`,"aria-invalid":!!t,...s})}function Ns({className:s,...t}){const{formDescriptionId:a}=Xe();return e.jsx("p",{"data-slot":"form-description",id:a,className:h("text-muted-foreground text-sm",s),...t})}function S({className:s,...t}){const{error:a,formMessageId:n}=Xe(),m=a?String(a?.message??""):t.children;return m?e.jsx("p",{"data-slot":"form-message",id:n,className:h("text-destructive text-sm",s),...t,children:m}):null}function Z({...s}){return e.jsx(At,{"data-slot":"select",...s})}function ee({...s}){return e.jsx($t,{"data-slot":"select-value",...s})}function se({className:s,size:t="default",children:a,...n}){return e.jsxs(Dt,{"data-slot":"select-trigger","data-size":t,className:h("border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",s),...n,children:[a,e.jsx(Tt,{asChild:!0,children:e.jsx(as,{className:"size-4 opacity-50"})})]})}function te({className:s,children:t,position:a="popper",...n}){return e.jsx(Mt,{children:e.jsxs(Pt,{"data-slot":"select-content",className:h("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",a==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",s),position:a,...n,children:[e.jsx(mr,{}),e.jsx(Ft,{className:h("p-1",a==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"),children:t}),e.jsx(ur,{})]})})}function q({className:s,children:t,...a}){return e.jsxs(Rt,{"data-slot":"select-item",className:h("focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",s),...a,children:[e.jsx("span",{className:"absolute right-2 flex size-3.5 items-center justify-center",children:e.jsx(Vt,{children:e.jsx(Ee,{className:"size-4"})})}),e.jsx(Ht,{children:t})]})}function mr({className:s,...t}){return e.jsx(Ut,{"data-slot":"select-scroll-up-button",className:h("flex cursor-default items-center justify-center py-1",s),...t,children:e.jsx(ua,{className:"size-4"})})}function ur({className:s,...t}){return e.jsx(Bt,{"data-slot":"select-scroll-down-button",className:h("flex cursor-default items-center justify-center py-1",s),...t,children:e.jsx(as,{className:"size-4"})})}const xr=J({name:R().min(1,"Name required"),email:Se("Enter a valid email"),role:Ne(["user","admin"]),password:R().min(8,"Min 8 characters")}),hr=J({name:R().min(1,"Name required"),email:Se("Enter a valid email"),role:Ne(["user","admin"]),password:R().min(8,"Min 8 characters").optional().or(at(""))});function jr(){const[s,t]=c.useState([]),[a,n]=c.useState(!0),[m,u]=c.useState(!1),[g,j]=c.useState(!1),[b,f]=c.useState(null),[k,p]=c.useState(null),_=B({resolver:K(xr),mode:"onChange",defaultValues:{name:"",email:"",role:"user",password:""}}),I=B({resolver:K(hr),mode:"onChange",defaultValues:{name:"",email:"",role:"user",password:""}});async function $(){n(!0);try{const l=await z.get("/api/v1/admin/users?page=1&page_size=100");t(l.users??[])}catch(l){O.error(l instanceof Y?l.message:"Failed to load users")}finally{n(!1)}}c.useEffect(()=>{$()},[]);async function M(l){try{const v=await z.post("/api/v1/admin/users",l);t(A=>[v,...A]),u(!1),_.reset({name:"",email:"",role:"user",password:""}),O.success(`Created ${v.email}`)}catch(v){O.error(v instanceof Y?v.message:"Failed to create user")}}function F(l){f(l),I.reset({name:l.name||"",email:l.email,role:l.role??"user",password:""}),j(!0)}async function o(l){if(!b)return;const v={name:l.name,email:l.email,role:l.role};l.password&&l.password.length>=8&&(v.password=l.password);try{const A=await z.patch(`/api/v1/admin/users/${b.id}`,v);t(H=>H.map(V=>V.id===A.id?A:V)),j(!1),f(null),O.success(`Updated ${A.email}`)}catch(A){O.error(A instanceof Y?A.message:"Failed to update user")}}async function d(l){try{p(l),await z.delete(`/api/v1/admin/users/${l}`),t(v=>v.filter(A=>A.id!==l)),O.success("User deleted")}catch(v){O.error(v instanceof Y?v.message:"Failed to delete user")}finally{p(null)}}return e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Users"}),e.jsxs(x,{onClick:()=>u(!0),children:[e.jsx(Pe,{className:"mr-2 h-4 w-4"}),"New user"]})]}),e.jsx(ze,{}),a?e.jsx("div",{className:"text-muted-foreground text-sm",children:"Loading…"}):s.length===0?e.jsx("div",{className:"text-muted-foreground text-sm",children:"No users yet."}):e.jsx("div",{className:"grid grid-cols-1 gap-4 pr-2 md:grid-cols-2 lg:grid-cols-3",children:s.map(l=>e.jsxs(oe,{className:"flex flex-col",children:[e.jsx(de,{children:e.jsx(he,{className:"text-base",children:l.name||l.email})}),e.jsxs(ce,{className:"text-muted-foreground space-y-1 text-sm",children:[e.jsxs("div",{children:["Email: ",l.email]}),e.jsxs("div",{children:["Role: ",l.role]}),e.jsxs("div",{children:["Verified: ",l.email_verified?"Yes":"No"]}),e.jsxs("div",{children:["Joined: ",new Date(l.created_at).toLocaleString()]})]}),e.jsxs(Ae,{className:"mt-auto w-full flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs(x,{variant:"outline",onClick:()=>F(l),children:[e.jsx(Je,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(cs,{children:[e.jsx(ms,{asChild:!0,children:e.jsxs(x,{variant:"destructive",disabled:k===l.id,children:[e.jsx(we,{className:"mr-2 h-4 w-4"}),k===l.id?"Deleting…":"Delete"]})}),e.jsxs(us,{children:[e.jsxs(xs,{children:[e.jsx(js,{children:"Delete user?"}),e.jsxs(fs,{children:["This will permanently delete ",e.jsx("b",{children:l.email}),"."]})]}),e.jsxs(hs,{className:"sm:justify-between",children:[e.jsx(ps,{disabled:k===l.id,children:"Cancel"}),e.jsx(gs,{asChild:!0,disabled:k===l.id,children:e.jsx(x,{variant:"destructive",onClick:()=>d(l.id),children:"Confirm delete"})})]})]})]})]})]},l.id))}),e.jsx(ae,{open:m,onOpenChange:u,children:e.jsxs(re,{className:"sm:max-w-[520px]",children:[e.jsxs(ne,{children:[e.jsx(le,{children:"Create user"}),e.jsx(qe,{children:"Add a new user account."})]}),e.jsx(G,{..._,children:e.jsxs("form",{onSubmit:_.handleSubmit(M),className:"grid gap-4 py-2",children:[e.jsx(w,{name:"name",control:_.control,render:({field:l})=>e.jsxs(y,{children:[e.jsx(N,{children:"Name"}),e.jsx(C,{children:e.jsx(L,{...l,placeholder:"Jane Doe"})}),e.jsx(S,{})]})}),e.jsx(w,{name:"email",control:_.control,render:({field:l})=>e.jsxs(y,{children:[e.jsx(N,{children:"Email"}),e.jsx(C,{children:e.jsx(L,{type:"email",...l,placeholder:"jane@example.com"})}),e.jsx(S,{})]})}),e.jsx(w,{name:"role",control:_.control,render:({field:l})=>e.jsxs(y,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Z,{value:l.value,onValueChange:l.onChange,children:[e.jsx(C,{children:e.jsx(se,{className:"w-[200px]",children:e.jsx(ee,{placeholder:"Select role"})})}),e.jsxs(te,{children:[e.jsx(q,{value:"user",children:"User"}),e.jsx(q,{value:"admin",children:"Admin"})]})]}),e.jsx(S,{})]})}),e.jsx(w,{name:"password",control:_.control,render:({field:l})=>e.jsxs(y,{children:[e.jsx(N,{children:"Password"}),e.jsx(C,{children:e.jsx(L,{type:"password",...l,placeholder:"••••••••"})}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"mt-2 flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>u(!1),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:!_.formState.isValid||_.formState.isSubmitting,children:_.formState.isSubmitting?"Creating…":"Create"})]})]})})]})}),e.jsx(ae,{open:g,onOpenChange:j,children:e.jsxs(re,{className:"sm:max-w-[520px]",children:[e.jsxs(ne,{children:[e.jsx(le,{children:"Edit user"}),e.jsx(qe,{children:"Update user details. Leave password blank to keep it unchanged."})]}),e.jsx(G,{...I,children:e.jsxs("form",{onSubmit:I.handleSubmit(o),className:"grid gap-4 py-2",children:[e.jsx(w,{name:"name",control:I.control,render:({field:l})=>e.jsxs(y,{children:[e.jsx(N,{children:"Name"}),e.jsx(C,{children:e.jsx(L,{...l})}),e.jsx(S,{})]})}),e.jsx(w,{name:"email",control:I.control,render:({field:l})=>e.jsxs(y,{children:[e.jsx(N,{children:"Email"}),e.jsx(C,{children:e.jsx(L,{type:"email",...l})}),e.jsx(S,{})]})}),e.jsx(w,{name:"role",control:I.control,render:({field:l})=>e.jsxs(y,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Z,{value:l.value,onValueChange:l.onChange,children:[e.jsx(C,{children:e.jsx(se,{className:"w-[200px]",children:e.jsx(ee,{placeholder:"Select role"})})}),e.jsxs(te,{children:[e.jsx(q,{value:"user",children:"User"}),e.jsx(q,{value:"admin",children:"Admin"})]})]}),e.jsx(S,{})]})}),e.jsx(w,{name:"password",control:I.control,render:({field:l})=>e.jsxs(y,{children:[e.jsx(N,{children:"New password (optional)"}),e.jsx(C,{children:e.jsx(L,{type:"password",...l,placeholder:"Leave blank to keep"})}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"mt-2 flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>j(!1),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:!I.formState.isValid||I.formState.isSubmitting,children:I.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})})]})}const fr=J({email:Se()});function gr(){const s=B({resolver:K(fr),defaultValues:{email:""}});async function t(a){try{await ue.forgot(a.email),O.success("If that email exists, we've sent instructions.")}catch(n){O.error(n.message||"Something went wrong")}}return e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(oe,{children:[e.jsx(de,{children:e.jsx(he,{children:"Forgot password"})}),e.jsx(ce,{children:e.jsx(G,{...s,children:e.jsxs("form",{onSubmit:s.handleSubmit(t),className:"space-y-4",children:[e.jsx(w,{name:"email",control:s.control,render:({field:a})=>e.jsxs(y,{children:[e.jsx(N,{children:"Email"}),e.jsx(C,{children:e.jsx(L,{placeholder:"you@example.com",...a})}),e.jsx(S,{})]})}),e.jsx(x,{type:"submit",className:"w-full",children:"Send reset link"})]})})})]})})}const pr=J({email:Se(),password:R().min(6)});function vr(){const s=Fe(),t=We(),a=B({resolver:K(pr),defaultValues:{email:"",password:""}});async function n(m){try{await ue.login(m.email,m.password),O.success("Welcome back!");const u=t.state?.from?.pathname??"/settings/me";s(u,{replace:!0})}catch(u){O.error(u.message||"Login failed")}}return e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(oe,{children:[e.jsx(de,{children:e.jsx(he,{children:"Sign in"})}),e.jsxs(ce,{children:[e.jsx(G,{...a,children:e.jsxs("form",{onSubmit:a.handleSubmit(n),className:"space-y-4",children:[e.jsx(w,{name:"email",control:a.control,render:({field:m})=>e.jsxs(y,{children:[e.jsx(N,{children:"Email"}),e.jsx(C,{children:e.jsx(L,{placeholder:"you@example.com",...m})}),e.jsx(S,{})]})}),e.jsx(w,{name:"password",control:a.control,render:({field:m})=>e.jsxs(y,{children:[e.jsx(N,{children:"Password"}),e.jsx(C,{children:e.jsx(L,{type:"password",placeholder:"••••••••",...m})}),e.jsx(S,{})]})}),e.jsx(x,{type:"submit",className:"w-full",children:"Sign in"})]})}),e.jsxs("div",{className:"mt-4 flex justify-between text-sm",children:[e.jsx(ve,{to:"/auth/forgot",className:"underline",children:"Forgot password?"}),e.jsx(ve,{to:"/auth/register",className:"underline",children:"Create an account"})]})]})]})})}function br(){const[s,t]=c.useState(null),a=Fe();c.useEffect(()=>{(async()=>{try{const m=await ue.me();t(m)}catch(m){O.error(m.message||"Failed to load profile")}})()},[]);async function n(){await ue.logout(),a("/auth/login")}return e.jsx("div",{className:"mx-auto max-w-xl",children:e.jsxs(oe,{children:[e.jsx(de,{children:e.jsx(he,{children:"My Account"})}),e.jsxs(ce,{className:"space-y-3",children:[s?e.jsx("pre",{className:"bg-muted overflow-auto rounded p-3 text-sm",children:JSON.stringify(s,null,2)}):e.jsx("p",{children:"Loading…"}),e.jsx(x,{onClick:n,children:"Sign out"})]})]})})}const wr=J({name:R().min(2),email:Se(),password:R().min(6)});function yr(){const s=Fe(),t=B({resolver:K(wr),defaultValues:{name:"",email:"",password:""}});async function a(n){try{await ue.register(n.name,n.email,n.password),O.success("Account created! Check your email to verify."),s("/auth/login")}catch(m){O.error(m.message||"Registration failed")}}return e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(oe,{children:[e.jsx(de,{children:e.jsx(he,{children:"Create account"})}),e.jsxs(ce,{children:[e.jsx(G,{...t,children:e.jsxs("form",{onSubmit:t.handleSubmit(a),className:"space-y-4",children:[e.jsx(w,{name:"name",control:t.control,render:({field:n})=>e.jsxs(y,{children:[e.jsx(N,{children:"Name"}),e.jsx(C,{children:e.jsx(L,{placeholder:"Jane Doe",...n})}),e.jsx(S,{})]})}),e.jsx(w,{name:"email",control:t.control,render:({field:n})=>e.jsxs(y,{children:[e.jsx(N,{children:"Email"}),e.jsx(C,{children:e.jsx(L,{placeholder:"you@example.com",...n})}),e.jsx(S,{})]})}),e.jsx(w,{name:"password",control:t.control,render:({field:n})=>e.jsxs(y,{children:[e.jsx(N,{children:"Password"}),e.jsx(C,{children:e.jsx(L,{type:"password",placeholder:"••••••••",...n})}),e.jsx(S,{})]})}),e.jsx(x,{type:"submit",className:"w-full",children:"Create account"})]})}),e.jsxs("div",{className:"mt-4 text-sm",children:["Already have an account?"," ",e.jsx(ve,{to:"/auth/login",className:"underline",children:"Sign in"})]})]})]})})}const Nr=J({new_password:R().min(6)});function Sr(){const[s]=Hs(),t=s.get("token"),a=B({resolver:K(Nr),defaultValues:{new_password:""}}),n=Fe();async function m(u){if(!t){O.error("Missing token");return}try{await ue.reset(t,u.new_password),O.success("Password updated. Please sign in."),n("/auth/login")}catch(g){O.error(g.message||"Reset failed")}}return e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(oe,{children:[e.jsx(de,{children:e.jsx(he,{children:"Reset password"})}),e.jsxs(ce,{children:[e.jsx(G,{...a,children:e.jsxs("form",{onSubmit:a.handleSubmit(m),className:"space-y-4",children:[e.jsx(w,{name:"new_password",control:a.control,render:({field:u})=>e.jsxs(y,{children:[e.jsx(N,{children:"New password"}),e.jsx(C,{children:e.jsx(L,{type:"password",placeholder:"••••••••",...u})}),e.jsx(S,{})]})}),e.jsx(x,{type:"submit",className:"w-full",children:"Update password"})]})}),e.jsx("div",{className:"mt-4 text-sm",children:e.jsx(ve,{to:"/auth/login",className:"underline",children:"Back to sign in"})})]})]})})}function Cr(){const[s]=Hs(),t=s.get("token"),[a,n]=c.useState("idle");return c.useEffect(()=>{async function m(){if(!t){n("error");return}try{await ue.verify(t),n("ok")}catch(u){O.error(u.message||"Verification failed"),n("error")}}m()},[t]),e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(oe,{children:[e.jsx(de,{children:e.jsx(he,{children:"Email verification"})}),e.jsxs(ce,{className:"space-y-3",children:[a==="idle"&&e.jsx("p",{children:"Verifying…"}),a==="ok"&&e.jsxs("div",{children:[e.jsx("p",{children:"Your email has been verified. You can now sign in."}),e.jsx(x,{asChild:!0,className:"mt-3",children:e.jsx(ve,{to:"/auth/login",children:"Go to sign in"})})]}),a==="error"&&e.jsxs("div",{children:[e.jsx("p",{children:"Verification failed. Please request a new verification email."}),e.jsx(x,{asChild:!0,className:"mt-3",children:e.jsx(ve,{to:"/auth/login",children:"Back to sign in"})})]})]})]})})}const kr=()=>e.jsx("div",{className:"space-y-4 p-6",children:e.jsx("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Annotations"})})}),_r=()=>e.jsx("div",{className:"space-y-4 p-6",children:e.jsx("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Clusters"})})});function De({className:s,...t}){return e.jsx("div",{"data-slot":"table-container",className:"relative w-full overflow-x-auto",children:e.jsx("table",{"data-slot":"table",className:h("w-full caption-bottom text-sm",s),...t})})}function Te({className:s,...t}){return e.jsx("thead",{"data-slot":"table-header",className:h("[&_tr]:border-b",s),...t})}function $e({className:s,...t}){return e.jsx("tbody",{"data-slot":"table-body",className:h("[&_tr:last-child]:border-0",s),...t})}function W({className:s,...t}){return e.jsx("tr",{"data-slot":"table-row",className:h("hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",s),...t})}function P({className:s,...t}){return e.jsx("th",{"data-slot":"table-head",className:h("text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",s),...t})}function D({className:s,...t}){return e.jsx("td",{"data-slot":"table-cell",className:h("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",s),...t})}const Ir=J({key:R().min(2),value:R().min(2)}),Er=()=>{const[s,t]=c.useState([]),[a,n]=c.useState(!1),[m,u]=c.useState(null),[g,j]=c.useState(!1);async function b(){n(!0),u(null);try{const p=await z.get("/api/v1/labels");console.log(JSON.stringify(p)),t(p)}catch(p){console.error(p)}finally{n(!1)}}c.useEffect(()=>{b()},[]);const f=B({resolver:K(Ir),defaultValues:{key:"",value:""}}),k=async p=>{const _={key:p.key,value:p.value};await z.post("/api/v1/labels",_),j(!1),f.reset(),await b()};return a?e.jsx("div",{className:"p-6",children:"Loading servers…"}):m?e.jsx("div",{className:"p-6 text-red-500",children:m}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Labels"}),e.jsxs(ae,{open:g,onOpenChange:j,children:[e.jsx(Ue,{asChild:!0,children:e.jsxs(x,{onClick:()=>j(!0),children:[e.jsx(Pe,{className:"mr-2 h-4 w-4"}),"Create Label"]})}),e.jsxs(re,{className:"sm:max-w-lg",children:[e.jsx(ne,{children:e.jsx(le,{children:"Create Label"})}),e.jsx(G,{...f,children:e.jsxs("form",{onSubmit:f.handleSubmit(k),className:"space-y-4",children:[e.jsx(w,{control:f.control,name:"key",render:({field:p})=>e.jsxs(y,{children:[e.jsx(N,{children:"Key"}),e.jsx(C,{children:e.jsx(L,{placeholder:"app.kubernetes.io/managed-by",...p})}),e.jsx(S,{})]})}),e.jsx(w,{control:f.control,name:"value",render:({field:p})=>e.jsxs(y,{children:[e.jsx(N,{children:"Value"}),e.jsx(C,{children:e.jsx(L,{placeholder:"GlueOps",...p})}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"gap-2",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>j(!1),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:f.formState.isSubmitting,children:f.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(De,{children:[e.jsx(Te,{children:e.jsxs(W,{children:[e.jsx(P,{children:"Key"}),e.jsx(P,{children:"Values"}),e.jsx(P,{className:"w-[180px] text-right",children:"Actions"})]})}),e.jsx($e,{children:s.map(p=>e.jsxs(W,{children:[e.jsx(D,{children:p.key}),e.jsx(D,{children:p.value}),e.jsx(D,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(x,{variant:"outline",size:"sm",children:[e.jsx(Je,{className:"mr-2 h-4 w-4"}),"Edit"]}),e.jsxs(x,{variant:"destructive",size:"sm",children:[e.jsx(we,{className:"mr-2 h-4 w-4"}),"Delete"]})]})})]},p.id))})]})})})]})},zr=ss("inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",secondary:"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",destructive:"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",outline:"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"}},defaultVariants:{variant:"default"}});function Be({className:s,variant:t,asChild:a=!1,...n}){const m=a?Me:"span";return e.jsx(m,{"data-slot":"badge",className:h(zr({variant:t}),s),...n})}function Ss({className:s,...t}){return e.jsx(Kt,{"data-slot":"checkbox",className:h("peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",s),...t,children:e.jsx(Gt,{"data-slot":"checkbox-indicator",className:"flex items-center justify-center text-current transition-none",children:e.jsx(Ee,{className:"size-3.5"})})})}const Or=J({name:R().trim().min(1,"Name is required").max(120,"Max 120 chars"),server_ids:zs(ts()).optional().default([])}),Lr=J({name:R().trim().min(1,"Name is required").max(120,"Max 120 chars")}),Ar=J({server_ids:zs(ts()).min(1,"Pick at least one server")});function Cs({status:s}){const t=s==="ready"?"default":s==="provisioning"?"secondary":s==="failed"?"destructive":"outline";return e.jsx(Be,{variant:t,className:"capitalize",children:s||"unknown"})}function Ke(s,t=12){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}function ks(s){const t=s.ip||s.ip_address,a=s.hostname||t||s.id,n=s.role?` · ${s.role}`:"";return`${a}${n}`}const Dr=()=>{const[s,t]=c.useState(!0),[a,n]=c.useState([]),[m,u]=c.useState([]),[g,j]=c.useState(null),[b,f]=c.useState(""),[k,p]=c.useState(!1),[_,I]=c.useState(null),[$,M]=c.useState(null);async function F(){t(!0),j(null);try{const[r,E]=await Promise.all([z.get("/api/v1/node-pools?include=servers"),z.get("/api/v1/servers")]);if(n(r||[]),u(E||[]),$){const X=(r||[]).find(ge=>ge.id===$.id)||null;M(X)}if(_){const X=(r||[]).find(ge=>ge.id===_.id)||null;I(X)}}catch(r){console.error(r);const E=r instanceof Y?r.message:"Failed to load node pools or servers";j(E)}finally{t(!1)}}c.useEffect(()=>{F()},[]);const o=c.useMemo(()=>{const r=b.trim().toLowerCase();return r?a.filter(E=>E.name.toLowerCase().includes(r)||(E.servers||[]).some(X=>(X.hostname||"").toLowerCase().includes(r)||(X.ip||X.ip_address||"").toLowerCase().includes(r)||(X.role||"").toLowerCase().includes(r))):a},[a,b]);async function d(r){confirm("Delete this node pool? This cannot be undone.")&&(await z.delete(`/api/v1/node-pools/${r}`),await F())}const l=B({resolver:K(Or),defaultValues:{name:"",server_ids:[]}}),v=async r=>{const E={name:r.name.trim()};r.server_ids&&r.server_ids.length>0&&(E.server_ids=r.server_ids),await z.post("/api/v1/node-pools",E),p(!1),l.reset({name:"",server_ids:[]}),await F()},A=B({resolver:K(Lr),defaultValues:{name:""}});function H(r){I(r),A.reset({name:r.name})}const V=async r=>{_&&(await z.patch(`/api/v1/node-pools/${_.id}`,{name:r.name.trim()}),I(null),await F())},Q=B({resolver:K(Ar),defaultValues:{server_ids:[]}});function U(r){M(r),Q.reset({server_ids:[]})}const ye=async r=>{$&&(await z.post(`/api/v1/node-pools/${$.id}/servers`,{server_ids:r.server_ids}),Q.reset({server_ids:[]}),await F())};async function xe(r){$&&confirm("Detach this server from the pool?")&&(await z.delete(`/api/v1/node-pools/${$.id}/servers/${r}`),await F())}const i=c.useMemo(()=>{if(!$)return[];const r=new Set(($.servers||[]).map(E=>E.id));return m.filter(E=>!r.has(E.id))},[$,m]);return s?e.jsx("div",{className:"p-6",children:"Loading node pools…"}):g?e.jsx("div",{className:"p-6 text-red-500",children:g}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Node Pools"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:"relative",children:[e.jsx(Rs,{className:"absolute top-2.5 left-2 h-4 w-4 opacity-60"}),e.jsx(L,{value:b,onChange:r=>f(r.target.value),placeholder:"Search pools or servers…",className:"w-72 pl-8"})]}),e.jsxs(x,{variant:"outline",onClick:F,children:[e.jsx(Vs,{className:"mr-2 h-4 w-4"})," Refresh"]}),e.jsxs(ae,{open:k,onOpenChange:p,children:[e.jsx(Ue,{asChild:!0,children:e.jsxs(x,{onClick:()=>p(!0),children:[e.jsx(Pe,{className:"mr-2 h-4 w-4"})," Create Pool"]})}),e.jsxs(re,{className:"sm:max-w-lg",children:[e.jsx(ne,{children:e.jsx(le,{children:"Create node pool"})}),e.jsx(G,{...l,children:e.jsxs("form",{onSubmit:l.handleSubmit(v),className:"space-y-4",children:[e.jsx(w,{control:l.control,name:"name",render:({field:r})=>e.jsxs(y,{children:[e.jsx(N,{children:"Name"}),e.jsx(C,{children:e.jsx(L,{placeholder:"pool-workers-a",...r})}),e.jsx(S,{})]})}),e.jsx(w,{control:l.control,name:"server_ids",render:({field:r})=>e.jsxs(y,{children:[e.jsx(N,{children:"Initial servers (optional)"}),e.jsxs("div",{className:"max-h-56 space-y-2 overflow-auto rounded-xl border p-2",children:[m.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No servers available"}),m.map(E=>{const X=r.value?.includes(E.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(Ss,{checked:X,onCheckedChange:ge=>{const pe=new Set(r.value||[]);ge===!0?pe.add(E.id):pe.delete(E.id),r.onChange(Array.from(pe))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:ks(E)}),e.jsx("div",{className:"text-muted-foreground text-xs",children:Ke(E.id,8)})]})]},E.id)})]}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"gap-2",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>p(!1),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:l.formState.isSubmitting,children:l.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(De,{children:[e.jsx(Te,{children:e.jsxs(W,{children:[e.jsx(P,{children:"Name"}),e.jsx(P,{children:"Servers"}),e.jsx(P,{children:"Annotations"}),e.jsx(P,{children:"Labels"}),e.jsx(P,{children:"Taints"}),e.jsx(P,{className:"w-[180px] text-right",children:"Actions"})]})}),e.jsxs($e,{children:[o.map(r=>e.jsxs(W,{children:[e.jsx(D,{className:"font-medium",children:r.name}),e.jsxs(D,{children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[(r.servers||[]).slice(0,6).map(E=>e.jsxs(Be,{variant:"secondary",className:"gap-1",children:[e.jsx(Fs,{className:"h-3 w-3"})," ",E.hostname||E.ip||E.ip_address||Ke(E.id,6),E.status&&e.jsx("span",{className:"ml-1",children:e.jsx(Cs,{status:E.status})})]},E.id)),(r.servers||[]).length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No servers"}),(r.servers||[]).length>6&&e.jsxs("span",{className:"text-muted-foreground",children:["+",(r.servers||[]).length-6," more"]})]}),e.jsxs(x,{variant:"outline",size:"sm",onClick:()=>U(r),children:[e.jsx(Ce,{className:"mr-2 h-4 w-4"})," Manage servers"]})]}),e.jsxs(D,{children:[e.jsx("div",{className:"flex flex-wrap gap-2",children:"Annotations"}),e.jsxs(x,{variant:"outline",size:"sm",children:[e.jsx(Ce,{className:"mr-2 h-4 w-4"})," Manage Annotations"]})]}),e.jsxs(D,{children:[e.jsx("div",{className:"flex flex-wrap gap-2",children:"Labels"}),e.jsxs(x,{variant:"outline",size:"sm",children:[e.jsx(Ce,{className:"mr-2 h-4 w-4"})," Manage Labels"]})]}),e.jsxs(D,{children:[e.jsx("div",{className:"flex flex-wrap gap-2",children:"Taints"}),e.jsxs(x,{variant:"outline",size:"sm",children:[e.jsx(Ce,{className:"mr-2 h-4 w-4"})," Manage Taints"]})]}),e.jsx(D,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(x,{variant:"outline",size:"sm",onClick:()=>H(r),children:[e.jsx(Je,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(Re,{children:[e.jsx(Ve,{asChild:!0,children:e.jsxs(x,{variant:"destructive",size:"sm",children:[e.jsx(we,{className:"mr-2 h-4 w-4"})," Delete"]})}),e.jsx(He,{align:"end",children:e.jsx(me,{onClick:()=>d(r.id),children:"Confirm delete"})})]})]})})]},r.id)),o.length===0&&e.jsx(W,{children:e.jsx(D,{colSpan:3,className:"text-muted-foreground py-10 text-center",children:"No node pools match your search."})})]})]})})}),e.jsx(ae,{open:!!_,onOpenChange:r=>!r&&I(null),children:e.jsxs(re,{className:"sm:max-w-md",children:[e.jsx(ne,{children:e.jsx(le,{children:"Edit node pool"})}),e.jsx(G,{...A,children:e.jsxs("form",{onSubmit:A.handleSubmit(V),className:"space-y-4",children:[e.jsx(w,{control:A.control,name:"name",render:({field:r})=>e.jsxs(y,{children:[e.jsx(N,{children:"Name"}),e.jsx(C,{children:e.jsx(L,{placeholder:"pool-workers-a",...r})}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"gap-2",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>I(null),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:A.formState.isSubmitting,children:A.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})}),e.jsx(ae,{open:!!$,onOpenChange:r=>!r&&M(null),children:e.jsxs(re,{className:"sm:max-w-2xl",children:[e.jsx(ne,{children:e.jsxs(le,{children:["Manage servers for ",e.jsx("span",{className:"font-mono",children:$?.name})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached servers"}),e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(De,{children:[e.jsx(Te,{children:e.jsxs(W,{children:[e.jsx(P,{children:"Server"}),e.jsx(P,{children:"IP"}),e.jsx(P,{children:"Role"}),e.jsx(P,{children:"Status"}),e.jsx(P,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs($e,{children:[($?.servers||[]).map(r=>e.jsxs(W,{children:[e.jsx(D,{className:"font-medium",children:r.hostname||Ke(r.id,8)}),e.jsx(D,{children:e.jsx("code",{className:"font-mono text-sm",children:r.ip||r.ip_address||"—"})}),e.jsx(D,{className:"capitalize",children:r.role||"—"}),e.jsx(D,{children:e.jsx(Cs,{status:r.status})}),e.jsx(D,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(x,{variant:"destructive",size:"sm",onClick:()=>xe(r.id),children:[e.jsx(xa,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},r.id)),($?.servers||[]).length===0&&e.jsx(W,{children:e.jsx(D,{colSpan:5,className:"text-muted-foreground py-8 text-center",children:"No servers attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(G,{...Q,children:e.jsxs("form",{onSubmit:Q.handleSubmit(ye),className:"space-y-3",children:[e.jsx(w,{control:Q.control,name:"server_ids",render:({field:r})=>e.jsxs(y,{children:[e.jsx(N,{children:"Attach more servers"}),e.jsxs("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:[i.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more servers available to attach"}),i.map(E=>{const X=r.value?.includes(E.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(Ss,{checked:X,onCheckedChange:ge=>{const pe=new Set(r.value||[]);ge===!0?pe.add(E.id):pe.delete(E.id),r.onChange(Array.from(pe))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:ks(E)}),e.jsx("div",{className:"text-muted-foreground text-xs",children:Ke(E.id,8)})]})]},E.id)})]}),e.jsx(S,{})]})}),e.jsx(ie,{className:"gap-2",children:e.jsxs(x,{type:"submit",disabled:Q.formState.isSubmitting,children:[e.jsx(Ce,{className:"mr-2 h-4 w-4"})," ",Q.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})})]})},_e=["pending","provisioning","ready","failed"],Ie=["master","worker","bastion"],Ys=J({hostname:R().trim().max(120,"Max 120 chars").optional(),ip_address:R().trim().min(1,"IP address is required"),role:Ne(Ie),ssh_key_id:ts("Pick a valid SSH key"),ssh_user:R().trim().min(1,"SSH user is required"),status:Ne(_e).default("pending")}),Tr=Ys.partial();function $r({status:s}){const t=s==="ready"?"default":s==="provisioning"?"secondary":s==="failed"?"destructive":"outline";return e.jsx(Be,{variant:t,className:"capitalize",children:s})}function Ze(s,t=16){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}const Mr=()=>{const[s,t]=c.useState([]),[a,n]=c.useState([]),[m,u]=c.useState(!1),[g,j]=c.useState(null),[b,f]=c.useState(""),[k,p]=c.useState(""),[_,I]=c.useState(""),[$,M]=c.useState(!1),[F,o]=c.useState(null);function d(){const i=new URLSearchParams;return k&&i.set("status",k),_&&i.set("role",_),`/api/v1/servers${i.toString()?`?${i.toString()}`:""}`}async function l(){u(!0),j(null);try{const[i,r]=await Promise.all([z.get(d()),z.get("/api/v1/ssh")]);t(i??[]),n(r??[])}catch(i){console.error(i),j("Failed to load servers or SSH keys")}finally{u(!1)}}c.useEffect(()=>{l();const i=r=>{r.key==="active_org_id"&&l()};return window.addEventListener("storage",i),()=>window.removeEventListener("storage",i)},[]),c.useEffect(()=>{l()},[k,_]);const v=c.useMemo(()=>{const i=new Map;return a.forEach(r=>i.set(r.id,r)),i},[a]),A=c.useMemo(()=>{const i=b.trim().toLowerCase();return i?s.filter(r=>(r.hostname??"").toLowerCase().includes(i)||r.ip_address.toLowerCase().includes(i)||r.role.toLowerCase().includes(i)||r.ssh_user.toLowerCase().includes(i)):s},[s,b]);async function H(i){confirm("Delete this server? This cannot be undone.")&&(await z.delete(`/api/v1/servers/${encodeURIComponent(i)}`),await l())}const V=B({resolver:K(Ys),defaultValues:{hostname:"",ip_address:"",role:"worker",ssh_key_id:"",ssh_user:"ubuntu",status:"pending"}}),Q=async i=>{const r={ip_address:i.ip_address.trim(),role:i.role,ssh_key_id:i.ssh_key_id,ssh_user:i.ssh_user.trim(),status:i.status};i.hostname&&i.hostname.trim()&&(r.hostname=i.hostname.trim()),await z.post("/api/v1/servers",r),M(!1),V.reset(),await l()},U=B({resolver:K(Tr),defaultValues:{}});function ye(i){o(i),U.reset({hostname:i.hostname??"",ip_address:i.ip_address,role:Ie.includes(i.role)?i.role:"worker",ssh_key_id:i.ssh_key_id,ssh_user:i.ssh_user,status:_e.includes(i.status)?i.status:"pending"})}const xe=async i=>{if(!F)return;const r={};i.hostname!==void 0&&(r.hostname=i.hostname?.trim()||""),i.ip_address!==void 0&&(r.ip_address=i.ip_address.trim()),i.role!==void 0&&(r.role=i.role),i.ssh_key_id!==void 0&&(r.ssh_key_id=i.ssh_key_id),i.ssh_user!==void 0&&(r.ssh_user=i.ssh_user.trim()),i.status!==void 0&&(r.status=i.status),await z.patch(`/api/v1/servers/${encodeURIComponent(F.id)}`,r),o(null),await l()};return m?e.jsx("div",{className:"p-6",children:"Loading servers…"}):g?e.jsx("div",{className:"p-6 text-red-500",children:g}):e.jsxs(Ye,{children:[e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Servers"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:"relative",children:[e.jsx(Rs,{className:"absolute top-2.5 left-2 h-4 w-4 opacity-60"}),e.jsx(L,{value:b,onChange:i=>f(i.target.value),placeholder:"Search hostname, IP, role, user…",className:"w-64 pl-8"})]}),e.jsxs(Z,{value:_,onValueChange:i=>I(i),children:[e.jsx(se,{className:"w-36",children:e.jsx(ee,{placeholder:"Role (all)"})}),e.jsx(te,{children:Ie.map(i=>e.jsx(q,{value:i,children:i},i))})]}),e.jsxs(Z,{value:k,onValueChange:i=>p(i),children:[e.jsx(se,{className:"w-40",children:e.jsx(ee,{placeholder:"Status (all)"})}),e.jsx(te,{children:_e.map(i=>e.jsx(q,{value:i,children:i},i))})]}),e.jsxs(x,{variant:"outline",onClick:l,children:[e.jsx(Vs,{className:"mr-2 h-4 w-4"}),"Refresh"]}),e.jsxs(ae,{open:$,onOpenChange:M,children:[e.jsx(Ue,{asChild:!0,children:e.jsxs(x,{onClick:()=>M(!0),children:[e.jsx(Pe,{className:"mr-2 h-4 w-4"}),"Create Server"]})}),e.jsxs(re,{className:"sm:max-w-lg",children:[e.jsx(ne,{children:e.jsx(le,{children:"Create server"})}),e.jsx(G,{...V,children:e.jsxs("form",{onSubmit:V.handleSubmit(Q),className:"space-y-4",children:[e.jsx(w,{control:V.control,name:"hostname",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"Hostname"}),e.jsx(C,{children:e.jsx(L,{placeholder:"worker-01",...i})}),e.jsx(S,{})]})}),e.jsx(w,{control:V.control,name:"ip_address",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"IP address"}),e.jsx(C,{children:e.jsx(L,{placeholder:"10.0.1.23",...i})}),e.jsx(S,{})]})}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[e.jsx(w,{control:V.control,name:"role",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Z,{onValueChange:i.onChange,value:i.value,children:[e.jsx(C,{children:e.jsx(se,{children:e.jsx(ee,{placeholder:"Select role"})})}),e.jsx(te,{children:Ie.map(r=>e.jsx(q,{value:r,children:r},r))})]}),e.jsx(S,{})]})}),e.jsx(w,{control:V.control,name:"ssh_user",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"SSH user"}),e.jsx(C,{children:e.jsx(L,{placeholder:"ubuntu",...i})}),e.jsx(S,{})]})})]}),e.jsx(w,{control:V.control,name:"ssh_key_id",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"SSH key"}),e.jsxs(Z,{onValueChange:i.onChange,value:i.value,children:[e.jsx(C,{children:e.jsx(se,{children:e.jsx(ee,{placeholder:a.length?"Select SSH key":"No SSH keys found"})})}),e.jsx(te,{children:a.map(r=>e.jsxs(q,{value:r.id,children:[r.name?r.name:"Unnamed key"," —"," ",Ze(r.fingerprint,8)]},r.id))})]}),e.jsx(S,{})]})}),e.jsx(w,{control:V.control,name:"status",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"Initial status"}),e.jsxs(Z,{onValueChange:i.onChange,value:i.value,children:[e.jsx(C,{children:e.jsx(se,{children:e.jsx(ee,{placeholder:"pending"})})}),e.jsx(te,{children:_e.map(r=>e.jsx(q,{value:r,children:r},r))})]}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"gap-2",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>M(!1),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:V.formState.isSubmitting,children:V.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(De,{children:[e.jsx(Te,{children:e.jsxs(W,{children:[e.jsx(P,{children:"Hostname"}),e.jsx(P,{children:"IP address"}),e.jsx(P,{children:"Role"}),e.jsx(P,{children:"SSH user"}),e.jsx(P,{children:"SSH key"}),e.jsx(P,{children:"Status"}),e.jsx(P,{children:"Created"}),e.jsx(P,{className:"w-[180px] text-right",children:"Actions"})]})}),e.jsxs($e,{children:[A.map(i=>{const r=v.get(i.ssh_key_id);return e.jsxs(W,{children:[e.jsx(D,{className:"font-medium",children:i.hostname||"—"}),e.jsx(D,{children:e.jsx("code",{className:"font-mono text-sm",children:i.ip_address})}),e.jsx(D,{className:"capitalize",children:i.role}),e.jsx(D,{children:e.jsx("code",{className:"font-mono text-sm",children:i.ssh_user})}),e.jsx(D,{children:r?e.jsxs(ls,{children:[e.jsx(os,{asChild:!0,children:e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx(Be,{variant:"secondary",children:r.name||"SSH key"}),e.jsx("code",{className:"font-mono text-xs",children:Ze(r.fingerprint,8)})]})}),e.jsx(ds,{className:"max-w-[70vw]",children:e.jsx("p",{className:"font-mono text-xs break-all",children:r.public_keys})})]}):e.jsx("span",{className:"text-muted-foreground",children:"Unknown"})}),e.jsx(D,{children:e.jsx($r,{status:i.status})}),e.jsx(D,{children:new Date(i.created_at).toLocaleString()}),e.jsx(D,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(x,{variant:"outline",size:"sm",onClick:()=>ye(i),children:[e.jsx(Je,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(Re,{children:[e.jsx(Ve,{asChild:!0,children:e.jsxs(x,{variant:"destructive",size:"sm",children:[e.jsx(we,{className:"mr-2 h-4 w-4"})," Delete"]})}),e.jsx(He,{align:"end",children:e.jsx(me,{onClick:()=>H(i.id),children:"Confirm delete"})})]})]})})]},i.id)}),A.length===0&&e.jsx(W,{children:e.jsx(D,{colSpan:8,className:"text-muted-foreground py-10 text-center",children:"No servers match your filters."})})]})]})})})]}),e.jsx(ae,{open:!!F,onOpenChange:i=>!i&&o(null),children:e.jsxs(re,{className:"sm:max-w-lg",children:[e.jsx(ne,{children:e.jsx(le,{children:"Edit server"})}),e.jsx(G,{...U,children:e.jsxs("form",{onSubmit:U.handleSubmit(xe),className:"space-y-4",children:[e.jsx(w,{control:U.control,name:"hostname",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"Hostname"}),e.jsx(C,{children:e.jsx(L,{placeholder:"worker-01",...i})}),e.jsx(S,{})]})}),e.jsx(w,{control:U.control,name:"ip_address",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"IP address"}),e.jsx(C,{children:e.jsx(L,{placeholder:"10.0.1.23",...i})}),e.jsx(S,{})]})}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[e.jsx(w,{control:U.control,name:"role",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Z,{onValueChange:i.onChange,value:i.value,children:[e.jsx(C,{children:e.jsx(se,{children:e.jsx(ee,{placeholder:"Select role"})})}),e.jsx(te,{children:Ie.map(r=>e.jsx(q,{value:r,children:r},r))})]}),e.jsx(S,{})]})}),e.jsx(w,{control:U.control,name:"ssh_user",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"SSH user"}),e.jsx(C,{children:e.jsx(L,{placeholder:"ubuntu",...i})}),e.jsx(S,{})]})})]}),e.jsx(w,{control:U.control,name:"ssh_key_id",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"SSH key"}),e.jsxs(Z,{onValueChange:i.onChange,value:i.value,children:[e.jsx(C,{children:e.jsx(se,{children:e.jsx(ee,{placeholder:a.length?"Select SSH key":"No SSH keys found"})})}),e.jsx(te,{children:a.map(r=>e.jsxs(q,{value:r.id,children:[r.name?r.name:"SSH key"," — ",Ze(r.fingerprint,8)]},r.id))})]}),e.jsx(S,{})]})}),e.jsx(w,{control:U.control,name:"status",render:({field:i})=>e.jsxs(y,{children:[e.jsx(N,{children:"Status"}),e.jsxs(Z,{onValueChange:i.onChange,value:i.value,children:[e.jsx(C,{children:e.jsx(se,{children:e.jsx(ee,{placeholder:"pending"})})}),e.jsx(te,{children:_e.map(r=>e.jsx(q,{value:r,children:r},r))})]}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"gap-2",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>o(null),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:U.formState.isSubmitting,children:U.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})})]})},Pr=()=>e.jsx("div",{className:"space-y-4 p-6",children:e.jsx("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Taints"})})});function _s(){return e.jsxs("div",{className:"p-6",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"403 — Forbidden"}),e.jsx("p",{className:"text-muted-foreground text-sm",children:"You don’t have access to this area."})]})}const Is=()=>{const s=Fe();return e.jsxs("div",{className:"bg-background text-foreground flex min-h-screen flex-col items-center justify-center",children:[e.jsx("h1",{className:"mb-4 text-6xl font-bold",children:"404"}),e.jsx("p",{className:"mb-8 text-2xl",children:"Oops! Page not found"}),e.jsx(x,{onClick:()=>s("/dashboard"),children:"Go back to Dashboard"})]})},Fr=J({name:R().min(1,"Name is required").max(100,"Max 100 characters"),comment:R().trim().max(100,"Max 100 characters").default(""),bits:Ne(["2048","3072","4096"])});function Rr(s,t="download.bin"){if(!s)return t;const a=/filename\*=UTF-8''([^;]+)/i.exec(s);return a?.[1]?decodeURIComponent(a[1]):/filename="?([^"]+)"?/i.exec(s)?.[1]??t}function Vr(s,t=24){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}function Hr(s){return s?.split(/\s+/)?.[0]??"ssh-key"}async function Ur(s){try{await navigator.clipboard.writeText(s)}catch{const t=document.createElement("textarea");t.value=s,t.setAttribute("readonly",""),t.style.position="absolute",t.style.left="-9999px",document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t)}}const Br=()=>{const[s,t]=c.useState([]),[a,n]=c.useState(null),[m,u]=c.useState(!0),[g,j]=c.useState(""),[b,f]=c.useState(!1),k=c.useMemo(()=>!!localStorage.getItem("active_org_id"),[]);async function p(){u(!0),n(null);try{if(!k){t([]),n("Select an organization first.");return}const o=await z.get("/api/v1/ssh");t(o??[])}catch(o){console.error(o),n("Failed to fetch SSH keys")}finally{u(!1)}}c.useEffect(()=>{p();const o=d=>{d.key==="active_org_id"&&p()};return window.addEventListener("storage",o),()=>window.removeEventListener("storage",o)},[]);const _=s.filter(o=>`${o.name} ${o.public_keys} ${o.fingerprint}`.toLowerCase().includes(g.toLowerCase()));async function I(o,d="both"){const l=localStorage.getItem("access_token"),v=localStorage.getItem("active_org_id"),A=`${Ge}/api/v1/ssh/${encodeURIComponent(o)}/download?part=${encodeURIComponent(d)}`;try{const H=await fetch(A,{method:"GET",headers:{...l?{Authorization:`Bearer ${l}`}:{},...v?{"X-Org-ID":v}:{}}});if(!H.ok){const i=await H.text().catch(()=>"");throw new Error(i||`HTTP ${H.status}`)}const V=await H.blob(),Q=d==="both"?`ssh_key_${o}.zip`:d==="public"?`id_rsa_${o}.pub`:`id_rsa_${o}.pem`,U=Rr(H.headers.get("content-disposition")??void 0,Q),ye=URL.createObjectURL(V),xe=document.createElement("a");xe.href=ye,xe.download=U,document.body.appendChild(xe),xe.click(),xe.remove(),URL.revokeObjectURL(ye)}catch(H){console.error(H),alert(H instanceof Error?H.message:"Download failed")}}async function $(o){try{await z.delete(`/api/v1/ssh/${encodeURIComponent(o)}`),await p()}catch(d){console.error(d),alert("Failed to delete key")}}const M=B({resolver:K(Fr),defaultValues:{name:"",comment:"deploy@autoglue",bits:"4096"}});async function F(o){try{await z.post("/api/v1/ssh",{bits:Number(o.bits),comment:o.comment?.trim()??"",name:o.name.trim(),download:"none"}),f(!1),M.reset(),await p()}catch(d){console.error(d),alert("Failed to create key")}}return m?e.jsx("div",{className:"p-6",children:"Loading SSH Keys…"}):a?e.jsx("div",{className:"p-6 text-red-500",children:a}):e.jsx(Ye,{children:e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"SSH Keys"}),e.jsx("div",{className:"w-full max-w-sm",children:e.jsx(L,{value:g,onChange:o=>j(o.target.value),placeholder:"Search by name, fingerprint or key"})}),e.jsxs(ae,{open:b,onOpenChange:f,children:[e.jsx(Ue,{asChild:!0,children:e.jsxs(x,{onClick:()=>f(!0),children:[e.jsx(Pe,{className:"mr-2 h-4 w-4"}),"Create New Keypair"]})}),e.jsxs(re,{className:"sm:max-w-lg",children:[e.jsx(ne,{children:e.jsx(le,{children:"Create SSH Keypair"})}),e.jsx(G,{...M,children:e.jsxs("form",{onSubmit:M.handleSubmit(F),className:"space-y-4",children:[e.jsx(w,{control:M.control,name:"name",render:({field:o})=>e.jsxs(y,{children:[e.jsx(N,{children:"Name"}),e.jsx(C,{children:e.jsx(L,{placeholder:"e.g., CI deploy key",...o})}),e.jsx(S,{})]})}),e.jsx(w,{control:M.control,name:"comment",render:({field:o})=>e.jsxs(y,{children:[e.jsx(N,{children:"Comment"}),e.jsx(C,{children:e.jsx(L,{placeholder:"e.g., deploy@autoglue",...o})}),e.jsx(S,{})]})}),e.jsx(w,{control:M.control,name:"bits",render:({field:o})=>e.jsxs(y,{children:[e.jsx(N,{children:"Key size"}),e.jsx(C,{children:e.jsxs("select",{className:"bg-background w-full rounded-md border px-3 py-2 text-sm",value:o.value,onChange:o.onChange,children:[e.jsx("option",{value:"2048",children:"2048"}),e.jsx("option",{value:"3072",children:"3072"}),e.jsx("option",{value:"4096",children:"4096"})]})}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"gap-2",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>f(!1),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:M.formState.isSubmitting,children:M.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(De,{children:[e.jsx(Te,{children:e.jsxs(W,{children:[e.jsx(P,{children:"Name"}),e.jsx(P,{className:"min-w-[360px]",children:"Public Key"}),e.jsx(P,{children:"Fingerprint"}),e.jsx(P,{children:"Created"}),e.jsx(P,{className:"w-[160px] text-right",children:"Actions"})]})}),e.jsx($e,{children:_.map(o=>{const d=Hr(o.public_keys),l=Vr(o.public_keys,18);return e.jsxs(W,{children:[e.jsx(D,{className:"align-top",children:o.name}),e.jsx(D,{className:"align-top",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(Be,{variant:"secondary",className:"whitespace-nowrap",children:d}),e.jsxs(ls,{children:[e.jsx(os,{asChild:!0,children:e.jsx("code",{className:"font-mono text-sm break-all md:max-w-[48ch] md:truncate md:break-normal",children:l})}),e.jsx(ds,{className:"max-w-[70vw]",children:e.jsx("div",{className:"max-w-full",children:e.jsx("p",{className:"font-mono text-xs break-all",children:o.public_keys})})})]})]})}),e.jsx(D,{className:"align-top",children:e.jsx("code",{className:"font-mono text-sm",children:o.fingerprint})}),e.jsx(D,{className:"align-top",children:new Date(o.created_at).toLocaleString(void 0,{year:"numeric",month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit"})}),e.jsx(D,{className:"align-top",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(x,{variant:"outline",size:"sm",onClick:()=>Ur(o.public_keys),title:"Copy public key",children:[e.jsx(ha,{className:"mr-2 h-4 w-4"}),"Copy"]}),e.jsxs(Re,{children:[e.jsx(Ve,{asChild:!0,children:e.jsxs(x,{variant:"outline",size:"sm",children:[e.jsx(ja,{className:"mr-2 h-4 w-4"}),"Download"]})}),e.jsxs(He,{align:"end",children:[e.jsx(me,{onClick:()=>I(o.id,"both"),children:"Public + Private (.zip)"}),e.jsx(me,{onClick:()=>I(o.id,"public"),children:"Public only (.pub)"}),e.jsx(me,{onClick:()=>I(o.id,"private"),children:"Private only (.pem)"})]})]}),e.jsxs(x,{variant:"destructive",size:"sm",onClick:()=>$(o.id),children:[e.jsx(we,{className:"mr-2 h-4 w-4"}),"Delete"]})]})})]},o.id)})})]})})})]})})};function Kr(s){const t=s?.user_id??s?.UserID??s?.user?.id??s?.User?.ID??"",a=s?.email??s?.Email??s?.user?.email??s?.User?.Email,n=s?.name??s?.Name??s?.user?.name??s?.User?.Name,m=s?.role??s?.Role??"member",u=s?.created_at??s?.CreatedAt;return{userId:String(t),email:a,name:n,role:String(m),joinedAt:u}}const Gr=J({email:Se("Enter a valid email"),role:Ne(["member","admin"])}),qr=()=>{const[s,t]=c.useState(!0),[a,n]=c.useState([]),[m,u]=c.useState(null),[g,j]=c.useState(!1),[b,f]=c.useState(!1),[k,p]=c.useState(null),_=c.useMemo(()=>je(),[]),I=B({resolver:K(Gr),defaultValues:{email:"",role:"member"},mode:"onChange"});async function $(){try{const d=await z.get("/api/v1/auth/me");u(d)}catch{}}async function M(d){if(!d){n([]),t(!1);return}t(!0);try{const l=await z.get("/api/v1/orgs/members");n((l??[]).map(Kr))}catch(l){const v=l instanceof Y?l.message:"Failed to load members";O.error(v)}finally{t(!1)}}c.useEffect(()=>{$(),M(_)},[_]),c.useEffect(()=>{const d=()=>void M(je()),l=v=>{v.key==="active_org_id"&&d()};return window.addEventListener(be,d),window.addEventListener("storage",l),()=>{window.removeEventListener(be,d),window.removeEventListener("storage",l)}},[]);async function F(d){const l=je();if(!l){O.error("Select an organization first");return}try{f(!0),await z.post("/api/v1/orgs/invite",d),O.success(`Invited ${d.email}`),j(!1),I.reset({email:"",role:"member"}),M(l)}catch(v){const A=v instanceof Y?v.message:"Failed to invite member";O.error(A)}finally{f(!1)}}async function o(d){const l=je();if(!l){O.error("Select an organization first");return}try{p(d),await z.delete(`/api/v1/orgs/members/${d}`,{headers:{"X-Org-ID":l}}),n(v=>v.filter(A=>A.userId!==d)),O.success("Member removed")}catch(v){const A=v instanceof Y?v.message:"Failed to remove member";O.error(A)}finally{p(null)}}return s?e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Members"}),e.jsxs(x,{disabled:!0,children:[e.jsx(bs,{className:"mr-2 h-4 w-4"}),"Invite"]})]}),e.jsx(ze,{}),e.jsx("div",{className:"grid gap-4 sm:grid-cols-2 lg:grid-cols-3",children:[...Array(6)].map((d,l)=>e.jsxs(oe,{children:[e.jsx(de,{children:e.jsx(fe,{className:"h-5 w-40"})}),e.jsxs(ce,{className:"space-y-2",children:[e.jsx(fe,{className:"h-4 w-56"}),e.jsx(fe,{className:"h-4 w-40"})]}),e.jsx(Ae,{children:e.jsx(fe,{className:"h-9 w-24"})})]},l))})]}):je()?e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Members"}),e.jsxs(ae,{open:g,onOpenChange:j,children:[e.jsx(Ue,{asChild:!0,children:e.jsxs(x,{children:[e.jsx(bs,{className:"mr-2 h-4 w-4"}),"Invite"]})}),e.jsxs(re,{className:"sm:max-w-[520px]",children:[e.jsxs(ne,{children:[e.jsx(le,{children:"Invite member"}),e.jsx(qe,{children:"Send an invite to join this organization."})]}),e.jsx(G,{...I,children:e.jsxs("form",{onSubmit:I.handleSubmit(F),className:"grid gap-4 py-2",children:[e.jsx(w,{control:I.control,name:"email",render:({field:d})=>e.jsxs(y,{children:[e.jsx(N,{children:"Email"}),e.jsx(C,{children:e.jsx(L,{type:"email",placeholder:"jane@example.com",...d})}),e.jsx(S,{})]})}),e.jsx(w,{control:I.control,name:"role",render:({field:d})=>e.jsxs(y,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Z,{onValueChange:d.onChange,defaultValue:d.value,children:[e.jsx(C,{children:e.jsx(se,{className:"w-[200px]",children:e.jsx(ee,{placeholder:"Select role"})})}),e.jsxs(te,{children:[e.jsx(q,{value:"member",children:"Member"}),e.jsx(q,{value:"admin",children:"Admin"})]})]}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"mt-2 flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>j(!1),children:"Cancel"}),e.jsx(x,{type:"submit",disabled:!I.formState.isValid||b,children:b?"Sending…":"Send invite"})]})]})})]})]})]}),e.jsx(ze,{}),a.length===0?e.jsx("div",{className:"text-muted-foreground text-sm",children:"No members yet."}):e.jsx("div",{className:"grid grid-cols-1 gap-4 pr-2 sm:grid-cols-2 lg:grid-cols-3",children:a.map(d=>{const l=m?.id&&d.userId===m.id;return e.jsxs(oe,{className:"flex flex-col",children:[e.jsx(de,{children:e.jsx(he,{className:"text-base",children:d.name||d.email||d.userId})}),e.jsxs(ce,{className:"text-muted-foreground space-y-1 text-sm",children:[d.email&&e.jsxs("div",{children:["Email: ",d.email]}),e.jsxs("div",{children:["Role: ",d.role]}),d.joinedAt&&e.jsxs("div",{children:["Joined: ",new Date(d.joinedAt).toLocaleString()]})]}),e.jsxs(Ae,{className:"mt-auto w-full flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx("div",{}),e.jsxs(cs,{children:[e.jsx(ms,{asChild:!0,children:e.jsxs(x,{variant:"destructive",disabled:l||k===d.userId,className:"ml-auto",children:[e.jsx(we,{className:"mr-2 h-5 w-5"}),k===d.userId?"Removing…":"Remove"]})}),e.jsxs(us,{children:[e.jsxs(xs,{children:[e.jsx(js,{children:"Remove member?"}),e.jsxs(fs,{children:["This will remove ",e.jsx("b",{children:d.name||d.email||d.userId})," from the organization."]})]}),e.jsxs(hs,{className:"sm:justify-between",children:[e.jsx(ps,{disabled:k===d.userId,children:"Cancel"}),e.jsx(gs,{asChild:!0,disabled:k===d.userId,children:e.jsx(x,{variant:"destructive",onClick:()=>o(d.userId),children:"Confirm remove"})})]})]})]})]})]},d.userId)})})]}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsx("h1",{className:"text-2xl font-bold",children:"Members"})}),e.jsx(ze,{}),e.jsx("p",{className:"text-muted-foreground text-sm",children:"No organization selected. Choose an organization to manage its members."})]})},Jr=J({name:R().min(2).max(100),slug:R().min(2).max(50).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/,"Use lowercase letters, numbers, and hyphens.")}),Wr=()=>{const[s,t]=c.useState([]),[a,n]=c.useState(!0),[m,u]=c.useState(!1),[g,j]=c.useState(null),[b,f]=c.useState(null),k=c.useRef(!1),p=B({resolver:K(Jr),mode:"onChange",defaultValues:{name:"",slug:""}}),_=p.watch("name");c.useEffect(()=>{k.current||p.setValue("slug",ws(_||""),{shouldValidate:!0})},[_,p]);const I=async()=>{n(!0);try{const o=await z.get("/api/v1/orgs");t(o),u(o.length===0)}catch(o){const d=o instanceof Y?o.message:"Failed to load organizations";O.error(d)}finally{n(!1)}};c.useEffect(()=>{j(je()),I();const o=v=>{v.key==="active_org_id"&&j(v.newValue)};window.addEventListener("storage",o);const d=v=>{const A=v.detail??null;j(A)};window.addEventListener(be,d);const l=()=>void I();return window.addEventListener(Le,l),()=>{window.removeEventListener("storage",o),window.removeEventListener(be,d),window.removeEventListener(Le,l)}},[]);async function $(o){try{const d=await z.post("/api/v1/orgs",o);t(l=>[d,...l]),Oe(d.id),j(d.id),ys(),O.success(`Created ${d.name}`),u(!1),p.reset({name:"",slug:""}),k.current=!1}catch(d){const l=d instanceof Y?d.message:"Failed to create organization";O.error(l)}}function M(o){Oe(o.id),j(o.id),O.success(`Switched to ${o.name}`)}async function F(o){try{f(o.id),await z.delete(`/api/v1/orgs/${o.id}`),t(d=>{const l=d.filter(v=>v.id!==o.id);if(g===o.id){const v=l[0]?.id??null;Oe(v),j(v)}return l}),ys(),O.success(`Deleted ${o.name}`)}catch(d){const l=d instanceof Y?d.message:"Failed to delete organization";O.error(l)}finally{f(null)}}return a?e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsx("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Organizations"})}),e.jsx("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",children:[...Array(6)].map((o,d)=>e.jsxs(oe,{children:[e.jsx(de,{children:e.jsx(fe,{className:"h-5 w-40"})}),e.jsxs(ce,{children:[e.jsx(fe,{className:"mb-2 h-4 w-24"}),e.jsx(fe,{className:"h-4 w-48"})]}),e.jsx(Ae,{children:e.jsx(fe,{className:"h-9 w-24"})})]},d))})]}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Organizations"}),e.jsx(x,{onClick:()=>u(!0),children:"New organization"})]}),e.jsx(ze,{}),s.length===0?e.jsx("div",{className:"text-muted-foreground text-sm",children:"No organizations yet."}):e.jsx("div",{className:"grid grid-cols-1 gap-4 pr-2 sm:grid-cols-2 lg:grid-cols-3",children:s.map(o=>e.jsxs(oe,{className:"flex flex-col",children:[e.jsx(de,{children:e.jsx(he,{className:"text-base",children:o.name})}),e.jsxs(ce,{className:"text-muted-foreground text-sm",children:[e.jsxs("div",{children:["Slug: ",o.slug]}),e.jsxs("div",{className:"mt-1",children:["ID: ",o.id]})]}),e.jsxs(Ae,{className:"mt-auto w-full flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(x,{onClick:()=>M(o),children:o.id===g?"Selected":"Select"}),e.jsxs(cs,{children:[e.jsx(ms,{asChild:!0,children:e.jsxs(x,{variant:"destructive",className:"ml-auto",disabled:b===o.id,children:[e.jsx(we,{className:"mr-2 h-5 w-5"}),b===o.id?"Deleting…":"Delete"]})}),e.jsxs(us,{children:[e.jsxs(xs,{children:[e.jsx(js,{children:"Delete organization?"}),e.jsxs(fs,{children:["This will permanently delete ",e.jsx("b",{children:o.name}),". This action cannot be undone."]})]}),e.jsxs(hs,{className:"sm:justify-between",children:[e.jsx(ps,{disabled:b===o.id,children:"Cancel"}),e.jsx(gs,{asChild:!0,disabled:b===o.id,children:e.jsx(x,{variant:"destructive",onClick:()=>F(o),children:"Confirm delete"})})]})]})]})]})]},o.id))}),e.jsx(ae,{open:m,onOpenChange:u,children:e.jsxs(re,{className:"sm:max-w-[480px]",children:[e.jsxs(ne,{children:[e.jsx(le,{children:"Create organization"}),e.jsx(qe,{children:"Set a name and a URL-friendly slug."})]}),e.jsx(G,{...p,children:e.jsxs("form",{onSubmit:p.handleSubmit($),className:"space-y-4",children:[e.jsx(w,{control:p.control,name:"name",render:({field:o})=>e.jsxs(y,{children:[e.jsx(N,{children:"Name"}),e.jsx(C,{children:e.jsx(L,{placeholder:"Acme Inc",autoFocus:!0,...o})}),e.jsx(Ns,{children:"This is your organization’s display name."}),e.jsx(S,{})]})}),e.jsx(w,{control:p.control,name:"slug",render:({field:o})=>e.jsxs(y,{children:[e.jsx(N,{children:"Slug"}),e.jsx(C,{children:e.jsx(L,{placeholder:"acme-inc",...o,onChange:d=>{k.current=!0,o.onChange(d)},onBlur:d=>{const l=ws(d.target.value);p.setValue("slug",l,{shouldValidate:!0}),o.onBlur()}})}),e.jsx(Ns,{children:"Lowercase, numbers and hyphens only."}),e.jsx(S,{})]})}),e.jsxs(ie,{className:"flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(x,{type:"button",variant:"outline",onClick:()=>{p.reset(),u(!1),k.current=!1},children:"Cancel"}),e.jsx(x,{type:"submit",disabled:!p.formState.isValid||p.formState.isSubmitting,children:p.formState.isSubmitting?"Creating...":"Create"})]})]})})]})})]})};function Yr(){return e.jsxs(fa,{children:[e.jsx(T,{path:"/",element:e.jsx(ns,{to:"/auth/login",replace:!0})}),e.jsxs(T,{path:"/auth",children:[e.jsx(T,{path:"login",element:e.jsx(vr,{})}),e.jsx(T,{path:"register",element:e.jsx(yr,{})}),e.jsx(T,{path:"forgot",element:e.jsx(gr,{})}),e.jsx(T,{path:"reset",element:e.jsx(Sr,{})}),e.jsx(T,{path:"verify",element:e.jsx(Cr,{})})]}),e.jsx(T,{element:e.jsx(rr,{}),children:e.jsxs(T,{element:e.jsx(ar,{}),children:[e.jsx(T,{element:e.jsx(nr,{}),children:e.jsx(T,{path:"/admin",children:e.jsx(T,{path:"users",element:e.jsx(jr,{})})})}),e.jsxs(T,{path:"/core",children:[e.jsx(T,{path:"annotations",element:e.jsx(kr,{})}),e.jsx(T,{path:"clusters",element:e.jsx(_r,{})}),e.jsx(T,{path:"labels",element:e.jsx(Er,{})}),e.jsx(T,{path:"nodepools",element:e.jsx(Dr,{})}),e.jsx(T,{path:"servers",element:e.jsx(Mr,{})}),e.jsx(T,{path:"taints",element:e.jsx(Pr,{})})]}),e.jsx(T,{path:"/security",children:e.jsx(T,{path:"ssh",element:e.jsx(Br,{})})}),e.jsxs(T,{path:"/settings",children:[e.jsx(T,{path:"orgs",element:e.jsx(Wr,{})}),e.jsx(T,{path:"members",element:e.jsx(qr,{})}),e.jsx(T,{path:"me",element:e.jsx(br,{})})]}),e.jsx(T,{path:"/403",element:e.jsx(_s,{})}),e.jsx(T,{path:"*",element:e.jsx(Is,{})})]})}),e.jsx(T,{path:"/403",element:e.jsx(_s,{})}),e.jsx(T,{path:"*",element:e.jsx(Is,{})})]})}const Xr=({...s})=>{const{theme:t="system"}=Es();return e.jsx(rt,{theme:t,className:"toaster group",style:{"--normal-bg":"var(--popover)","--normal-text":"var(--popover-foreground)","--normal-border":"var(--border)"},...s})};function Qr({children:s,defaultTheme:t="system",storageKey:a="vite-ui-theme"}){return e.jsx(nt,{attribute:"class",defaultTheme:t,enableSystem:!0,storageKey:a,disableTransitionOnChange:!0,children:s})}it.createRoot(document.getElementById("root")).render(e.jsx(c.StrictMode,{children:e.jsx(ga,{children:e.jsxs(Qr,{defaultTheme:"system",storageKey:"dragon-theme",children:[e.jsx(Yr,{}),e.jsx(Xr,{richColors:!0,position:"top-right"})]})})})); diff --git a/internal/ui/dist/assets/index-DSxuk_EI.js b/internal/ui/dist/assets/index-DSxuk_EI.js new file mode 100644 index 0000000..c17962b --- /dev/null +++ b/internal/ui/dist/assets/index-DSxuk_EI.js @@ -0,0 +1 @@ +import{t as ia,m as oa,r as o,j as e,n as qs,z as yt,F as la,C as da,p as ca,q as ma,v as re,w as F,_ as Je,x as js,y as St,A as te,B as ae,D as ee,E as Oe,G as us,T as xa,J as ha,H as ua}from"./vendor-DvippHRz.js";import{S as Cs,R as ja,a as Ct,C as _t,b as kt,T as At,D as Et,P as $t,O as Lt,c as fa,d as pa,e as ga,f as va,g as ba,A as Na,h as wa,i as ya,j as Sa,k as Ca,l as _a,m as ka,n as Aa,I as Ea,o as $a,p as La,q as Da,r as Ia,s as Ta,t as Pa,u as Ma,v as Oa,w as za,x as Fa,y as Ra,z as Va,B as Ua,E as Ba,V as Ha,F as Ka,G as qa,H as Ga,J as Ja,K as Qa,L as Wa,M as Ya,N as Xa,Q as Za,U as en}from"./radix-DRmH1vcw.js";import{X as Dt,S as sn,M as tn,L as an,C as bs,H as nn,A as rn,B as on,a as ln,T as It,b as dn,c as hs,d as cn,K as mn,F as xn,e as hn,f as un,G as jn,g as fn,U as mt,h as pn,i as gn,j as vn,k as Gs,l as bn,m as Nn,P as Qe,n as rs,o as Ue,p as Ts,R as Ps,q as ye,r as qe,s as wn,t as $s,u as yn,v as Sn,w as Cn,x as _n,y as xt}from"./icons-B5E6SSBo.js";import{u as Ms,L as as,O as Js,N as Qs,a as _s,b as Tt,R as kn,c as se,B as An}from"./router-CANfZtzM.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))d(u);new MutationObserver(u=>{for(const f of u)if(f.type==="childList")for(const $ of f.addedNodes)$.tagName==="LINK"&&$.rel==="modulepreload"&&d($)}).observe(document,{childList:!0,subtree:!0});function r(u){const f={};return u.integrity&&(f.integrity=u.integrity),u.referrerPolicy&&(f.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?f.credentials="include":u.crossOrigin==="anonymous"?f.credentials="omit":f.credentials="same-origin",f}function d(u){if(u.ep)return;u.ep=!0;const f=r(u);fetch(u.href,f)}})();function L(...s){return ia(oa(s))}function ht(s){return s.toLowerCase().trim().replace(/['"]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)+/g,"")}const Us=768;function En(){const[s,t]=o.useState(void 0);return o.useEffect(()=>{const r=window.matchMedia(`(max-width: ${Us-1}px)`),d=()=>{t(window.innerWidthr.removeEventListener("change",d)},[]),!!s}const Ws=qs("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",{variants:{variant:{default:"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",destructive:"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",outline:"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",secondary:"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2 has-[>svg]:px-3",sm:"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",lg:"h-10 rounded-md px-6 has-[>svg]:px-4",icon:"size-9"}},defaultVariants:{variant:"default",size:"default"}});function h({className:s,variant:t,size:r,asChild:d=!1,...u}){const f=d?Cs:"button";return e.jsx(f,{"data-slot":"button",className:L(Ws({variant:t,size:r,className:s})),...u})}function z({className:s,type:t,...r}){return e.jsx("input",{type:t,"data-slot":"input",className:L("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm","focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]","aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",s),...r})}function Ns({className:s,orientation:t="horizontal",decorative:r=!0,...d}){return e.jsx(ja,{"data-slot":"separator",decorative:r,orientation:t,className:L("bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",s),...d})}function $n({...s}){return e.jsx(Ct,{"data-slot":"sheet",...s})}function Ln({...s}){return e.jsx($t,{"data-slot":"sheet-portal",...s})}function Dn({className:s,...t}){return e.jsx(Lt,{"data-slot":"sheet-overlay",className:L("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",s),...t})}function In({className:s,children:t,side:r="right",...d}){return e.jsxs(Ln,{children:[e.jsx(Dn,{}),e.jsxs(_t,{"data-slot":"sheet-content",className:L("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",r==="right"&&"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",r==="left"&&"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",r==="top"&&"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",r==="bottom"&&"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",s),...d,children:[t,e.jsxs(kt,{className:"ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none",children:[e.jsx(Dt,{className:"size-4"}),e.jsx("span",{className:"sr-only",children:"Close"})]})]})]})}function Tn({className:s,...t}){return e.jsx("div",{"data-slot":"sheet-header",className:L("flex flex-col gap-1.5 p-4",s),...t})}function Pn({className:s,...t}){return e.jsx(At,{"data-slot":"sheet-title",className:L("text-foreground font-semibold",s),...t})}function Mn({className:s,...t}){return e.jsx(Et,{"data-slot":"sheet-description",className:L("text-muted-foreground text-sm",s),...t})}function Ge({className:s,...t}){return e.jsx("div",{"data-slot":"skeleton",className:L("bg-accent animate-pulse rounded-md",s),...t})}function Os({delayDuration:s=0,...t}){return e.jsx(fa,{"data-slot":"tooltip-provider",delayDuration:s,...t})}function Ys({...s}){return e.jsx(Os,{children:e.jsx(pa,{"data-slot":"tooltip",...s})})}function Xs({...s}){return e.jsx(ga,{"data-slot":"tooltip-trigger",...s})}function Zs({className:s,sideOffset:t=0,children:r,...d}){return e.jsx(va,{children:e.jsxs(ba,{"data-slot":"tooltip-content",sideOffset:t,className:L("bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",s),...d,children:[r,e.jsx(Na,{className:"bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]"})]})})}const On="sidebar_state",zn=3600*24*7,Fn="16rem",Rn="18rem",Vn="3rem",Un="b",Pt=o.createContext(null);function Mt(){const s=o.useContext(Pt);if(!s)throw new Error("useSidebar must be used within a SidebarProvider.");return s}function Bn({defaultOpen:s=!0,open:t,onOpenChange:r,className:d,style:u,children:f,...$}){const C=En(),[O,M]=o.useState(!1),[R,U]=o.useState(s),T=t??R,P=o.useCallback(m=>{const x=typeof m=="function"?m(T):m;r?r(x):U(x),document.cookie=`${On}=${x}; path=/; max-age=${zn}`},[r,T]),j=o.useCallback(()=>C?M(m=>!m):P(m=>!m),[C,P,M]);o.useEffect(()=>{const m=x=>{x.key===Un&&(x.metaKey||x.ctrlKey)&&(x.preventDefault(),j())};return window.addEventListener("keydown",m),()=>window.removeEventListener("keydown",m)},[j]);const V=T?"expanded":"collapsed",H=o.useMemo(()=>({state:V,open:T,setOpen:P,isMobile:C,openMobile:O,setOpenMobile:M,toggleSidebar:j}),[V,T,P,C,O,M,j]);return e.jsx(Pt.Provider,{value:H,children:e.jsx(Os,{delayDuration:0,children:e.jsx("div",{"data-slot":"sidebar-wrapper",style:{"--sidebar-width":Fn,"--sidebar-width-icon":Vn,...u},className:L("group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",d),...$,children:f})})})}function Hn({side:s="left",variant:t="sidebar",collapsible:r="offcanvas",className:d,children:u,...f}){const{isMobile:$,state:C,openMobile:O,setOpenMobile:M}=Mt();return r==="none"?e.jsx("div",{"data-slot":"sidebar",className:L("bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",d),...f,children:u}):$?e.jsx($n,{open:O,onOpenChange:M,...f,children:e.jsxs(In,{"data-sidebar":"sidebar","data-slot":"sidebar","data-mobile":"true",className:"bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden",style:{"--sidebar-width":Rn},side:s,children:[e.jsxs(Tn,{className:"sr-only",children:[e.jsx(Pn,{children:"Sidebar"}),e.jsx(Mn,{children:"Displays the mobile sidebar."})]}),e.jsx("div",{className:"flex h-full w-full flex-col",children:u})]})}):e.jsxs("div",{className:"group peer text-sidebar-foreground hidden md:block","data-state":C,"data-collapsible":C==="collapsed"?r:"","data-variant":t,"data-side":s,"data-slot":"sidebar",children:[e.jsx("div",{"data-slot":"sidebar-gap",className:L("relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear","group-data-[collapsible=offcanvas]:w-0","group-data-[side=right]:rotate-180",t==="floating"||t==="inset"?"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]":"group-data-[collapsible=icon]:w-(--sidebar-width-icon)")}),e.jsx("div",{"data-slot":"sidebar-container",className:L("fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",s==="left"?"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]":"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",t==="floating"||t==="inset"?"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]":"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",d),...f,children:e.jsx("div",{"data-sidebar":"sidebar","data-slot":"sidebar-inner",className:"bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm",children:u})})]})}function Kn({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-header","data-sidebar":"header",className:L("flex flex-col gap-2 p-2",s),...t})}function qn({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-footer","data-sidebar":"footer",className:L("flex flex-col gap-2 p-2",s),...t})}function Gn({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-content","data-sidebar":"content",className:L("flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",s),...t})}function Jn({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-group","data-sidebar":"group",className:L("relative flex w-full min-w-0 flex-col p-2",s),...t})}function Qn({className:s,asChild:t=!1,...r}){const d=t?Cs:"div";return e.jsx(d,{"data-slot":"sidebar-group-label","data-sidebar":"group-label",className:L("text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0","group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",s),...r})}function Wn({className:s,...t}){return e.jsx("div",{"data-slot":"sidebar-group-content","data-sidebar":"group-content",className:L("w-full text-sm",s),...t})}function Yn({className:s,...t}){return e.jsx("ul",{"data-slot":"sidebar-menu","data-sidebar":"menu",className:L("flex w-full min-w-0 flex-col gap-1",s),...t})}function Xn({className:s,...t}){return e.jsx("li",{"data-slot":"sidebar-menu-item","data-sidebar":"menu-item",className:L("group/menu-item relative",s),...t})}const Zn=qs("peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",{variants:{variant:{default:"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",outline:"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"},size:{default:"h-8 text-sm",sm:"h-7 text-xs",lg:"h-12 text-sm group-data-[collapsible=icon]:p-0!"}},defaultVariants:{variant:"default",size:"default"}});function er({asChild:s=!1,isActive:t=!1,variant:r="default",size:d="default",tooltip:u,className:f,...$}){const C=s?Cs:"button",{isMobile:O,state:M}=Mt(),R=e.jsx(C,{"data-slot":"sidebar-menu-button","data-sidebar":"menu-button","data-size":d,"data-active":t,className:L(Zn({variant:r,size:d}),f),...$});return u?(typeof u=="string"&&(u={children:u}),e.jsxs(Ys,{children:[e.jsx(Xs,{asChild:!0,children:R}),e.jsx(Zs,{side:"right",align:"center",hidden:M!=="collapsed"||O,...u})]})):R}const Ls="";class je extends Error{status;body;constructor(t,r,d){super(r),this.status=t,this.body=d}}function sr(s){const t={};if(!s)return t;if(s instanceof Headers)s.forEach((r,d)=>t[d]=r);else if(Array.isArray(s))for(const[r,d]of s)t[r]=d;else Object.assign(t,s);return t}function tr(){const s={},t=localStorage.getItem("access_token");return t&&(s.Authorization=`Bearer ${t}`),s}function ar(){const s=localStorage.getItem("active_org_id");return s?{"X-Org-ID":s}:{}}async function fs(s,t,r,d={}){const f={...{"Content-Type":"application/json"},...d.auth===!1?{}:tr(),...ar(),...sr(d.headers)},$=await fetch(`${Ls}${s}`,{method:t,headers:f,body:r===void 0?void 0:JSON.stringify(r),...d}),O=($.headers.get("content-type")||"").includes("application/json"),M=O?await $.json().catch(()=>{}):await $.text().catch(()=>"");if(!$.ok){const R=O&&M&&typeof M=="object"&&"error"in M&&M.error||O&&M&&typeof M=="object"&&"message"in M&&M.message||typeof M=="string"&&M||`HTTP ${$.status}`;throw new je($.status,String(R),M)}return console.debug("API ->",t,`${Ls}${s}`,f),O?M:void 0}const g={get:(s,t)=>fs(s,"GET",void 0,t),post:(s,t,r)=>fs(s,"POST",t,r),put:(s,t,r)=>fs(s,"PUT",t,r),patch:(s,t,r)=>fs(s,"PATCH",t,r),delete:(s,t)=>fs(s,"DELETE",void 0,t)};function nr(s){return s&&(s.user||s.user_id)}function Ot(s){return nr(s)?.role==="admin"}function rr(s){return(s?.org_role??"")==="admin"}const Ve={isAuthenticated(){return!!localStorage.getItem("access_token")},async login(s,t){const r=await g.post("/api/v1/auth/login",{email:s,password:t});localStorage.setItem("access_token",r.access_token),localStorage.setItem("refresh_token",r.refresh_token)},async register(s,t,r){await g.post("/api/v1/auth/register",{name:s,email:t,password:r})},async me(){return await g.get("/api/v1/auth/me")},async logout(){const s=localStorage.getItem("refresh_token");if(s)try{await g.post("/api/v1/auth/logout",{refresh_token:s})}catch{}localStorage.removeItem("access_token"),localStorage.removeItem("refresh_token")},async forgot(s){await g.post("/api/v1/auth/password/forgot",{email:s})},async reset(s,t){await g.post("/api/v1/auth/password/reset",{token:s,new_password:t})},async verify(s){const t=await fetch(`${Ls}/api/v1/auth/verify?token=${encodeURIComponent(s)}`);if(!t.ok){const r=await t.text();throw new Error(r)}}};function ir({...s}){return e.jsx(wa,{"data-slot":"collapsible",...s})}function or({...s}){return e.jsx(ya,{"data-slot":"collapsible-trigger",...s})}function lr({...s}){return e.jsx(Sa,{"data-slot":"collapsible-content",...s})}function is({...s}){return e.jsx(Ca,{"data-slot":"dropdown-menu",...s})}function os({...s}){return e.jsx(_a,{"data-slot":"dropdown-menu-trigger",...s})}function ls({className:s,sideOffset:t=4,...r}){return e.jsx(ka,{children:e.jsx(Aa,{"data-slot":"dropdown-menu-content",sideOffset:t,className:L("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",s),...r})})}function Ie({className:s,inset:t,variant:r="default",...d}){return e.jsx(Ea,{"data-slot":"dropdown-menu-item","data-inset":t,"data-variant":r,className:L("focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",s),...d})}function dr(){const{setTheme:s,theme:t}=yt();return e.jsxs(is,{children:[e.jsx(os,{asChild:!0,children:e.jsx(h,{variant:"outline",size:"icon","aria-label":"Toggle theme",children:t==="light"?e.jsx(sn,{className:"h-5 w-5"}):t==="dark"?e.jsx(tn,{className:"h-5 w-5"}):e.jsx(an,{className:"h-5 w-5"})})}),e.jsxs(ls,{align:"end",children:[e.jsxs(Ie,{onClick:()=>s("light"),children:[t==="light"&&e.jsx(bs,{}),"Light"]}),e.jsxs(Ie,{onClick:()=>s("dark"),children:[t==="dark"&&e.jsx(bs,{}),"Dark"]}),e.jsxs(Ie,{onClick:()=>s("system"),children:[t==="system"&&e.jsx(bs,{}),"System"]})]})]})}const Ks="active_org_id",ns="active-org-changed",ys="orgs-changed";function Ke(){return localStorage.getItem(Ks)}function ws(s){s?localStorage.setItem(Ks,s):localStorage.removeItem(Ks),window.dispatchEvent(new CustomEvent(ns,{detail:s}))}function ut(){window.dispatchEvent(new Event(ys))}const cr=()=>{const[s,t]=o.useState([]),[r,d]=o.useState(null);async function u(){try{const C=await g.get("/api/v1/orgs");t(C),!Ke()&&C.length>0&&(ws(C[0].id),d(C[0].id))}catch(C){const O=C instanceof je?C.message:"Failed to load organizations";console.error(O)}}o.useEffect(()=>{d(Ke()),u();const C=R=>{R.key==="active_org_id"&&d(R.newValue)};window.addEventListener("storage",C);const O=R=>d(R.detail??null),M=()=>void u();return window.addEventListener(ns,O),window.addEventListener(ys,M),()=>{window.removeEventListener("storage",C),window.removeEventListener(ns,O),window.removeEventListener(ys,M)}},[]);const f=C=>{ws(C),d(C)},$=s.find(C=>C.id===r)?.name??"Select Org";return e.jsxs(is,{children:[e.jsx(os,{asChild:!0,children:e.jsx(h,{variant:"outline",className:"w-full justify-start",children:$})}),e.jsx(ls,{className:"w-48",children:s.length===0?e.jsx(Ie,{disabled:!0,children:"No organizations"}):s.map(C=>e.jsx(Ie,{onClick:()=>f(C.id),className:C.id===r?"font-semibold":void 0,children:C.name},C.id))})]})},mr=[{label:"Dashboard",icon:nn,to:"/dashboard"},{label:"Core",icon:cn,items:[{label:"Cluster",to:"/core/clusters",icon:rn},{label:"Node Pools",icon:on,to:"/core/nodepools"},{label:"Annotations",icon:ln,to:"/core/annotations"},{label:"Labels",icon:It,to:"/core/labels"},{label:"Taints",icon:dn,to:"/core/taints"},{label:"Servers",icon:hs,to:"/core/servers"}]},{label:"Security",icon:hn,items:[{label:"Keys & Tokens",icon:mn,to:"/security/keys"},{label:"SSH Keys",to:"/security/ssh",icon:xn}]},{label:"Tasks",icon:un,items:[]},{label:"Settings",icon:gn,items:[{label:"Jobs",icon:jn,to:"/settings/jobs"},{label:"Organizations",to:"/settings/orgs",icon:fn},{label:"Members",to:"/settings/members",icon:mt},{label:"Profile",to:"/settings/me",icon:pn}]},{label:"Admin",icon:vn,requiresAdmin:!0,items:[{label:"Users",to:"/admin/users",icon:mt,requiresAdmin:!0}]}];function zt(s,t,r){return s.filter(d=>!(d.requiresAdmin&&!t||d.requiresOrgAdmin&&!r)).map(d=>({...d,items:d.items?zt(d.items,t,r):void 0})).filter(d=>!d.items||d.items.length>0)}const Ft=({item:s})=>{const t=Ms(),r=s.icon;return s.to?e.jsxs(as,{to:s.to,className:`hover:bg-accent hover:text-accent-foreground flex items-center space-x-2 rounded-md px-4 py-2 text-sm ${t.pathname===s.to?"bg-accent text-accent-foreground":""}`,children:[e.jsx(r,{className:"mr-4 h-4 w-4"}),s.label]}):s.items?e.jsx(ir,{defaultOpen:!0,className:"group/collapsible",children:e.jsxs(Jn,{children:[e.jsx(Qn,{asChild:!0,children:e.jsxs(or,{children:[e.jsx(r,{className:"mr-4 h-4 w-4"}),s.label,e.jsx(Gs,{className:"ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180"})]})}),e.jsx(lr,{children:e.jsx(Wn,{children:e.jsx(Yn,{children:s.items.map((d,u)=>e.jsx(Xn,{children:e.jsx(er,{asChild:!0,children:e.jsx(Ft,{item:d})})},u))})})})]})}):null},xr=()=>{const[s,t]=o.useState(null),[r,d]=o.useState(!0);o.useEffect(()=>{let f=!0;return(async()=>{try{const $=await Ve.me();if(!f)return;t($)}catch{}finally{d(!1)}})(),()=>{f=!1}},[]);const u=o.useMemo(()=>{const f=Ot(s),$=rr(s);return zt(mr,f,$)},[s]);return r?e.jsx("div",{className:"p-6",children:"Loading…"}):e.jsxs(Hn,{children:[e.jsx(Kn,{className:"flex items-center justify-between p-4",children:e.jsx("h1",{className:"text-xl font-bold",children:"AutoGlue"})}),e.jsx(Gn,{children:u.map((f,$)=>e.jsx(Ft,{item:f},$))}),e.jsxs(qn,{className:"space-y-2 p-4",children:[e.jsx(cr,{}),e.jsx(dr,{}),e.jsx(h,{onClick:()=>{localStorage.clear(),window.location.reload()},className:"w-full",children:"Logout"})]})]})};function hr(){return e.jsx("footer",{className:"border-t",children:e.jsxs("div",{className:"container flex flex-col items-center justify-between gap-4 py-10 md:h-24 md:flex-row md:py-0",children:[e.jsx("div",{className:"flex flex-col items-center gap-4 px-8 md:flex-row md:gap-2 md:px-0",children:e.jsxs("p",{className:"text-muted-foreground text-center text-sm leading-loose md:text-left",children:["Built for"," ",e.jsx("a",{href:"https://www.glueops.dev/",target:"_blank",rel:"noreferrer",className:"font-medium underline underline-offset-4",children:"GlueOps"}),". The source code is available on"," ",e.jsx("a",{href:"https://github.com/GlueOps/autoglue",target:"_blank",rel:"noreferrer",className:"font-medium underline underline-offset-4",children:"GitHub"}),"."]})}),e.jsx("div",{className:"flex items-center space-x-4",children:e.jsx("a",{href:"https://github.com/GlueOps/autoglue",target:"_blank",rel:"noreferrer",children:e.jsx(bn,{className:"h-5 w-5"})})})]})})}function ur(){return e.jsx("div",{className:"flex h-screen",children:e.jsxs(Bn,{children:[e.jsx(xr,{}),e.jsxs("div",{className:"flex flex-1 flex-col",children:[e.jsx("main",{className:"flex-1 overflow-auto p-4",children:e.jsx(Js,{})}),e.jsx(hr,{})]})]})})}function jr({children:s}){const t=Ms();return Ve.isAuthenticated()?s?e.jsx(e.Fragment,{children:s}):e.jsx(Js,{}):e.jsx(Qs,{to:"/auth/login",state:{from:t},replace:!0})}function fr({children:s}){const[t,r]=o.useState(!0),[d,u]=o.useState(!1),f=Ms();return o.useEffect(()=>{let $=!0;return(async()=>{try{const C=await Ve.me();if(!$)return;u(Ot(C))}catch{if(!$)return;u(!1)}finally{if(r(!1),!$)return}})(),()=>{$=!1}},[]),t?null:d?s?e.jsx(e.Fragment,{children:s}):e.jsx(Js,{}):e.jsx(Qs,{to:"/403",replace:!0,state:{from:f}})}function et({...s}){return e.jsx($a,{"data-slot":"alert-dialog",...s})}function st({...s}){return e.jsx(La,{"data-slot":"alert-dialog-trigger",...s})}function pr({...s}){return e.jsx(Oa,{"data-slot":"alert-dialog-portal",...s})}function gr({className:s,...t}){return e.jsx(za,{"data-slot":"alert-dialog-overlay",className:L("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",s),...t})}function tt({className:s,...t}){return e.jsxs(pr,{children:[e.jsx(gr,{}),e.jsx(Da,{"data-slot":"alert-dialog-content",className:L("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",s),...t})]})}function at({className:s,...t}){return e.jsx("div",{"data-slot":"alert-dialog-header",className:L("flex flex-col gap-2 text-center sm:text-left",s),...t})}function nt({className:s,...t}){return e.jsx("div",{"data-slot":"alert-dialog-footer",className:L("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",s),...t})}function rt({className:s,...t}){return e.jsx(Ia,{"data-slot":"alert-dialog-title",className:L("text-lg font-semibold",s),...t})}function it({className:s,...t}){return e.jsx(Ta,{"data-slot":"alert-dialog-description",className:L("text-muted-foreground text-sm",s),...t})}function ot({className:s,...t}){return e.jsx(Ma,{className:L(Ws(),s),...t})}function lt({className:s,...t}){return e.jsx(Pa,{className:L(Ws({variant:"outline"}),s),...t})}function Te({className:s,...t}){return e.jsx("div",{"data-slot":"card",className:L("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",s),...t})}function Pe({className:s,...t}){return e.jsx("div",{"data-slot":"card-header",className:L("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",s),...t})}function Be({className:s,...t}){return e.jsx("div",{"data-slot":"card-title",className:L("leading-none font-semibold",s),...t})}function Me({className:s,...t}){return e.jsx("div",{"data-slot":"card-content",className:L("px-6",s),...t})}function Ss({className:s,...t}){return e.jsx("div",{"data-slot":"card-footer",className:L("flex items-center px-6 [.border-t]:pt-6",s),...t})}function ie({...s}){return e.jsx(Ct,{"data-slot":"dialog",...s})}function We({...s}){return e.jsx(Fa,{"data-slot":"dialog-trigger",...s})}function vr({...s}){return e.jsx($t,{"data-slot":"dialog-portal",...s})}function br({className:s,...t}){return e.jsx(Lt,{"data-slot":"dialog-overlay",className:L("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",s),...t})}function oe({className:s,children:t,showCloseButton:r=!0,...d}){return e.jsxs(vr,{"data-slot":"dialog-portal",children:[e.jsx(br,{}),e.jsxs(_t,{"data-slot":"dialog-content",className:L("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",s),...d,children:[t,r&&e.jsxs(kt,{"data-slot":"dialog-close",className:"ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",children:[e.jsx(Dt,{}),e.jsx("span",{className:"sr-only",children:"Close"})]})]})]})}function le({className:s,...t}){return e.jsx("div",{"data-slot":"dialog-header",className:L("flex flex-col gap-2 text-center sm:text-left",s),...t})}function de({className:s,...t}){return e.jsx("div",{"data-slot":"dialog-footer",className:L("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",s),...t})}function ce({className:s,...t}){return e.jsx(At,{"data-slot":"dialog-title",className:L("text-lg leading-none font-semibold",s),...t})}function Ds({className:s,...t}){return e.jsx(Et,{"data-slot":"dialog-description",className:L("text-muted-foreground text-sm",s),...t})}function Nr({className:s,...t}){return e.jsx(Ra,{"data-slot":"label",className:L("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",s),...t})}const ne=la,Rt=o.createContext({}),v=({...s})=>e.jsx(Rt.Provider,{value:{name:s.name},children:e.jsx(da,{...s})}),zs=()=>{const s=o.useContext(Rt),t=o.useContext(Vt),{getFieldState:r}=ca(),d=ma({name:s.name}),u=r(s.name,d);if(!s)throw new Error("useFormField should be used within ");const{id:f}=t;return{id:f,name:s.name,formItemId:`${f}-form-item`,formDescriptionId:`${f}-form-item-description`,formMessageId:`${f}-form-item-message`,...u}},Vt=o.createContext({});function b({className:s,...t}){const r=o.useId();return e.jsx(Vt.Provider,{value:{id:r},children:e.jsx("div",{"data-slot":"form-item",className:L("grid gap-2",s),...t})})}function N({className:s,...t}){const{error:r,formItemId:d}=zs();return e.jsx(Nr,{"data-slot":"form-label","data-error":!!r,className:L("data-[error=true]:text-destructive",s),htmlFor:d,...t})}function E({...s}){const{error:t,formItemId:r,formDescriptionId:d,formMessageId:u}=zs();return e.jsx(Cs,{"data-slot":"form-control",id:r,"aria-describedby":t?`${d} ${u}`:`${d}`,"aria-invalid":!!t,...s})}function jt({className:s,...t}){const{formDescriptionId:r}=zs();return e.jsx("p",{"data-slot":"form-description",id:r,className:L("text-muted-foreground text-sm",s),...t})}function w({className:s,...t}){const{error:r,formMessageId:d}=zs(),u=r?String(r?.message??""):t.children;return u?e.jsx("p",{"data-slot":"form-message",id:d,className:L("text-destructive text-sm",s),...t,children:u}):null}function Ae({...s}){return e.jsx(Va,{"data-slot":"select",...s})}function Ee({...s}){return e.jsx(Ha,{"data-slot":"select-value",...s})}function $e({className:s,size:t="default",children:r,...d}){return e.jsxs(Ua,{"data-slot":"select-trigger","data-size":t,className:L("border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",s),...d,children:[r,e.jsx(Ba,{asChild:!0,children:e.jsx(Gs,{className:"size-4 opacity-50"})})]})}function Le({className:s,children:t,position:r="popper",...d}){return e.jsx(Ka,{children:e.jsxs(qa,{"data-slot":"select-content",className:L("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",r==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",s),position:r,...d,children:[e.jsx(wr,{}),e.jsx(Ga,{className:L("p-1",r==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"),children:t}),e.jsx(yr,{})]})})}function ve({className:s,children:t,...r}){return e.jsxs(Ja,{"data-slot":"select-item",className:L("focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",s),...r,children:[e.jsx("span",{className:"absolute right-2 flex size-3.5 items-center justify-center",children:e.jsx(Qa,{children:e.jsx(bs,{className:"size-4"})})}),e.jsx(Wa,{children:t})]})}function wr({className:s,...t}){return e.jsx(Ya,{"data-slot":"select-scroll-up-button",className:L("flex cursor-default items-center justify-center py-1",s),...t,children:e.jsx(Nn,{className:"size-4"})})}function yr({className:s,...t}){return e.jsx(Xa,{"data-slot":"select-scroll-down-button",className:L("flex cursor-default items-center justify-center py-1",s),...t,children:e.jsx(Gs,{className:"size-4"})})}const Sr=re({name:F().min(1,"Name required"),email:js("Enter a valid email"),role:Je(["user","admin"]),password:F().min(8,"Min 8 characters")}),Cr=re({name:F().min(1,"Name required"),email:js("Enter a valid email"),role:Je(["user","admin"]),password:F().min(8,"Min 8 characters").optional().or(St(""))});function _r(){const[s,t]=o.useState([]),[r,d]=o.useState(!0),[u,f]=o.useState(!1),[$,C]=o.useState(!1),[O,M]=o.useState(null),[R,U]=o.useState(null),T=te({resolver:ae(Sr),mode:"onChange",defaultValues:{name:"",email:"",role:"user",password:""}}),P=te({resolver:ae(Cr),mode:"onChange",defaultValues:{name:"",email:"",role:"user",password:""}});async function j(){d(!0);try{const c=await g.get("/api/v1/admin/users?page=1&page_size=100");t(c.users??[])}catch(c){ee.error(c instanceof je?c.message:"Failed to load users")}finally{d(!1)}}o.useEffect(()=>{j()},[]);async function V(c){try{const S=await g.post("/api/v1/admin/users",c);t(G=>[S,...G]),f(!1),T.reset({name:"",email:"",role:"user",password:""}),ee.success(`Created ${S.email}`)}catch(S){ee.error(S instanceof je?S.message:"Failed to create user")}}function H(c){M(c),P.reset({name:c.name||"",email:c.email,role:c.role??"user",password:""}),C(!0)}async function m(c){if(!O)return;const S={name:c.name,email:c.email,role:c.role};c.password&&c.password.length>=8&&(S.password=c.password);try{const G=await g.patch(`/api/v1/admin/users/${O.id}`,S);t(K=>K.map(B=>B.id===G.id?G:B)),C(!1),M(null),ee.success(`Updated ${G.email}`)}catch(G){ee.error(G instanceof je?G.message:"Failed to update user")}}async function x(c){try{U(c),await g.delete(`/api/v1/admin/users/${c}`),t(S=>S.filter(G=>G.id!==c)),ee.success("User deleted")}catch(S){ee.error(S instanceof je?S.message:"Failed to delete user")}finally{U(null)}}return e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Users"}),e.jsxs(h,{onClick:()=>f(!0),children:[e.jsx(Qe,{className:"mr-2 h-4 w-4"}),"New user"]})]}),e.jsx(Ns,{}),r?e.jsx("div",{className:"text-muted-foreground text-sm",children:"Loading…"}):s.length===0?e.jsx("div",{className:"text-muted-foreground text-sm",children:"No users yet."}):e.jsx("div",{className:"grid grid-cols-1 gap-4 pr-2 md:grid-cols-2 lg:grid-cols-3",children:s.map(c=>e.jsxs(Te,{className:"flex flex-col",children:[e.jsx(Pe,{children:e.jsx(Be,{className:"text-base",children:c.name||c.email})}),e.jsxs(Me,{className:"text-muted-foreground space-y-1 text-sm",children:[e.jsxs("div",{children:["Email: ",c.email]}),e.jsxs("div",{children:["Role: ",c.role]}),e.jsxs("div",{children:["Verified: ",c.email_verified?"Yes":"No"]}),e.jsxs("div",{children:["Joined: ",new Date(c.created_at).toLocaleString()]})]}),e.jsxs(Ss,{className:"mt-auto w-full flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs(h,{variant:"outline",onClick:()=>H(c),children:[e.jsx(rs,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(et,{children:[e.jsx(st,{asChild:!0,children:e.jsxs(h,{variant:"destructive",disabled:R===c.id,children:[e.jsx(Ue,{className:"mr-2 h-4 w-4"}),R===c.id?"Deleting…":"Delete"]})}),e.jsxs(tt,{children:[e.jsxs(at,{children:[e.jsx(rt,{children:"Delete user?"}),e.jsxs(it,{children:["This will permanently delete ",e.jsx("b",{children:c.email}),"."]})]}),e.jsxs(nt,{className:"sm:justify-between",children:[e.jsx(lt,{disabled:R===c.id,children:"Cancel"}),e.jsx(ot,{asChild:!0,disabled:R===c.id,children:e.jsx(h,{variant:"destructive",onClick:()=>x(c.id),children:"Confirm delete"})})]})]})]})]})]},c.id))}),e.jsx(ie,{open:u,onOpenChange:f,children:e.jsxs(oe,{className:"sm:max-w-[520px]",children:[e.jsxs(le,{children:[e.jsx(ce,{children:"Create user"}),e.jsx(Ds,{children:"Add a new user account."})]}),e.jsx(ne,{...T,children:e.jsxs("form",{onSubmit:T.handleSubmit(V),className:"grid gap-4 py-2",children:[e.jsx(v,{name:"name",control:T.control,render:({field:c})=>e.jsxs(b,{children:[e.jsx(N,{children:"Name"}),e.jsx(E,{children:e.jsx(z,{...c,placeholder:"Jane Doe"})}),e.jsx(w,{})]})}),e.jsx(v,{name:"email",control:T.control,render:({field:c})=>e.jsxs(b,{children:[e.jsx(N,{children:"Email"}),e.jsx(E,{children:e.jsx(z,{type:"email",...c,placeholder:"jane@example.com"})}),e.jsx(w,{})]})}),e.jsx(v,{name:"role",control:T.control,render:({field:c})=>e.jsxs(b,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Ae,{value:c.value,onValueChange:c.onChange,children:[e.jsx(E,{children:e.jsx($e,{className:"w-[200px]",children:e.jsx(Ee,{placeholder:"Select role"})})}),e.jsxs(Le,{children:[e.jsx(ve,{value:"user",children:"User"}),e.jsx(ve,{value:"admin",children:"Admin"})]})]}),e.jsx(w,{})]})}),e.jsx(v,{name:"password",control:T.control,render:({field:c})=>e.jsxs(b,{children:[e.jsx(N,{children:"Password"}),e.jsx(E,{children:e.jsx(z,{type:"password",...c,placeholder:"••••••••"})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"mt-2 flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>f(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:!T.formState.isValid||T.formState.isSubmitting,children:T.formState.isSubmitting?"Creating…":"Create"})]})]})})]})}),e.jsx(ie,{open:$,onOpenChange:C,children:e.jsxs(oe,{className:"sm:max-w-[520px]",children:[e.jsxs(le,{children:[e.jsx(ce,{children:"Edit user"}),e.jsx(Ds,{children:"Update user details. Leave password blank to keep it unchanged."})]}),e.jsx(ne,{...P,children:e.jsxs("form",{onSubmit:P.handleSubmit(m),className:"grid gap-4 py-2",children:[e.jsx(v,{name:"name",control:P.control,render:({field:c})=>e.jsxs(b,{children:[e.jsx(N,{children:"Name"}),e.jsx(E,{children:e.jsx(z,{...c})}),e.jsx(w,{})]})}),e.jsx(v,{name:"email",control:P.control,render:({field:c})=>e.jsxs(b,{children:[e.jsx(N,{children:"Email"}),e.jsx(E,{children:e.jsx(z,{type:"email",...c})}),e.jsx(w,{})]})}),e.jsx(v,{name:"role",control:P.control,render:({field:c})=>e.jsxs(b,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Ae,{value:c.value,onValueChange:c.onChange,children:[e.jsx(E,{children:e.jsx($e,{className:"w-[200px]",children:e.jsx(Ee,{placeholder:"Select role"})})}),e.jsxs(Le,{children:[e.jsx(ve,{value:"user",children:"User"}),e.jsx(ve,{value:"admin",children:"Admin"})]})]}),e.jsx(w,{})]})}),e.jsx(v,{name:"password",control:P.control,render:({field:c})=>e.jsxs(b,{children:[e.jsx(N,{children:"New password (optional)"}),e.jsx(E,{children:e.jsx(z,{type:"password",...c,placeholder:"Leave blank to keep"})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"mt-2 flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>C(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:!P.formState.isValid||P.formState.isSubmitting,children:P.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})})]})}const kr=re({email:js()});function Ar(){const s=te({resolver:ae(kr),defaultValues:{email:""}});async function t(r){try{await Ve.forgot(r.email),ee.success("If that email exists, we've sent instructions.")}catch(d){ee.error(d.message||"Something went wrong")}}return e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Be,{children:"Forgot password"})}),e.jsx(Me,{children:e.jsx(ne,{...s,children:e.jsxs("form",{onSubmit:s.handleSubmit(t),className:"space-y-4",children:[e.jsx(v,{name:"email",control:s.control,render:({field:r})=>e.jsxs(b,{children:[e.jsx(N,{children:"Email"}),e.jsx(E,{children:e.jsx(z,{placeholder:"you@example.com",...r})}),e.jsx(w,{})]})}),e.jsx(h,{type:"submit",className:"w-full",children:"Send reset link"})]})})})]})})}const Er=re({email:js(),password:F().min(6)});function $r(){const s=_s(),t=Ms(),r=te({resolver:ae(Er),defaultValues:{email:"",password:""}});async function d(u){try{await Ve.login(u.email,u.password),ee.success("Welcome back!");const f=t.state?.from?.pathname??"/settings/me";s(f,{replace:!0})}catch(f){ee.error(f.message||"Login failed")}}return e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Be,{children:"Sign in"})}),e.jsxs(Me,{children:[e.jsx(ne,{...r,children:e.jsxs("form",{onSubmit:r.handleSubmit(d),className:"space-y-4",children:[e.jsx(v,{name:"email",control:r.control,render:({field:u})=>e.jsxs(b,{children:[e.jsx(N,{children:"Email"}),e.jsx(E,{children:e.jsx(z,{placeholder:"you@example.com",...u})}),e.jsx(w,{})]})}),e.jsx(v,{name:"password",control:r.control,render:({field:u})=>e.jsxs(b,{children:[e.jsx(N,{children:"Password"}),e.jsx(E,{children:e.jsx(z,{type:"password",placeholder:"••••••••",...u})}),e.jsx(w,{})]})}),e.jsx(h,{type:"submit",className:"w-full",children:"Sign in"})]})}),e.jsxs("div",{className:"mt-4 flex justify-between text-sm",children:[e.jsx(as,{to:"/auth/forgot",className:"underline",children:"Forgot password?"}),e.jsx(as,{to:"/auth/register",className:"underline",children:"Create an account"})]})]})]})})}function Lr(){const[s,t]=o.useState(null),r=_s();o.useEffect(()=>{(async()=>{try{const u=await Ve.me();t(u)}catch(u){ee.error(u.message||"Failed to load profile")}})()},[]);async function d(){await Ve.logout(),r("/auth/login")}return e.jsx("div",{className:"mx-auto max-w-xl",children:e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Be,{children:"My Account"})}),e.jsxs(Me,{className:"space-y-3",children:[s?e.jsx("pre",{className:"bg-muted overflow-auto rounded p-3 text-sm",children:JSON.stringify(s,null,2)}):e.jsx("p",{children:"Loading…"}),e.jsx(h,{onClick:d,children:"Sign out"})]})]})})}const Dr=re({name:F().min(2),email:js(),password:F().min(6)});function Ir(){const s=_s(),t=te({resolver:ae(Dr),defaultValues:{name:"",email:"",password:""}});async function r(d){try{await Ve.register(d.name,d.email,d.password),ee.success("Account created! Check your email to verify."),s("/auth/login")}catch(u){ee.error(u.message||"Registration failed")}}return e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Be,{children:"Create account"})}),e.jsxs(Me,{children:[e.jsx(ne,{...t,children:e.jsxs("form",{onSubmit:t.handleSubmit(r),className:"space-y-4",children:[e.jsx(v,{name:"name",control:t.control,render:({field:d})=>e.jsxs(b,{children:[e.jsx(N,{children:"Name"}),e.jsx(E,{children:e.jsx(z,{placeholder:"Jane Doe",...d})}),e.jsx(w,{})]})}),e.jsx(v,{name:"email",control:t.control,render:({field:d})=>e.jsxs(b,{children:[e.jsx(N,{children:"Email"}),e.jsx(E,{children:e.jsx(z,{placeholder:"you@example.com",...d})}),e.jsx(w,{})]})}),e.jsx(v,{name:"password",control:t.control,render:({field:d})=>e.jsxs(b,{children:[e.jsx(N,{children:"Password"}),e.jsx(E,{children:e.jsx(z,{type:"password",placeholder:"••••••••",...d})}),e.jsx(w,{})]})}),e.jsx(h,{type:"submit",className:"w-full",children:"Create account"})]})}),e.jsxs("div",{className:"mt-4 text-sm",children:["Already have an account?"," ",e.jsx(as,{to:"/auth/login",className:"underline",children:"Sign in"})]})]})]})})}const Tr=re({new_password:F().min(6)});function Pr(){const[s]=Tt(),t=s.get("token"),r=te({resolver:ae(Tr),defaultValues:{new_password:""}}),d=_s();async function u(f){if(!t){ee.error("Missing token");return}try{await Ve.reset(t,f.new_password),ee.success("Password updated. Please sign in."),d("/auth/login")}catch($){ee.error($.message||"Reset failed")}}return e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Be,{children:"Reset password"})}),e.jsxs(Me,{children:[e.jsx(ne,{...r,children:e.jsxs("form",{onSubmit:r.handleSubmit(u),className:"space-y-4",children:[e.jsx(v,{name:"new_password",control:r.control,render:({field:f})=>e.jsxs(b,{children:[e.jsx(N,{children:"New password"}),e.jsx(E,{children:e.jsx(z,{type:"password",placeholder:"••••••••",...f})}),e.jsx(w,{})]})}),e.jsx(h,{type:"submit",className:"w-full",children:"Update password"})]})}),e.jsx("div",{className:"mt-4 text-sm",children:e.jsx(as,{to:"/auth/login",className:"underline",children:"Back to sign in"})})]})]})})}function Mr(){const[s]=Tt(),t=s.get("token"),[r,d]=o.useState("idle");return o.useEffect(()=>{async function u(){if(!t){d("error");return}try{await Ve.verify(t),d("ok")}catch(f){ee.error(f.message||"Verification failed"),d("error")}}u()},[t]),e.jsx("div",{className:"mx-auto max-w-md",children:e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Be,{children:"Email verification"})}),e.jsxs(Me,{className:"space-y-3",children:[r==="idle"&&e.jsx("p",{children:"Verifying…"}),r==="ok"&&e.jsxs("div",{children:[e.jsx("p",{children:"Your email has been verified. You can now sign in."}),e.jsx(h,{asChild:!0,className:"mt-3",children:e.jsx(as,{to:"/auth/login",children:"Go to sign in"})})]}),r==="error"&&e.jsxs("div",{children:[e.jsx("p",{children:"Verification failed. Please request a new verification email."}),e.jsx(h,{asChild:!0,className:"mt-3",children:e.jsx(as,{to:"/auth/login",children:"Back to sign in"})})]})]})]})})}const Or=qs("inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",secondary:"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",destructive:"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",outline:"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"}},defaultVariants:{variant:"default"}});function Ce({className:s,variant:t,asChild:r=!1,...d}){const u=r?Cs:"span";return e.jsx(u,{"data-slot":"badge",className:L(Or({variant:t}),s),...d})}function De({className:s,...t}){return e.jsx(Za,{"data-slot":"checkbox",className:L("peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",s),...t,children:e.jsx(en,{"data-slot":"checkbox-indicator",className:"flex items-center justify-center text-current transition-none",children:e.jsx(bs,{className:"size-3.5"})})})}function be({className:s,...t}){return e.jsx("div",{"data-slot":"table-container",className:"relative w-full overflow-x-auto",children:e.jsx("table",{"data-slot":"table",className:L("w-full caption-bottom text-sm",s),...t})})}function Ne({className:s,...t}){return e.jsx("thead",{"data-slot":"table-header",className:L("[&_tr]:border-b",s),...t})}function we({className:s,...t}){return e.jsx("tbody",{"data-slot":"table-body",className:L("[&_tr:last-child]:border-0",s),...t})}function q({className:s,...t}){return e.jsx("tr",{"data-slot":"table-row",className:L("hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",s),...t})}function A({className:s,...t}){return e.jsx("th",{"data-slot":"table-head",className:L("text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",s),...t})}function p({className:s,...t}){return e.jsx("td",{"data-slot":"table-cell",className:L("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",s),...t})}const zr=re({key:F().trim().min(1,"Key is required").max(120,"Max 120 chars"),value:F().trim().min(1,"Value is required").max(512,"Max 512 chars"),node_pool_ids:Oe(F().uuid()).optional().default([])}),Fr=re({key:F().trim().min(1,"Key is required").max(120,"Max 120 chars"),value:F().trim().min(1,"Value is required").max(512,"Max 512 chars")}),Rr=re({node_pool_ids:Oe(F().uuid()).min(1,"Pick at least one node pool")});function ft(s,t=12){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}const Vr=()=>{const[s,t]=o.useState(!0),[r,d]=o.useState(null),[u,f]=o.useState([]),[$,C]=o.useState([]),[O,M]=o.useState(""),[R,U]=o.useState(!1),[T,P]=o.useState(null),[j,V]=o.useState(null),[H,m]=o.useState([]),[x,c]=o.useState(!1),[S,G]=o.useState(null);async function K(){t(!0),d(null);try{const[y,Y]=await Promise.all([g.get("/api/v1/annotations?include=node_pools"),g.get("/api/v1/node-pools")]);if(f(y||[]),C(Y||[]),T){const he=(y||[]).find(i=>i.id===T.id)||null;P(he)}if(j){const he=(y||[]).find(i=>i.id===j.id)||null;V(he),he&&B(he.id)}}catch(y){console.error(y);const Y=y instanceof je?y.message:"Failed to load annotations / node pools";d(Y)}finally{t(!1)}}async function B(y){c(!0),G(null);try{const Y=await g.get(`/api/v1/annotations/${y}/node_pools`);m(Y||[])}catch(Y){console.error(Y);const he=Y instanceof je?Y.message:"Failed to load pools for annotation";G(he)}finally{c(!1)}}o.useEffect(()=>{K()},[]);const xe=o.useMemo(()=>{const y=O.trim().toLowerCase();return y?u.filter(Y=>Y.key.toLowerCase().includes(y)||Y.value.toLowerCase().includes(y)||(Y.node_pools||[]).some(he=>he.name.toLowerCase().includes(y))):u},[u,O]);async function W(y){confirm("Delete this annotation? This cannot be undone.")&&(await g.delete(`/api/v1/annotations/${y}`),await K())}const ue=te({resolver:ae(zr),defaultValues:{key:"",value:"",node_pool_ids:[]}}),fe=async y=>{const Y={key:y.key.trim(),value:y.value.trim()};y.node_pool_ids&&y.node_pool_ids.length>0&&(Y.node_pool_ids=y.node_pool_ids),await g.post("/api/v1/annotations",Y),U(!1),ue.reset({key:"",value:"",node_pool_ids:[]}),await K()},a=te({resolver:ae(Fr),defaultValues:{key:"",value:""}});function n(y){P(y),a.reset({key:y.key,value:y.value})}const _=async y=>{T&&(await g.patch(`/api/v1/annotations/${T.id}`,{name:y.key.trim(),value:y.value.trim()}),P(null),await K())},X=te({resolver:ae(Rr),defaultValues:{node_pool_ids:[]}});function me(y){V(y),X.reset({node_pool_ids:[]}),B(y.id)}const ge=async y=>{j&&(await g.post(`/api/v1/annotations/${j.id}/node_pools`,{node_pool_ids:y.node_pool_ids}),X.reset({node_pool_ids:[]}),await B(j.id),await K())};async function Re(y){j&&confirm("Detach this node pool from the annotation?")&&(await g.delete(`/api/v1/annotations/${j.id}/node_pools/${y}`),await B(j.id),await K())}return s?e.jsx("div",{className:"p-6",children:"Loading annotations…"}):r?e.jsx("div",{className:"p-6 text-red-500",children:r}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Annotations"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:"relative",children:[e.jsx(Ts,{className:"absolute top-2.5 left-2 h-4 w-4 opacity-60"}),e.jsx(z,{value:O,onChange:y=>M(y.target.value),placeholder:"Search name, value, pool…",className:"w-72 pl-8"})]}),e.jsxs(h,{variant:"outline",onClick:K,children:[e.jsx(Ps,{className:"mr-2 h-4 w-4"})," Refresh"]}),e.jsxs(ie,{open:R,onOpenChange:U,children:[e.jsx(We,{asChild:!0,children:e.jsxs(h,{onClick:()=>U(!0),children:[e.jsx(Qe,{className:"mr-2 h-4 w-4"})," Create Annotation"]})}),e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsx(ce,{children:"Create annotation"})}),e.jsx(ne,{...ue,children:e.jsxs("form",{onSubmit:ue.handleSubmit(fe),className:"space-y-4",children:[e.jsx(v,{control:ue.control,name:"key",render:({field:y})=>e.jsxs(b,{children:[e.jsx(N,{children:"Key"}),e.jsx(E,{children:e.jsx(z,{placeholder:"cluster-autoscaler.kubernetes.io/safe-to-evict",...y})}),e.jsx(w,{})]})}),e.jsx(v,{control:ue.control,name:"value",render:({field:y})=>e.jsxs(b,{children:[e.jsx(N,{children:"Value"}),e.jsx(E,{children:e.jsx(z,{placeholder:"true",...y})}),e.jsx(w,{})]})}),e.jsx(v,{control:ue.control,name:"node_pool_ids",render:({field:y})=>e.jsxs(b,{children:[e.jsx(N,{children:"Initial node pools (optional)"}),e.jsxs("div",{className:"max-h-56 space-y-2 overflow-auto rounded-xl border p-2",children:[$.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No node pools available"}),$.map(Y=>{const he=y.value?.includes(Y.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:he,onCheckedChange:i=>{const D=new Set(y.value||[]);i===!0?D.add(Y.id):D.delete(Y.id),y.onChange(Array.from(D))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:Y.name}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ft(Y.id,8)})]})]},Y.id)})]}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>U(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:ue.formState.isSubmitting,children:ue.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Key"}),e.jsx(A,{children:"Value"}),e.jsx(A,{children:"Node Pools"}),e.jsx(A,{className:"w-[180px] text-right",children:"Actions"})]})}),e.jsxs(we,{children:[xe.map(y=>{const Y=y.node_pools||[];return e.jsxs(q,{children:[e.jsx(p,{className:"font-mono text-sm",children:y.key}),e.jsx(p,{className:"font-mono text-sm",children:y.value}),e.jsxs(p,{children:[e.jsxs("div",{className:"mb-2 flex flex-wrap gap-2",children:[Y.slice(0,6).map(he=>e.jsxs(Ce,{variant:"secondary",className:"gap-1",children:[e.jsx(hs,{className:"h-3 w-3"})," ",he.name]},he.id)),Y.length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No node pools"}),Y.length>6&&e.jsxs("span",{className:"text-muted-foreground",children:["+",Y.length-6," more"]})]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>me(y),children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," Manage Node Pools"]})]}),e.jsx(p,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>n(y),children:[e.jsx(rs,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(is,{children:[e.jsx(os,{asChild:!0,children:e.jsxs(h,{variant:"destructive",size:"sm",children:[e.jsx(Ue,{className:"mr-2 h-4 w-4"})," Delete"]})}),e.jsx(ls,{align:"end",children:e.jsx(Ie,{onClick:()=>W(y.id),children:"Confirm delete"})})]})]})})]},y.id)}),xe.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:4,className:"text-muted-foreground py-10 text-center",children:"No annotations match your search."})})]})]})})}),e.jsx(ie,{open:!!T,onOpenChange:y=>!y&&P(null),children:e.jsxs(oe,{className:"sm:max-w-md",children:[e.jsx(le,{children:e.jsx(ce,{children:"Edit annotation"})}),e.jsx(ne,{...a,children:e.jsxs("form",{onSubmit:a.handleSubmit(_),className:"space-y-4",children:[e.jsx(v,{control:a.control,name:"key",render:({field:y})=>e.jsxs(b,{children:[e.jsx(N,{children:"Key"}),e.jsx(E,{children:e.jsx(z,{placeholder:"example.com/some",...y})}),e.jsx(w,{})]})}),e.jsx(v,{control:a.control,name:"value",render:({field:y})=>e.jsxs(b,{children:[e.jsx(N,{children:"Value"}),e.jsx(E,{children:e.jsx(z,{placeholder:"true",...y})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>P(null),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:a.formState.isSubmitting,children:a.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})}),e.jsx(ie,{open:!!j,onOpenChange:y=>!y&&V(null),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage node pools for ",e.jsx("span",{className:"font-mono",children:j?.key})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached node pools"}),x?e.jsx("div",{className:"text-muted-foreground rounded-md border p-3 text-sm",children:"Loading…"}):S?e.jsx("div",{className:"rounded-md border p-3 text-sm text-red-500",children:S}):e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Name"}),e.jsx(A,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs(we,{children:[H.map(y=>e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:y.name}),e.jsx(p,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>Re(y.id),children:[e.jsx(qe,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},y.id)),H.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:2,className:"text-muted-foreground py-8 text-center",children:"No node pools attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(ne,{...X,children:e.jsxs("form",{onSubmit:X.handleSubmit(ge),className:"space-y-3",children:[e.jsx(v,{control:X.control,name:"node_pool_ids",render:({field:y})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach more node pools"}),e.jsx("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:(()=>{const Y=new Set(H.map(i=>i.id)),he=$.filter(i=>!Y.has(i.id));return he.length===0?e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more node pools available to attach"}):he.map(i=>{const D=y.value?.includes(i.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:D,onCheckedChange:ze=>{const Fe=new Set(y.value||[]);ze===!0?Fe.add(i.id):Fe.delete(i.id),y.onChange(Array.from(Fe))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:i.name}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ft(i.id,8)})]})]},i.id)})})()}),e.jsx(w,{})]})}),e.jsx(de,{className:"gap-2",children:e.jsxs(h,{type:"submit",disabled:X.formState.isSubmitting,children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," ",X.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})})]})};function cs({className:s,...t}){return e.jsx("textarea",{"data-slot":"textarea",className:L("border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",s),...t})}const Ur=re({name:F().trim().min(2,"Name is too short"),provider:F().trim().min(2,"Provider is too short"),region:F().trim().min(1,"Region is required"),node_pool_ids:Oe(us()).default([]).optional(),bastion_server_id:us().optional(),cluster_load_balancer:F().optional(),control_load_balancer:F().optional(),kubeconfig:F().optional()}),Br=re({name:F().trim().min(2,"Name is too short").optional(),provider:F().trim().min(2,"Provider is too short").optional(),region:F().trim().min(1,"Region is required").optional(),status:F().trim().min(1,"Status is required").optional(),bastion_server_id:us().or(St("")).optional(),cluster_load_balancer:F().optional(),control_load_balancer:F().optional(),kubeconfig:F().optional()}).refine(s=>s.name!==void 0||s.provider!==void 0||s.region!==void 0||s.status!==void 0||s.bastion_server_id!==void 0||s.cluster_load_balancer!==void 0||s.control_load_balancer!==void 0||s.kubeconfig!==void 0,{message:"Provide at least one change",path:["name"]}),Hr=re({node_pool_ids:Oe(F().uuid()).min(1,"Pick at least one node pool")}),Kr=re({server_id:us({message:"Enter a valid Server UUID"})});function ps(s,t=8){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}function qr(){const[s,t]=o.useState([]),[r,d]=o.useState([]),[u,f]=o.useState([]),[$,C]=o.useState(!1),[O,M]=o.useState(null),[R,U]=o.useState(""),[T,P]=o.useState(!1),[j,V]=o.useState(!1),[H,m]=o.useState(null),[x,c]=o.useState(null),[S,G]=o.useState(null);async function K(){C(!0),M(null);try{const i=`/api/v1/clusters?include=node_pools,bastion${R?`&q=${encodeURIComponent(R)}`:""}`,[D,ze,Fe]=await Promise.all([g.get(i),g.get("/api/v1/node-pools"),g.get("/api/v1/servers?role=bastion").catch(()=>[])]),Se=(D||[]).map(pe=>({id:pe.id,name:pe.name,provider:pe.provider,region:pe.region,status:pe.status,cluster_load_balancer:pe.cluster_load_balancer,control_load_balancer:pe.control_load_balancer,node_pools:pe.node_pools??[],bastion_server:pe.bastion_server??null}));if(t(Se),d(ze||[]),f(Fe||[]),x){const pe=Se.find(He=>He.id===x.id)||null;c(pe)}if(S){const pe=Se.find(He=>He.id===S.id)||null;G(pe)}if(H){const pe=Se.find(He=>He.id===H.id)||null;m(pe)}}catch(i){console.error(i);const D=i instanceof je?i.message:"Failed to load clusters";M(D)}finally{C(!1)}}o.useEffect(()=>{K()},[]);const B=te({resolver:ae(Ur),defaultValues:{name:"",provider:"",region:"",node_pool_ids:[],bastion_server_id:void 0,cluster_load_balancer:"",control_load_balancer:"",kubeconfig:""}}),xe=async i=>{const D={name:i.name.trim(),provider:i.provider.trim(),region:i.region.trim(),node_pool_ids:i.node_pool_ids||[]};i.bastion_server_id&&(D.bastion_server_id=i.bastion_server_id),i.cluster_load_balancer&&(D.cluster_load_balancer=i.cluster_load_balancer),i.control_load_balancer&&(D.control_load_balancer=i.control_load_balancer),i.kubeconfig&&i.kubeconfig.trim()&&(D.kubeconfig=i.kubeconfig.trim()),await g.post("/api/v1/clusters",D),P(!1),B.reset(),await K()},W=te({resolver:ae(Br),defaultValues:{name:void 0,provider:void 0,region:void 0,status:void 0,bastion_server_id:void 0,cluster_load_balancer:void 0,control_load_balancer:void 0,kubeconfig:void 0}});function ue(i){m(i),W.reset({name:void 0,provider:void 0,region:void 0,status:void 0,bastion_server_id:void 0,cluster_load_balancer:void 0,control_load_balancer:void 0}),V(!0)}const fe=async i=>{if(!H)return;const D={};i.name!==void 0&&(D.name=i.name.trim()),i.provider!==void 0&&(D.provider=i.provider.trim()),i.region!==void 0&&(D.region=i.region.trim()),i.status!==void 0&&(D.status=i.status.trim()),i.bastion_server_id!==void 0&&(D.bastion_server_id=i.bastion_server_id||""),i.cluster_load_balancer!==void 0&&(D.cluster_load_balancer=i.cluster_load_balancer),i.control_load_balancer!==void 0&&(D.control_load_balancer=i.control_load_balancer),i.kubeconfig!==void 0&&i.kubeconfig.trim()&&(D.kubeconfig=i.kubeconfig.trim()),await g.patch(`/api/v1/clusters/${H.id}`,D),V(!1),m(null),await K()};async function a(i){confirm("Delete this cluster? This cannot be undone.")&&(await g.delete(`/api/v1/clusters/${i}`),await K())}const n=te({resolver:ae(Hr),defaultValues:{node_pool_ids:[]}});function _(i){c(i),n.reset({node_pool_ids:[]})}const X=async i=>{x&&(await g.post(`/api/v1/clusters/${x.id}/node_pools`,{node_pool_ids:i.node_pool_ids}),n.reset({node_pool_ids:[]}),await K())};async function me(i,D){confirm("Detach selected node pool?")&&(await g.delete(`/api/v1/clusters/${i}/node_pools/${D}`),await K())}const ge=o.useMemo(()=>{if(!x)return[];const i=new Set((x.node_pools||[]).map(D=>D.id));return r.filter(D=>!i.has(D.id))},[x,r]),Re=te({resolver:ae(Kr),defaultValues:{server_id:""}});function y(i){G(i),Re.reset({server_id:""})}const Y=async i=>{S&&(await g.post(`/api/v1/clusters/${S.id}/bastion`,{server_id:i.server_id}),await K())};async function he(){S&&confirm("Clear bastion for this cluster?")&&(await g.delete(`/api/v1/clusters/${S.id}/bastion`),await K())}return $?e.jsx("div",{className:"p-6",children:"Loading clusters…"}):O?e.jsx("div",{className:"p-6 text-red-500",children:O}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Clusters"}),e.jsxs("div",{className:"flex flex-1 items-center gap-2 md:justify-end",children:[e.jsx(z,{className:"max-w-xs",placeholder:"Filter by name…",value:R,onChange:i=>U(i.target.value),onKeyDown:i=>{i.key==="Enter"&&K()}}),e.jsxs(h,{variant:"outline",onClick:()=>void K(),children:[e.jsx(wn,{className:"mr-2 h-4 w-4"}),"Apply"]}),e.jsxs(ie,{open:T,onOpenChange:P,children:[e.jsx(We,{asChild:!0,children:e.jsxs(h,{onClick:()=>P(!0),children:[e.jsx(Qe,{className:"mr-2 h-4 w-4"}),"Create Cluster"]})}),e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsx(ce,{children:"Create Cluster"})}),e.jsx(ne,{...B,children:e.jsxs("form",{onSubmit:B.handleSubmit(xe),className:"grid gap-4 md:grid-cols-2",children:[e.jsx(v,{control:B.control,name:"name",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"Name"}),e.jsx(E,{children:e.jsx(z,{placeholder:"my-eks-prod",...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"provider",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"Provider"}),e.jsx(E,{children:e.jsx(z,{placeholder:"aws|gcp|azure|onprem",...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"region",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"Region"}),e.jsx(E,{children:e.jsx(z,{placeholder:"eu-west-1",...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"bastion_server_id",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"Bastion server (UUID, optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:"paste server UUID",...i})}),u.length>0&&e.jsxs("div",{className:"text-xs text-muted-foreground",children:["Suggestions:",e.jsx("div",{className:"mt-1 flex flex-wrap gap-2",children:u.slice(0,6).map(D=>e.jsxs(h,{type:"button",size:"sm",variant:i.value===D.id?"default":"outline",onClick:()=>i.onChange(D.id),className:"font-normal",children:[e.jsx(hs,{className:"mr-1 h-3 w-3"})," ",D.hostname||ps(D.id,6)]},D.id))})]}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"cluster_load_balancer",render:({field:i})=>e.jsxs(b,{className:"md:col-span-2",children:[e.jsx(N,{children:"Cluster Load Balancer (optional)"}),e.jsx(E,{children:e.jsx(cs,{placeholder:"e.g. JSON or URL or ARN",rows:2,...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"control_load_balancer",render:({field:i})=>e.jsxs(b,{className:"md:col-span-2",children:[e.jsx(N,{children:"Control Load Balancer (optional)"}),e.jsx(E,{children:e.jsx(cs,{placeholder:"e.g. JSON or URL or ARN",rows:2,...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"node_pool_ids",render:({field:i})=>e.jsxs(b,{className:"md:col-span-2",children:[e.jsx(N,{children:"Attach node pools (optional)"}),e.jsxs("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:[r.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No node pools available"}),r.map(D=>{const ze=i.value?.includes(D.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:ze,onCheckedChange:Fe=>{const Se=new Set(i.value||[]);Fe===!0?Se.add(D.id):Se.delete(D.id),i.onChange(Array.from(Se))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:D.name}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ps(D.id,8)})]})]},D.id)})]}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"kubeconfig",render:({field:i})=>e.jsxs(b,{className:"md:colspan-2",children:[e.jsx(N,{children:"Kubeconfig (optional)"}),e.jsx(E,{children:e.jsx(cs,{placeholder:"Paste full kubeconfig YAML here. It will be encrypted and never returned by the API.",rows:8,className:"font-mono",...i})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"md:col-span-2 gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>P(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:B.formState.isSubmitting,children:B.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Name"}),e.jsx(A,{children:"Provider / Region"}),e.jsx(A,{children:"Status"}),e.jsx(A,{children:"Node Pools"}),e.jsx(A,{children:"Bastion"}),e.jsx(A,{className:"w-[360px] text-right",children:"Actions"})]})}),e.jsxs(we,{children:[s.map(i=>e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:i.name}),e.jsxs(p,{children:[e.jsx("div",{className:"text-sm font-medium",children:i.provider||"—"}),e.jsx("div",{className:"text-muted-foreground text-xs",children:i.region||"—"})]}),e.jsx(p,{children:e.jsx(Ce,{variant:i.status==="ready"?"default":i.status==="error"?"destructive":"secondary",children:i.status||"unknown"})}),e.jsx(p,{children:e.jsxs("div",{className:"flex max-w-[280px] flex-wrap gap-2",children:[(i.node_pools||[]).slice(0,4).map(D=>e.jsx(Ce,{variant:"secondary",children:D.name},D.id)),(i.node_pools||[]).length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No pools"}),(i.node_pools||[]).length>4&&e.jsxs("span",{className:"text-muted-foreground",children:["+",(i.node_pools||[]).length-4," more"]})]})}),e.jsx(p,{children:i.bastion_server?e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:i.bastion_server.hostname||ps(i.bastion_server.id,6)}),e.jsx("div",{className:"text-muted-foreground text-xs",children:i.bastion_server.ip})]}):e.jsx("span",{className:"text-muted-foreground",children:"None"})}),e.jsx(p,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>_(i),children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," Manage pools"]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>y(i),children:[e.jsx(hs,{className:"mr-2 h-4 w-4"})," Bastion"]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>ue(i),children:[e.jsx(rs,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>a(i.id),children:[e.jsx(Ue,{className:"mr-2 h-4 w-4"})," Delete"]})]})})]},i.id)),s.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:6,className:"text-muted-foreground py-10 text-center",children:"No clusters yet."})})]})]})})}),e.jsx(ie,{open:j,onOpenChange:i=>!i&&V(!1),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Edit Cluster",H?e.jsxs("span",{className:"text-muted-foreground ml-2 font-mono text-sm",children:["(",H.name,")"]}):null]})}),e.jsx(ne,{...W,children:e.jsxs("form",{onSubmit:W.handleSubmit(fe),className:"grid gap-4 md:grid-cols-2",children:[e.jsx(v,{control:W.control,name:"name",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"New name (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:H?.name||"e.g. my-eks-prod",...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"provider",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"New provider (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:H?.provider||"aws",...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"region",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"New region (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:H?.region||"eu-west-1",...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"status",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"New status (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:H?.status||"pending|ready|error",...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"bastion_server_id",render:({field:i})=>e.jsxs(b,{className:"md:col-span-2",children:[e.jsx(N,{children:"Replace/clear bastion (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:"paste new server UUID or leave blank to clear",...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"cluster_load_balancer",render:({field:i})=>e.jsxs(b,{className:"md:col-span-2",children:[e.jsx(N,{children:"Cluster Load Balancer (optional)"}),e.jsx(E,{children:e.jsx(cs,{placeholder:H?.cluster_load_balancer||"e.g. JSON or URL or ARN",rows:2,...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"control_load_balancer",render:({field:i})=>e.jsxs(b,{className:"md:col-span-2",children:[e.jsx(N,{children:"Control Load Balancer (optional)"}),e.jsx(E,{children:e.jsx(cs,{placeholder:H?.control_load_balancer||"e.g. JSON or URL or ARN",rows:2,...i})}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"kubeconfig",render:({field:i})=>e.jsxs(b,{className:"md:colspan-2",children:[e.jsx(N,{children:"Replace Kubeconfig (optional)"}),e.jsx(E,{children:e.jsx(cs,{placeholder:"Paste NEW kubeconfig YAML to replace the stored one. Leave empty for no change.",rows:8,className:"font-mono",...i})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"md:col-span-2 gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>V(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:W.formState.isSubmitting,children:W.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})}),e.jsx(ie,{open:!!x,onOpenChange:i=>!i&&c(null),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage node pools for ",e.jsx("span",{className:"font-mono",children:x?.name})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached node pools"}),e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Name"}),e.jsx(A,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs(we,{children:[(x?.node_pools||[]).map(i=>e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:i.name}),e.jsx(p,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>me(x.id,i.id),children:[e.jsx(qe,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},i.id)),(x?.node_pools||[]).length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:2,className:"text-muted-foreground py-8 text-center",children:"No pools attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(ne,{...n,children:e.jsxs("form",{onSubmit:n.handleSubmit(X),className:"space-y-3",children:[e.jsx(v,{control:n.control,name:"node_pool_ids",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach more node pools"}),e.jsxs("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:[ge.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more node pools available to attach"}),ge.map(D=>{const ze=i.value?.includes(D.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:ze,onCheckedChange:Fe=>{const Se=new Set(i.value||[]);Fe===!0?Se.add(D.id):Se.delete(D.id),i.onChange(Array.from(Se))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:D.name}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ps(D.id,8)})]})]},D.id)})]}),e.jsx(w,{})]})}),e.jsx(de,{className:"gap-2",children:e.jsxs(h,{type:"submit",disabled:n.formState.isSubmitting,children:[e.jsx(ye,{className:"mr-2 h-4 w-4"}),n.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})}),e.jsx(ie,{open:!!S,onOpenChange:i=>!i&&G(null),children:e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage bastion for ",e.jsx("span",{className:"font-mono",children:S?.name})]})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"text-sm font-medium",children:"Current"}),e.jsx("div",{className:"rounded-xl border p-3 text-sm",children:S?.bastion_server?e.jsxs("div",{children:[e.jsx("div",{className:"font-medium",children:S.bastion_server.hostname}),e.jsx("div",{className:"text-muted-foreground",children:S.bastion_server.ip})]}):e.jsx("div",{className:"text-muted-foreground",children:"None"})})]}),e.jsx(ne,{...Re,children:e.jsxs("form",{onSubmit:Re.handleSubmit(Y),className:"space-y-4",children:[e.jsx(v,{control:Re.control,name:"server_id",render:({field:i})=>e.jsxs(b,{children:[e.jsx(N,{children:"New bastion server (UUID)"}),e.jsx(E,{children:e.jsx(z,{placeholder:"paste server UUID",...i})}),u.length>0&&e.jsxs("div",{className:"text-xs text-muted-foreground",children:["Suggestions:",e.jsx("div",{className:"mt-1 flex flex-wrap gap-2",children:u.slice(0,8).map(D=>e.jsxs(h,{type:"button",size:"sm",variant:i.value===D.id?"default":"outline",onClick:()=>i.onChange(D.id),className:"font-normal",children:[e.jsx(hs,{className:"mr-1 h-3 w-3"})," ",D.hostname||ps(D.id,6)]},D.id))})]}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"secondary",onClick:()=>void he(),children:"Clear bastion"}),e.jsx(h,{type:"submit",disabled:Re.formState.isSubmitting,children:Re.formState.isSubmitting?"Saving…":"Set bastion"})]})]})})]})}),e.jsx("pre",{children:JSON.stringify(s,null,2)})]})}const Gr=re({key:F().trim().min(2,"Key is too short"),value:F().trim().min(2,"Value is too short")}),Jr=re({key:F().trim().min(2,"Key is too short").optional(),value:F().trim().min(2,"Value is too short").optional()}).refine(s=>s.key!==void 0||s.value!==void 0,{message:"Provide a new key or value",path:["key"]}),Qr=re({node_pool_ids:Oe(F().uuid()).min(1,"Pick at least one node pool")});function Wr(s,t=8){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}const Yr=()=>{const[s,t]=o.useState([]),[r,d]=o.useState([]),[u,f]=o.useState(!1),[$,C]=o.useState(null),[O,M]=o.useState(!1),[R,U]=o.useState(!1),[T,P]=o.useState(null),[j,V]=o.useState(null);async function H(){f(!0),C(null);try{const[a,n]=await Promise.all([g.get("/api/v1/labels?include=node_pools"),g.get("/api/v1/node-pools")]),_=(a||[]).map(X=>({id:X.id,key:X.key,value:X.value,node_pools:X.node_pools??X.node_groups??[]}));if(t(_),d(n||[]),j){const X=_.find(me=>me.id===j.id)||null;V(X)}if(T){const X=_.find(me=>me.id===T.id)||null;P(X)}}catch(a){console.error(a);const n=a instanceof je?a.message:"Failed to load labels/pools";C(n)}finally{f(!1)}}o.useEffect(()=>{H()},[]);const m=te({resolver:ae(Gr),defaultValues:{key:"",value:""}}),x=async a=>{await g.post("/api/v1/labels",{key:a.key.trim(),value:a.value.trim()}),M(!1),m.reset(),await H()},c=te({resolver:ae(Jr),defaultValues:{key:void 0,value:void 0}});function S(a){P(a),c.reset({key:void 0,value:void 0}),U(!0)}const G=async a=>{if(!T)return;const n={};a.key!==void 0&&(n.key=a.key.trim()),a.value!==void 0&&(n.value=a.value.trim()),await g.patch(`/api/v1/labels/${T.id}`,n),U(!1),P(null),await H()};async function K(a){confirm("Delete this label? This cannot be undone.")&&(await g.delete(`/api/v1/labels/${a}`),await H())}const B=te({resolver:ae(Qr),defaultValues:{node_pool_ids:[]}});function xe(a){V(a),B.reset({node_pool_ids:[]})}const W=async a=>{j&&(await g.post(`/api/v1/labels/${j.id}/node_pools`,{node_pool_ids:a.node_pool_ids}),B.reset({node_pool_ids:[]}),await H())};async function ue(a){j&&confirm("Detach this label from the selected node pool?")&&(await g.delete(`/api/v1/labels/${j.id}/node_pools/${a}`),await H())}const fe=o.useMemo(()=>{if(!j)return[];const a=new Set((j.node_pools||[]).map(n=>n.id));return r.filter(n=>!a.has(n.id))},[j,r]);return u?e.jsx("div",{className:"p-6",children:"Loading labels…"}):$?e.jsx("div",{className:"p-6 text-red-500",children:$}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Labels"}),e.jsxs(ie,{open:O,onOpenChange:M,children:[e.jsx(We,{asChild:!0,children:e.jsxs(h,{onClick:()=>M(!0),children:[e.jsx(Qe,{className:"mr-2 h-4 w-4"}),"Create Label"]})}),e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsx(ce,{children:"Create Label"})}),e.jsx(ne,{...m,children:e.jsxs("form",{onSubmit:m.handleSubmit(x),className:"space-y-4",children:[e.jsx(v,{control:m.control,name:"key",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Key"}),e.jsx(E,{children:e.jsx(z,{placeholder:"app.kubernetes.io/managed-by",...a})}),e.jsx(w,{})]})}),e.jsx(v,{control:m.control,name:"value",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Value"}),e.jsx(E,{children:e.jsx(z,{placeholder:"GlueOps",...a})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>M(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:m.formState.isSubmitting,children:m.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Key"}),e.jsx(A,{children:"Value"}),e.jsx(A,{children:"Node Pools"}),e.jsx(A,{className:"w-[260px] text-right",children:"Actions"})]})}),e.jsxs(we,{children:[s.map(a=>e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:a.key}),e.jsx(p,{children:a.value}),e.jsx(p,{children:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[(a.node_pools||[]).slice(0,6).map(n=>e.jsx(Ce,{variant:"secondary",children:n.name},n.id)),(a.node_pools||[]).length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No pools"}),(a.node_pools||[]).length>6&&e.jsxs("span",{className:"text-muted-foreground",children:["+",(a.node_pools||[]).length-6," more"]})]})}),e.jsx(p,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>xe(a),children:[e.jsx(ye,{className:"mr-2 h-4 w-4"}),"Manage node pools"]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>S(a),children:[e.jsx(rs,{className:"mr-2 h-4 w-4"}),"Edit"]}),e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>K(a.id),children:[e.jsx(Ue,{className:"mr-2 h-4 w-4"}),"Delete"]})]})})]},a.id)),s.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:4,className:"text-muted-foreground py-10 text-center",children:"No labels yet."})})]})]})})}),e.jsx(ie,{open:R,onOpenChange:a=>!a&&U(!1),children:e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Edit Label"," ",T?e.jsxs("span",{className:"text-muted-foreground ml-2 font-mono text-sm",children:["(",T.key," = ",T.value,")"]}):null]})}),e.jsx(ne,{...c,children:e.jsxs("form",{onSubmit:c.handleSubmit(G),className:"space-y-4",children:[e.jsx(v,{control:c.control,name:"key",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"New key (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:T?.key||"e.g. app",...a})}),e.jsx(w,{})]})}),e.jsx(v,{control:c.control,name:"value",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"New value (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:T?.value||"e.g. GlueOps",...a})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>U(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:c.formState.isSubmitting,children:c.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})}),e.jsx(ie,{open:!!j,onOpenChange:a=>!a&&V(null),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage node pools for"," ",e.jsx("span",{className:"font-mono",children:j?`${j.key}=${j.value}`:""})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached node pools"}),e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Name"}),e.jsx(A,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs(we,{children:[(j?.node_pools||[]).map(a=>e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:a.name}),e.jsx(p,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>ue(a.id),children:[e.jsx(qe,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},a.id)),(j?.node_pools||[]).length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:2,className:"text-muted-foreground py-8 text-center",children:"No pools attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(ne,{...B,children:e.jsxs("form",{onSubmit:B.handleSubmit(W),className:"space-y-3",children:[e.jsx(v,{control:B.control,name:"node_pool_ids",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach more node pools"}),e.jsxs("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:[fe.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more node pools available to attach"}),fe.map(n=>{const _=a.value?.includes(n.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:_,onCheckedChange:X=>{const me=new Set(a.value||[]);X===!0?me.add(n.id):me.delete(n.id),a.onChange(Array.from(me))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:n.name}),e.jsx("div",{className:"text-muted-foreground text-xs",children:Wr(n.id,8)})]})]},n.id)})]}),e.jsx(w,{})]})}),e.jsx(de,{className:"gap-2",children:e.jsxs(h,{type:"submit",disabled:B.formState.isSubmitting,children:[e.jsx(ye,{className:"mr-2 h-4 w-4"}),B.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})})]})},Xr=re({name:F().trim().min(1,"Name is required").max(120,"Max 120 chars"),server_ids:Oe(F().uuid()).optional().default([])}),Zr=re({name:F().trim().min(1,"Name is required").max(120,"Max 120 chars")}),ei=re({server_ids:Oe(F().uuid()).min(1,"Pick at least one server")}),si=re({label_ids:Oe(F().uuid()).min(1,"Pick at least one label")}),ti=re({taint_ids:Oe(F().uuid()).min(1,"Pick at least one taint")}),ai=re({annotation_ids:Oe(F().uuid()).min(1,"Pick at least one annotation")});function pt({status:s}){const t=s==="ready"?"default":s==="provisioning"?"secondary":s==="failed"?"destructive":"outline";return e.jsx(Ce,{variant:t,className:"capitalize",children:s||"unknown"})}function ts(s,t=12){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}function gt(s){const t=s.ip||s.ip_address,r=s.hostname||t||s.id,d=s.role?` · ${s.role}`:"";return`${r}${d}`}function ni(s){return`${s.key}=${s.value}`}function vt(s){return`${s.value?`${s.key}=${s.value}`:s.key}:${s.effect}`}function bt(s){return`${s.name}=${s.value}`}const ri=()=>{const[s,t]=o.useState(!0),[r,d]=o.useState([]),[u,f]=o.useState([]),[$,C]=o.useState([]),[O,M]=o.useState([]),[R,U]=o.useState([]),[T,P]=o.useState(null),[j,V]=o.useState(""),[H,m]=o.useState(!1),[x,c]=o.useState(null),[S,G]=o.useState(null),[K,B]=o.useState(null),[xe,W]=o.useState([]),[ue,fe]=o.useState(!1),[a,n]=o.useState(null),[_,X]=o.useState(null),[me,ge]=o.useState([]),[Re,y]=o.useState(!1),[Y,he]=o.useState(null),[i,D]=o.useState(null),[ze,Fe]=o.useState([]),[Se,pe]=o.useState(!1),[He,dt]=o.useState(null);async function _e(){t(!0),P(null);try{const[l,k,Q,I,Z]=await Promise.all([g.get("/api/v1/node-pools?include=servers"),g.get("/api/v1/servers"),g.get("/api/v1/labels?include=node_pools"),g.get("/api/v1/taints?include=node_pools"),g.get("/api/v1/annotations?include=node_pools")]);if(d(l||[]),f(k||[]),C(Q||[]),M(I||[]),U(Z||[]),S){const ke=(l||[]).find(J=>J.id===S.id)||null;G(ke)}if(x){const ke=(l||[]).find(J=>J.id===x.id)||null;c(ke)}K&&await ks(K.id),_&&await As(_.id),i&&await Es(i.id)}catch(l){console.error(l);const k=l instanceof je?l.message:"Failed to load node pools / servers / labels / taints / annotations";P(k)}finally{t(!1)}}async function ks(l){fe(!0),n(null);try{const k=await g.get(`/api/v1/node-pools/${l}/labels`);W(k||[])}catch(k){console.error(k);const Q=k instanceof je?k.message:"Failed to load labels for pool";n(Q)}finally{fe(!1)}}async function As(l){y(!0),he(null);try{const k=await g.get(`/api/v1/node-pools/${l}/taints`);ge(k||[])}catch(k){console.error(k);const Q=k instanceof je?k.message:"Failed to load taints for pool";he(Q)}finally{y(!1)}}async function Es(l){pe(!0),dt(null);try{const k=await g.get(`/api/v1/node-pools/${l}/annotations`);Fe(k||[])}catch(k){console.error(k);const Q=k instanceof je?k.message:"Failed to load annotations for pool";dt(Q)}finally{pe(!1)}}o.useEffect(()=>{_e()},[]);const Fs=o.useMemo(()=>{const l=new Map;for(const k of $)for(const Q of k.node_groups||[]){const I=l.get(Q.id)||[];I.push({id:k.id,key:k.key,value:k.value}),l.set(Q.id,I)}return l},[$]),Rs=o.useMemo(()=>{const l=new Map;for(const k of O)for(const Q of k.node_groups||[]){const I=l.get(Q.id)||[];I.push({id:k.id,key:k.key,value:k.value,effect:k.effect}),l.set(Q.id,I)}return l},[O]),Vs=o.useMemo(()=>{const l=new Map;for(const k of R)for(const Q of k.node_pools||[]){const I=l.get(Q.id)||[];I.push({id:k.id,name:k.name,value:k.value}),l.set(Q.id,I)}return l},[R]),ct=o.useMemo(()=>{const l=j.trim().toLowerCase();return l?r.filter(k=>{const Q=(k.servers||[]).some(J=>(J.hostname||"").toLowerCase().includes(l)||(J.ip||J.ip_address||"").toLowerCase().includes(l)||(J.role||"").toLowerCase().includes(l)),I=(Fs.get(k.id)||[]).some(J=>J.key.toLowerCase().includes(l)||(J.value||"").toLowerCase().includes(l)),Z=(Rs.get(k.id)||[]).some(J=>{const ra=`${J.key}=${J.value}`.toLowerCase();return J.key.toLowerCase().includes(l)||(J.value||"").toLowerCase().includes(l)||J.effect.toLowerCase().includes(l)||ra.includes(l)}),ke=(Vs.get(k.id)||[]).some(J=>J.name.toLowerCase().includes(l)||(J.value||"").toLowerCase().includes(l)||`${J.name}=${J.value}`.toLowerCase().includes(l));return k.name.toLowerCase().includes(l)||Q||I||Z||ke}):r},[r,j,Fs,Rs,Vs]);async function Bt(l){confirm("Delete this node pool? This cannot be undone.")&&(await g.delete(`/api/v1/node-pools/${l}`),await _e())}const Ye=te({resolver:ae(Xr),defaultValues:{name:"",server_ids:[]}}),Ht=async l=>{const k={name:l.name.trim()};l.server_ids&&l.server_ids.length>0&&(k.server_ids=l.server_ids),await g.post("/api/v1/node-pools",k),m(!1),Ye.reset({name:"",server_ids:[]}),await _e()},ds=te({resolver:ae(Zr),defaultValues:{name:""}});function Kt(l){c(l),ds.reset({name:l.name})}const qt=async l=>{x&&(await g.patch(`/api/v1/node-pools/${x.id}`,{name:l.name.trim()}),c(null),await _e())},Xe=te({resolver:ae(ei),defaultValues:{server_ids:[]}});function Gt(l){G(l),Xe.reset({server_ids:[]})}const Jt=async l=>{S&&(await g.post(`/api/v1/node-pools/${S.id}/servers`,{server_ids:l.server_ids}),Xe.reset({server_ids:[]}),await _e())};async function Qt(l){S&&confirm("Detach this server from the pool?")&&(await g.delete(`/api/v1/node-pools/${S.id}/servers/${l}`),await _e())}const Ze=te({resolver:ae(si),defaultValues:{label_ids:[]}});function Wt(l){B(l),Ze.reset({label_ids:[]}),ks(l.id)}const Yt=async l=>{K&&(await g.post(`/api/v1/node-pools/${K.id}/labels`,{label_ids:l.label_ids}),Ze.reset({label_ids:[]}),await ks(K.id),await _e())};async function Xt(l){K&&confirm("Detach this label from the pool?")&&(await g.delete(`/api/v1/node-pools/${K.id}/labels/${l}`),await ks(K.id),await _e())}const es=te({resolver:ae(ti),defaultValues:{taint_ids:[]}});function Zt(l){X(l),es.reset({taint_ids:[]}),As(l.id)}const ea=async l=>{_&&(await g.post(`/api/v1/node-pools/${_.id}/taints`,{taint_ids:l.taint_ids}),es.reset({taint_ids:[]}),await As(_.id),await _e())};async function sa(l){_&&confirm("Detach this taint from the pool?")&&(await g.delete(`/api/v1/node-pools/${_.id}/taints/${l}`),await As(_.id),await _e())}const ss=te({resolver:ae(ai),defaultValues:{annotation_ids:[]}});function ta(l){D(l),ss.reset({annotation_ids:[]}),Es(l.id)}const aa=async l=>{i&&(await g.post(`/api/v1/node-pools/${i.id}/annotations`,{annotation_ids:l.annotation_ids}),ss.reset({annotation_ids:[]}),await Es(i.id),await _e())};async function na(l){i&&confirm("Detach this annotation from the pool?")&&(await g.delete(`/api/v1/node-pools/${i.id}/annotations/${l}`),await Es(i.id),await _e())}return s?e.jsx("div",{className:"p-6",children:"Loading node pools…"}):T?e.jsx("div",{className:"p-6 text-red-500",children:T}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Node Pools"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:"relative",children:[e.jsx(Ts,{className:"absolute top-2.5 left-2 h-4 w-4 opacity-60"}),e.jsx(z,{value:j,onChange:l=>V(l.target.value),placeholder:"Search pools, servers, labels, taints, annotations…",className:"w-72 pl-8"})]}),e.jsxs(h,{variant:"outline",onClick:_e,children:[e.jsx(Ps,{className:"mr-2 h-4 w-4"})," Refresh"]}),e.jsxs(ie,{open:H,onOpenChange:m,children:[e.jsx(We,{asChild:!0,children:e.jsxs(h,{onClick:()=>m(!0),children:[e.jsx(Qe,{className:"mr-2 h-4 w-4"})," Create Pool"]})}),e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsx(ce,{children:"Create node pool"})}),e.jsx(ne,{...Ye,children:e.jsxs("form",{onSubmit:Ye.handleSubmit(Ht),className:"space-y-4",children:[e.jsx(v,{control:Ye.control,name:"name",render:({field:l})=>e.jsxs(b,{children:[e.jsx(N,{children:"Name"}),e.jsx(E,{children:e.jsx(z,{placeholder:"pool-workers-a",...l})}),e.jsx(w,{})]})}),e.jsx(v,{control:Ye.control,name:"server_ids",render:({field:l})=>e.jsxs(b,{children:[e.jsx(N,{children:"Initial servers (optional)"}),e.jsxs("div",{className:"max-h-56 space-y-2 overflow-auto rounded-xl border p-2",children:[u.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No servers available"}),u.map(k=>{const Q=l.value?.includes(k.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:Q,onCheckedChange:I=>{const Z=new Set(l.value||[]);I===!0?Z.add(k.id):Z.delete(k.id),l.onChange(Array.from(Z))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:gt(k)}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ts(k.id,8)})]})]},k.id)})]}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>m(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:Ye.formState.isSubmitting,children:Ye.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Name"}),e.jsx(A,{children:"Servers"}),e.jsx(A,{children:"Annotations"}),e.jsx(A,{children:"Labels"}),e.jsx(A,{children:"Taints"}),e.jsx(A,{className:"w-[180px] text-right",children:"Actions"})]})}),e.jsxs(we,{children:[ct.map(l=>{const k=Fs.get(l.id)||[],Q=Rs.get(l.id)||[],I=Vs.get(l.id)||[];return e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:l.name}),e.jsxs(p,{children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[(l.servers||[]).slice(0,6).map(Z=>e.jsxs(Ce,{variant:"secondary",className:"gap-1",children:[e.jsx(hs,{className:"h-3 w-3"})," ",Z.hostname||Z.ip||Z.ip_address||ts(Z.id,6),e.jsx("span",{className:"ml-1",children:Z.role}),Z.status&&e.jsx("span",{className:"ml-1",children:e.jsx(pt,{status:Z.status})})]},Z.id)),(l.servers||[]).length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No servers"}),(l.servers||[]).length>6&&e.jsxs("span",{className:"text-muted-foreground",children:["+",(l.servers||[]).length-6," more"]})]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>Gt(l),children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," Manage servers"]})]}),e.jsxs(p,{children:[e.jsxs("div",{className:"mb-2 flex flex-wrap gap-2",children:[I.slice(0,6).map(Z=>e.jsxs(Ce,{variant:"outline",className:"font-mono",children:[e.jsx($s,{className:"mr-1 h-3 w-3"}),bt(Z)]},Z.id)),I.length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No annotations"}),I.length>6&&e.jsxs("span",{className:"text-muted-foreground",children:["+",I.length-6," more"]})]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>ta(l),children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," Manage Annotations"]})]}),e.jsxs(p,{children:[e.jsxs("div",{className:"mb-2 flex flex-wrap gap-2",children:[k.slice(0,6).map(Z=>e.jsxs(Ce,{variant:"outline",className:"font-mono",children:[e.jsx($s,{className:"mr-1 h-3 w-3"}),Z.key,"=",Z.value]},Z.id)),k.length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No labels"}),k.length>6&&e.jsxs("span",{className:"text-muted-foreground",children:["+",k.length-6," more"]})]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>Wt(l),children:[e.jsx($s,{className:"mr-2 h-4 w-4"})," Manage Labels"]})]}),e.jsxs(p,{children:[e.jsxs("div",{className:"mb-2 flex flex-wrap gap-2",children:[Q.slice(0,6).map(Z=>e.jsxs(Ce,{variant:"outline",className:"font-mono",children:[e.jsx($s,{className:"mr-1 h-3 w-3"}),vt(Z)]},Z.id)),Q.length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No taints"}),Q.length>6&&e.jsxs("span",{className:"text-muted-foreground",children:["+",Q.length-6," more"]})]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>Zt(l),children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," Manage Taints"]})]}),e.jsx(p,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>Kt(l),children:[e.jsx(rs,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(is,{children:[e.jsx(os,{asChild:!0,children:e.jsxs(h,{variant:"destructive",size:"sm",children:[e.jsx(Ue,{className:"mr-2 h-4 w-4"})," Delete"]})}),e.jsx(ls,{align:"end",children:e.jsx(Ie,{onClick:()=>Bt(l.id),children:"Confirm delete"})})]})]})})]},l.id)}),ct.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:6,className:"text-muted-foreground py-10 text-center",children:"No node pools match your search."})})]})]})})}),e.jsx(ie,{open:!!x,onOpenChange:l=>!l&&c(null),children:e.jsxs(oe,{className:"sm:max-w-md",children:[e.jsx(le,{children:e.jsx(ce,{children:"Edit node pool"})}),e.jsx(ne,{...ds,children:e.jsxs("form",{onSubmit:ds.handleSubmit(qt),className:"space-y-4",children:[e.jsx(v,{control:ds.control,name:"name",render:({field:l})=>e.jsxs(b,{children:[e.jsx(N,{children:"Name"}),e.jsx(E,{children:e.jsx(z,{placeholder:"pool-workers-a",...l})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>c(null),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:ds.formState.isSubmitting,children:ds.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})}),e.jsx(ie,{open:!!S,onOpenChange:l=>!l&&G(null),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage servers for ",e.jsx("span",{className:"font-mono",children:S?.name})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached servers"}),e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Server"}),e.jsx(A,{children:"IP"}),e.jsx(A,{children:"Role"}),e.jsx(A,{children:"Status"}),e.jsx(A,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs(we,{children:[(S?.servers||[]).map(l=>e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:l.hostname||ts(l.id,8)}),e.jsx(p,{children:e.jsx("code",{className:"font-mono text-sm",children:l.ip||l.ip_address||"—"})}),e.jsx(p,{className:"capitalize",children:l.role||"—"}),e.jsx(p,{children:e.jsx(pt,{status:l.status})}),e.jsx(p,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>Qt(l.id),children:[e.jsx(qe,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},l.id)),(S?.servers||[]).length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:5,className:"text-muted-foreground py-8 text-center",children:"No servers attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(ne,{...Xe,children:e.jsxs("form",{onSubmit:Xe.handleSubmit(Jt),className:"space-y-3",children:[e.jsx(v,{control:Xe.control,name:"server_ids",render:({field:l})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach more servers"}),e.jsx("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:(()=>{const k=new Set((S?.servers||[]).map(I=>I.id)),Q=u.filter(I=>!k.has(I.id));return Q.length===0?e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more servers available to attach"}):Q.map(I=>{const Z=l.value?.includes(I.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:Z,onCheckedChange:ke=>{const J=new Set(l.value||[]);ke===!0?J.add(I.id):J.delete(I.id),l.onChange(Array.from(J))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:gt(I)}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ts(I.id,8)})]})]},I.id)})})()}),e.jsx(w,{})]})}),e.jsx(de,{className:"gap-2",children:e.jsxs(h,{type:"submit",disabled:Xe.formState.isSubmitting,children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," ",Xe.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})}),e.jsx(ie,{open:!!K,onOpenChange:l=>!l&&B(null),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage labels for ",e.jsx("span",{className:"font-mono",children:K?.name})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached labels"}),ue?e.jsx("div",{className:"text-muted-foreground rounded-md border p-3 text-sm",children:"Loading…"}):a?e.jsx("div",{className:"rounded-md border p-3 text-sm text-red-500",children:a}):e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Key"}),e.jsx(A,{children:"Value"}),e.jsx(A,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs(we,{children:[xe.map(l=>e.jsxs(q,{children:[e.jsx(p,{className:"font-mono text-sm",children:l.key}),e.jsx(p,{className:"font-mono text-sm",children:l.value}),e.jsx(p,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>Xt(l.id),children:[e.jsx(qe,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},l.id)),xe.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:3,className:"text-muted-foreground py-8 text-center",children:"No labels attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(ne,{...Ze,children:e.jsxs("form",{onSubmit:Ze.handleSubmit(Yt),className:"space-y-3",children:[e.jsx(v,{control:Ze.control,name:"label_ids",render:({field:l})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach more labels"}),e.jsx("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:(()=>{const k=new Set(xe.map(I=>I.id)),Q=$.filter(I=>!k.has(I.id));return Q.length===0?e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more labels available to attach"}):Q.map(I=>{const Z=l.value?.includes(I.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:Z,onCheckedChange:ke=>{const J=new Set(l.value||[]);ke===!0?J.add(I.id):J.delete(I.id),l.onChange(Array.from(J))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:ni(I)}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ts(I.id,8)})]})]},I.id)})})()}),e.jsx(w,{})]})}),e.jsx(de,{className:"gap-2",children:e.jsxs(h,{type:"submit",disabled:Ze.formState.isSubmitting,children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," ",Ze.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})}),e.jsx(ie,{open:!!_,onOpenChange:l=>!l&&X(null),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage taints for ",e.jsx("span",{className:"font-mono",children:_?.name})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached taints"}),Re?e.jsx("div",{className:"text-muted-foreground rounded-md border p-3 text-sm",children:"Loading…"}):Y?e.jsx("div",{className:"rounded-md border p-3 text-sm text-red-500",children:Y}):e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Key"}),e.jsx(A,{children:"Value"}),e.jsx(A,{children:"Effect"}),e.jsx(A,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs(we,{children:[me.map(l=>e.jsxs(q,{children:[e.jsx(p,{className:"font-mono text-sm",children:l.key}),e.jsx(p,{className:"font-mono text-sm",children:l.value}),e.jsx(p,{className:"font-mono text-sm",children:l.effect}),e.jsx(p,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>sa(l.id),children:[e.jsx(qe,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},l.id)),me.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:4,className:"text-muted-foreground py-8 text-center",children:"No taints attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(ne,{...es,children:e.jsxs("form",{onSubmit:es.handleSubmit(ea),className:"space-y-3",children:[e.jsx(v,{control:es.control,name:"taint_ids",render:({field:l})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach more taints"}),e.jsx("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:(()=>{const k=new Set(me.map(I=>I.id)),Q=O.filter(I=>!k.has(I.id));return Q.length===0?e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more taints available to attach"}):Q.map(I=>{const Z=l.value?.includes(I.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:Z,onCheckedChange:ke=>{const J=new Set(l.value||[]);ke===!0?J.add(I.id):J.delete(I.id),l.onChange(Array.from(J))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:vt(I)}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ts(I.id,8)})]})]},I.id)})})()}),e.jsx(w,{})]})}),e.jsx(de,{className:"gap-2",children:e.jsxs(h,{type:"submit",disabled:es.formState.isSubmitting,children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," ",es.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})}),e.jsx(ie,{open:!!i,onOpenChange:l=>!l&&D(null),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage annotations for"," ",e.jsx("span",{className:"font-mono",children:i?.name})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached annotations"}),Se?e.jsx("div",{className:"text-muted-foreground rounded-md border p-3 text-sm",children:"Loading…"}):He?e.jsx("div",{className:"rounded-md border p-3 text-sm text-red-500",children:He}):e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Name"}),e.jsx(A,{children:"Value"}),e.jsx(A,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs(we,{children:[ze.map(l=>e.jsxs(q,{children:[e.jsx(p,{className:"font-mono text-sm",children:l.name}),e.jsx(p,{className:"font-mono text-sm",children:l.value}),e.jsx(p,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>na(l.id),children:[e.jsx(qe,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},l.id)),ze.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:3,className:"text-muted-foreground py-8 text-center",children:"No annotations attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(ne,{...ss,children:e.jsxs("form",{onSubmit:ss.handleSubmit(aa),className:"space-y-3",children:[e.jsx(v,{control:ss.control,name:"annotation_ids",render:({field:l})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach more annotations"}),e.jsx("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:(()=>{const k=new Set(ze.map(I=>I.id)),Q=R.filter(I=>!k.has(I.id));return Q.length===0?e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more annotations available to attach"}):Q.map(I=>{const Z=l.value?.includes(I.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:Z,onCheckedChange:ke=>{const J=new Set(l.value||[]);ke===!0?J.add(I.id):J.delete(I.id),l.onChange(Array.from(J))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:bt(I)}),e.jsx("div",{className:"text-muted-foreground text-xs",children:ts(I.id,8)})]})]},I.id)})})()}),e.jsx(w,{})]})}),e.jsx(de,{className:"gap-2",children:e.jsxs(h,{type:"submit",disabled:ss.formState.isSubmitting,children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," ",ss.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})})]})},gs=["pending","provisioning","ready","failed"],vs=["master","worker","bastion"],Ut=re({hostname:F().trim().max(120,"Max 120 chars").optional(),ip_address:F().trim().min(1,"IP address is required"),role:Je(vs),ssh_key_id:us("Pick a valid SSH key"),ssh_user:F().trim().min(1,"SSH user is required"),status:Je(gs).default("pending")}),ii=Ut.partial();function oi({status:s}){const t=s==="ready"?"default":s==="provisioning"?"secondary":s==="failed"?"destructive":"outline";return e.jsx(Ce,{variant:t,className:"capitalize",children:s})}function Bs(s,t=16){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}const li=()=>{const[s,t]=o.useState([]),[r,d]=o.useState([]),[u,f]=o.useState(!1),[$,C]=o.useState(null),[O,M]=o.useState(""),[R,U]=o.useState(""),[T,P]=o.useState(""),[j,V]=o.useState(!1),[H,m]=o.useState(null);function x(){const a=new URLSearchParams;return R&&a.set("status",R),T&&a.set("role",T),`/api/v1/servers${a.toString()?`?${a.toString()}`:""}`}async function c(){f(!0),C(null);try{const[a,n]=await Promise.all([g.get(x()),g.get("/api/v1/ssh")]);t(a??[]),d(n??[])}catch(a){console.error(a),C("Failed to load servers or SSH keys")}finally{f(!1)}}o.useEffect(()=>{c();const a=n=>{n.key==="active_org_id"&&c()};return window.addEventListener("storage",a),()=>window.removeEventListener("storage",a)},[]),o.useEffect(()=>{c()},[R,T]);const S=o.useMemo(()=>{const a=new Map;return r.forEach(n=>a.set(n.id,n)),a},[r]),G=o.useMemo(()=>{const a=O.trim().toLowerCase();return a?s.filter(n=>(n.hostname??"").toLowerCase().includes(a)||n.ip_address.toLowerCase().includes(a)||n.role.toLowerCase().includes(a)||n.ssh_user.toLowerCase().includes(a)):s},[s,O]);async function K(a){confirm("Delete this server? This cannot be undone.")&&(await g.delete(`/api/v1/servers/${encodeURIComponent(a)}`),await c())}const B=te({resolver:ae(Ut),defaultValues:{hostname:"",ip_address:"",role:"worker",ssh_key_id:"",ssh_user:"ubuntu",status:"pending"}}),xe=async a=>{const n={ip_address:a.ip_address.trim(),role:a.role,ssh_key_id:a.ssh_key_id,ssh_user:a.ssh_user.trim(),status:a.status};a.hostname&&a.hostname.trim()&&(n.hostname=a.hostname.trim()),await g.post("/api/v1/servers",n),V(!1),B.reset(),await c()},W=te({resolver:ae(ii),defaultValues:{}});function ue(a){m(a),W.reset({hostname:a.hostname??"",ip_address:a.ip_address,role:vs.includes(a.role)?a.role:"worker",ssh_key_id:a.ssh_key_id,ssh_user:a.ssh_user,status:gs.includes(a.status)?a.status:"pending"})}const fe=async a=>{if(!H)return;const n={};a.hostname!==void 0&&(n.hostname=a.hostname?.trim()||""),a.ip_address!==void 0&&(n.ip_address=a.ip_address.trim()),a.role!==void 0&&(n.role=a.role),a.ssh_key_id!==void 0&&(n.ssh_key_id=a.ssh_key_id),a.ssh_user!==void 0&&(n.ssh_user=a.ssh_user.trim()),a.status!==void 0&&(n.status=a.status),await g.patch(`/api/v1/servers/${encodeURIComponent(H.id)}`,n),m(null),await c()};return u?e.jsx("div",{className:"p-6",children:"Loading servers…"}):$?e.jsx("div",{className:"p-6 text-red-500",children:$}):e.jsxs(Os,{children:[e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Servers"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:"relative",children:[e.jsx(Ts,{className:"absolute top-2.5 left-2 h-4 w-4 opacity-60"}),e.jsx(z,{value:O,onChange:a=>M(a.target.value),placeholder:"Search hostname, IP, role, user…",className:"w-64 pl-8"})]}),e.jsxs(Ae,{value:T,onValueChange:a=>P(a),children:[e.jsx($e,{className:"w-36",children:e.jsx(Ee,{placeholder:"Role (all)"})}),e.jsx(Le,{children:vs.map(a=>e.jsx(ve,{value:a,children:a},a))})]}),e.jsxs(Ae,{value:R,onValueChange:a=>U(a),children:[e.jsx($e,{className:"w-40",children:e.jsx(Ee,{placeholder:"Status (all)"})}),e.jsx(Le,{children:gs.map(a=>e.jsx(ve,{value:a,children:a},a))})]}),e.jsxs(h,{variant:"outline",onClick:c,children:[e.jsx(Ps,{className:"mr-2 h-4 w-4"}),"Refresh"]}),e.jsxs(ie,{open:j,onOpenChange:V,children:[e.jsx(We,{asChild:!0,children:e.jsxs(h,{onClick:()=>V(!0),children:[e.jsx(Qe,{className:"mr-2 h-4 w-4"}),"Create Server"]})}),e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsx(ce,{children:"Create server"})}),e.jsx(ne,{...B,children:e.jsxs("form",{onSubmit:B.handleSubmit(xe),className:"space-y-4",children:[e.jsx(v,{control:B.control,name:"hostname",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Hostname"}),e.jsx(E,{children:e.jsx(z,{placeholder:"worker-01",...a})}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"ip_address",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"IP address"}),e.jsx(E,{children:e.jsx(z,{placeholder:"10.0.1.23",...a})}),e.jsx(w,{})]})}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[e.jsx(v,{control:B.control,name:"role",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Ae,{onValueChange:a.onChange,value:a.value,children:[e.jsx(E,{children:e.jsx($e,{children:e.jsx(Ee,{placeholder:"Select role"})})}),e.jsx(Le,{children:vs.map(n=>e.jsx(ve,{value:n,children:n},n))})]}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"ssh_user",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"SSH user"}),e.jsx(E,{children:e.jsx(z,{placeholder:"ubuntu",...a})}),e.jsx(w,{})]})})]}),e.jsx(v,{control:B.control,name:"ssh_key_id",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"SSH key"}),e.jsxs(Ae,{onValueChange:a.onChange,value:a.value,children:[e.jsx(E,{children:e.jsx($e,{children:e.jsx(Ee,{placeholder:r.length?"Select SSH key":"No SSH keys found"})})}),e.jsx(Le,{children:r.map(n=>e.jsxs(ve,{value:n.id,children:[n.name?n.name:"Unnamed key"," —"," ",Bs(n.fingerprint,8)]},n.id))})]}),e.jsx(w,{})]})}),e.jsx(v,{control:B.control,name:"status",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Initial status"}),e.jsxs(Ae,{onValueChange:a.onChange,value:a.value,children:[e.jsx(E,{children:e.jsx($e,{children:e.jsx(Ee,{placeholder:"pending"})})}),e.jsx(Le,{children:gs.map(n=>e.jsx(ve,{value:n,children:n},n))})]}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>V(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:B.formState.isSubmitting,children:B.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Hostname"}),e.jsx(A,{children:"IP address"}),e.jsx(A,{children:"Role"}),e.jsx(A,{children:"SSH user"}),e.jsx(A,{children:"SSH key"}),e.jsx(A,{children:"Status"}),e.jsx(A,{children:"Created"}),e.jsx(A,{className:"w-[180px] text-right",children:"Actions"})]})}),e.jsxs(we,{children:[G.map(a=>{const n=S.get(a.ssh_key_id);return e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:a.hostname||"—"}),e.jsx(p,{children:e.jsx("code",{className:"font-mono text-sm",children:a.ip_address})}),e.jsx(p,{className:"capitalize",children:a.role}),e.jsx(p,{children:e.jsx("code",{className:"font-mono text-sm",children:a.ssh_user})}),e.jsx(p,{children:n?e.jsxs(Ys,{children:[e.jsx(Xs,{asChild:!0,children:e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx(Ce,{variant:"secondary",children:n.name||"SSH key"}),e.jsx("code",{className:"font-mono text-xs",children:Bs(n.fingerprint,8)})]})}),e.jsx(Zs,{className:"max-w-[70vw]",children:e.jsx("p",{className:"font-mono text-xs break-all",children:n.public_keys})})]}):e.jsx("span",{className:"text-muted-foreground",children:"Unknown"})}),e.jsx(p,{children:e.jsx(oi,{status:a.status})}),e.jsx(p,{children:new Date(a.created_at).toLocaleString()}),e.jsx(p,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>ue(a),children:[e.jsx(rs,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(is,{children:[e.jsx(os,{asChild:!0,children:e.jsxs(h,{variant:"destructive",size:"sm",children:[e.jsx(Ue,{className:"mr-2 h-4 w-4"})," Delete"]})}),e.jsx(ls,{align:"end",children:e.jsx(Ie,{onClick:()=>K(a.id),children:"Confirm delete"})})]})]})})]},a.id)}),G.length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:8,className:"text-muted-foreground py-10 text-center",children:"No servers match your filters."})})]})]})})})]}),e.jsx(ie,{open:!!H,onOpenChange:a=>!a&&m(null),children:e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsx(ce,{children:"Edit server"})}),e.jsx(ne,{...W,children:e.jsxs("form",{onSubmit:W.handleSubmit(fe),className:"space-y-4",children:[e.jsx(v,{control:W.control,name:"hostname",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Hostname"}),e.jsx(E,{children:e.jsx(z,{placeholder:"worker-01",...a})}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"ip_address",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"IP address"}),e.jsx(E,{children:e.jsx(z,{placeholder:"10.0.1.23",...a})}),e.jsx(w,{})]})}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[e.jsx(v,{control:W.control,name:"role",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Ae,{onValueChange:a.onChange,value:a.value,children:[e.jsx(E,{children:e.jsx($e,{children:e.jsx(Ee,{placeholder:"Select role"})})}),e.jsx(Le,{children:vs.map(n=>e.jsx(ve,{value:n,children:n},n))})]}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"ssh_user",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"SSH user"}),e.jsx(E,{children:e.jsx(z,{placeholder:"ubuntu",...a})}),e.jsx(w,{})]})})]}),e.jsx(v,{control:W.control,name:"ssh_key_id",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"SSH key"}),e.jsxs(Ae,{onValueChange:a.onChange,value:a.value,children:[e.jsx(E,{children:e.jsx($e,{children:e.jsx(Ee,{placeholder:r.length?"Select SSH key":"No SSH keys found"})})}),e.jsx(Le,{children:r.map(n=>e.jsxs(ve,{value:n.id,children:[n.name?n.name:"SSH key"," — ",Bs(n.fingerprint,8)]},n.id))})]}),e.jsx(w,{})]})}),e.jsx(v,{control:W.control,name:"status",render:({field:a})=>e.jsxs(b,{children:[e.jsx(N,{children:"Status"}),e.jsxs(Ae,{onValueChange:a.onChange,value:a.value,children:[e.jsx(E,{children:e.jsx($e,{children:e.jsx(Ee,{placeholder:"pending"})})}),e.jsx(Le,{children:gs.map(n=>e.jsx(ve,{value:n,children:n},n))})]}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>m(null),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:W.formState.isSubmitting,children:W.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})})]})},Is=["NoSchedule","PreferNoSchedule","NoExecute"],di=re({key:F().trim().min(1,"Key is required").max(120,"Max 120 chars"),value:F().trim().optional(),effect:Je(Is),node_pool_ids:Oe(us()).optional().default([])}),ci=re({key:F().trim().min(1,"Key is required").max(120).optional(),value:F().trim().optional(),effect:Je(Is).optional()}),mi=re({node_pool_ids:Oe(F().uuid()).min(1,"Pick at least one node pool")});function Hs(s,t=12){return s?s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`:""}function xi({t:s}){const t=`${s.key}${s.value?`=${s.value}`:""}${s.effect?`:${s.effect}`:""}`;return e.jsxs(Ce,{variant:"secondary",className:"font-mono text-xs",children:[e.jsx(It,{className:"mr-1 h-3 w-3"}),t]})}const hi=()=>{const[s,t]=o.useState(!0),[r,d]=o.useState(null),[u,f]=o.useState([]),[$,C]=o.useState([]),[O,M]=o.useState(""),[R,U]=o.useState(!1),[T,P]=o.useState(null),[j,V]=o.useState(null);async function H(){t(!0),d(null);try{const[n,_]=await Promise.all([g.get("/api/v1/taints?include=node_groups"),g.get("/api/v1/node-pools")]);if(f(n||[]),C(_||[]),j){const X=(n||[]).find(me=>me.id===j.id)||null;V(X)}if(T){const X=(n||[]).find(me=>me.id===T.id)||null;P(X)}}catch(n){console.error(n);const _=n instanceof je?n.message:"Failed to load taints or node pools";d(_)}finally{t(!1)}}o.useEffect(()=>{H()},[]);const m=o.useMemo(()=>{const n=O.trim().toLowerCase();return n?u.filter(_=>{const X=`${_.key}${_.value?`=${_.value}`:""}${_.effect?`:${_.effect}`:""}`.toLowerCase(),me=(_.node_groups||[]).some(ge=>ge.name.toLowerCase().includes(n));return X.includes(n)||me}):u},[u,O]);async function x(n){confirm("Delete this taint? This cannot be undone.")&&(await g.delete(`/api/v1/taints/${n}`),await H())}const c=te({resolver:ae(di),defaultValues:{key:"",value:"",effect:void 0,node_pool_ids:[]}}),S=async n=>{const _={key:n.key.trim(),effect:n.effect};n.value&&(_.value=n.value.trim()),n.node_pool_ids&&n.node_pool_ids.length>0&&(_.node_pool_ids=n.node_pool_ids),await g.post("/api/v1/taints",_),U(!1),c.reset({key:"",value:"",effect:void 0,node_pool_ids:[]}),await H()},G=te({resolver:ae(ci),defaultValues:{}});function K(n){P(n),G.reset({key:n.key,value:n.value||"",effect:n.effect||void 0})}const B=async n=>{if(!T)return;const _={};n.key!==void 0&&(_.key=n.key.trim()),n.value!==void 0&&(_.value=n.value?.trim()??""),n.effect!==void 0&&(_.effect=n.effect),await g.patch(`/api/v1/taints/${T.id}`,_),P(null),await H()},xe=te({resolver:ae(mi),defaultValues:{node_pool_ids:[]}});function W(n){V(n),xe.reset({node_pool_ids:[]})}const ue=async n=>{j&&(await g.post(`/api/v1/taints/${j.id}/node_pools`,{node_pool_ids:n.node_pool_ids}),xe.reset({node_pool_ids:[]}),await H())};async function fe(n){j&&confirm("Detach this taint from the node pool?")&&(await g.delete(`/api/v1/taints/${j.id}/node_pools/${n}`),await H())}const a=o.useMemo(()=>{if(!j)return[];const n=new Set((j.node_groups||[]).map(_=>_.id));return $.filter(_=>!n.has(_.id))},[j,$]);return s?e.jsx("div",{className:"p-6",children:"Loading taints…"}):r?e.jsx("div",{className:"p-6 text-red-500",children:r}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Taints"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:"relative",children:[e.jsx(Ts,{className:"absolute top-2.5 left-2 h-4 w-4 opacity-60"}),e.jsx(z,{value:O,onChange:n=>M(n.target.value),placeholder:"Search taints or attached pools…",className:"w-72 pl-8"})]}),e.jsxs(h,{variant:"outline",onClick:H,children:[e.jsx(Ps,{className:"mr-2 h-4 w-4"})," Refresh"]}),e.jsxs(ie,{open:R,onOpenChange:U,children:[e.jsx(We,{asChild:!0,children:e.jsxs(h,{onClick:()=>U(!0),children:[e.jsx(Qe,{className:"mr-2 h-4 w-4"})," Create Taint"]})}),e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsx(ce,{children:"Create taint"})}),e.jsx(ne,{...c,children:e.jsxs("form",{onSubmit:c.handleSubmit(S),className:"space-y-4",children:[e.jsx(v,{control:c.control,name:"key",render:({field:n})=>e.jsxs(b,{children:[e.jsx(N,{children:"Key"}),e.jsx(E,{children:e.jsx(z,{placeholder:"dedicated",...n})}),e.jsx(w,{})]})}),e.jsx(v,{control:c.control,name:"value",render:({field:n})=>e.jsxs(b,{children:[e.jsx(N,{children:"Value (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:"gpu",...n})}),e.jsx(w,{})]})}),e.jsx(v,{control:c.control,name:"effect",render:({field:n})=>e.jsxs(b,{children:[e.jsx(N,{children:"Effect"}),e.jsxs(Ae,{onValueChange:n.onChange,value:n.value,children:[e.jsx(E,{children:e.jsx($e,{children:e.jsx(Ee,{placeholder:"Select effect"})})}),e.jsx(Le,{children:Is.map(_=>e.jsx(ve,{value:_,children:_},_))})]}),e.jsx(w,{})]})}),e.jsx(v,{control:c.control,name:"node_pool_ids",render:({field:n})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach to node pools (optional)"}),e.jsxs("div",{className:"max-h-56 space-y-2 overflow-auto rounded-xl border p-2",children:[$.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No node pools available"}),$.map(_=>{const X=n.value?.includes(_.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:X,onCheckedChange:me=>{const ge=new Set(n.value||[]);me===!0?ge.add(_.id):ge.delete(_.id),n.onChange(Array.from(ge))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:_.name}),e.jsx("div",{className:"text-muted-foreground text-xs",children:Hs(_.id,8)})]})]},_.id)})]}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>U(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:c.formState.isSubmitting,children:c.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Taint"}),e.jsx(A,{children:"Attached Node Pools"}),e.jsx(A,{className:"w-[180px] text-right",children:"Actions"})]})}),e.jsxs(we,{children:[m.map(n=>e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(xi,{t:n}),e.jsx("code",{className:"text-muted-foreground text-xs",children:Hs(n.id,6)})]})}),e.jsxs(p,{children:[e.jsxs("div",{className:"mb-2 flex flex-wrap gap-2",children:[(n.node_groups||[]).slice(0,6).map(_=>e.jsxs(Ce,{variant:"outline",className:"gap-1",children:[e.jsx(yn,{className:"h-3 w-3"}),_.name]},_.id)),(n.node_groups||[]).length===0&&e.jsx("span",{className:"text-muted-foreground",children:"No node pools"}),(n.node_groups||[]).length>6&&e.jsxs("span",{className:"text-muted-foreground",children:["+",(n.node_groups||[]).length-6," more"]})]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>W(n),children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," Manage node pools"]})]}),e.jsx(p,{children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>K(n),children:[e.jsx(rs,{className:"mr-2 h-4 w-4"})," Edit"]}),e.jsxs(is,{children:[e.jsx(os,{asChild:!0,children:e.jsxs(h,{variant:"destructive",size:"sm",children:[e.jsx(Ue,{className:"mr-2 h-4 w-4"})," Delete"]})}),e.jsx(ls,{align:"end",children:e.jsx(Ie,{onClick:()=>x(n.id),children:"Confirm delete"})})]})]})})]},n.id)),m.length===0&&e.jsx(q,{children:e.jsxs(p,{colSpan:3,className:"text-muted-foreground py-10 text-center",children:[e.jsx(Sn,{className:"mx-auto mb-2 h-6 w-6 opacity-60"}),"No taints match your search."]})})]})]})})}),e.jsx(ie,{open:!!T,onOpenChange:n=>!n&&P(null),children:e.jsxs(oe,{className:"sm:max-w-md",children:[e.jsx(le,{children:e.jsx(ce,{children:"Edit taint"})}),e.jsx(ne,{...G,children:e.jsxs("form",{onSubmit:G.handleSubmit(B),className:"space-y-4",children:[e.jsx(v,{control:G.control,name:"key",render:({field:n})=>e.jsxs(b,{children:[e.jsx(N,{children:"Key"}),e.jsx(E,{children:e.jsx(z,{placeholder:"dedicated",...n})}),e.jsx(w,{})]})}),e.jsx(v,{control:G.control,name:"value",render:({field:n})=>e.jsxs(b,{children:[e.jsx(N,{children:"Value (optional)"}),e.jsx(E,{children:e.jsx(z,{placeholder:"gpu",...n})}),e.jsx(w,{})]})}),e.jsx(v,{control:G.control,name:"effect",render:({field:n})=>e.jsxs(b,{children:[e.jsx(N,{children:"Effect"}),e.jsxs(Ae,{onValueChange:n.onChange,value:n.value,children:[e.jsx(E,{children:e.jsx($e,{children:e.jsx(Ee,{placeholder:"Select effect"})})}),e.jsx(Le,{children:Is.map(_=>e.jsx(ve,{value:_,children:_},_))})]}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>P(null),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:G.formState.isSubmitting,children:G.formState.isSubmitting?"Saving…":"Save changes"})]})]})})]})}),e.jsx(ie,{open:!!j,onOpenChange:n=>!n&&V(null),children:e.jsxs(oe,{className:"sm:max-w-2xl",children:[e.jsx(le,{children:e.jsxs(ce,{children:["Manage pools for"," ",e.jsx("span",{className:"font-mono",children:j?`${j.key}${j.value?`=${j.value}`:""}${j.effect?`:${j.effect}`:""}`:""})]})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-medium",children:"Attached node pools"}),e.jsx("div",{className:"overflow-hidden rounded-xl border",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Name"}),e.jsx(A,{className:"w-[120px] text-right",children:"Detach"})]})}),e.jsxs(we,{children:[(j?.node_groups||[]).map(n=>e.jsxs(q,{children:[e.jsx(p,{className:"font-medium",children:n.name}),e.jsx(p,{children:e.jsx("div",{className:"flex justify-end",children:e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>fe(n.id),children:[e.jsx(qe,{className:"mr-2 h-4 w-4"})," Detach"]})})})]},n.id)),(j?.node_groups||[]).length===0&&e.jsx(q,{children:e.jsx(p,{colSpan:2,className:"text-muted-foreground py-8 text-center",children:"No node pools attached yet."})})]})]})})]}),e.jsx("div",{className:"pt-4",children:e.jsx(ne,{...xe,children:e.jsxs("form",{onSubmit:xe.handleSubmit(ue),className:"space-y-3",children:[e.jsx(v,{control:xe.control,name:"node_pool_ids",render:({field:n})=>e.jsxs(b,{children:[e.jsx(N,{children:"Attach more node pools"}),e.jsxs("div",{className:"grid max-h-64 grid-cols-1 gap-2 overflow-auto rounded-xl border p-2 md:grid-cols-2",children:[a.length===0&&e.jsx("div",{className:"text-muted-foreground p-2 text-sm",children:"No more node pools available to attach"}),a.map(_=>{const X=n.value?.includes(_.id)||!1;return e.jsxs("label",{className:"hover:bg-accent flex cursor-pointer items-start gap-2 rounded p-1",children:[e.jsx(De,{checked:X,onCheckedChange:me=>{const ge=new Set(n.value||[]);me===!0?ge.add(_.id):ge.delete(_.id),n.onChange(Array.from(ge))}}),e.jsxs("div",{className:"leading-tight",children:[e.jsx("div",{className:"text-sm font-medium",children:_.name}),e.jsx("div",{className:"text-muted-foreground text-xs",children:Hs(_.id,8)})]})]},_.id)})]}),e.jsx(w,{})]})}),e.jsx(de,{className:"gap-2",children:e.jsxs(h,{type:"submit",disabled:xe.formState.isSubmitting,children:[e.jsx(ye,{className:"mr-2 h-4 w-4"})," ",xe.formState.isSubmitting?"Attaching…":"Attach selected"]})})]})})})]})})]})};function Nt(){return e.jsxs("div",{className:"p-6",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"403 — Forbidden"}),e.jsx("p",{className:"text-muted-foreground text-sm",children:"You don’t have access to this area."})]})}const wt=()=>{const s=_s();return e.jsxs("div",{className:"bg-background text-foreground flex min-h-screen flex-col items-center justify-center",children:[e.jsx("h1",{className:"mb-4 text-6xl font-bold",children:"404"}),e.jsx("p",{className:"mb-8 text-2xl",children:"Oops! Page not found"}),e.jsx(h,{onClick:()=>s("/dashboard"),children:"Go back to Dashboard"})]})},ui=re({name:F().min(1,"Name is required").max(100,"Max 100 characters"),comment:F().trim().max(100,"Max 100 characters").default(""),bits:Je(["2048","3072","4096"])});function ji(s,t="download.bin"){if(!s)return t;const r=/filename\*=UTF-8''([^;]+)/i.exec(s);return r?.[1]?decodeURIComponent(r[1]):/filename="?([^"]+)"?/i.exec(s)?.[1]??t}function fi(s,t=24){return!s||s.length<=t*2+3?s:`${s.slice(0,t)}…${s.slice(-t)}`}function pi(s){return s?.split(/\s+/)?.[0]??"ssh-key"}async function gi(s){try{await navigator.clipboard.writeText(s)}catch{const t=document.createElement("textarea");t.value=s,t.setAttribute("readonly",""),t.style.position="absolute",t.style.left="-9999px",document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t)}}const vi=()=>{const[s,t]=o.useState([]),[r,d]=o.useState(null),[u,f]=o.useState(!0),[$,C]=o.useState(""),[O,M]=o.useState(!1),R=o.useMemo(()=>!!localStorage.getItem("active_org_id"),[]);async function U(){f(!0),d(null);try{if(!R){t([]),d("Select an organization first.");return}const m=await g.get("/api/v1/ssh");t(m??[])}catch(m){console.error(m),d("Failed to fetch SSH keys")}finally{f(!1)}}o.useEffect(()=>{U();const m=x=>{x.key==="active_org_id"&&U()};return window.addEventListener("storage",m),()=>window.removeEventListener("storage",m)},[]);const T=s.filter(m=>`${m.name} ${m.public_keys} ${m.fingerprint}`.toLowerCase().includes($.toLowerCase()));async function P(m,x="both"){const c=localStorage.getItem("access_token"),S=localStorage.getItem("active_org_id"),G=`${Ls}/api/v1/ssh/${encodeURIComponent(m)}/download?part=${encodeURIComponent(x)}`;try{const K=await fetch(G,{method:"GET",headers:{...c?{Authorization:`Bearer ${c}`}:{},...S?{"X-Org-ID":S}:{}}});if(!K.ok){const a=await K.text().catch(()=>"");throw new Error(a||`HTTP ${K.status}`)}const B=await K.blob(),xe=x==="both"?`ssh_key_${m}.zip`:x==="public"?`id_rsa_${m}.pub`:`id_rsa_${m}.pem`,W=ji(K.headers.get("content-disposition")??void 0,xe),ue=URL.createObjectURL(B),fe=document.createElement("a");fe.href=ue,fe.download=W,document.body.appendChild(fe),fe.click(),fe.remove(),URL.revokeObjectURL(ue)}catch(K){console.error(K),alert(K instanceof Error?K.message:"Download failed")}}async function j(m){try{await g.delete(`/api/v1/ssh/${encodeURIComponent(m)}`),await U()}catch(x){console.error(x),alert("Failed to delete key")}}const V=te({resolver:ae(ui),defaultValues:{name:"",comment:"deploy@autoglue",bits:"4096"}});async function H(m){try{await g.post("/api/v1/ssh",{bits:Number(m.bits),comment:m.comment?.trim()??"",name:m.name.trim(),download:"none"}),M(!1),V.reset(),await U()}catch(x){console.error(x),alert("Failed to create key")}}return u?e.jsx("div",{className:"p-6",children:"Loading SSH Keys…"}):r?e.jsx("div",{className:"p-6 text-red-500",children:r}):e.jsx(Os,{children:e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"SSH Keys"}),e.jsx("div",{className:"w-full max-w-sm",children:e.jsx(z,{value:$,onChange:m=>C(m.target.value),placeholder:"Search by name, fingerprint or key"})}),e.jsxs(ie,{open:O,onOpenChange:M,children:[e.jsx(We,{asChild:!0,children:e.jsxs(h,{onClick:()=>M(!0),children:[e.jsx(Qe,{className:"mr-2 h-4 w-4"}),"Create New Keypair"]})}),e.jsxs(oe,{className:"sm:max-w-lg",children:[e.jsx(le,{children:e.jsx(ce,{children:"Create SSH Keypair"})}),e.jsx(ne,{...V,children:e.jsxs("form",{onSubmit:V.handleSubmit(H),className:"space-y-4",children:[e.jsx(v,{control:V.control,name:"name",render:({field:m})=>e.jsxs(b,{children:[e.jsx(N,{children:"Name"}),e.jsx(E,{children:e.jsx(z,{placeholder:"e.g., CI deploy key",...m})}),e.jsx(w,{})]})}),e.jsx(v,{control:V.control,name:"comment",render:({field:m})=>e.jsxs(b,{children:[e.jsx(N,{children:"Comment"}),e.jsx(E,{children:e.jsx(z,{placeholder:"e.g., deploy@autoglue",...m})}),e.jsx(w,{})]})}),e.jsx(v,{control:V.control,name:"bits",render:({field:m})=>e.jsxs(b,{children:[e.jsx(N,{children:"Key size"}),e.jsx(E,{children:e.jsxs("select",{className:"bg-background w-full rounded-md border px-3 py-2 text-sm",value:m.value,onChange:m.onChange,children:[e.jsx("option",{value:"2048",children:"2048"}),e.jsx("option",{value:"3072",children:"3072"}),e.jsx("option",{value:"4096",children:"4096"})]})}),e.jsx(w,{})]})}),e.jsxs(de,{className:"gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>M(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:V.formState.isSubmitting,children:V.formState.isSubmitting?"Creating…":"Create"})]})]})})]})]})]}),e.jsx("div",{className:"bg-background overflow-hidden rounded-2xl border shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(be,{children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Name"}),e.jsx(A,{className:"min-w-[360px]",children:"Public Key"}),e.jsx(A,{children:"Fingerprint"}),e.jsx(A,{children:"Created"}),e.jsx(A,{className:"w-[160px] text-right",children:"Actions"})]})}),e.jsx(we,{children:T.map(m=>{const x=pi(m.public_keys),c=fi(m.public_keys,18);return e.jsxs(q,{children:[e.jsx(p,{className:"align-top",children:m.name}),e.jsx(p,{className:"align-top",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(Ce,{variant:"secondary",className:"whitespace-nowrap",children:x}),e.jsxs(Ys,{children:[e.jsx(Xs,{asChild:!0,children:e.jsx("code",{className:"font-mono text-sm break-all md:max-w-[48ch] md:truncate md:break-normal",children:c})}),e.jsx(Zs,{className:"max-w-[70vw]",children:e.jsx("div",{className:"max-w-full",children:e.jsx("p",{className:"font-mono text-xs break-all",children:m.public_keys})})})]})]})}),e.jsx(p,{className:"align-top",children:e.jsx("code",{className:"font-mono text-sm",children:m.fingerprint})}),e.jsx(p,{className:"align-top",children:new Date(m.created_at).toLocaleString(void 0,{year:"numeric",month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit"})}),e.jsx(p,{className:"align-top",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>gi(m.public_keys),title:"Copy public key",children:[e.jsx(Cn,{className:"mr-2 h-4 w-4"}),"Copy"]}),e.jsxs(is,{children:[e.jsx(os,{asChild:!0,children:e.jsxs(h,{variant:"outline",size:"sm",children:[e.jsx(_n,{className:"mr-2 h-4 w-4"}),"Download"]})}),e.jsxs(ls,{align:"end",children:[e.jsx(Ie,{onClick:()=>P(m.id,"both"),children:"Public + Private (.zip)"}),e.jsx(Ie,{onClick:()=>P(m.id,"public"),children:"Public only (.pub)"}),e.jsx(Ie,{onClick:()=>P(m.id,"private"),children:"Private only (.pem)"})]})]}),e.jsxs(h,{variant:"destructive",size:"sm",onClick:()=>j(m.id),children:[e.jsx(Ue,{className:"mr-2 h-4 w-4"}),"Delete"]})]})})]},m.id)})})]})})})]})})};function bi(s){const t=s?.user_id??s?.UserID??s?.user?.id??s?.User?.ID??"",r=s?.email??s?.Email??s?.user?.email??s?.User?.Email,d=s?.name??s?.Name??s?.user?.name??s?.User?.Name,u=s?.role??s?.Role??"member",f=s?.created_at??s?.CreatedAt;return{userId:String(t),email:r,name:d,role:String(u),joinedAt:f}}const Ni=re({email:js("Enter a valid email"),role:Je(["member","admin"])}),wi=()=>{const[s,t]=o.useState(!0),[r,d]=o.useState([]),[u,f]=o.useState(null),[$,C]=o.useState(!1),[O,M]=o.useState(!1),[R,U]=o.useState(null),T=o.useMemo(()=>Ke(),[]),P=te({resolver:ae(Ni),defaultValues:{email:"",role:"member"},mode:"onChange"});async function j(){try{const x=await g.get("/api/v1/auth/me");f(x)}catch{}}async function V(x){if(!x){d([]),t(!1);return}t(!0);try{const c=await g.get("/api/v1/orgs/members");d((c??[]).map(bi))}catch(c){const S=c instanceof je?c.message:"Failed to load members";ee.error(S)}finally{t(!1)}}o.useEffect(()=>{j(),V(T)},[T]),o.useEffect(()=>{const x=()=>void V(Ke()),c=S=>{S.key==="active_org_id"&&x()};return window.addEventListener(ns,x),window.addEventListener("storage",c),()=>{window.removeEventListener(ns,x),window.removeEventListener("storage",c)}},[]);async function H(x){const c=Ke();if(!c){ee.error("Select an organization first");return}try{M(!0),await g.post("/api/v1/orgs/invite",x),ee.success(`Invited ${x.email}`),C(!1),P.reset({email:"",role:"member"}),V(c)}catch(S){const G=S instanceof je?S.message:"Failed to invite member";ee.error(G)}finally{M(!1)}}async function m(x){const c=Ke();if(!c){ee.error("Select an organization first");return}try{U(x),await g.delete(`/api/v1/orgs/members/${x}`,{headers:{"X-Org-ID":c}}),d(S=>S.filter(G=>G.userId!==x)),ee.success("Member removed")}catch(S){const G=S instanceof je?S.message:"Failed to remove member";ee.error(G)}finally{U(null)}}return s?e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Members"}),e.jsxs(h,{disabled:!0,children:[e.jsx(xt,{className:"mr-2 h-4 w-4"}),"Invite"]})]}),e.jsx(Ns,{}),e.jsx("div",{className:"grid gap-4 sm:grid-cols-2 lg:grid-cols-3",children:[...Array(6)].map((x,c)=>e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Ge,{className:"h-5 w-40"})}),e.jsxs(Me,{className:"space-y-2",children:[e.jsx(Ge,{className:"h-4 w-56"}),e.jsx(Ge,{className:"h-4 w-40"})]}),e.jsx(Ss,{children:e.jsx(Ge,{className:"h-9 w-24"})})]},c))})]}):Ke()?e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Members"}),e.jsxs(ie,{open:$,onOpenChange:C,children:[e.jsx(We,{asChild:!0,children:e.jsxs(h,{children:[e.jsx(xt,{className:"mr-2 h-4 w-4"}),"Invite"]})}),e.jsxs(oe,{className:"sm:max-w-[520px]",children:[e.jsxs(le,{children:[e.jsx(ce,{children:"Invite member"}),e.jsx(Ds,{children:"Send an invite to join this organization."})]}),e.jsx(ne,{...P,children:e.jsxs("form",{onSubmit:P.handleSubmit(H),className:"grid gap-4 py-2",children:[e.jsx(v,{control:P.control,name:"email",render:({field:x})=>e.jsxs(b,{children:[e.jsx(N,{children:"Email"}),e.jsx(E,{children:e.jsx(z,{type:"email",placeholder:"jane@example.com",...x})}),e.jsx(w,{})]})}),e.jsx(v,{control:P.control,name:"role",render:({field:x})=>e.jsxs(b,{children:[e.jsx(N,{children:"Role"}),e.jsxs(Ae,{onValueChange:x.onChange,defaultValue:x.value,children:[e.jsx(E,{children:e.jsx($e,{className:"w-[200px]",children:e.jsx(Ee,{placeholder:"Select role"})})}),e.jsxs(Le,{children:[e.jsx(ve,{value:"member",children:"Member"}),e.jsx(ve,{value:"admin",children:"Admin"})]})]}),e.jsx(w,{})]})}),e.jsxs(de,{className:"mt-2 flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>C(!1),children:"Cancel"}),e.jsx(h,{type:"submit",disabled:!P.formState.isValid||O,children:O?"Sending…":"Send invite"})]})]})})]})]})]}),e.jsx(Ns,{}),r.length===0?e.jsx("div",{className:"text-muted-foreground text-sm",children:"No members yet."}):e.jsx("div",{className:"grid grid-cols-1 gap-4 pr-2 sm:grid-cols-2 lg:grid-cols-3",children:r.map(x=>{const c=u?.id&&x.userId===u.id;return e.jsxs(Te,{className:"flex flex-col",children:[e.jsx(Pe,{children:e.jsx(Be,{className:"text-base",children:x.name||x.email||x.userId})}),e.jsxs(Me,{className:"text-muted-foreground space-y-1 text-sm",children:[x.email&&e.jsxs("div",{children:["Email: ",x.email]}),e.jsxs("div",{children:["Role: ",x.role]}),x.joinedAt&&e.jsxs("div",{children:["Joined: ",new Date(x.joinedAt).toLocaleString()]})]}),e.jsxs(Ss,{className:"mt-auto w-full flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx("div",{}),e.jsxs(et,{children:[e.jsx(st,{asChild:!0,children:e.jsxs(h,{variant:"destructive",disabled:c||R===x.userId,className:"ml-auto",children:[e.jsx(Ue,{className:"mr-2 h-5 w-5"}),R===x.userId?"Removing…":"Remove"]})}),e.jsxs(tt,{children:[e.jsxs(at,{children:[e.jsx(rt,{children:"Remove member?"}),e.jsxs(it,{children:["This will remove ",e.jsx("b",{children:x.name||x.email||x.userId})," from the organization."]})]}),e.jsxs(nt,{className:"sm:justify-between",children:[e.jsx(lt,{disabled:R===x.userId,children:"Cancel"}),e.jsx(ot,{asChild:!0,disabled:R===x.userId,children:e.jsx(h,{variant:"destructive",onClick:()=>m(x.userId),children:"Confirm remove"})})]})]})]})]})]},x.userId)})})]}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsx("h1",{className:"text-2xl font-bold",children:"Members"})}),e.jsx(Ns,{}),e.jsx("p",{className:"text-muted-foreground text-sm",children:"No organization selected. Choose an organization to manage its members."})]})},yi=re({name:F().min(2).max(100),slug:F().min(2).max(50).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/,"Use lowercase letters, numbers, and hyphens.")}),Si=()=>{const[s,t]=o.useState([]),[r,d]=o.useState(!0),[u,f]=o.useState(!1),[$,C]=o.useState(null),[O,M]=o.useState(null),R=o.useRef(!1),U=te({resolver:ae(yi),mode:"onChange",defaultValues:{name:"",slug:""}}),T=U.watch("name");o.useEffect(()=>{R.current||U.setValue("slug",ht(T||""),{shouldValidate:!0})},[T,U]);const P=async()=>{d(!0);try{const m=await g.get("/api/v1/orgs");t(m),f(m.length===0)}catch(m){const x=m instanceof je?m.message:"Failed to load organizations";ee.error(x)}finally{d(!1)}};o.useEffect(()=>{C(Ke()),P();const m=S=>{S.key==="active_org_id"&&C(S.newValue)};window.addEventListener("storage",m);const x=S=>{const G=S.detail??null;C(G)};window.addEventListener(ns,x);const c=()=>void P();return window.addEventListener(ys,c),()=>{window.removeEventListener("storage",m),window.removeEventListener(ns,x),window.removeEventListener(ys,c)}},[]);async function j(m){try{const x=await g.post("/api/v1/orgs",m);t(c=>[x,...c]),ws(x.id),C(x.id),ut(),ee.success(`Created ${x.name}`),f(!1),U.reset({name:"",slug:""}),R.current=!1}catch(x){const c=x instanceof je?x.message:"Failed to create organization";ee.error(c)}}function V(m){ws(m.id),C(m.id),ee.success(`Switched to ${m.name}`)}async function H(m){try{M(m.id),await g.delete(`/api/v1/orgs/${m.id}`),t(x=>{const c=x.filter(S=>S.id!==m.id);if($===m.id){const S=c[0]?.id??null;ws(S),C(S)}return c}),ut(),ee.success(`Deleted ${m.name}`)}catch(x){const c=x instanceof je?x.message:"Failed to delete organization";ee.error(c)}finally{M(null)}}return r?e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsx("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Organizations"})}),e.jsx("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",children:[...Array(6)].map((m,x)=>e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Ge,{className:"h-5 w-40"})}),e.jsxs(Me,{children:[e.jsx(Ge,{className:"mb-2 h-4 w-24"}),e.jsx(Ge,{className:"h-4 w-48"})]}),e.jsx(Ss,{children:e.jsx(Ge,{className:"h-9 w-24"})})]},x))})]}):e.jsxs("div",{className:"space-y-4 p-6",children:[e.jsxs("div",{className:"flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[e.jsx("h1",{className:"mb-4 text-2xl font-bold",children:"Organizations"}),e.jsx(h,{onClick:()=>f(!0),children:"New organization"})]}),e.jsx(Ns,{}),s.length===0?e.jsx("div",{className:"text-muted-foreground text-sm",children:"No organizations yet."}):e.jsx("div",{className:"grid grid-cols-1 gap-4 pr-2 sm:grid-cols-2 lg:grid-cols-3",children:s.map(m=>e.jsxs(Te,{className:"flex flex-col",children:[e.jsx(Pe,{children:e.jsx(Be,{className:"text-base",children:m.name})}),e.jsxs(Me,{className:"text-muted-foreground text-sm",children:[e.jsxs("div",{children:["Slug: ",m.slug]}),e.jsxs("div",{className:"mt-1",children:["ID: ",m.id]})]}),e.jsxs(Ss,{className:"mt-auto w-full flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(h,{onClick:()=>V(m),children:m.id===$?"Selected":"Select"}),e.jsxs(et,{children:[e.jsx(st,{asChild:!0,children:e.jsxs(h,{variant:"destructive",className:"ml-auto",disabled:O===m.id,children:[e.jsx(Ue,{className:"mr-2 h-5 w-5"}),O===m.id?"Deleting…":"Delete"]})}),e.jsxs(tt,{children:[e.jsxs(at,{children:[e.jsx(rt,{children:"Delete organization?"}),e.jsxs(it,{children:["This will permanently delete ",e.jsx("b",{children:m.name}),". This action cannot be undone."]})]}),e.jsxs(nt,{className:"sm:justify-between",children:[e.jsx(lt,{disabled:O===m.id,children:"Cancel"}),e.jsx(ot,{asChild:!0,disabled:O===m.id,children:e.jsx(h,{variant:"destructive",onClick:()=>H(m),children:"Confirm delete"})})]})]})]})]})]},m.id))}),e.jsx(ie,{open:u,onOpenChange:f,children:e.jsxs(oe,{className:"sm:max-w-[480px]",children:[e.jsxs(le,{children:[e.jsx(ce,{children:"Create organization"}),e.jsx(Ds,{children:"Set a name and a URL-friendly slug."})]}),e.jsx(ne,{...U,children:e.jsxs("form",{onSubmit:U.handleSubmit(j),className:"space-y-4",children:[e.jsx(v,{control:U.control,name:"name",render:({field:m})=>e.jsxs(b,{children:[e.jsx(N,{children:"Name"}),e.jsx(E,{children:e.jsx(z,{placeholder:"Acme Inc",autoFocus:!0,...m})}),e.jsx(jt,{children:"This is your organization’s display name."}),e.jsx(w,{})]})}),e.jsx(v,{control:U.control,name:"slug",render:({field:m})=>e.jsxs(b,{children:[e.jsx(N,{children:"Slug"}),e.jsx(E,{children:e.jsx(z,{placeholder:"acme-inc",...m,onChange:x=>{R.current=!0,m.onChange(x)},onBlur:x=>{const c=ht(x.target.value);U.setValue("slug",c,{shouldValidate:!0}),m.onBlur()}})}),e.jsx(jt,{children:"Lowercase, numbers and hyphens only."}),e.jsx(w,{})]})}),e.jsxs(de,{className:"flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>{U.reset(),f(!1),R.current=!1},children:"Cancel"}),e.jsx(h,{type:"submit",disabled:!U.formState.isValid||U.formState.isSubmitting,children:U.formState.isSubmitting?"Creating...":"Create"})]})]})})]})})]})},ms=s=>(s??0).toLocaleString(),Ci=s=>{if(!isFinite(s)||s<=0)return"–";if(s<60)return`${s.toFixed(0)}s`;if(s<3600)return`${Math.floor(s/60)}m ${Math.floor(s%60)}s`;const t=Math.floor(s/3600),r=Math.floor(s%3600/60);return`${t}h ${r}m`};function _i(){const[s,t]=o.useState(null),[r,d]=o.useState([]),[u,f]=o.useState(!1),[$,C]=o.useState(null),[O,M]=o.useState(!0),[R,U]=o.useState(5e3),T=o.useCallback(async()=>{f(!0),C(null);try{const[j,V]=await Promise.all([g.get("/api/v1/jobs/kpi"),g.get("/api/v1/jobs/queues")]);t(j),d(V)}catch(j){C(j.message||String(j))}finally{f(!1)}},[]);o.useEffect(()=>{T()},[T]),o.useEffect(()=>{if(!O)return;const j=setInterval(T,R);return()=>clearInterval(j)},[O,R,T]);const P=o.useMemo(()=>({queues:r.length,running:r.reduce((j,V)=>j+V.Running,0),due:r.reduce((j,V)=>j+V.QueuedDue,0),future:r.reduce((j,V)=>j+V.QueuedFuture,0)}),[r]);return e.jsxs("div",{className:"p-6 space-y-6",children:[e.jsxs("header",{className:"flex items-center justify-between gap-3",children:[e.jsx("h1",{className:"text-2xl font-semibold tracking-tight",children:"Jobs Dashboard"}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("label",{className:"flex items-center gap-2 text-sm",children:[e.jsx("input",{type:"checkbox",className:"h-4 w-4",checked:O,onChange:j=>M(j.target.checked)}),"Auto refresh"]}),e.jsxs("select",{className:"border rounded px-2 py-1 text-sm",value:R,onChange:j=>U(parseInt(j.target.value)),children:[e.jsx("option",{value:3e3,children:"3s"}),e.jsx("option",{value:5e3,children:"5s"}),e.jsx("option",{value:1e4,children:"10s"}),e.jsx("option",{value:3e4,children:"30s"})]}),e.jsx("button",{className:"px-3 py-1.5 rounded bg-slate-900 text-white text-sm hover:opacity-90",onClick:T,disabled:u,children:u?"Refreshing…":"Refresh"})]})]}),$&&e.jsx("div",{className:"rounded border border-red-300 bg-red-50 text-red-800 p-3 text-sm",children:$}),e.jsxs("section",{className:"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-6",children:[e.jsx(xs,{label:"Running",value:ms(s?.RunningNow)}),e.jsx(xs,{label:"Due now",value:ms(s?.DueNow)}),e.jsx(xs,{label:"Scheduled",value:ms(s?.ScheduledFuture)}),e.jsx(xs,{label:"Succeeded (24h)",value:ms(s?.Succeeded24h)}),e.jsx(xs,{label:"Failed (24h)",value:ms(s?.Failed24h)}),e.jsx(xs,{label:"Retryable",value:ms(s?.Retryable)})]}),e.jsxs("section",{className:"space-y-2",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsxs("h2",{className:"text-lg font-medium",children:["Queues ",e.jsxs("span",{className:"text-slate-500 text-sm",children:["(",P.queues,")"]})]})}),e.jsx("div",{className:"overflow-x-auto rounded border",children:e.jsxs(be,{className:"min-w-full text-sm",children:[e.jsx(Ne,{children:e.jsxs(q,{children:[e.jsx(A,{children:"Queue"}),e.jsx(A,{className:"text-right",children:"Running"}),e.jsx(A,{className:"text-right",children:"Due"}),e.jsx(A,{className:"text-right",children:"Future"}),e.jsx(A,{className:"text-right",children:"Success 24h"}),e.jsx(A,{className:"text-right",children:"Failed 24h"}),e.jsx(A,{className:"text-right",children:"Avg Duration"})]})}),e.jsx(we,{children:r.map(j=>e.jsxs(q,{className:"border-t",children:[e.jsx(p,{children:j.QueueName}),e.jsx(p,{className:"text-right",children:j.Running}),e.jsx(p,{className:"text-right",children:j.QueuedDue}),e.jsx(p,{className:"text-right",children:j.QueuedFuture}),e.jsx(p,{className:"text-right",children:j.Success24h}),e.jsx(p,{className:"text-right",children:j.Failed24h}),e.jsx(p,{className:"text-right",children:Ci(j.AvgDurationSecs)})]},j.QueueName))})]})})]})]})}function xs({label:s,value:t}){return e.jsxs(Te,{children:[e.jsx(Pe,{children:e.jsx(Be,{children:s})}),e.jsx(Me,{children:e.jsx("div",{className:"mt-1 text-2xl font-semibold",children:t})})]})}function ki(){return e.jsxs(kn,{children:[e.jsx(se,{path:"/",element:e.jsx(Qs,{to:"/auth/login",replace:!0})}),e.jsxs(se,{path:"/auth",children:[e.jsx(se,{path:"login",element:e.jsx($r,{})}),e.jsx(se,{path:"register",element:e.jsx(Ir,{})}),e.jsx(se,{path:"forgot",element:e.jsx(Ar,{})}),e.jsx(se,{path:"reset",element:e.jsx(Pr,{})}),e.jsx(se,{path:"verify",element:e.jsx(Mr,{})})]}),e.jsx(se,{element:e.jsx(jr,{}),children:e.jsxs(se,{element:e.jsx(ur,{}),children:[e.jsx(se,{element:e.jsx(fr,{}),children:e.jsx(se,{path:"/admin",children:e.jsx(se,{path:"users",element:e.jsx(_r,{})})})}),e.jsxs(se,{path:"/core",children:[e.jsx(se,{path:"annotations",element:e.jsx(Vr,{})}),e.jsx(se,{path:"clusters",element:e.jsx(qr,{})}),e.jsx(se,{path:"labels",element:e.jsx(Yr,{})}),e.jsx(se,{path:"nodepools",element:e.jsx(ri,{})}),e.jsx(se,{path:"servers",element:e.jsx(li,{})}),e.jsx(se,{path:"taints",element:e.jsx(hi,{})})]}),e.jsx(se,{path:"/security",children:e.jsx(se,{path:"ssh",element:e.jsx(vi,{})})}),e.jsxs(se,{path:"/settings",children:[e.jsx(se,{path:"jobs",element:e.jsx(_i,{})}),e.jsx(se,{path:"orgs",element:e.jsx(Si,{})}),e.jsx(se,{path:"members",element:e.jsx(wi,{})}),e.jsx(se,{path:"me",element:e.jsx(Lr,{})})]}),e.jsx(se,{path:"/403",element:e.jsx(Nt,{})}),e.jsx(se,{path:"*",element:e.jsx(wt,{})})]})}),e.jsx(se,{path:"/403",element:e.jsx(Nt,{})}),e.jsx(se,{path:"*",element:e.jsx(wt,{})})]})}const Ai=({...s})=>{const{theme:t="system"}=yt();return e.jsx(xa,{theme:t,className:"toaster group",style:{"--normal-bg":"var(--popover)","--normal-text":"var(--popover-foreground)","--normal-border":"var(--border)"},...s})};function Ei({children:s,defaultTheme:t="system",storageKey:r="vite-ui-theme"}){return e.jsx(ha,{attribute:"class",defaultTheme:t,enableSystem:!0,storageKey:r,disableTransitionOnChange:!0,children:s})}ua.createRoot(document.getElementById("root")).render(e.jsx(o.StrictMode,{children:e.jsx(An,{children:e.jsxs(Ei,{defaultTheme:"system",storageKey:"dragon-theme",children:[e.jsx(ki,{}),e.jsx(Ai,{richColors:!0,position:"top-right"})]})})})); diff --git a/internal/ui/dist/index.html b/internal/ui/dist/index.html index f182080..197fb39 100644 --- a/internal/ui/dist/index.html +++ b/internal/ui/dist/index.html @@ -5,12 +5,12 @@ AutoGlue - + - - + +
diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 014df11..9b23c8e 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -21,6 +21,7 @@ import { NotFoundPage } from "@/pages/error/not-found.tsx" import { SshKeysPage } from "@/pages/security/ssh.tsx" import { MemberManagement } from "@/pages/settings/members.tsx" import { OrgManagement } from "@/pages/settings/orgs.tsx" +import JobsDashboard from "@/pages/settings/jobs.tsx"; function App() { return ( @@ -57,6 +58,7 @@ function App() { + } /> } /> } /> } /> diff --git a/ui/src/components/sidebar/items.ts b/ui/src/components/sidebar/items.ts index 57b4a79..68216c8 100644 --- a/ui/src/components/sidebar/items.ts +++ b/ui/src/components/sidebar/items.ts @@ -18,6 +18,7 @@ import { UsersIcon, } from "lucide-react" import { AiOutlineCluster } from "react-icons/ai" +import {GrUserWorker} from "react-icons/gr"; export type NavItem = { label: string @@ -95,6 +96,11 @@ export const items = [ label: "Settings", icon: SettingsIcon, items: [ + { + label: "Jobs", + icon: GrUserWorker, + to: '/settings/jobs', + }, { label: "Organizations", to: "/settings/orgs", diff --git a/ui/src/pages/core/clusters-page.tsx b/ui/src/pages/core/clusters-page.tsx index 655f97c..96d4417 100644 --- a/ui/src/pages/core/clusters-page.tsx +++ b/ui/src/pages/core/clusters-page.tsx @@ -74,8 +74,8 @@ const CreateClusterSchema = z.object({ name: z.string().trim().min(2, "Name is too short"), provider: z.string().trim().min(2, "Provider is too short"), region: z.string().trim().min(1, "Region is required"), - node_pool_ids: z.array(z.string().uuid()).optional().default([]), - bastion_server_id: z.string().uuid().optional(), + node_pool_ids: z.array(z.uuid()).default([]).optional(), + bastion_server_id: z.uuid().optional(), cluster_load_balancer: z.string().optional(), control_load_balancer: z.string().optional(), kubeconfig: z.string().optional(), @@ -88,7 +88,7 @@ const UpdateClusterSchema = z provider: z.string().trim().min(2, "Provider is too short").optional(), region: z.string().trim().min(1, "Region is required").optional(), status: z.string().trim().min(1, "Status is required").optional(), - bastion_server_id: z.string().uuid().or(z.literal("")).optional(), + bastion_server_id: z.uuid().or(z.literal("")).optional(), cluster_load_balancer: z.string().optional(), control_load_balancer: z.string().optional(), kubeconfig: z.string().optional(), @@ -113,7 +113,7 @@ const AttachPoolsSchema = z.object({ export type AttachPoolsValues = z.infer const SetBastionSchema = z.object({ - server_id: z.string().uuid({ message: "Enter a valid Server UUID" }), + server_id: z.uuid({ message: "Enter a valid Server UUID" }), }) export type SetBastionValues = z.infer diff --git a/ui/src/pages/settings/jobs.tsx b/ui/src/pages/settings/jobs.tsx new file mode 100644 index 0000000..8d1aede --- /dev/null +++ b/ui/src/pages/settings/jobs.tsx @@ -0,0 +1,189 @@ +import {useCallback, useEffect, useMemo, useState} from "react"; +import {api} from "@/lib/api.ts"; +import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card.tsx"; +import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table.tsx"; + +export interface KPI { + RunningNow: number; + DueNow: number; + ScheduledFuture: number; + Succeeded24h: number; + Failed24h: number; + Retryable: number; +} + +export interface QueueRollup { + QueueName: string; + Running: number; + QueuedDue: number; + QueuedFuture: number; + Success24h: number; + Failed24h: number; + AvgDurationSecs: number; +} + + +export interface JobListItem { + id: string; + queue_name: string; + status: string; + retry_count: number; + max_retry: number; + scheduled_at: string; // ISO + started_at?: string; // ISO + updated_at: string; // ISO + last_error?: string; +} + + +const fmtNumber = (n: number | undefined) => (n ?? 0).toLocaleString(); + + +const fmtSeconds = (secs: number) => { + if (!isFinite(secs) || secs <= 0) return "–"; + if (secs < 60) return `${secs.toFixed(0)}s`; + if (secs < 3600) return `${Math.floor(secs / 60)}m ${Math.floor(secs % 60)}s`; + const h = Math.floor(secs / 3600); + const m = Math.floor((secs % 3600) / 60); + return `${h}h ${m}m`; +}; + +export default function JobsDashboard() { + const [kpi, setKpi] = useState(null); + const [queues, setQueues] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [autoRefresh, setAutoRefresh] = useState(true); + const [refreshMs, setRefreshMs] = useState(5000); + + const loadAll = useCallback(async () => { + setLoading(true); + setError(null); + try { + const [k, q] = await Promise.all([ + api.get("/api/v1/jobs/kpi"), + api.get("/api/v1/jobs/queues"), + ]) + setKpi(k) + setQueues(q) + } catch (e: any) { + setError(e.message || String(e)); + } finally { + setLoading(false); + } + + }, []) + + useEffect(() => { void loadAll(); }, [loadAll]); + + + useEffect(() => { + if (!autoRefresh) return; + const id = setInterval(loadAll, refreshMs); + return () => clearInterval(id); + }, [autoRefresh, refreshMs, loadAll]); + + const totals = useMemo(() => ({ + queues: queues.length, + running: queues.reduce((s, q) => s + q.Running, 0), + due: queues.reduce((s, q) => s + q.QueuedDue, 0), + future: queues.reduce((s, q) => s + q.QueuedFuture, 0), + }), [queues]); + + + return ( +
+
+

Jobs Dashboard

+
+ + + + +
+
+ + {error && ( +
+ {error} +
+ )} + + {/* KPI cards */} +
+ + + + + + +
+ + {/* Per-queue table */} +
+
+

Queues ({totals.queues})

+
+
+ + + + Queue + Running + Due + Future + Success 24h + Failed 24h + Avg Duration + + + + {queues.map((q) => ( + + {q.QueueName} + {q.Running} + {q.QueuedDue} + {q.QueuedFuture} + {q.Success24h} + {q.Failed24h} + {fmtSeconds(q.AvgDurationSecs)} + + ))} + +
+
+
+ + {/* */} +
+ ) +} + +function KpiCard({ label, value }: { label: string; value: string }) { + return ( + + + {label} + + +
{value}
+
+
+ ); +}