@k2b/cloud 0.6.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -0
- package/package.json +128 -0
- package/public/logo.svg +1 -0
- package/scripts/app-favicon.test.ts +49 -0
- package/scripts/app-favicon.ts +51 -0
- package/scripts/build.ts +205 -0
- package/scripts/preload.ts +164 -0
- package/scripts/sync-recovery-smoke.ts +200 -0
- package/src/_internal/app-favicon.ts +2 -0
- package/src/_internal/app-presentation.ts +61 -0
- package/src/_internal/app-workspace-state.ts +24 -0
- package/src/_internal/bounded-json.ts +47 -0
- package/src/_internal/build-metadata.ts +9 -0
- package/src/_internal/capabilities.ts +1118 -0
- package/src/_internal/define-app.ts +801 -0
- package/src/_internal/heartbeat.ts +167 -0
- package/src/_internal/help-catalog.ts +241 -0
- package/src/_internal/help.ts +95 -0
- package/src/_internal/nats-connection.ts +34 -0
- package/src/_internal/page-responses.ts +40 -0
- package/src/_internal/process-sync.ts +117 -0
- package/src/_internal/readiness.ts +3 -0
- package/src/_internal/registry-validation.ts +136 -0
- package/src/_internal/registry-watch.ts +52 -0
- package/src/_internal/registry.ts +338 -0
- package/src/_internal/runtime-compatibility.ts +64 -0
- package/src/_internal/runtime-context.ts +84 -0
- package/src/_internal/runtime-watcher.ts +78 -0
- package/src/_internal/static-assets.ts +86 -0
- package/src/_internal/status-preserving-ssr.ts +49 -0
- package/src/access/PermissionEditor.tsx +486 -0
- package/src/access/ResourceApiKeys.tsx +271 -0
- package/src/access/messages.ts +121 -0
- package/src/access/ui.ts +16 -0
- package/src/account/Avatar.tsx +28 -0
- package/src/account/EntitySearch.tsx +363 -0
- package/src/account/avatar-upload-dialog.tsx +197 -0
- package/src/account/avatar-upload.ts +149 -0
- package/src/account/ui.ts +3 -0
- package/src/ai/admin.ts +47 -0
- package/src/ai/approval-routes.ts +130 -0
- package/src/ai/approvals.ts +139 -0
- package/src/ai/assistant-models.ts +61 -0
- package/src/ai/attachments.ts +40 -0
- package/src/ai/browser.ts +92 -0
- package/src/ai/capabilities.ts +714 -0
- package/src/ai/capability-execution.ts +151 -0
- package/src/ai/chat/blocks.render.test.tsx +1108 -0
- package/src/ai/chat/blocks.tsx +730 -0
- package/src/ai/chat/builtin-tools.tsx +428 -0
- package/src/ai/chat/capability-table.tsx +87 -0
- package/src/ai/chat/composer-adapter.ts +169 -0
- package/src/ai/chat/file-tools.tsx +81 -0
- package/src/ai/chat/message-actions.tsx +370 -0
- package/src/ai/chat/message-utils.ts +479 -0
- package/src/ai/chat/messages.ts +43 -0
- package/src/ai/chat/presentation.tsx +395 -0
- package/src/ai/chat/primitives.tsx +3 -0
- package/src/ai/chat/tool-disclosure.tsx +41 -0
- package/src/ai/chat/turn-navigator-utils.ts +28 -0
- package/src/ai/chat/turn-navigator.tsx +164 -0
- package/src/ai/chat/user-message.tsx +149 -0
- package/src/ai/chat/visual-tools.tsx +435 -0
- package/src/ai/chat/web-tools.tsx +202 -0
- package/src/ai/chat-task-contracts.ts +113 -0
- package/src/ai/chat-tasks.ts +952 -0
- package/src/ai/client/controller.ts +1211 -0
- package/src/ai/client/file-source.ts +95 -0
- package/src/ai/client/live-connection.ts +140 -0
- package/src/ai/client/projection.ts +178 -0
- package/src/ai/client/transport.ts +111 -0
- package/src/ai/compaction.ts +182 -0
- package/src/ai/credentials.ts +124 -0
- package/src/ai/default-tool-contracts.ts +108 -0
- package/src/ai/default-tools.ts +127 -0
- package/src/ai/enrich.ts +280 -0
- package/src/ai/executor.ts +1624 -0
- package/src/ai/fetch-file-tool.ts +313 -0
- package/src/ai/file-context.ts +92 -0
- package/src/ai/file-media-type.ts +28 -0
- package/src/ai/file-mount.ts +16 -0
- package/src/ai/file-tools.ts +566 -0
- package/src/ai/files-store.ts +390 -0
- package/src/ai/firecrawl-tools.ts +305 -0
- package/src/ai/grids-skill.ts +126 -0
- package/src/ai/http.ts +265 -0
- package/src/ai/index.ts +337 -0
- package/src/ai/kit-skill.ts +22 -0
- package/src/ai/limits.ts +5 -0
- package/src/ai/live-events.ts +289 -0
- package/src/ai/live-messages.ts +45 -0
- package/src/ai/live-outbox.ts +102 -0
- package/src/ai/live-routes.ts +412 -0
- package/src/ai/live.ts +2 -0
- package/src/ai/maintenance.ts +302 -0
- package/src/ai/markdown-pdf-tool.ts +95 -0
- package/src/ai/memories.ts +605 -0
- package/src/ai/memory-learning-runs.ts +222 -0
- package/src/ai/memory-learning.ts +619 -0
- package/src/ai/memory-tool.ts +120 -0
- package/src/ai/memory-workflow-evidence.ts +158 -0
- package/src/ai/migrate.ts +2082 -0
- package/src/ai/model-access-migrate.ts +30 -0
- package/src/ai/model-access.ts +191 -0
- package/src/ai/personal-agent.ts +6 -0
- package/src/ai/prefs.ts +72 -0
- package/src/ai/project-tool.ts +94 -0
- package/src/ai/projects-routes.ts +277 -0
- package/src/ai/projects.ts +902 -0
- package/src/ai/protocol.ts +279 -0
- package/src/ai/provider.ts +73 -0
- package/src/ai/public-projection.ts +25 -0
- package/src/ai/resource-markers.ts +31 -0
- package/src/ai/resource-refs.ts +70 -0
- package/src/ai/routes.ts +1131 -0
- package/src/ai/runtime-tools.ts +39 -0
- package/src/ai/runtime.ts +544 -0
- package/src/ai/settings.ts +529 -0
- package/src/ai/short-id.ts +45 -0
- package/src/ai/skill-catalog.ts +73 -0
- package/src/ai/skill-format.ts +145 -0
- package/src/ai/skill-seeds.ts +430 -0
- package/src/ai/skill-tool.ts +81 -0
- package/src/ai/skills-routes.ts +143 -0
- package/src/ai/skills.ts +934 -0
- package/src/ai/solid.ts +27 -0
- package/src/ai/store.ts +3113 -0
- package/src/ai/stream.ts +308 -0
- package/src/ai/structured-runs.ts +66 -0
- package/src/ai/structured.ts +186 -0
- package/src/ai/system-prompt.ts +170 -0
- package/src/ai/task-prompt.ts +22 -0
- package/src/ai/timeline.ts +148 -0
- package/src/ai/tool-audit.ts +177 -0
- package/src/ai/tool-result-budget.ts +16 -0
- package/src/ai/tools.ts +155 -0
- package/src/ai/types.ts +967 -0
- package/src/ai/ui.tsx +39 -0
- package/src/ai/usage-migrate.ts +81 -0
- package/src/ai/usage.ts +315 -0
- package/src/ai/validate.ts +54 -0
- package/src/ai/vision-tool.ts +79 -0
- package/src/api/accounts-entities.ts +174 -0
- package/src/api/admin-ai-projects.ts +74 -0
- package/src/api/admin-ai-skills.ts +76 -0
- package/src/api/admin-ai-usage.ts +42 -0
- package/src/api/admin-core-settings.ts +508 -0
- package/src/api/admin-identity.ts +148 -0
- package/src/api/admin-lifecycle.ts +206 -0
- package/src/api/admin-linux-identities.ts +66 -0
- package/src/api/announcements.ts +131 -0
- package/src/api/app-approval.ts +129 -0
- package/src/api/apps.ts +51 -0
- package/src/api/auth/schemas.ts +54 -0
- package/src/api/auth.ts +370 -0
- package/src/api/capabilities.ts +658 -0
- package/src/api/help-messages.ts +19 -0
- package/src/api/help.ts +78 -0
- package/src/api/index.ts +108 -0
- package/src/api/mcp.ts +744 -0
- package/src/api/me-rail.ts +45 -0
- package/src/api/me.ts +753 -0
- package/src/api/search/schemas.ts +79 -0
- package/src/api/search.bench.ts +185 -0
- package/src/api/search.ts +407 -0
- package/src/api/sync-ops.ts +79 -0
- package/src/api/widgets.ts +143 -0
- package/src/browser/CloudResourceSearch.behavior.test.tsx +74 -0
- package/src/browser/CloudResourceSearch.tsx +791 -0
- package/src/browser/app-approval-vault.ts +305 -0
- package/src/browser/app-approval.ts +234 -0
- package/src/browser/live-websocket.ts +268 -0
- package/src/browser/locale-preference.ts +25 -0
- package/src/browser/notification-target.ts +27 -0
- package/src/browser/notification-timeout.ts +14 -0
- package/src/browser/notifications.ts +181 -0
- package/src/browser/resource-clipboard.ts +70 -0
- package/src/browser/resource-picker.tsx +39 -0
- package/src/browser/resource-search-messages.ts +55 -0
- package/src/browser/resource-search.ts +27 -0
- package/src/capabilities/client.ts +149 -0
- package/src/capabilities/response.ts +39 -0
- package/src/capabilities/server.ts +215 -0
- package/src/capabilities/signals.ts +4 -0
- package/src/capabilities/testing.ts +12 -0
- package/src/capabilities/types.ts +32 -0
- package/src/cli/access.ts +499 -0
- package/src/cli/account.ts +382 -0
- package/src/cli/admin/account-administration.ts +45 -0
- package/src/cli/admin/account-categories.ts +49 -0
- package/src/cli/admin/ai-usage.ts +118 -0
- package/src/cli/admin/app-sign-in.ts +49 -0
- package/src/cli/admin/data.ts +343 -0
- package/src/cli/admin/documentation.ts +34 -0
- package/src/cli/admin/gateway.ts +155 -0
- package/src/cli/admin/index.ts +61 -0
- package/src/cli/admin/instance.ts +250 -0
- package/src/cli/admin/jobs.ts +223 -0
- package/src/cli/admin/legal.ts +122 -0
- package/src/cli/admin/linux.ts +53 -0
- package/src/cli/admin/logs.ts +324 -0
- package/src/cli/admin/metrics.ts +142 -0
- package/src/cli/admin/nats.ts +167 -0
- package/src/cli/admin/notifications.ts +516 -0
- package/src/cli/admin/shared.ts +113 -0
- package/src/cli/admin/sync.ts +188 -0
- package/src/cli/admin/telemetry.ts +314 -0
- package/src/cli/admin/webhooks.ts +222 -0
- package/src/cli/admin/workflows.ts +367 -0
- package/src/cli/apps.ts +40 -0
- package/src/cli/capabilities.ts +239 -0
- package/src/cli/commands.ts +604 -0
- package/src/cli/index.ts +61 -0
- package/src/cli/locale.ts +31 -0
- package/src/cli/output.ts +58 -0
- package/src/clients/core.ts +20 -0
- package/src/config/env.ts +54 -0
- package/src/config/index.ts +6 -0
- package/src/contracts/account-categories.ts +62 -0
- package/src/contracts/announcements.ts +121 -0
- package/src/contracts/app-approval.ts +197 -0
- package/src/contracts/app.ts +162 -0
- package/src/contracts/capabilities.ts +484 -0
- package/src/contracts/index.ts +14 -0
- package/src/contracts/notification-live.ts +66 -0
- package/src/contracts/notification-types.ts +235 -0
- package/src/contracts/posix.ts +69 -0
- package/src/contracts/profile.ts +85 -0
- package/src/contracts/rail-preferences.ts +53 -0
- package/src/contracts/registry.ts +110 -0
- package/src/contracts/resource-clipboard.ts +33 -0
- package/src/contracts/settings-types.ts +98 -0
- package/src/contracts/shared.ts +408 -0
- package/src/contracts/user-notifications.ts +101 -0
- package/src/contracts/widgets.ts +183 -0
- package/src/desktop/index.ts +704 -0
- package/src/desktop/solid.tsx +938 -0
- package/src/index.ts +58 -0
- package/src/server/actor.ts +41 -0
- package/src/server/api/index.ts +2 -0
- package/src/server/api/respond.ts +96 -0
- package/src/server/api-client.ts +54 -0
- package/src/server/app-context.ts +39 -0
- package/src/server/help.ts +187 -0
- package/src/server/index.ts +89 -0
- package/src/server/locale.ts +55 -0
- package/src/server/middleware/auth.ts +386 -0
- package/src/server/middleware/index.ts +28 -0
- package/src/server/middleware/invocation.ts +55 -0
- package/src/server/middleware/middleware.ts +65 -0
- package/src/server/middleware/openapi.ts +126 -0
- package/src/server/middleware/rate-limit.ts +125 -0
- package/src/server/middleware/request-logger.ts +41 -0
- package/src/server/middleware/route-template.ts +46 -0
- package/src/server/middleware/runtime.ts +22 -0
- package/src/server/middleware/settings.ts +55 -0
- package/src/server/middleware/validator.ts +49 -0
- package/src/server/middleware/workload.ts +22 -0
- package/src/server/ratelimit.ts +151 -0
- package/src/server/request-cookies.ts +18 -0
- package/src/server/services/access.ts +644 -0
- package/src/server/services/freeipa/client.ts +137 -0
- package/src/server/services/freeipa/index.ts +9 -0
- package/src/server/services/freeipa/session.ts +123 -0
- package/src/server/services/freeipa/test-certificates.ts +44 -0
- package/src/server/services/freeipa/tls.ts +44 -0
- package/src/server/services/freeipa/transport.ts +116 -0
- package/src/server/services/freeipa/util.ts +59 -0
- package/src/server/services/geo.ts +198 -0
- package/src/server/services/index.ts +48 -0
- package/src/server/services/pagination.ts +22 -0
- package/src/server/services/services.ts +13 -0
- package/src/server/time.ts +33 -0
- package/src/services/account-category-policy.ts +51 -0
- package/src/services/account-lifecycle/audit.ts +41 -0
- package/src/services/account-lifecycle/index.ts +940 -0
- package/src/services/account-lifecycle/ipa-backfill.ts +152 -0
- package/src/services/account-lifecycle/notification-sender.ts +13 -0
- package/src/services/account-lifecycle/scheduler.ts +506 -0
- package/src/services/account-model.ts +22 -0
- package/src/services/accounts/app.ts +1671 -0
- package/src/services/accounts/authz.ts +44 -0
- package/src/services/accounts/avatar.ts +120 -0
- package/src/services/accounts/base-group.ts +11 -0
- package/src/services/accounts/base-user.ts +46 -0
- package/src/services/accounts/duplicate-emails.ts +82 -0
- package/src/services/accounts/entities.ts +622 -0
- package/src/services/accounts/group-sql.ts +106 -0
- package/src/services/accounts/groups.ts +272 -0
- package/src/services/accounts/index.ts +14 -0
- package/src/services/accounts/ipa-data.ts +66 -0
- package/src/services/accounts/lifecycle.ts +2 -0
- package/src/services/accounts/local-groups.ts +499 -0
- package/src/services/accounts/model.ts +129 -0
- package/src/services/accounts/notification-sender.ts +31 -0
- package/src/services/accounts/posix.ts +386 -0
- package/src/services/accounts/request-policy.ts +11 -0
- package/src/services/accounts/switching.ts +126 -0
- package/src/services/accounts/users.ts +745 -0
- package/src/services/announcements/index.ts +224 -0
- package/src/services/app-approval.ts +498 -0
- package/src/services/audit/index.ts +438 -0
- package/src/services/auth-flows/index.ts +15 -0
- package/src/services/auth-flows/ipa.ts +197 -0
- package/src/services/auth-flows/magic-link.ts +185 -0
- package/src/services/auth-flows/notification-sender.ts +10 -0
- package/src/services/auth-flows/password-reset.ts +268 -0
- package/src/services/auth-flows/proxy-return.ts +49 -0
- package/src/services/document-extraction.ts +148 -0
- package/src/services/freeipa-config.ts +179 -0
- package/src/services/gateway.ts +186 -0
- package/src/services/identity/constants.ts +18 -0
- package/src/services/identity/index.ts +52 -0
- package/src/services/identity/invocation-actor.ts +120 -0
- package/src/services/identity/invocation-authority.ts +53 -0
- package/src/services/identity/invocation-operations.ts +15 -0
- package/src/services/identity/invocation-token.ts +276 -0
- package/src/services/identity/key-config.ts +41 -0
- package/src/services/identity/key-ring.ts +530 -0
- package/src/services/identity/metrics.ts +29 -0
- package/src/services/identity/routes.ts +18 -0
- package/src/services/identity/runtime-config.ts +88 -0
- package/src/services/identity/session-token.ts +152 -0
- package/src/services/identity/signer-refresh.ts +44 -0
- package/src/services/identity/workload-auth.ts +64 -0
- package/src/services/index.ts +187 -0
- package/src/services/ipa/auth.ts +216 -0
- package/src/services/ipa/connection.ts +57 -0
- package/src/services/ipa/effective-groups.ts +70 -0
- package/src/services/ipa/groups.ts +722 -0
- package/src/services/ipa/guard.ts +17 -0
- package/src/services/ipa/index.ts +17 -0
- package/src/services/ipa/posix.ts +19 -0
- package/src/services/ipa/profile.ts +132 -0
- package/src/services/ipa/runtime.ts +28 -0
- package/src/services/ipa/search.ts +154 -0
- package/src/services/ipa/service-account.ts +15 -0
- package/src/services/ipa/sync-planning.ts +100 -0
- package/src/services/ipa/sync.ts +862 -0
- package/src/services/ipa/users.ts +806 -0
- package/src/services/legal-consent.ts +76 -0
- package/src/services/logging/index.ts +477 -0
- package/src/services/logging/redaction.ts +20 -0
- package/src/services/logging/trace.ts +1231 -0
- package/src/services/mandates/index.ts +855 -0
- package/src/services/mandates/policy.ts +85 -0
- package/src/services/network-security.ts +31 -0
- package/src/services/notifications/batches.ts +722 -0
- package/src/services/notifications/browser.ts +252 -0
- package/src/services/notifications/catalog.ts +113 -0
- package/src/services/notifications/channels.ts +104 -0
- package/src/services/notifications/dispatcher.ts +139 -0
- package/src/services/notifications/email.ts +118 -0
- package/src/services/notifications/index.ts +633 -0
- package/src/services/notifications/live.ts +50 -0
- package/src/services/notifications/observability.ts +407 -0
- package/src/services/notifications/platform.ts +421 -0
- package/src/services/notifications/runtime.ts +120 -0
- package/src/services/notifications/user.ts +248 -0
- package/src/services/notifications/web-push-transport.ts +135 -0
- package/src/services/oauth-tokens.ts +209 -0
- package/src/services/outbox.ts +187 -0
- package/src/services/pdf/gotenberg.ts +290 -0
- package/src/services/pdf/index.ts +43 -0
- package/src/services/pdf/markdown.ts +209 -0
- package/src/services/pdf/template-preview.ts +122 -0
- package/src/services/postgres.ts +76 -0
- package/src/services/providers/index.ts +27 -0
- package/src/services/providers/local/auth.ts +51 -0
- package/src/services/providers/local/index.ts +4 -0
- package/src/services/providers/local/users.ts +263 -0
- package/src/services/rail-preferences.ts +27 -0
- package/src/services/runtime-lifecycle.ts +191 -0
- package/src/services/secrets.ts +10 -0
- package/src/services/service-account-credentials.ts +891 -0
- package/src/services/service-accounts.ts +184 -0
- package/src/services/session/index.ts +236 -0
- package/src/services/session/test-fixture.ts +18 -0
- package/src/services/session/user.ts +144 -0
- package/src/services/settings/api.ts +61 -0
- package/src/services/settings/app.ts +86 -0
- package/src/services/settings/core-settings.ts +796 -0
- package/src/services/settings/crypto.ts +69 -0
- package/src/services/settings/defaults.ts +374 -0
- package/src/services/settings/index.ts +215 -0
- package/src/services/settings/namespace.ts +9 -0
- package/src/services/settings/snapshot.ts +49 -0
- package/src/services/settings/store.ts +241 -0
- package/src/services/settings/templates.ts +4 -0
- package/src/services/sync-ops.ts +403 -0
- package/src/services/topic-cursor.ts +22 -0
- package/src/services/weather/forecast.ts +323 -0
- package/src/services/weather/geo.ts +119 -0
- package/src/services/weather/index.ts +67 -0
- package/src/services/weather/location.ts +24 -0
- package/src/services/weather/locations.ts +133 -0
- package/src/services/weather/migrate.ts +45 -0
- package/src/services/weather/settings.ts +66 -0
- package/src/services/weather/short-id.ts +57 -0
- package/src/services/weather/types.ts +61 -0
- package/src/services/weather/ui.ts +50 -0
- package/src/services/webauthn.ts +385 -0
- package/src/shared/account-action-notice.ts +70 -0
- package/src/shared/account-display.ts +15 -0
- package/src/shared/account-session.ts +15 -0
- package/src/shared/ai-platform-prompt.ts +134 -0
- package/src/shared/ai-usage.ts +49 -0
- package/src/shared/app-presentation.ts +48 -0
- package/src/shared/app-url.ts +12 -0
- package/src/shared/branding.ts +14 -0
- package/src/shared/capability-messages.ts +70 -0
- package/src/shared/email-html.ts +54 -0
- package/src/shared/format.ts +91 -0
- package/src/shared/help.ts +68 -0
- package/src/shared/icons.ts +400 -0
- package/src/shared/index.ts +54 -0
- package/src/shared/locale.ts +48 -0
- package/src/shared/login-method.ts +44 -0
- package/src/shared/markdown/client.ts +130 -0
- package/src/shared/markdown/extensions/code.ts +105 -0
- package/src/shared/markdown/extensions/guided-help.ts +100 -0
- package/src/shared/markdown/extensions/images.ts +79 -0
- package/src/shared/markdown/extensions/info-blocks.ts +97 -0
- package/src/shared/markdown/extensions/katex.ts +120 -0
- package/src/shared/markdown/extensions/links.ts +43 -0
- package/src/shared/markdown/extensions/mark.ts +48 -0
- package/src/shared/markdown/extensions/sub-sup.ts +60 -0
- package/src/shared/markdown/extensions/tables.ts +109 -0
- package/src/shared/markdown/extensions/task-list.ts +53 -0
- package/src/shared/markdown/formula.ts +1187 -0
- package/src/shared/markdown/index.ts +193 -0
- package/src/shared/markdown/shared.ts +36 -0
- package/src/shared/mock-cover.ts +130 -0
- package/src/shared/network-address.ts +106 -0
- package/src/shared/redirect.ts +56 -0
- package/src/shared/template-rendering.ts +140 -0
- package/src/shared/theme.ts +68 -0
- package/src/shared/time.ts +13 -0
- package/src/ssr/AdminLayout.tsx +53 -0
- package/src/ssr/AdminSidebar.tsx +50 -0
- package/src/ssr/AppLaunchpad.island.tsx +236 -0
- package/src/ssr/AppWorkspaceController.island.tsx +21 -0
- package/src/ssr/BrowserNotifications.island.tsx +135 -0
- package/src/ssr/GlobalAnnouncements.island.tsx +142 -0
- package/src/ssr/GlobalSearchDialog.behavior.test.tsx +96 -0
- package/src/ssr/GlobalSearchDialog.tsx +35 -0
- package/src/ssr/GlobalSearchHelpDialog.tsx +104 -0
- package/src/ssr/GlobalSearchTrigger.island.tsx +55 -0
- package/src/ssr/HotkeysHelpRail.island.tsx +55 -0
- package/src/ssr/Layout.render.test.tsx +148 -0
- package/src/ssr/Layout.tsx +292 -0
- package/src/ssr/LayoutBreadcrumbs.island.tsx +44 -0
- package/src/ssr/LayoutFooter.tsx +22 -0
- package/src/ssr/LayoutHeader.tsx +81 -0
- package/src/ssr/LayoutHelp.tsx +869 -0
- package/src/ssr/LayoutPreferences.island.tsx +36 -0
- package/src/ssr/LayoutRail.tsx +58 -0
- package/src/ssr/MinimalLayout.tsx +46 -0
- package/src/ssr/PageError.tsx +29 -0
- package/src/ssr/ProfilePreferences.island.tsx +92 -0
- package/src/ssr/RailApps.island.tsx +61 -0
- package/src/ssr/RailEditor.tsx +293 -0
- package/src/ssr/RegisteredHelpDocuments.island.tsx +3 -0
- package/src/ssr/TimezoneCookie.island.tsx +23 -0
- package/src/ssr/admin-active-link.ts +47 -0
- package/src/ssr/admin-navigation.ts +78 -0
- package/src/ssr/app-appearance.ts +23 -0
- package/src/ssr/app-navigation.ts +41 -0
- package/src/ssr/help-messages.ts +104 -0
- package/src/ssr/index.ts +14 -0
- package/src/ssr/islands/SearchBar.island.tsx +80 -0
- package/src/ssr/islands/index.ts +16 -0
- package/src/ssr/layout-context.ts +17 -0
- package/src/ssr/layout-help-markdown.ts +9 -0
- package/src/ssr/layout-help-navigation.ts +24 -0
- package/src/ssr/layout-help-url.ts +5 -0
- package/src/ssr/layout-runtime.ts +22 -0
- package/src/ssr/page-error-messages.ts +25 -0
- package/src/ssr/platform-messages.ts +135 -0
- package/src/ssr/preference-controller.ts +44 -0
- package/src/ssr/profile-preferences-messages.ts +29 -0
- package/src/ssr/rail-context.ts +21 -0
- package/src/ssr/rail-messages.ts +66 -0
- package/src/ssr/rail-navigation.ts +60 -0
- package/src/ssr/runtime.ts +31 -0
- package/src/ssr/url-filter.ts +127 -0
- package/src/styles/base-popover.css +36 -0
- package/src/styles/effects.css +851 -0
- package/src/styles/global.css +268 -0
- package/src/styles/input.css +58 -0
- package/src/styles/tokens.css +230 -0
- package/src/styles/utilities-buttons.css +405 -0
- package/src/styles/utilities-data.css +33 -0
- package/src/styles/utilities-feedback.css +232 -0
- package/src/styles/utilities-layout.css +603 -0
- package/src/styles/utilities-markdown-editor.css +525 -0
- package/src/styles/utilities-markdown-table.css +234 -0
- package/src/styles/utilities-navigation.css +1054 -0
- package/src/types/ambient.d.ts +24 -0
- package/src/workflows/ai/index.ts +17 -0
- package/src/workflows/ai/runtime.ts +286 -0
- package/src/workflows/ai/store.ts +314 -0
- package/src/workflows/ai/types.ts +111 -0
- package/src/workflows/ai-actions.ts +269 -0
- package/src/workflows/authoring.ts +88 -0
- package/src/workflows/builtins.ts +193 -0
- package/src/workflows/contracts.ts +280 -0
- package/src/workflows/definition.ts +334 -0
- package/src/workflows/editor.ts +113 -0
- package/src/workflows/index.ts +71 -0
- package/src/workflows/language/binder.ts +45 -0
- package/src/workflows/language/canonical.ts +29 -0
- package/src/workflows/language/compiler.ts +396 -0
- package/src/workflows/language/expressions.ts +34 -0
- package/src/workflows/language/index.ts +20 -0
- package/src/workflows/language/references.ts +55 -0
- package/src/workflows/language/schema.ts +134 -0
- package/src/workflows/language/strict-yaml.ts +131 -0
- package/src/workflows/manifest.ts +24 -0
- package/src/workflows/module.ts +12 -0
- package/src/workflows/runtime/coordinator.ts +115 -0
- package/src/workflows/runtime/executor.ts +1003 -0
- package/src/workflows/runtime/index.ts +60 -0
- package/src/workflows/runtime/instant.ts +8 -0
- package/src/workflows/runtime/ports.ts +213 -0
- package/src/workflows/runtime/schedule.ts +203 -0
- package/src/workflows/runtime/trigger.ts +37 -0
- package/src/workflows/runtime/wake.ts +13 -0
- package/src/workflows/store/actions.ts +438 -0
- package/src/workflows/store/budget.ts +145 -0
- package/src/workflows/store/definitions.ts +345 -0
- package/src/workflows/store/events.ts +383 -0
- package/src/workflows/store/index.ts +107 -0
- package/src/workflows/store/observability.ts +594 -0
- package/src/workflows/store/runs.ts +975 -0
- package/src/workflows/store/transaction.ts +23 -0
- package/src/workflows/store/worker.ts +439 -0
- package/src/workflows/testing/conformance.ts +72 -0
- package/src/workflows/testing/index.ts +11 -0
- package/src/workflows/testing/process-fixtures.ts +275 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { DropdownItem } from "@k2b/ui";
|
|
2
|
+
import { createMemo, createSignal, onCleanup, onMount } from "solid-js";
|
|
3
|
+
import { profilePreferenceLocale, setLocalePreference } from "../browser/locale-preference";
|
|
4
|
+
import { type CloudTheme, getCurrentThemePreference, setThemePreference } from "../shared/theme";
|
|
5
|
+
import { profilePreferencesMessages } from "./profile-preferences-messages";
|
|
6
|
+
|
|
7
|
+
const THEME_PREFERENCE_EVENT = "cloud:theme-preference";
|
|
8
|
+
|
|
9
|
+
export const createPreferenceController = (initialTheme: CloudTheme, locale: () => string) => {
|
|
10
|
+
const [theme, setTheme] = createSignal(initialTheme);
|
|
11
|
+
const messages = () => profilePreferencesMessages.resolve([locale()]).t;
|
|
12
|
+
const language = () => profilePreferenceLocale(locale());
|
|
13
|
+
const nextLanguage = () => (language() === "de" ? "en" : "de");
|
|
14
|
+
const themeLabel = () => (theme() === "light" ? messages().switchToDark : messages().switchToLight);
|
|
15
|
+
const languageLabel = () => (nextLanguage() === "de" ? messages().switchToGerman : messages().switchToEnglish);
|
|
16
|
+
|
|
17
|
+
const toggleTheme = () => {
|
|
18
|
+
setTheme(setThemePreference(theme() === "dark" ? "light" : "dark"));
|
|
19
|
+
window.dispatchEvent(new Event(THEME_PREFERENCE_EVENT));
|
|
20
|
+
};
|
|
21
|
+
const toggleLanguage = () => setLocalePreference(nextLanguage());
|
|
22
|
+
|
|
23
|
+
onMount(() => {
|
|
24
|
+
const syncTheme = () => setTheme(getCurrentThemePreference());
|
|
25
|
+
syncTheme();
|
|
26
|
+
window.addEventListener(THEME_PREFERENCE_EVENT, syncTheme);
|
|
27
|
+
onCleanup(() => window.removeEventListener(THEME_PREFERENCE_EVENT, syncTheme));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const items = createMemo<DropdownItem[]>(() => [
|
|
31
|
+
{
|
|
32
|
+
action: toggleTheme,
|
|
33
|
+
icon: theme() === "light" ? "ti ti-moon" : "ti ti-sun-high",
|
|
34
|
+
label: themeLabel(),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
action: toggleLanguage,
|
|
38
|
+
icon: "ti ti-language",
|
|
39
|
+
label: languageLabel(),
|
|
40
|
+
},
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
return { items, languageLabel, messages, theme, themeLabel, toggleLanguage, toggleTheme };
|
|
44
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { i18n } from "@k2b/stdlib";
|
|
2
|
+
|
|
3
|
+
export const profilePreferencesMessages = i18n.define({
|
|
4
|
+
baseLocale: "en",
|
|
5
|
+
messages: {
|
|
6
|
+
en: {
|
|
7
|
+
menuLabel: "Profile and preferences",
|
|
8
|
+
preferencesMenuLabel: "Appearance and language",
|
|
9
|
+
profileSettings: "Profile settings",
|
|
10
|
+
signOut: "Sign out",
|
|
11
|
+
signOutFailed: "Sign out failed. Please try again.",
|
|
12
|
+
switchToDark: "Dark mode",
|
|
13
|
+
switchToLight: "Light mode",
|
|
14
|
+
switchToGerman: "Deutsch",
|
|
15
|
+
switchToEnglish: "English",
|
|
16
|
+
},
|
|
17
|
+
de: {
|
|
18
|
+
menuLabel: "Profil und Einstellungen",
|
|
19
|
+
preferencesMenuLabel: "Darstellung und Sprache",
|
|
20
|
+
profileSettings: "Profileinstellungen",
|
|
21
|
+
signOut: "Abmelden",
|
|
22
|
+
signOutFailed: "Abmelden fehlgeschlagen. Bitte versuche es erneut.",
|
|
23
|
+
switchToDark: "Dunkler Modus",
|
|
24
|
+
switchToLight: "Heller Modus",
|
|
25
|
+
switchToGerman: "Deutsch",
|
|
26
|
+
switchToEnglish: "English",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type RailPreferences, RailPreferencesSchema } from "../contracts/rail-preferences";
|
|
2
|
+
import type { RailApp } from "./rail-navigation";
|
|
3
|
+
|
|
4
|
+
export type RailContext = { apps: RailApp[]; settings: RailPreferences };
|
|
5
|
+
export const RAIL_PREFERENCES_EVENT = "cloud:rail-preferences";
|
|
6
|
+
|
|
7
|
+
export const readRailContext = (): RailContext | undefined => {
|
|
8
|
+
if (typeof document === "undefined") return undefined;
|
|
9
|
+
const text = document.getElementById("cloud-rail-data")?.textContent;
|
|
10
|
+
if (!text) return undefined;
|
|
11
|
+
// Framework-generated, escaped SSR data; never loaded from localStorage.
|
|
12
|
+
const value: RailContext = JSON.parse(text);
|
|
13
|
+
return { apps: value.apps, settings: RailPreferencesSchema.parse(value.settings) };
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const publishRailPreferences = (settings: RailPreferences) => {
|
|
17
|
+
const context = readRailContext();
|
|
18
|
+
const element = document.getElementById("cloud-rail-data");
|
|
19
|
+
if (context && element) element.textContent = JSON.stringify({ ...context, settings }).replace(/</g, "\\u003c");
|
|
20
|
+
window.dispatchEvent(new CustomEvent(RAIL_PREFERENCES_EVENT));
|
|
21
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { i18n } from "@k2b/stdlib";
|
|
2
|
+
|
|
3
|
+
export const railMessages = i18n.define({
|
|
4
|
+
baseLocale: "en",
|
|
5
|
+
messages: {
|
|
6
|
+
en: {
|
|
7
|
+
customize: "Customize app bar",
|
|
8
|
+
apps: "Visible apps",
|
|
9
|
+
shortcuts: "App bar shortcuts",
|
|
10
|
+
description: "Choose the apps in your app bar. Shortcuts appear above them and are separate from your dashboard shortcuts.",
|
|
11
|
+
pinned: "Pinned above the app list",
|
|
12
|
+
unavailable: "App currently unavailable",
|
|
13
|
+
empty: "No app bar shortcuts yet.",
|
|
14
|
+
addApp: "Add app shortcut",
|
|
15
|
+
addLink: "Add link shortcut",
|
|
16
|
+
app: "App",
|
|
17
|
+
title: "Title",
|
|
18
|
+
url: "Link",
|
|
19
|
+
icon: "Icon",
|
|
20
|
+
urlHint: "Use /app/… or a complete https:// address.",
|
|
21
|
+
up: "Move up",
|
|
22
|
+
down: "Move down",
|
|
23
|
+
remove: "Remove shortcut",
|
|
24
|
+
save: "Save",
|
|
25
|
+
saving: "Saving…",
|
|
26
|
+
reset: "Reset app bar",
|
|
27
|
+
unsaved: "Unsaved changes",
|
|
28
|
+
loading: "Loading app bar settings…",
|
|
29
|
+
retry: "Reload",
|
|
30
|
+
loadFailed: "Could not load app bar settings.",
|
|
31
|
+
saveFailed: "Could not save app bar settings. Your edits are still here.",
|
|
32
|
+
conflict: "The app bar changed in another editor. Cancel and reopen this editor to load the latest settings.",
|
|
33
|
+
invalid: "Check shortcut titles, links and icons. Each app can be pinned once; settings must fit within 16 KiB.",
|
|
34
|
+
},
|
|
35
|
+
de: {
|
|
36
|
+
customize: "App-Leiste anpassen",
|
|
37
|
+
apps: "Sichtbare Apps",
|
|
38
|
+
shortcuts: "Shortcuts der App-Leiste",
|
|
39
|
+
description: "Wähle die Apps für deine App-Leiste. Shortcuts stehen darüber und sind unabhängig von deinen Dashboard-Shortcuts.",
|
|
40
|
+
pinned: "Über der App-Liste angeheftet",
|
|
41
|
+
unavailable: "App derzeit nicht verfügbar",
|
|
42
|
+
empty: "Noch keine Shortcuts in der App-Leiste.",
|
|
43
|
+
addApp: "App-Shortcut hinzufügen",
|
|
44
|
+
addLink: "Link-Shortcut hinzufügen",
|
|
45
|
+
app: "App",
|
|
46
|
+
title: "Titel",
|
|
47
|
+
url: "Link",
|
|
48
|
+
icon: "Icon",
|
|
49
|
+
urlHint: "Verwende /app/… oder eine vollständige https://-Adresse.",
|
|
50
|
+
up: "Nach oben",
|
|
51
|
+
down: "Nach unten",
|
|
52
|
+
remove: "Shortcut entfernen",
|
|
53
|
+
save: "Speichern",
|
|
54
|
+
saving: "Wird gespeichert…",
|
|
55
|
+
reset: "App-Leiste zurücksetzen",
|
|
56
|
+
unsaved: "Ungespeicherte Änderungen",
|
|
57
|
+
loading: "App-Leiste wird geladen…",
|
|
58
|
+
retry: "Erneut laden",
|
|
59
|
+
loadFailed: "App-Leiste konnte nicht geladen werden.",
|
|
60
|
+
saveFailed: "App-Leiste konnte nicht gespeichert werden. Deine Änderungen sind noch vorhanden.",
|
|
61
|
+
conflict:
|
|
62
|
+
"Die App-Leiste wurde in einem anderen Editor geändert. Brich ab und öffne den Editor erneut, um den aktuellen Stand zu laden.",
|
|
63
|
+
invalid: "Prüfe Titel, Links und Icons. Jede App kann einmal angeheftet werden; die Einstellungen dürfen höchstens 16 KiB belegen.",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { RailPreferences } from "../contracts/rail-preferences";
|
|
2
|
+
|
|
3
|
+
export type RailApp = {
|
|
4
|
+
id: string;
|
|
5
|
+
iconClass: string;
|
|
6
|
+
label: string;
|
|
7
|
+
href: string;
|
|
8
|
+
match: string;
|
|
9
|
+
defaultVisible: boolean;
|
|
10
|
+
description?: string;
|
|
11
|
+
accent?: string;
|
|
12
|
+
};
|
|
13
|
+
export type RailLink = Omit<RailApp, "defaultVisible"> & { exact?: boolean };
|
|
14
|
+
|
|
15
|
+
export const isRailAppVisible = (app: RailApp, settings: RailPreferences): boolean =>
|
|
16
|
+
Object.hasOwn(settings.visibility, app.id) ? (settings.visibility[app.id] ?? app.defaultVisible) : app.defaultVisible;
|
|
17
|
+
|
|
18
|
+
export const sortRailApps = (apps: readonly RailApp[], locale: string): RailApp[] => {
|
|
19
|
+
const collator = new Intl.Collator(locale, { sensitivity: "base", numeric: true });
|
|
20
|
+
return [...apps].sort((a, b) => collator.compare(a.label, b.label) || a.id.localeCompare(b.id, "en"));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Input is the authorized navigation catalog, never the unfiltered registry. */
|
|
24
|
+
export const projectRailNavigation = (apps: readonly RailApp[], settings: RailPreferences, locale: string) => {
|
|
25
|
+
const catalog = new Map(apps.map((app) => [app.id, app]));
|
|
26
|
+
const pinned = new Set<string>();
|
|
27
|
+
const shortcuts: RailLink[] = [];
|
|
28
|
+
for (const shortcut of settings.shortcuts) {
|
|
29
|
+
if (shortcut.kind === "app") {
|
|
30
|
+
const app = catalog.get(shortcut.appId);
|
|
31
|
+
if (!app || pinned.has(app.id)) continue;
|
|
32
|
+
pinned.add(app.id);
|
|
33
|
+
shortcuts.push({ ...app, id: shortcut.id });
|
|
34
|
+
} else {
|
|
35
|
+
shortcuts.push({
|
|
36
|
+
id: shortcut.id,
|
|
37
|
+
href: shortcut.href,
|
|
38
|
+
label: shortcut.title,
|
|
39
|
+
iconClass: shortcut.icon,
|
|
40
|
+
match: shortcut.href,
|
|
41
|
+
exact: true,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
shortcuts,
|
|
47
|
+
apps: sortRailApps(apps, locale).filter((app) => !pinned.has(app.id) && isRailAppVisible(app, settings)),
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const railLinkActive = (link: RailLink, currentUrl: string): boolean => {
|
|
52
|
+
const current = new URL(currentUrl, "https://cloud.invalid");
|
|
53
|
+
const target = new URL(link.match, current);
|
|
54
|
+
if (target.origin !== current.origin) return false;
|
|
55
|
+
if (link.exact) return target.pathname === current.pathname && target.search === current.search && target.hash === current.hash;
|
|
56
|
+
return (
|
|
57
|
+
current.pathname === target.pathname ||
|
|
58
|
+
(target.pathname !== "/" && current.pathname.startsWith(`${target.pathname.replace(/\/$/, "")}/`))
|
|
59
|
+
);
|
|
60
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime context helpers for SSR components.
|
|
3
|
+
* Extracted from _core/runtime-helpers.ts — only the generic parts.
|
|
4
|
+
*/
|
|
5
|
+
import type { CloudRuntime } from "../contracts/app";
|
|
6
|
+
import { getLocale } from "../server/locale";
|
|
7
|
+
import { resolveAppPresentations } from "../shared/app-presentation";
|
|
8
|
+
|
|
9
|
+
export type RuntimeContext = CloudRuntime;
|
|
10
|
+
|
|
11
|
+
type RuntimeCarrier = {
|
|
12
|
+
get: (key: any) => unknown;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Reads the runtime context from a Hono request context.
|
|
17
|
+
*/
|
|
18
|
+
export const getRuntimeContext = (carrier: RuntimeCarrier): RuntimeContext => {
|
|
19
|
+
const runtime = carrier.get("runtime");
|
|
20
|
+
if (!runtime || typeof runtime !== "object" || !Array.isArray((runtime as RuntimeContext).apps)) {
|
|
21
|
+
throw new Error("Runtime context is missing on request context");
|
|
22
|
+
}
|
|
23
|
+
return runtime as RuntimeContext;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** Request-scoped runtime projection with only app-owned human presentation localized. */
|
|
27
|
+
export const getLocalizedRuntimeContext = (carrier: RuntimeCarrier & { req: { raw: { headers: Headers } } }): RuntimeContext => {
|
|
28
|
+
const runtime = getRuntimeContext(carrier);
|
|
29
|
+
const locale = getLocale(carrier as Parameters<typeof getLocale>[0]);
|
|
30
|
+
return { ...runtime, apps: resolveAppPresentations(runtime.apps, locale) };
|
|
31
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL-backed filter state for server-rendered pages.
|
|
3
|
+
*
|
|
4
|
+
* Every admin page reimplemented the same triple — parse the query string,
|
|
5
|
+
* rebuild it with a patch, decide whether anything is active — and the copies
|
|
6
|
+
* diverged in ways that leaked into behaviour: some baked the path in and some
|
|
7
|
+
* took it as a parameter, some reset pagination and some did not, one dropped
|
|
8
|
+
* the time window when clearing filters, and several rebuilt the pagination
|
|
9
|
+
* base URL a second time by hand.
|
|
10
|
+
*
|
|
11
|
+
* The URL stays the single source of truth: filtering, sorting and paging are
|
|
12
|
+
* server concerns, and a page that keeps them in the address bar is reloadable
|
|
13
|
+
* and shareable by construction.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export type UrlFilterField<T> = {
|
|
17
|
+
/** Query parameter name. */
|
|
18
|
+
param: string;
|
|
19
|
+
/** Value when the parameter is absent or invalid. Omitted from built URLs. */
|
|
20
|
+
fallback: T;
|
|
21
|
+
/** Rejects hand-edited values before they reach SQL. */
|
|
22
|
+
parse: (raw: string | null, all: string[]) => T;
|
|
23
|
+
/** Omit the parameter entirely by returning an empty array. */
|
|
24
|
+
serialize?: (value: T) => string[];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// biome-ignore lint/suspicious/noExplicitAny: each field carries its own value type; `any` is the only constraint that preserves them through inference.
|
|
28
|
+
type FieldMap = Record<string, UrlFilterField<any>>;
|
|
29
|
+
|
|
30
|
+
type StateOf<F extends FieldMap> = { [K in keyof F]: F[K] extends UrlFilterField<infer T> ? T : never };
|
|
31
|
+
|
|
32
|
+
const defaultSerialize = (value: unknown): string[] => {
|
|
33
|
+
if (value === null || value === undefined || value === "" || value === false) return [];
|
|
34
|
+
if (Array.isArray(value)) return value.map(String);
|
|
35
|
+
return [String(value)];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** A string field constrained to a known set — the common case for enums. */
|
|
39
|
+
export const oneOf = <T extends string>(param: string, values: readonly T[], fallback: T): UrlFilterField<T> => ({
|
|
40
|
+
param,
|
|
41
|
+
fallback,
|
|
42
|
+
parse: (raw) => (raw !== null && (values as readonly string[]).includes(raw) ? (raw as T) : fallback),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const text = (param: string, fallback = ""): UrlFilterField<string> => ({
|
|
46
|
+
param,
|
|
47
|
+
fallback,
|
|
48
|
+
parse: (raw) => raw?.trim() ?? fallback,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
/** Present-means-true, so the parameter disappears when switched off. */
|
|
52
|
+
export const flag = (param: string): UrlFilterField<boolean> => ({
|
|
53
|
+
param,
|
|
54
|
+
fallback: false,
|
|
55
|
+
parse: (raw) => raw === "1",
|
|
56
|
+
serialize: (value) => (value ? ["1"] : []),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export const list = (param: string): UrlFilterField<string[]> => ({
|
|
60
|
+
param,
|
|
61
|
+
fallback: [],
|
|
62
|
+
parse: (_raw, all) => [...new Set(all.map((value) => value.trim()).filter(Boolean))],
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export const page = (param = "page"): UrlFilterField<number> => ({
|
|
66
|
+
param,
|
|
67
|
+
fallback: 1,
|
|
68
|
+
parse: (raw) => {
|
|
69
|
+
const parsed = Number(raw ?? "1");
|
|
70
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.trunc(parsed) : 1;
|
|
71
|
+
},
|
|
72
|
+
serialize: (value) => (value > 1 ? [String(value)] : []),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
export const createUrlFilter = <F extends FieldMap>(basePath: string, fields: F) => {
|
|
76
|
+
const entries = Object.entries(fields) as [keyof F & string, UrlFilterField<unknown>][];
|
|
77
|
+
|
|
78
|
+
const parse = (url: URL): StateOf<F> => {
|
|
79
|
+
const state = {} as Record<string, unknown>;
|
|
80
|
+
for (const [key, field] of entries) {
|
|
81
|
+
state[key] = field.parse(url.searchParams.get(field.param), url.searchParams.getAll(field.param));
|
|
82
|
+
}
|
|
83
|
+
return state as StateOf<F>;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/** Values equal to the fallback are omitted, so the common URL stays clean. */
|
|
87
|
+
const build = (current: StateOf<F>, updates: Partial<StateOf<F>> = {}): string => {
|
|
88
|
+
const next = { ...current, ...updates } as Record<string, unknown>;
|
|
89
|
+
const params = new URLSearchParams();
|
|
90
|
+
for (const [key, field] of entries) {
|
|
91
|
+
const value = next[key];
|
|
92
|
+
if (JSON.stringify(value) === JSON.stringify(field.fallback)) continue;
|
|
93
|
+
for (const serialized of (field.serialize ?? defaultSerialize)(value as never)) params.append(field.param, serialized);
|
|
94
|
+
}
|
|
95
|
+
const query = params.toString();
|
|
96
|
+
return query ? `${basePath}?${query}` : basePath;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Pagination components append the page number to this, so it must always
|
|
101
|
+
* end in a usable separator. Eight pages derived it by hand before.
|
|
102
|
+
*/
|
|
103
|
+
const paginationBase = (current: StateOf<F>, pageKey: keyof F & string): string => {
|
|
104
|
+
const field = fields[pageKey] as UrlFilterField<unknown> | undefined;
|
|
105
|
+
if (!field) return basePath;
|
|
106
|
+
const url = build({ ...current, [pageKey]: field.fallback } as StateOf<F>);
|
|
107
|
+
return url.includes("?") ? `${url}&${field.param}=` : `${url}?${field.param}=`;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/** Whether anything differs from the defaults — drives the clear affordance. */
|
|
111
|
+
const isActive = (current: StateOf<F>, ignore: (keyof F & string)[] = []): boolean =>
|
|
112
|
+
entries.some(
|
|
113
|
+
([key, field]) =>
|
|
114
|
+
!ignore.includes(key) && JSON.stringify((current as Record<string, unknown>)[key]) !== JSON.stringify(field.fallback),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
/** Resets to defaults, optionally keeping fields that are not really filters. */
|
|
118
|
+
const clear = (current: StateOf<F>, keep: (keyof F & string)[] = []): string => {
|
|
119
|
+
const next = {} as Record<string, unknown>;
|
|
120
|
+
for (const [key, field] of entries) {
|
|
121
|
+
next[key] = keep.includes(key) ? (current as Record<string, unknown>)[key] : field.fallback;
|
|
122
|
+
}
|
|
123
|
+
return build(next as StateOf<F>);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return { basePath, parse, build, paginationBase, isActive, clear };
|
|
127
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* Popover and island base behavior */
|
|
2
|
+
/* Make solid-island transparent in layout */
|
|
3
|
+
solid-island {
|
|
4
|
+
display: contents;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* Popover positioning. Strip the UA-default white box only when a
|
|
8
|
+
popover has not opted into one of the shared floating surfaces. */
|
|
9
|
+
:where([popover]:not(.paper):not(.popup):not(.tooltip-surface):not(.dropdown-menu-surface):not(.context-menu-surface)) {
|
|
10
|
+
background: transparent;
|
|
11
|
+
border: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
[popover] {
|
|
15
|
+
margin: 0;
|
|
16
|
+
inset: unset;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Popovers are interaction primitives, not one animation family. A global
|
|
20
|
+
display/overlay transition keeps a closing popover painted after
|
|
21
|
+
`hidePopover()` and strips its `:popover-open` layout during that frame.
|
|
22
|
+
Surfaces that benefit from motion opt in below. */
|
|
23
|
+
.tooltip-surface[popover] {
|
|
24
|
+
transform: none;
|
|
25
|
+
transition:
|
|
26
|
+
opacity 0.12s,
|
|
27
|
+
overlay 0.12s allow-discrete,
|
|
28
|
+
display 0.12s allow-discrete;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.tooltip-surface[popover]:popover-open {
|
|
32
|
+
@starting-style {
|
|
33
|
+
opacity: 0;
|
|
34
|
+
transform: none;
|
|
35
|
+
}
|
|
36
|
+
}
|