chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
import { createParser, parseAsArrayOf, parseAsString, parseAsStringLiteral } from 'nuqs/server'
|
||||
import {
|
||||
CORE_TRIGGER_TYPES,
|
||||
type LogLevel,
|
||||
type TimeRange,
|
||||
type TriggerType,
|
||||
} from '@/stores/logs/filters/types'
|
||||
|
||||
/**
|
||||
* Co-located, typed URL query-param definitions for the logs feature. The
|
||||
* client hook (`useLogFilters`) consumes this typed param definition as the
|
||||
* single source of truth.
|
||||
*
|
||||
* The encoding here intentionally preserves the exact wire format the logs page
|
||||
* shipped before nuqs: `timeRange` uses kebab tokens, `level` / `workflowIds` /
|
||||
* `folderIds` / `triggers` are comma-joined, and `search` is trimmed.
|
||||
*/
|
||||
|
||||
const DEFAULT_TIME_RANGE: TimeRange = 'All time'
|
||||
|
||||
/** Maps a {@link TimeRange} label to its stable URL token and back. */
|
||||
const TIME_RANGE_TO_TOKEN: Record<TimeRange, string> = {
|
||||
'All time': 'all-time',
|
||||
'Past 30 minutes': 'past-30-minutes',
|
||||
'Past hour': 'past-hour',
|
||||
'Past 6 hours': 'past-6-hours',
|
||||
'Past 12 hours': 'past-12-hours',
|
||||
'Past 24 hours': 'past-24-hours',
|
||||
'Past 3 days': 'past-3-days',
|
||||
'Past 7 days': 'past-7-days',
|
||||
'Past 14 days': 'past-14-days',
|
||||
'Past 30 days': 'past-30-days',
|
||||
'Custom range': 'custom',
|
||||
}
|
||||
|
||||
const TOKEN_TO_TIME_RANGE: Record<string, TimeRange> = Object.fromEntries(
|
||||
Object.entries(TIME_RANGE_TO_TOKEN).map(([label, token]) => [token, label as TimeRange])
|
||||
) as Record<string, TimeRange>
|
||||
|
||||
/**
|
||||
* Parser for the `timeRange` param. Serializes labels to kebab tokens and
|
||||
* tolerantly maps unknown tokens back to the default ("All time").
|
||||
*/
|
||||
export const parseAsTimeRange = createParser<TimeRange>({
|
||||
parse(value) {
|
||||
return TOKEN_TO_TIME_RANGE[value] ?? DEFAULT_TIME_RANGE
|
||||
},
|
||||
serialize(value) {
|
||||
return TIME_RANGE_TO_TOKEN[value] ?? 'all-time'
|
||||
},
|
||||
})
|
||||
|
||||
const VALID_LEVELS = ['error', 'info', 'running', 'pending'] as const
|
||||
|
||||
/**
|
||||
* Parser for the `level` param. `level` is a comma-joined list of statuses on
|
||||
* the wire but is surfaced as a single `LogLevel` value ("all", a single status,
|
||||
* or a comma-joined string) to match the existing store contract.
|
||||
*/
|
||||
export const parseAsLogLevel = createParser<LogLevel>({
|
||||
parse(value) {
|
||||
const levels = value
|
||||
.split(',')
|
||||
.filter((l): l is (typeof VALID_LEVELS)[number] =>
|
||||
(VALID_LEVELS as readonly string[]).includes(l)
|
||||
)
|
||||
if (levels.length === 0) return 'all'
|
||||
if (levels.length === 1) return levels[0]
|
||||
return levels.join(',') as LogLevel
|
||||
},
|
||||
serialize(value) {
|
||||
return value
|
||||
},
|
||||
})
|
||||
|
||||
const CORE_TRIGGER_SET = new Set<string>(CORE_TRIGGER_TYPES)
|
||||
|
||||
/**
|
||||
* Parser for the `triggers` param, restricted to known core trigger types.
|
||||
* Surfaced as `TriggerType[]` to match the consumer contract — unknown tokens
|
||||
* are dropped (mirrors the prior `parseTriggerArrayFromURL` behavior).
|
||||
*/
|
||||
export const parseAsTriggers = createParser<TriggerType[]>({
|
||||
parse(value) {
|
||||
const triggers = value.split(',').filter((t): t is TriggerType => CORE_TRIGGER_SET.has(t))
|
||||
return triggers
|
||||
},
|
||||
serialize(value) {
|
||||
return value.join(',')
|
||||
},
|
||||
eq(a, b) {
|
||||
return a.length === b.length && a.every((v, i) => v === b[i])
|
||||
},
|
||||
}).withDefault([])
|
||||
|
||||
/**
|
||||
* The nuqs parser map for every URL-synced logs filter. `clearOnDefault` keeps
|
||||
* the URL clean (params drop out when they hold their default value) and
|
||||
* `history: 'replace'` matches the prior `history.replaceState` behavior so
|
||||
* filter changes don't pollute the browser back stack.
|
||||
*/
|
||||
export const logFilterParsers = {
|
||||
timeRange: parseAsTimeRange.withDefault(DEFAULT_TIME_RANGE),
|
||||
startDate: parseAsString,
|
||||
endDate: parseAsString,
|
||||
level: parseAsLogLevel.withDefault('all'),
|
||||
workflowIds: parseAsArrayOf(parseAsString).withDefault([]),
|
||||
folderIds: parseAsArrayOf(parseAsString).withDefault([]),
|
||||
triggers: parseAsTriggers,
|
||||
search: parseAsString.withDefault(''),
|
||||
} as const
|
||||
|
||||
/** Shared nuqs options for the logs filters: clean URLs, no back-stack churn. */
|
||||
export const logFilterUrlKeys = {
|
||||
history: 'replace',
|
||||
clearOnDefault: true,
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Read-only deep link to a specific execution. Resolves to a log row and opens
|
||||
* the details sidebar on load. Intentionally NOT stripped — the link stays
|
||||
* shareable — so it carries no `clearOnDefault`/`history` options here.
|
||||
*/
|
||||
export const executionIdParam = {
|
||||
key: 'executionId',
|
||||
parser: parseAsString,
|
||||
} as const
|
||||
|
||||
const LOG_DETAILS_TABS = ['overview', 'trace'] as const
|
||||
|
||||
/**
|
||||
* Active tab of the log-details sidebar (`overview` / `trace`). Deep-linkable so
|
||||
* a shared link can land on the trace view; `replace` keeps it off the back
|
||||
* stack and `clearOnDefault` drops it from the URL when on the default tab.
|
||||
*/
|
||||
export const logDetailsTabParam = {
|
||||
key: 'tab',
|
||||
parser: parseAsStringLiteral(LOG_DETAILS_TABS).withDefault('overview'),
|
||||
} as const
|
||||
|
||||
/** Tab change is view-state, not a destination: replace, clean URL on default. */
|
||||
export const logDetailsTabUrlKeys = {
|
||||
history: 'replace',
|
||||
clearOnDefault: true,
|
||||
} as const
|
||||
Reference in New Issue
Block a user