├── .dockerignore
├── .env
├── .env.local-temporal
├── .env.test
├── .env.test.e2e
├── .env.test.integration
├── .env.testing
├── .env.ui-server
├── .eslintrc.cjs
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── actions
│ └── setup-node
│ │ └── action.yml
├── pull_request_template.md
├── release-drafter.yml
└── workflows
│ ├── chromatic.yml
│ ├── lint-and-test.yml
│ ├── playwright.yml
│ ├── release-draft.yml
│ ├── release-published.yml
│ ├── storybook-tests.yml
│ └── test.yml
├── .gitignore
├── .husky
└── pre-commit
├── .lintstagedrc.json
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── .storybook
├── main.ts
├── preview.ts
└── test-runner.ts
├── .stylelintrc
├── .vscode
├── css-custom-data.json
├── extensions.json
├── launch.json
├── settings.json
└── temporal-ui.code-snippets
├── .whitesource
├── LICENSE
├── README.md
├── chromatic.config.json
├── package.json
├── playwright.config.ts
├── plugins
├── vite-plugin-temporal-server.ts
└── vite-plugin-ui-server.ts
├── pnpm-lock.yaml
├── postcss.config.cjs
├── scripts
├── audit-tailwind-colors
│ ├── index.ts
│ ├── parse-tailwind-class.ts
│ ├── to-rows.ts
│ ├── types.ts
│ └── utilities.ts
├── download-temporal.ts
├── generate-holocene-props.ts
├── get-project-root.ts
├── start-codec-server.ts
├── start-temporal-server.ts
├── start-ui-server.ts
└── workflows.ts
├── server
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cmd
│ └── server
│ │ ├── main.go
│ │ └── main_test.go
├── config
│ ├── base.yaml
│ ├── development.yaml
│ ├── docker.yaml
│ └── e2e.yaml
├── docker
│ ├── README.md
│ └── start-ui-server.sh
├── go.mod
├── go.sum
├── plugins
│ └── fs_config_provider
│ │ ├── fs_config_provider.go
│ │ ├── loader.go
│ │ └── loader_test.go
├── proto
│ └── dependencies
│ │ └── github.com
│ │ ├── gogo
│ │ ├── googleapis
│ │ │ └── google
│ │ │ │ ├── api
│ │ │ │ ├── annotations.proto
│ │ │ │ ├── http.proto
│ │ │ │ └── httpbody.proto
│ │ │ │ └── rpc
│ │ │ │ ├── code.proto
│ │ │ │ ├── error_details.proto
│ │ │ │ └── status.proto
│ │ └── protobuf
│ │ │ └── gogoproto
│ │ │ ├── gogo.pb.golden
│ │ │ └── gogo.proto
│ │ └── grpc-ecosystem
│ │ └── grpc-gateway
│ │ ├── internal
│ │ └── descriptor
│ │ │ ├── apiconfig
│ │ │ └── apiconfig.proto
│ │ │ └── openapiconfig
│ │ │ └── openapiconfig.proto
│ │ └── protoc-gen-openapiv2
│ │ └── options
│ │ ├── annotations.proto
│ │ └── openapiv2.proto
├── server
│ ├── api
│ │ ├── handler.go
│ │ ├── marshaler.go
│ │ ├── middleware.go
│ │ ├── rawhistory.go
│ │ └── rawhistory_test.go
│ ├── auth
│ │ ├── auth.go
│ │ ├── auth_test.go
│ │ └── oidc.go
│ ├── config
│ │ ├── auth.go
│ │ ├── config.go
│ │ ├── config_provider.go
│ │ └── config_provider_with_refresh.go
│ ├── csrf
│ │ ├── skipper.go
│ │ └── skipper_test.go
│ ├── headers
│ │ └── headers.go
│ ├── route
│ │ ├── api.go
│ │ ├── auth.go
│ │ ├── health.go
│ │ ├── public_path.go
│ │ └── ui.go
│ ├── rpc
│ │ ├── rpc.go
│ │ ├── tls.go
│ │ └── tls_cert_loader_test.go
│ ├── server.go
│ ├── server_options
│ │ ├── apply_func_container.go
│ │ ├── server_option.go
│ │ └── server_options.go
│ └── version
│ │ ├── version.go
│ │ └── with_version_header.go
└── ui
│ └── embed.go
├── src
├── app.css
├── app.d.ts
├── app.html
├── env.d.ts
├── fixtures
│ ├── all-event-types.json
│ ├── cluster.json
│ ├── event-groups.canceled.json
│ ├── event-groups.completed.json
│ ├── event-groups.continued-as-new.json
│ ├── event-groups.failed.json
│ ├── event-groups.running.json
│ ├── event-groups.terminated.json
│ ├── event-groups.timed-out.json
│ ├── events.canceled.json
│ ├── events.children.json
│ ├── events.completed.json
│ ├── events.continued-as-new.json
│ ├── events.failed.json
│ ├── events.running.json
│ ├── events.terminated.json
│ ├── events.timed-out.json
│ ├── large-number-of-child-workflows.json
│ ├── list-workflows.json
│ ├── local-activities
│ │ ├── dotnet_local_activity.json
│ │ ├── go_local_activity.json
│ │ ├── java_local_activity.json
│ │ ├── python_local_activity.json
│ │ └── ts_local_activity.json
│ ├── namespaces.json
│ ├── raw-events.ascending.canceled.json
│ ├── raw-events.ascending.completed.json
│ ├── raw-events.ascending.continued-as-new.json
│ ├── raw-events.ascending.failed.json
│ ├── raw-events.ascending.running.json
│ ├── raw-events.ascending.terminated.json
│ ├── raw-events.ascending.timed-out.json
│ ├── raw-events.descending.canceled.json
│ ├── raw-events.descending.completed.json
│ ├── raw-events.descending.continued-as-new.json
│ ├── raw-events.descending.failed.json
│ ├── raw-events.descending.running.json
│ ├── raw-events.descending.terminated.json
│ ├── raw-events.descending.timed-out.json
│ ├── settings.json
│ ├── stacktrace-query.go-sdk.json
│ ├── stacktrace-query.go-sdk.windows.json
│ ├── stacktrace-query.java-sdk.json
│ ├── stacktrace-query.java-sdk.windows.json
│ ├── stacktrace-query.ts-sdk.json
│ ├── stacktrace-query.ts-sdk.windows.json
│ ├── task-queue-rules.json
│ ├── workflow.canceled.json
│ ├── workflow.completed.json
│ ├── workflow.continued-as-new.json
│ ├── workflow.failed.json
│ ├── workflow.pending-activities.json
│ ├── workflow.pending-children.json
│ ├── workflow.running.json
│ ├── workflow.scheduled.json
│ ├── workflow.terminated.json
│ └── workflow.timed-out.json
├── global.d.ts
├── hooks.server.ts
├── lib
│ ├── components
│ │ ├── advanced-visibility-guard.svelte
│ │ ├── auto-refresh-workflow.svelte
│ │ ├── batch-operations
│ │ │ ├── details.svelte
│ │ │ ├── header.svelte
│ │ │ ├── results.svelte
│ │ │ └── table.svelte
│ │ ├── bottom-nav-links.svelte
│ │ ├── bottom-nav-namespaces.svelte
│ │ ├── bottom-nav-settings.svelte
│ │ ├── bottom-nav.svelte
│ │ ├── codec-endpoint-settings.svelte
│ │ ├── codec-server-error-banner.svelte
│ │ ├── dark-mode-menu.svelte
│ │ ├── data-encoder-settings.svelte
│ │ ├── data-encoder-status.svelte
│ │ ├── deployments
│ │ │ ├── deployment-status.svelte
│ │ │ ├── deployment-table-row.svelte
│ │ │ ├── version-details.svelte
│ │ │ └── version-table-row.svelte
│ │ ├── detail-list
│ │ │ ├── detail-list-column.svelte
│ │ │ ├── detail-list-label.svelte
│ │ │ ├── detail-list-link-value.svelte
│ │ │ ├── detail-list-text-value.svelte
│ │ │ ├── detail-list-value.svelte
│ │ │ ├── detail-list.svelte
│ │ │ └── index.ts
│ │ ├── event
│ │ │ ├── event-category-multiselect-filter.svelte
│ │ │ ├── event-date-filter.svelte
│ │ │ ├── event-details-full.svelte
│ │ │ ├── event-details-link.svelte
│ │ │ ├── event-details-row-expanded.svelte
│ │ │ ├── event-details-row.svelte
│ │ │ ├── event-empty-row.svelte
│ │ │ ├── event-group-details.svelte
│ │ │ ├── event-link.svelte
│ │ │ ├── event-links-expanded.svelte
│ │ │ ├── event-metadata-expanded.svelte
│ │ │ ├── event-shortcut-keys.svelte
│ │ │ ├── event-summary-row.svelte
│ │ │ ├── event-summary-table.svelte
│ │ │ ├── event-summary.svelte
│ │ │ ├── metadata-decoder.svelte
│ │ │ ├── payload-decoder.svelte
│ │ │ ├── pending-activity-summary-row.svelte
│ │ │ └── pending-nexus-summary-row.svelte
│ │ ├── feature-guard.svelte
│ │ ├── feedback-button.svelte
│ │ ├── heart-beat-indicator.svelte
│ │ ├── import
│ │ │ └── event-history-file-import.svelte
│ │ ├── is-cloud-guard.svelte
│ │ ├── is-legacy-cloud-guard.svelte
│ │ ├── is-oss-guard.svelte
│ │ ├── is-temporal-server-version-guard.svelte
│ │ ├── lines-and-dots
│ │ │ ├── constants.ts
│ │ │ ├── end-time-interval.svelte
│ │ │ ├── event-classification-filter.svelte
│ │ │ ├── event-sort-filter.svelte
│ │ │ ├── event-type-filter.svelte
│ │ │ ├── sdk-logo.svelte
│ │ │ ├── svg
│ │ │ │ ├── box.svelte
│ │ │ │ ├── dot.svelte
│ │ │ │ ├── graph-widget.svelte
│ │ │ │ ├── group-details-row.svelte
│ │ │ │ ├── group-details-text.svelte
│ │ │ │ ├── history-graph-row-visual.svelte
│ │ │ │ ├── history-graph.svelte
│ │ │ │ ├── line.svelte
│ │ │ │ ├── text-link.svelte
│ │ │ │ ├── text.svelte
│ │ │ │ ├── timeline-axis.svelte
│ │ │ │ ├── timeline-graph-row.svelte
│ │ │ │ ├── timeline-graph.svelte
│ │ │ │ └── workflow-row.svelte
│ │ │ ├── workflow-detail.svelte
│ │ │ ├── workflow-details.svelte
│ │ │ ├── workflow-error-stack-trace.svelte
│ │ │ ├── workflow-error.svelte
│ │ │ └── workflow-pending-task.svelte
│ │ ├── login-button.svelte
│ │ ├── namespace-picker.svelte
│ │ ├── nexus-guard.svelte
│ │ ├── page-title.svelte
│ │ ├── panel.svelte
│ │ ├── payload-input-with-encoding.svelte
│ │ ├── payload-input.svelte
│ │ ├── poller-icon.svelte
│ │ ├── schedule
│ │ │ ├── schedule-advanced-settings.svelte
│ │ │ ├── schedule-basic-frequency.svelte
│ │ │ ├── schedule-day-of-month-view.svelte
│ │ │ ├── schedule-day-of-week-view.svelte
│ │ │ ├── schedule-error.svelte
│ │ │ ├── schedule-form-view.svelte
│ │ │ ├── schedule-frequency-panel.svelte
│ │ │ ├── schedule-frequency.svelte
│ │ │ ├── schedule-input-payload.svelte
│ │ │ ├── schedule-input.svelte
│ │ │ ├── schedule-notes.svelte
│ │ │ ├── schedule-recent-runs.svelte
│ │ │ ├── schedule-search-attributes.svelte
│ │ │ ├── schedule-upcoming-runs.svelte
│ │ │ ├── schedules-calendar-view.svelte
│ │ │ ├── schedules-count.svelte
│ │ │ ├── schedules-interval-view.svelte
│ │ │ ├── schedules-search-attributes-inputs.svelte
│ │ │ ├── schedules-table-row.svelte
│ │ │ └── schedules-time-view.svelte
│ │ ├── search-attribute-filter
│ │ │ ├── boolean-filter.svelte
│ │ │ ├── close-filter-button.svelte
│ │ │ ├── conditional-menu.svelte
│ │ │ ├── datetime-filter.svelte
│ │ │ ├── duration-filter.svelte
│ │ │ ├── filter-list.svelte
│ │ │ ├── index.svelte
│ │ │ ├── list-filter.svelte
│ │ │ ├── number-filter.svelte
│ │ │ ├── search-attribute-menu.svelte
│ │ │ ├── status-filter.svelte
│ │ │ └── text-filter.svelte
│ │ ├── search.stories.svelte
│ │ ├── search.svelte
│ │ ├── side-nav.svelte
│ │ ├── skip-nav.svelte
│ │ ├── timezone-select.svelte
│ │ ├── top-nav.svelte
│ │ ├── worker-compatibility.svelte
│ │ ├── worker-rules.svelte
│ │ ├── worker-table.svelte
│ │ ├── workflow-actions.svelte
│ │ ├── workflow-raw-history-link.svelte
│ │ ├── workflow-status.stories.svelte
│ │ ├── workflow-status.svelte
│ │ ├── workflow-versioning-header.svelte
│ │ └── workflow
│ │ │ ├── add-search-attributes.svelte
│ │ │ ├── child-workflows-table.svelte
│ │ │ ├── client-actions
│ │ │ ├── batch-cancel-confirmation-modal.svelte
│ │ │ ├── batch-operation-confirmation-form.svelte
│ │ │ ├── batch-reset-confirmation-modal.svelte
│ │ │ ├── batch-terminate-confirmation-modal.svelte
│ │ │ ├── cancel-confirmation-modal.svelte
│ │ │ ├── reset-confirmation-modal.svelte
│ │ │ ├── signal-confirmation-modal.svelte
│ │ │ ├── terminate-confirmation-modal.svelte
│ │ │ └── update-confirmation-modal.svelte
│ │ │ ├── configurable-table-headers-drawer
│ │ │ ├── index.svelte
│ │ │ └── orderable-list.svelte
│ │ │ ├── download-event-history-modal.svelte
│ │ │ ├── dropdown-filter
│ │ │ ├── conditional.svelte
│ │ │ ├── datetime-inputs.svelte
│ │ │ ├── text-filter.svelte
│ │ │ ├── workflow-datetime-filter.svelte
│ │ │ └── workflow-status.svelte
│ │ │ ├── first-previous-next-workflow-table.svelte
│ │ │ ├── input-and-results-payload.svelte
│ │ │ ├── input-and-results.svelte
│ │ │ ├── live-child-workflows-table.svelte
│ │ │ ├── metadata
│ │ │ ├── workflow-current-details.svelte
│ │ │ └── workflow-summary-and-details.svelte
│ │ │ ├── parent-workflow-table.svelte
│ │ │ ├── pending-activities.svelte
│ │ │ ├── pending-activity
│ │ │ └── workflow-pending-activity.svelte
│ │ │ ├── relationships
│ │ │ ├── workflow-family-node-description-details.svelte
│ │ │ ├── workflow-family-node-description-tree.svelte
│ │ │ ├── workflow-family-node-description.svelte
│ │ │ ├── workflow-family-node-tree.svelte
│ │ │ └── workflow-family-tree.svelte
│ │ │ ├── scheduler-table.svelte
│ │ │ ├── search-attribute-filter
│ │ │ └── index.svelte
│ │ │ ├── search-attribute-input
│ │ │ ├── datetime-input.svelte
│ │ │ └── index.svelte
│ │ │ ├── start-workflow-button.svelte
│ │ │ ├── workflow-advanced-search.svelte
│ │ │ ├── workflow-call-stack-error.svelte
│ │ │ ├── workflow-callback.svelte
│ │ │ ├── workflow-callbacks.svelte
│ │ │ ├── workflow-compatibility-error.svelte
│ │ │ ├── workflow-count-refresh.svelte
│ │ │ ├── workflow-counts.svelte
│ │ │ ├── workflow-detail.svelte
│ │ │ ├── workflow-error.svelte
│ │ │ ├── workflow-filters.svelte
│ │ │ ├── workflow-json-navigator.svelte
│ │ │ ├── workflow-loading-row.svelte
│ │ │ ├── workflow-relationships-old.svelte
│ │ │ ├── workflow-relationships.svelte
│ │ │ ├── workflow-summary.svelte
│ │ │ ├── workflows-summary-configurable-table.svelte
│ │ │ ├── workflows-summary-configurable-table
│ │ │ ├── batch-actions.svelte
│ │ │ ├── filterable-table-cell.svelte
│ │ │ ├── table-body-cell.svelte
│ │ │ ├── table-empty-state.svelte
│ │ │ ├── table-header-cell.svelte
│ │ │ ├── table-header-row.svelte
│ │ │ ├── table-row.svelte
│ │ │ └── table.svelte
│ │ │ ├── workflows-summary-row.svelte
│ │ │ └── workflows-summary-table.svelte
│ ├── holocene
│ │ ├── README.md
│ │ ├── accordion
│ │ │ ├── accordion-group.svelte
│ │ │ ├── accordion-light.svelte
│ │ │ ├── accordion.stories.svelte
│ │ │ └── accordion.svelte
│ │ ├── alert.stories.svelte
│ │ ├── alert.svelte
│ │ ├── api-pagination.svelte
│ │ ├── badge.stories.svelte
│ │ ├── badge.svelte
│ │ ├── banner
│ │ │ └── banner.svelte
│ │ ├── button.stories.svelte
│ │ ├── button.svelte
│ │ ├── calendar.svelte
│ │ ├── card.stories.svelte
│ │ ├── card.svelte
│ │ ├── checkbox.stories.svelte
│ │ ├── checkbox.svelte
│ │ ├── chip.stories.svelte
│ │ ├── chip.svelte
│ │ ├── code-block.stories.svelte
│ │ ├── code-block.svelte
│ │ ├── collapsible-divider
│ │ │ ├── collapsible-divider.stories.svelte
│ │ │ └── collapsible-divider.svelte
│ │ ├── combobox
│ │ │ ├── async-test.svelte
│ │ │ ├── combobox-option.svelte
│ │ │ ├── combobox.stories.svelte
│ │ │ └── combobox.svelte
│ │ ├── compatibility-badge.stories.svelte
│ │ ├── compatibility-badge.svelte
│ │ ├── copyable
│ │ │ ├── button.svelte
│ │ │ └── index.svelte
│ │ ├── date-picker.stories.svelte
│ │ ├── date-picker.svelte
│ │ ├── day-of-month-picker.svelte
│ │ ├── day-of-week-picker.svelte
│ │ ├── drawer-content.svelte
│ │ ├── drawer.stories.svelte
│ │ ├── drawer.svelte
│ │ ├── empty-state.stories.svelte
│ │ ├── empty-state.svelte
│ │ ├── error-boundary.svelte
│ │ ├── error.svelte
│ │ ├── expandable
│ │ │ └── button.svelte
│ │ ├── feature-tag.svelte
│ │ ├── file-input.stories.svelte
│ │ ├── file-input.svelte
│ │ ├── filter-or-copy-buttons.svelte
│ │ ├── holocene-components.json
│ │ ├── icon-button.stories.svelte
│ │ ├── icon-button.svelte
│ │ ├── icon
│ │ │ ├── __snapshots__
│ │ │ │ └── icon.test.ts.snap
│ │ │ ├── icon.stories.svelte
│ │ │ ├── icon.story.md
│ │ │ ├── icon.svelte
│ │ │ ├── index.ts
│ │ │ ├── paths.ts
│ │ │ ├── svg.svelte
│ │ │ └── svg
│ │ │ │ ├── activity.svelte
│ │ │ │ ├── add.svelte
│ │ │ │ ├── apple.svelte
│ │ │ │ ├── archives.svelte
│ │ │ │ ├── arrow-down.svelte
│ │ │ │ ├── arrow-left.svelte
│ │ │ │ ├── arrow-right.svelte
│ │ │ │ ├── arrow-up.svelte
│ │ │ │ ├── ascending.svelte
│ │ │ │ ├── astronaut.svelte
│ │ │ │ ├── batch-operation.svelte
│ │ │ │ ├── book-sparkles.svelte
│ │ │ │ ├── book.svelte
│ │ │ │ ├── bookmark.svelte
│ │ │ │ ├── calendar-plus.svelte
│ │ │ │ ├── calendar.svelte
│ │ │ │ ├── canceled.svelte
│ │ │ │ ├── chart-ascending.svelte
│ │ │ │ ├── chart.svelte
│ │ │ │ ├── checkmark.svelte
│ │ │ │ ├── chevron-down.svelte
│ │ │ │ ├── chevron-left.svelte
│ │ │ │ ├── chevron-right.svelte
│ │ │ │ ├── chevron-selector-vertical.svelte
│ │ │ │ ├── chevron-up.svelte
│ │ │ │ ├── circle-check-filled.svelte
│ │ │ │ ├── circle-check.svelte
│ │ │ │ ├── circle-question.svelte
│ │ │ │ ├── clock.svelte
│ │ │ │ ├── close.svelte
│ │ │ │ ├── comet-solid.svelte
│ │ │ │ ├── comet.svelte
│ │ │ │ ├── compact.svelte
│ │ │ │ ├── connection.svelte
│ │ │ │ ├── converter-down.svelte
│ │ │ │ ├── converter-up.svelte
│ │ │ │ ├── copy.svelte
│ │ │ │ ├── credit-card.svelte
│ │ │ │ ├── descending.svelte
│ │ │ │ ├── dollar-badge.svelte
│ │ │ │ ├── download.svelte
│ │ │ │ ├── drained.svelte
│ │ │ │ ├── error.svelte
│ │ │ │ ├── exit.svelte
│ │ │ │ ├── expand.svelte
│ │ │ │ ├── external-link.svelte
│ │ │ │ ├── eye-hide.svelte
│ │ │ │ ├── eye-show.svelte
│ │ │ │ ├── feather.svelte
│ │ │ │ ├── feed.svelte
│ │ │ │ ├── feedback-circle.svelte
│ │ │ │ ├── feedback.svelte
│ │ │ │ ├── file-import.svelte
│ │ │ │ ├── file-upload.svelte
│ │ │ │ ├── filter-solid.svelte
│ │ │ │ ├── filter.svelte
│ │ │ │ ├── fire-extinguisher.svelte
│ │ │ │ ├── flag.svelte
│ │ │ │ ├── github.svelte
│ │ │ │ ├── graph.svelte
│ │ │ │ ├── heartbeat.svelte
│ │ │ │ ├── hyphen.svelte
│ │ │ │ ├── import.svelte
│ │ │ │ ├── inactive.svelte
│ │ │ │ ├── info.svelte
│ │ │ │ ├── json.svelte
│ │ │ │ ├── keyboard.svelte
│ │ │ │ ├── labs.svelte
│ │ │ │ ├── lightning-bolt.svelte
│ │ │ │ ├── link.svelte
│ │ │ │ ├── linux.svelte
│ │ │ │ ├── lock.svelte
│ │ │ │ ├── logout.svelte
│ │ │ │ ├── marker.svelte
│ │ │ │ ├── merge.svelte
│ │ │ │ ├── microsoft.svelte
│ │ │ │ ├── minimize.svelte
│ │ │ │ ├── moon.svelte
│ │ │ │ ├── namespace-switcher.svelte
│ │ │ │ ├── namespace.svelte
│ │ │ │ ├── nexus.svelte
│ │ │ │ ├── office-buildings.svelte
│ │ │ │ ├── pause.svelte
│ │ │ │ ├── pin-filled.svelte
│ │ │ │ ├── pin.svelte
│ │ │ │ ├── play.svelte
│ │ │ │ ├── regions.svelte
│ │ │ │ ├── relationship.svelte
│ │ │ │ ├── retention.svelte
│ │ │ │ ├── retry.svelte
│ │ │ │ ├── robot.svelte
│ │ │ │ ├── rocket-ship.svelte
│ │ │ │ ├── schedules.svelte
│ │ │ │ ├── search.svelte
│ │ │ │ ├── settings.svelte
│ │ │ │ ├── signal.svelte
│ │ │ │ ├── sliders.svelte
│ │ │ │ ├── spinner-solid.svelte
│ │ │ │ ├── spinner.svelte
│ │ │ │ ├── star-empty.svelte
│ │ │ │ ├── star-filled.svelte
│ │ │ │ ├── summary.svelte
│ │ │ │ ├── sun.svelte
│ │ │ │ ├── support.svelte
│ │ │ │ ├── system-window.svelte
│ │ │ │ ├── table.svelte
│ │ │ │ ├── target.svelte
│ │ │ │ ├── temporal-logo.svelte
│ │ │ │ ├── terminal.svelte
│ │ │ │ ├── timeline.svelte
│ │ │ │ ├── toolbox.svelte
│ │ │ │ ├── transcoder-error.svelte
│ │ │ │ ├── transcoder-off.svelte
│ │ │ │ ├── transcoder-on.svelte
│ │ │ │ ├── trash.svelte
│ │ │ │ ├── trending-down.svelte
│ │ │ │ ├── trending-up.svelte
│ │ │ │ ├── tutorial.svelte
│ │ │ │ ├── update.svelte
│ │ │ │ ├── upload.svelte
│ │ │ │ ├── usage.svelte
│ │ │ │ ├── vertical-ellipsis.svelte
│ │ │ │ ├── warning.svelte
│ │ │ │ ├── workflow.svelte
│ │ │ │ └── xmark-filled.svelte
│ │ ├── input
│ │ │ ├── chip-input.stories.svelte
│ │ │ ├── chip-input.svelte
│ │ │ ├── input.stories.svelte
│ │ │ ├── input.svelte
│ │ │ ├── number-input.stories.svelte
│ │ │ ├── number-input.svelte
│ │ │ ├── range-input.stories.svelte
│ │ │ └── range-input.svelte
│ │ ├── keyboard-shortcut
│ │ │ ├── arrow-down.svelte
│ │ │ ├── arrow-left.svelte
│ │ │ ├── arrow-right.svelte
│ │ │ ├── arrow-up.svelte
│ │ │ └── shortcut.svelte
│ │ ├── label.stories.svelte
│ │ ├── label.svelte
│ │ ├── labs-mode-guard.svelte
│ │ ├── link.stories.svelte
│ │ ├── link.svelte
│ │ ├── loading.svelte
│ │ ├── logo.svelte
│ │ ├── main-content-container.svelte
│ │ ├── menu
│ │ │ ├── index.ts
│ │ │ ├── menu-button.svelte
│ │ │ ├── menu-container.svelte
│ │ │ ├── menu-divider.svelte
│ │ │ ├── menu-item.svelte
│ │ │ ├── menu.stories.svelte
│ │ │ └── menu.svelte
│ │ ├── modal.stories.svelte
│ │ ├── modal.svelte
│ │ ├── monaco
│ │ │ ├── editor.svelte
│ │ │ ├── index.ts
│ │ │ └── markdown.svelte
│ │ ├── month-picker.svelte
│ │ ├── navigation
│ │ │ ├── navigation-badge.svelte
│ │ │ ├── navigation-button.svelte
│ │ │ ├── navigation-container.svelte
│ │ │ └── navigation-item.svelte
│ │ ├── orderable-list
│ │ │ ├── orderable-list-item.svelte
│ │ │ ├── orderable-list.stories.svelte
│ │ │ └── orderable-list.svelte
│ │ ├── outside-click.ts
│ │ ├── page-transition.svelte
│ │ ├── pagination.svelte
│ │ ├── pill-container
│ │ │ ├── pill-container.stories.svelte
│ │ │ ├── pill-container.svelte
│ │ │ └── pill.svelte
│ │ ├── progress-bar.stories.svelte
│ │ ├── progress-bar.svelte
│ │ ├── radio-input
│ │ │ ├── index.ts
│ │ │ ├── radio-group.svelte
│ │ │ ├── radio-input.stories.svelte
│ │ │ ├── radio-input.svelte
│ │ │ └── types.ts
│ │ ├── scroll-to-bottom.svelte
│ │ ├── scroll-to-container.svelte
│ │ ├── scroll-to-top.svelte
│ │ ├── select
│ │ │ ├── filter-select.svelte
│ │ │ ├── multi-select.svelte
│ │ │ ├── option-group.svelte
│ │ │ ├── option.svelte
│ │ │ ├── select.stories.svelte
│ │ │ ├── select.svelte
│ │ │ ├── simple-option.svelte
│ │ │ └── simple-select.svelte
│ │ ├── skeleton
│ │ │ ├── index.svelte
│ │ │ ├── skeleton-table.stories.svelte
│ │ │ ├── skeleton.stories.svelte
│ │ │ ├── table.svelte
│ │ │ └── workflow.svelte
│ │ ├── split-button.stories.svelte
│ │ ├── split-button.svelte
│ │ ├── tab-buttons
│ │ │ ├── tab-button.stories.svelte
│ │ │ ├── tab-button.svelte
│ │ │ └── tab-buttons.svelte
│ │ ├── tab
│ │ │ ├── tab-list.svelte
│ │ │ ├── tab-panel.svelte
│ │ │ ├── tab.stories.svelte
│ │ │ ├── tab.svelte
│ │ │ └── tabs.svelte
│ │ ├── table
│ │ │ ├── paginated-table
│ │ │ │ ├── api-paginated.svelte
│ │ │ │ ├── index.svelte
│ │ │ │ └── paginated.svelte
│ │ │ ├── table-header-row.svelte
│ │ │ ├── table-row.svelte
│ │ │ ├── table.stories.svelte
│ │ │ ├── table.story.md
│ │ │ └── table.svelte
│ │ ├── test-utilities.ts
│ │ ├── textarea.stories.svelte
│ │ ├── textarea.svelte
│ │ ├── time-picker.svelte
│ │ ├── toast.svelte
│ │ ├── toaster.stories.svelte
│ │ ├── toaster.svelte
│ │ ├── toggle-button
│ │ │ ├── toggle-button.stories.svelte
│ │ │ ├── toggle-button.svelte
│ │ │ └── toggle-buttons.svelte
│ │ ├── toggle-switch.stories.svelte
│ │ ├── toggle-switch.svelte
│ │ ├── tooltip.stories.svelte
│ │ ├── tooltip.svelte
│ │ ├── user-menu-mobile.svelte
│ │ ├── user-menu.svelte
│ │ └── zoom-svg.svelte
│ ├── i18n
│ │ ├── index.ts
│ │ ├── locales
│ │ │ ├── en
│ │ │ │ ├── batch.ts
│ │ │ │ ├── common.ts
│ │ │ │ ├── data-encoder.ts
│ │ │ │ ├── date-picker.ts
│ │ │ │ ├── deployments.ts
│ │ │ │ ├── events.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── namespaces.ts
│ │ │ │ ├── nexus.ts
│ │ │ │ ├── schedules.ts
│ │ │ │ ├── typed-errors.ts
│ │ │ │ ├── workers.ts
│ │ │ │ └── workflows.ts
│ │ │ └── index.ts
│ │ ├── translate.svelte
│ │ ├── translate.test.ts
│ │ └── translate.ts
│ ├── layouts
│ │ ├── workflow-header.svelte
│ │ ├── workflow-history-layout.svelte
│ │ ├── workflow-padded-layout.svelte
│ │ └── workflow-run-layout.svelte
│ ├── models
│ │ ├── __snapshots__
│ │ │ ├── workflow-execution.test.ts.snap
│ │ │ └── workflow-execution.write-disabled.test.ts.snap
│ │ ├── core-user.ts
│ │ ├── event-groups
│ │ │ ├── create-event-group.test.ts
│ │ │ ├── create-event-group.ts
│ │ │ ├── event-groups.d.ts
│ │ │ ├── get-event-in-group.test.ts
│ │ │ ├── get-event-in-group.ts
│ │ │ ├── get-group-for-event.test.ts
│ │ │ ├── get-group-for-event.ts
│ │ │ ├── get-group-id.test.ts
│ │ │ ├── get-group-id.ts
│ │ │ ├── get-group-name.ts
│ │ │ ├── get-last-event.test.ts
│ │ │ ├── get-last-event.ts
│ │ │ ├── group-events.test.ts
│ │ │ ├── index.ts
│ │ │ └── is-event-groups.test.ts
│ │ ├── event-history
│ │ │ ├── __snapshots__
│ │ │ │ └── get-event-categorization.test.ts.snap
│ │ │ ├── get-event-attributes.test.ts
│ │ │ ├── get-event-categorization.test.ts
│ │ │ ├── get-event-categorization.ts
│ │ │ ├── get-event-classification.test.ts
│ │ │ ├── get-event-classification.ts
│ │ │ ├── index.ts
│ │ │ ├── is-event.test.ts
│ │ │ ├── simplify-attributes.test.ts
│ │ │ ├── simplify-attributes.ts
│ │ │ └── to-event-history.test.ts
│ │ ├── pending-activities
│ │ │ ├── index.ts
│ │ │ └── to-decoded-pending-activities.test.ts
│ │ ├── search-attribute-filters.ts
│ │ ├── workflow-actions.ts
│ │ ├── workflow-execution.test.ts
│ │ ├── workflow-execution.ts
│ │ ├── workflow-execution.write-disabled.test.ts
│ │ ├── workflow-filters.ts
│ │ └── workflow-status.ts
│ ├── pages
│ │ ├── batch-operation.svelte
│ │ ├── batch-operations.svelte
│ │ ├── deployment.svelte
│ │ ├── deployments.svelte
│ │ ├── import-events-view.svelte
│ │ ├── import-events.svelte
│ │ ├── nexus-create-endpoint.svelte
│ │ ├── nexus-edit-endpoint.svelte
│ │ ├── nexus-empty-state.svelte
│ │ ├── nexus-endpoint.svelte
│ │ ├── nexus-endpoints.svelte
│ │ ├── nexus-form.svelte
│ │ ├── schedule-edit.svelte
│ │ ├── schedule-view.svelte
│ │ ├── schedules-create.svelte
│ │ ├── schedules.svelte
│ │ ├── start-workflow.svelte
│ │ ├── task-queue-versioning.svelte
│ │ ├── task-queue.svelte
│ │ ├── workflow-call-stack.svelte
│ │ ├── workflow-history-event.svelte
│ │ ├── workflow-history-json.svelte
│ │ ├── workflow-history.svelte
│ │ ├── workflow-metadata.svelte
│ │ ├── workflow-pending-activities.svelte
│ │ ├── workflow-query.svelte
│ │ ├── workflow-workers.svelte
│ │ └── workflows-with-new-search.svelte
│ ├── services
│ │ ├── batch-service.test.ts
│ │ ├── batch-service.ts
│ │ ├── cluster-service.ts
│ │ ├── data-encoder.test.ts
│ │ ├── data-encoder.ts
│ │ ├── deployments-service.ts
│ │ ├── events-service.ts
│ │ ├── namespaces-service.test.ts
│ │ ├── namespaces-service.ts
│ │ ├── nexus-service.ts
│ │ ├── pollers-service.ts
│ │ ├── query-service.ts
│ │ ├── schedule-service.ts
│ │ ├── search-attributes-service.ts
│ │ ├── settings-service.test.ts
│ │ ├── settings-service.ts
│ │ ├── workflow-activities-service.ts
│ │ ├── workflow-counts.ts
│ │ ├── workflow-service.test.ts
│ │ └── workflow-service.ts
│ ├── stores
│ │ ├── active-events.ts
│ │ ├── advanced-visibility.ts
│ │ ├── api-pagination.test.ts
│ │ ├── api-pagination.ts
│ │ ├── auth-user.ts
│ │ ├── batch-operations.ts
│ │ ├── bulk-actions.test.ts
│ │ ├── bulk-actions.ts
│ │ ├── capability-enablement.ts
│ │ ├── cluster.ts
│ │ ├── column-width.ts
│ │ ├── configurable-table-columns.test.ts
│ │ ├── configurable-table-columns.ts
│ │ ├── core-user.ts
│ │ ├── data-converter-config.ts
│ │ ├── data-encoder-config.ts
│ │ ├── data-encoder.test.ts
│ │ ├── data-encoder.ts
│ │ ├── error.ts
│ │ ├── event-view.ts
│ │ ├── events.ts
│ │ ├── filters.ts
│ │ ├── import-events.test.ts
│ │ ├── import-events.ts
│ │ ├── labs-mode.ts
│ │ ├── namespaces.test.ts
│ │ ├── namespaces.ts
│ │ ├── nav-open.ts
│ │ ├── new-feature-tags.ts
│ │ ├── pagination.test.ts
│ │ ├── pagination.ts
│ │ ├── persist-store.ts
│ │ ├── persisted-search-parameter.ts
│ │ ├── previous-events.ts
│ │ ├── reset-workflows.ts
│ │ ├── schedules.ts
│ │ ├── search-attributes.test.ts
│ │ ├── search-attributes.ts
│ │ ├── settings.ts
│ │ ├── task-queue-view.ts
│ │ ├── time-format.test.ts
│ │ ├── time-format.ts
│ │ ├── toaster.test.ts
│ │ ├── toaster.ts
│ │ ├── versions.ts
│ │ ├── workflow-run.ts
│ │ └── workflows.ts
│ ├── svelte-mocks
│ │ └── app
│ │ │ ├── environment.ts
│ │ │ ├── navigation.ts
│ │ │ ├── paths.ts
│ │ │ └── stores.ts
│ ├── theme
│ │ ├── colors.ts
│ │ ├── plugin.ts
│ │ ├── preset.ts
│ │ ├── types.d.ts
│ │ ├── utilities.ts
│ │ └── variables.ts
│ ├── types
│ │ ├── api.ts
│ │ ├── batch.ts
│ │ ├── deployments.ts
│ │ ├── events.ts
│ │ ├── global.ts
│ │ ├── holocene.ts
│ │ ├── index.ts
│ │ ├── nexus.ts
│ │ ├── schedule.ts
│ │ └── workflows.ts
│ ├── utilities
│ │ ├── advanced-visibility-enabled.test.ts
│ │ ├── advanced-visibility-enabled.ts
│ │ ├── atob.test.ts
│ │ ├── atob.ts
│ │ ├── auth-user-cookie.ts
│ │ ├── btoa.test.ts
│ │ ├── btoa.ts
│ │ ├── bulk-actions-enabled.test.ts
│ │ ├── bulk-actions-enabled.ts
│ │ ├── calendar.ts
│ │ ├── cancel-in-progress.test.ts
│ │ ├── cancel-in-progress.ts
│ │ ├── copy-to-clipboard.ts
│ │ ├── dark-mode
│ │ │ ├── dark-mode.svelte
│ │ │ ├── dark-mode.test.ts
│ │ │ ├── dark-mode.ts
│ │ │ └── index.ts
│ │ ├── decode-payload-test-fixtures.ts
│ │ ├── decode-payload.test.ts
│ │ ├── decode-payload.ts
│ │ ├── encode-payload.test.ts
│ │ ├── encode-payload.ts
│ │ ├── encode-uri.test.ts
│ │ ├── encode-uri.ts
│ │ ├── event-formatting.test.ts
│ │ ├── event-formatting.ts
│ │ ├── event-link-href.test.ts
│ │ ├── event-link-href.ts
│ │ ├── export-history.ts
│ │ ├── export-workflows.ts
│ │ ├── focus-trap.test.ts
│ │ ├── focus-trap.ts
│ │ ├── format-bytes.ts
│ │ ├── format-camel-case.test.ts
│ │ ├── format-camel-case.ts
│ │ ├── format-date.test.ts
│ │ ├── format-date.ts
│ │ ├── format-event-attributes.test.ts
│ │ ├── format-event-attributes.ts
│ │ ├── format-time.test.ts
│ │ ├── format-time.ts
│ │ ├── get-api-origin.test.ts
│ │ ├── get-api-origin.ts
│ │ ├── get-clusters.test.ts
│ │ ├── get-clusters.ts
│ │ ├── get-codec.test.ts
│ │ ├── get-codec.ts
│ │ ├── get-context.ts
│ │ ├── get-environment.ts
│ │ ├── get-failed-or-pending.test.ts
│ │ ├── get-failed-or-pending.ts
│ │ ├── get-float-style.test.ts
│ │ ├── get-float-style.ts
│ │ ├── get-group-status-and-count.ts
│ │ ├── get-namespace.test.ts
│ │ ├── get-namespace.ts
│ │ ├── get-query-types-from-error.test.ts
│ │ ├── get-query-types-from-error.ts
│ │ ├── get-sdk-version.test.ts
│ │ ├── get-sdk-version.ts
│ │ ├── get-single-attribute-for-event.test.ts
│ │ ├── get-single-attribute-for-event.ts
│ │ ├── get-started-completed-and-task-failed-events.test.ts
│ │ ├── get-started-completed-and-task-failed-events.ts
│ │ ├── get-truncated-word.test.ts
│ │ ├── get-truncated-word.ts
│ │ ├── get-workflow-relationships.test.ts
│ │ ├── get-workflow-relationships.ts
│ │ ├── get-workflow-status-filter-code.test.ts
│ │ ├── get-workflow-status-filter-code.ts
│ │ ├── get-workflow-task-failed-event.test.ts
│ │ ├── get-workflow-task-failed-event.ts
│ │ ├── handle-error.test.ts
│ │ ├── handle-error.ts
│ │ ├── has.test.ts
│ │ ├── has.ts
│ │ ├── is-authorized.test.ts
│ │ ├── is-authorized.ts
│ │ ├── is-email.ts
│ │ ├── is-event-type.test.ts
│ │ ├── is-event-type.ts
│ │ ├── is-function.test.ts
│ │ ├── is-function.ts
│ │ ├── is-http.test.ts
│ │ ├── is-http.ts
│ │ ├── is-network-error.test.ts
│ │ ├── is-network-error.ts
│ │ ├── is-pending-activity.test.ts
│ │ ├── is-pending-activity.ts
│ │ ├── is.test.ts
│ │ ├── is.ts
│ │ ├── merge.test.ts
│ │ ├── merge.ts
│ │ ├── namespace-url-pattern.test.ts
│ │ ├── namespace-url-pattern.ts
│ │ ├── nexus-enabled.ts
│ │ ├── omit.test.ts
│ │ ├── omit.ts
│ │ ├── paginated.test.ts
│ │ ├── paginated.ts
│ │ ├── parse-with-big-int.test.ts
│ │ ├── parse-with-big-int.ts
│ │ ├── path-matches.test.ts
│ │ ├── path-matches.ts
│ │ ├── payload-to-string.test.ts
│ │ ├── payload-to-string.ts
│ │ ├── pending-activities.test.ts
│ │ ├── pending-activities.ts
│ │ ├── pick.test.ts
│ │ ├── pick.ts
│ │ ├── pluralize.ts
│ │ ├── query
│ │ │ ├── filter-workflow-query.test.ts
│ │ │ ├── filter-workflow-query.ts
│ │ │ ├── is-search-attribute.test.ts
│ │ │ ├── is-search-attribute.ts
│ │ │ ├── list-workflow-query.test.ts
│ │ │ ├── list-workflow-query.ts
│ │ │ ├── search-attribute-filter.test.ts
│ │ │ ├── search-attribute-filter.ts
│ │ │ ├── to-list-workflow-filters.test.ts
│ │ │ ├── to-list-workflow-filters.ts
│ │ │ ├── to-list-workflow-parameters.test.ts
│ │ │ ├── to-list-workflow-parameters.ts
│ │ │ ├── tokenize.test.ts
│ │ │ └── tokenize.ts
│ │ ├── refresh-rate.test.ts
│ │ ├── refresh-rate.ts
│ │ ├── render-markdown.ts
│ │ ├── request-from-api.test.ts
│ │ ├── request-from-api.ts
│ │ ├── request-from-api.with-access-token.test.ts
│ │ ├── route-for-api.test.ts
│ │ ├── route-for-api.ts
│ │ ├── route-for.test.ts
│ │ ├── route-for.ts
│ │ ├── schedule-data-formatting.test.ts
│ │ ├── schedule-data-formatting.ts
│ │ ├── screaming-enums.test.ts
│ │ ├── screaming-enums.ts
│ │ ├── search-type-parameter.test.ts
│ │ ├── search-type-parameter.ts
│ │ ├── stack-trace
│ │ │ ├── get-file-paths-from-go-stack-trace.test.ts
│ │ │ ├── get-file-paths-from-go-stack-trace.ts
│ │ │ ├── get-file-paths-from-stack-trace.test.ts
│ │ │ ├── get-file-paths-from-stack-trace.ts
│ │ │ ├── get-file-paths-from-typescript-stack-trace.test.ts
│ │ │ ├── get-file-paths-from-typescript-stack-trace.ts
│ │ │ ├── get-sdk-origin.test.ts
│ │ │ ├── get-sdk-origin.ts
│ │ │ ├── is-from-go-sdk.test.ts
│ │ │ ├── is-from-go-sdk.ts
│ │ │ ├── is-from-java-sdk.test.ts
│ │ │ ├── is-from-java-sdk.ts
│ │ │ ├── is-from-typescript-sdk.test.ts
│ │ │ └── is-from-typescript-sdk.ts
│ │ ├── task-queue-compatibility.test.ts
│ │ ├── task-queue-compatibility.ts
│ │ ├── to-duration.test.ts
│ │ ├── to-duration.ts
│ │ ├── to-time-difference.test.ts
│ │ ├── to-time-difference.ts
│ │ ├── to-url.test.ts
│ │ ├── to-url.ts
│ │ ├── trim-trailing-slash.test.ts
│ │ ├── trim-trailing-slash.ts
│ │ ├── unique.test.ts
│ │ ├── unique.ts
│ │ ├── update-query-parameters.test.ts
│ │ ├── update-query-parameters.ts
│ │ ├── version-check.test.ts
│ │ ├── version-check.ts
│ │ ├── workflow-actions.test.ts
│ │ ├── workflow-actions.ts
│ │ ├── workflow-cancel-enabled.test.ts
│ │ ├── workflow-cancel-enabled.ts
│ │ ├── workflow-create-disabled.ts
│ │ ├── workflow-reset-enabled.test.ts
│ │ ├── workflow-reset-enabled.ts
│ │ ├── workflow-signal-enabled.test.ts
│ │ ├── workflow-signal-enabled.ts
│ │ ├── workflow-terminate-enabled.test.ts
│ │ ├── workflow-terminate-enabled.ts
│ │ ├── workflow-update-enabled.test.ts
│ │ ├── workflow-update-enabled.ts
│ │ ├── write-actions-are-allowed.test.ts
│ │ └── write-actions-are-allowed.ts
│ └── vendor
│ │ ├── Temporal_Logo_Animation.gif
│ │ ├── Temporal_Logo_Animation.mp4
│ │ ├── Temporal_Logo_Animation.webm
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── andromeda.png
│ │ ├── apple-touch-icon.png
│ │ ├── banner.png
│ │ ├── codemirror
│ │ └── theme.ts
│ │ ├── css
│ │ └── normalize.css
│ │ ├── empty-state-dark_2x.png
│ │ ├── empty-state-dark_4x.png
│ │ ├── empty-state-light_2x.png
│ │ ├── empty-state-light_4x.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── logo-dark.svg
│ │ ├── logo.svg
│ │ ├── sdk-logos
│ │ ├── dot-net-logo.png
│ │ ├── go-logo.png
│ │ ├── java-logo.png
│ │ ├── php-logo.png
│ │ ├── python-logo.png
│ │ ├── ruby-logo.png
│ │ ├── rust-logo.png
│ │ └── ts-logo.png
│ │ └── site.webmanifest
├── markdown.reset.css
└── routes
│ ├── (app)
│ ├── +layout.svelte
│ ├── +layout.ts
│ ├── +page.svelte
│ ├── +page.ts
│ ├── import
│ │ ├── +layout.svelte
│ │ ├── +page.ts
│ │ └── events
│ │ │ ├── +page.svelte
│ │ │ └── [namespace]
│ │ │ └── [workflow]
│ │ │ └── [run]
│ │ │ └── history
│ │ │ ├── +layout.svelte
│ │ │ ├── +page.ts
│ │ │ ├── compact
│ │ │ └── +page.svelte
│ │ │ ├── feed
│ │ │ └── +page.svelte
│ │ │ └── json
│ │ │ └── +page.svelte
│ ├── namespaces
│ │ ├── +page.svelte
│ │ └── [namespace]
│ │ │ ├── +layout.ts
│ │ │ ├── +page.svelte
│ │ │ ├── +page.ts
│ │ │ ├── archival
│ │ │ ├── +page.svelte
│ │ │ ├── +page.ts
│ │ │ ├── _filter-input.svelte
│ │ │ └── _workflow-filters.svelte
│ │ │ ├── batch-operations
│ │ │ ├── +page.svelte
│ │ │ └── [jobId]
│ │ │ │ └── +page.svelte
│ │ │ ├── schedules
│ │ │ ├── +page.svelte
│ │ │ ├── [schedule]
│ │ │ │ ├── +page.svelte
│ │ │ │ └── edit
│ │ │ │ │ └── +page.svelte
│ │ │ └── create
│ │ │ │ └── +page.svelte
│ │ │ ├── task-queues
│ │ │ ├── +layout.svelte
│ │ │ ├── +page.svelte
│ │ │ └── [queue]
│ │ │ │ └── +page.svelte
│ │ │ ├── worker-deployments
│ │ │ ├── +page.svelte
│ │ │ └── [deployment]
│ │ │ │ ├── +layout.svelte
│ │ │ │ └── +page.svelte
│ │ │ └── workflows
│ │ │ ├── +page.svelte
│ │ │ ├── +page.ts
│ │ │ ├── [workflow]
│ │ │ ├── +page.ts
│ │ │ └── [run]
│ │ │ │ ├── +layout.svelte
│ │ │ │ ├── +page.svelte
│ │ │ │ ├── +page.ts
│ │ │ │ ├── call-stack
│ │ │ │ └── +page.svelte
│ │ │ │ ├── history.json
│ │ │ │ └── +page.ts
│ │ │ │ ├── history
│ │ │ │ ├── +page.svelte
│ │ │ │ ├── compact
│ │ │ │ │ └── +page.ts
│ │ │ │ ├── events
│ │ │ │ │ └── [id]
│ │ │ │ │ │ └── +page.svelte
│ │ │ │ ├── feed
│ │ │ │ │ └── +page.ts
│ │ │ │ └── json
│ │ │ │ │ └── +page.ts
│ │ │ │ ├── metadata
│ │ │ │ └── +page.svelte
│ │ │ │ ├── pending-activities
│ │ │ │ └── +page.svelte
│ │ │ │ ├── query
│ │ │ │ └── +page.svelte
│ │ │ │ ├── relationships
│ │ │ │ └── +page.svelte
│ │ │ │ ├── stack-trace
│ │ │ │ └── +page.ts
│ │ │ │ └── workers
│ │ │ │ └── +page.svelte
│ │ │ └── start-workflow
│ │ │ ├── +page.svelte
│ │ │ └── +page.ts
│ ├── nexus
│ │ ├── +layout.svelte
│ │ ├── +page.svelte
│ │ ├── +page.ts
│ │ ├── [id]
│ │ │ ├── +layout.svelte
│ │ │ ├── +layout.ts
│ │ │ ├── +page.svelte
│ │ │ └── edit
│ │ │ │ └── +page.svelte
│ │ └── create
│ │ │ └── +page.svelte
│ ├── render
│ │ └── +server.ts
│ └── select-namespace
│ │ └── +page.svelte
│ ├── (login)
│ ├── +layout.svelte
│ ├── +layout.ts
│ ├── login
│ │ └── +page.svelte
│ └── signin
│ │ └── +page.svelte
│ ├── +error.svelte
│ └── +layout.ts
├── static
└── favicon.ico
├── svelte.config.js
├── tailwind.config.ts
├── temporal
├── activities
│ ├── double.ts
│ ├── echo.ts
│ └── index.ts
├── client.ts
├── codec-server.ts
├── data-converter.ts
├── payload-codec.ts
├── workers.ts
└── workflows.ts
├── tests
├── accessibility
│ ├── empty-states.accessibility.spec.ts
│ ├── network-requests
│ │ ├── empty-states.har
│ │ ├── with-schedules.har
│ │ └── with-workflows.har
│ ├── with-schedules.accessibility.spec.ts
│ └── with-workflows.accessibility.spec.ts
├── e2e
│ ├── call-stack.spec.ts
│ ├── schedules.spec.ts
│ ├── storageState.json
│ ├── workflows-summary-table-configuration.spec.ts
│ └── workflows.spec.ts
├── fixtures
│ └── completed-event-history.json
├── global-setup.ts
├── global-teardown.ts
├── integration
│ ├── archival-namespace.spec.ts
│ ├── dark-mode.desktop.spec.ts
│ ├── dark-mode.mobile.spec.ts
│ ├── data-encoder.desktop.spec.ts
│ ├── data-encoder.mobile.spec.ts
│ ├── disable-write-actions.spec.ts
│ ├── import-event-history.spec.ts
│ ├── schedule-edit.spec.ts
│ ├── schedules-create.spec.ts
│ ├── schedules-list.spec.ts
│ ├── start-a-workflow.spec.ts
│ ├── storageState.json
│ ├── workflow-actions.spec.ts
│ ├── workflow-bulk-actions.spec.ts
│ ├── workflow-event-history.spec.ts
│ ├── workflow-navigation.desktop.spec.ts
│ ├── workflow-navigation.mobile.spec.ts
│ ├── workflow-reset.spec.ts
│ ├── workflows-count.spec.ts
│ ├── workflows-search-attribute-filter.desktop.spec.ts
│ └── workflows-search-attribute-filter.mobile.spec.ts
├── test-utilities
│ ├── accessibility-reporter
│ │ ├── index.ts
│ │ ├── summarize.ts
│ │ ├── to-markdown.ts
│ │ └── unique.ts
│ ├── attach-violations.ts
│ ├── custom-matchers.ts
│ ├── mock-apis.ts
│ ├── mock-date.ts
│ ├── mock-local-storage.ts
│ └── mocks
│ │ ├── batch-operations.ts
│ │ ├── cluster.ts
│ │ ├── event-history.ts
│ │ ├── namespace.ts
│ │ ├── namespaces.ts
│ │ ├── query.ts
│ │ ├── schedules.ts
│ │ ├── search-attributes.ts
│ │ ├── settings.ts
│ │ ├── system-info.ts
│ │ ├── task-queues.ts
│ │ ├── workflow.ts
│ │ ├── workflows-count.ts
│ │ └── workflows.ts
└── tsconfig.json
├── tsconfig.json
├── utilities
├── temporal-server.ts
└── ui-server.ts
├── vercel.json
├── vite.config.ts
├── vitest-setup.ts
└── vitest.config.ts
/.dockerignore:
--------------------------------------------------------------------------------
1 | .github
2 | .husky
3 | .svelte-kit
4 | .vscode
5 | build
6 | e2e
7 | node_modules
8 | server/ui/assets
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | VITE_TEMPORAL_PORT="7233"
2 | VITE_API="http://localhost:8233"
3 | VITE_MODE="development"
4 |
--------------------------------------------------------------------------------
/.env.local-temporal:
--------------------------------------------------------------------------------
1 | VITE_TEMPORAL_PORT="7134"
2 | VITE_API="http://localhost:8081"
3 | VITE_MODE="development"
4 | VITE_TEMPORAL_UI_BUILD_TARGET="local"
5 |
--------------------------------------------------------------------------------
/.env.test:
--------------------------------------------------------------------------------
1 | VITE_API="http://localhost:8233"
2 | VITE_MODE="test"
3 |
--------------------------------------------------------------------------------
/.env.test.e2e:
--------------------------------------------------------------------------------
1 | VITE_TEMPORAL_UI_BUILD_TARGET="local"
2 | VITE_TEMPORAL_PORT="7233"
3 | VITE_API="http://localhost:8080"
4 | VITE_MODE="development"
--------------------------------------------------------------------------------
/.env.test.integration:
--------------------------------------------------------------------------------
1 | VITE_TEMPORAL_PORT="4444"
2 | VITE_API="http://localhost:8233"
3 | VITE_MODE="development"
4 |
--------------------------------------------------------------------------------
/.env.testing:
--------------------------------------------------------------------------------
1 | VITE_API="http://localhost:7777"
2 | VITE_TEMPORAL_PORT="6666"
3 | VITE_UI_SERVER_PORT="7777"
4 | VITE_MODE="testing"
5 |
--------------------------------------------------------------------------------
/.env.ui-server:
--------------------------------------------------------------------------------
1 | VITE_TEMPORAL_PORT="7233"
2 | VITE_API="http://localhost:8081"
3 | VITE_MODE="development"
4 | VITE_TEMPORAL_UI_BUILD_TARGET="local"
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 |
28 | - OS: [e.g. iOS]
29 | - Browser [e.g. chrome, safari]
30 | - Version [e.g. 22]
31 |
32 | **Additional context**
33 | Add any other context about the problem here.
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 | ---
8 |
9 | ## Is your feature request related to a problem? Please describe.
10 |
11 |
12 |
13 | ## Describe the solution you'd like
14 |
15 |
16 |
17 | ## Describe alternatives you've considered
18 |
19 |
20 |
21 | ## Additional context
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | # https://github.com/release-drafter/release-drafter?tab=readme-ov-file#configuration-options
2 | name-template: 'v$RESOLVED_VERSION 🤖'
3 | tag-template: 'v$RESOLVED_VERSION'
4 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
5 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
6 | version-resolver:
7 | major:
8 | labels:
9 | - 'major'
10 | minor:
11 | labels:
12 | - 'minor'
13 | patch:
14 | labels:
15 | - 'patch'
16 | default: patch
17 | template: |
18 | ## What’s Changed
19 |
20 | $CHANGES
21 |
--------------------------------------------------------------------------------
/.github/workflows/chromatic.yml:
--------------------------------------------------------------------------------
1 | name: 'Chromatic'
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request_target:
7 | branches: [main, 'codefreeze-*']
8 |
9 | jobs:
10 | chromatic:
11 | name: Run Chromatic
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v4
16 | with:
17 | fetch-depth: 0
18 | - name: Checkout and Setup Node
19 | uses: ./.github/actions/setup-node
20 | - name: Run Chromatic
21 | uses: chromaui/action@latest
22 | with:
23 | projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
24 | autoAcceptChanges: 'main'
25 | exitZeroOnChanges: true
26 | exitOnceUploaded: true
27 | onlyChanged: true
28 | skip: 'dependabot/**'
29 |
--------------------------------------------------------------------------------
/.github/workflows/storybook-tests.yml:
--------------------------------------------------------------------------------
1 | name: Storybook Tests
2 | on: deployment_status
3 | jobs:
4 | test:
5 | timeout-minutes: 60
6 | runs-on: ubuntu-latest
7 | if: github.event.deployment_status.state == 'success'
8 | steps:
9 | - uses: actions/checkout@v4
10 | - name: Checkout and Setup Node
11 | uses: ./.github/actions/setup-node
12 | - name: Install Playwright
13 | run: pnpm exec playwright install --with-deps
14 | - name: Run Storybook tests
15 | run: pnpm stories:test
16 | env:
17 | TARGET_URL: '${{ github.event.deployment_status.target_url }}'
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /.svelte-kit
4 | /package
5 | /coverage
6 | *.log
7 | *.swp
8 | /.vercel_build_output
9 | /.vercel
10 | /build-local
11 | /.history
12 | /build
13 | /bin
14 | server/ui-server
15 | server/api
16 | server/ui/assets
17 | /test-results/
18 | /playwright-report/
19 | /playwright/.cache/
20 | /dist
21 | /audits
22 | go.work
23 | go.work.sum
24 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.lintstagedrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "*.{ts,js}": ["eslint --fix", "prettier --write"],
3 | "*.{css,postcss}": ["stylelint --fix"],
4 | "*.svelte": ["eslint --fix", "prettier --write", "stylelint --fix"],
5 | "*.{json,md}": "prettier --write"
6 | }
7 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 18
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .svelte-kit/**
2 | build/**
3 | e2e/test-results/**
4 | e2e/playwright-report/**
5 | node_modules/**
6 | coverage/**
7 | server/**
8 | .vercel/**
9 | /package
10 | pnpm-lock.yaml
11 | README.md
12 | playwright-report
13 | dist/**/*
14 | tests/**/storageState.json
15 | *.har
16 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": true,
7 | "trailingComma": "all",
8 | "bracketSpacing": true,
9 | "bracketSameLine": false,
10 | "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"]
11 | }
12 |
--------------------------------------------------------------------------------
/.storybook/main.ts:
--------------------------------------------------------------------------------
1 | import type { StorybookConfig } from '@storybook/sveltekit';
2 |
3 | const config: StorybookConfig = {
4 | stories: ['../src/**/*.stories.@(ts|svelte)'],
5 | addons: [
6 | '@storybook/addon-links',
7 | '@storybook/addon-essentials',
8 | '@storybook/addon-interactions',
9 | {
10 | name: '@storybook/addon-svelte-csf',
11 | options: {
12 | // REMOVE WHEN STORIES ARE UPGRADED TO NEW CSF SYNTAX
13 | legacyTemplate: true,
14 | },
15 | },
16 | '@storybook/addon-a11y',
17 | '@storybook/addon-themes',
18 | '@chromatic-com/storybook',
19 | ],
20 | framework: '@storybook/sveltekit',
21 | };
22 |
23 | export default config;
24 |
--------------------------------------------------------------------------------
/.storybook/test-runner.ts:
--------------------------------------------------------------------------------
1 | import type { TestRunnerConfig } from '@storybook/test-runner';
2 | import { getStoryContext } from '@storybook/test-runner';
3 | import { injectAxe, checkA11y } from 'axe-playwright';
4 |
5 | const config: TestRunnerConfig = {
6 | async preVisit(page) {
7 | await injectAxe(page);
8 | },
9 | async postVisit(page, context) {
10 | const storyContext = await getStoryContext(page, context);
11 | if (storyContext.parameters?.a11y?.disable) {
12 | return;
13 | }
14 | await checkA11y(page, '#storybook-root', {
15 | detailedReport: true,
16 | detailedReportOptions: {
17 | html: true,
18 | },
19 | });
20 | },
21 | };
22 |
23 | export default config;
24 |
--------------------------------------------------------------------------------
/.vscode/css-custom-data.json:
--------------------------------------------------------------------------------
1 | {
2 | "atDirectives": [
3 | {
4 | "name": "@tailwind",
5 | "description": "Use the @tailwind directive to insert Tailwind’s `base`, `components`, `utilities`, and `screens` styles into your CSS.",
6 | "references": [
7 | {
8 | "name": "Tailwind’s “Functions & Directives” documentation",
9 | "url": "https://tailwindcss.com/docs/functions-and-directives/#tailwind"
10 | }
11 | ]
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "dbaeumer.vscode-eslint",
4 | "esbenp.prettier-vscode",
5 | "bradlc.vscode-tailwindcss",
6 | "svelte.svelte-vscode",
7 | "yoavbls.pretty-ts-errors"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "search.exclude": {
3 | "**/node_modules": true,
4 | "**/.svelte-kit": true,
5 | "**/.vercel": true
6 | },
7 | "editor.formatOnSave": true,
8 | "eslint.validate": ["javascript", "typescript", "svelte"],
9 | "css.customData": [".vscode/css-custom-data.json"],
10 | "typescript.tsdk": "node_modules/typescript/lib",
11 | "tailwindCSS.experimental.classRegex": [
12 | ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
13 | ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
14 | ],
15 | "files.associations": {
16 | "*.css": "tailwindcss"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.vscode/temporal-ui.code-snippets:
--------------------------------------------------------------------------------
1 | {
2 | "Playwright Test": {
3 | "prefix": "pwt",
4 | "body": ["test('${1}', async ({ page }) => {", " $0", "});"],
5 | "description": "useState()",
6 | },
7 | }
8 |
--------------------------------------------------------------------------------
/.whitesource:
--------------------------------------------------------------------------------
1 | {
2 | "settingsInheritedFrom": "temporalio/whitesource-config@main"
3 | }
--------------------------------------------------------------------------------
/chromatic.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "autoAcceptChanges": "main",
3 | "buildScriptName": "stories:build",
4 | "exitOnceUploaded": true,
5 | "exitZeroOnChanges": true,
6 | "externals": ["public/**"],
7 | "onlyChanged": true,
8 | "skip": "dependabot/**"
9 | }
10 |
--------------------------------------------------------------------------------
/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | const tailwindcss = require('tailwindcss');
2 | const tailwindcssNesting = require('tailwindcss/nesting');
3 | const autoprefixer = require('autoprefixer');
4 | const cssnano = require('cssnano');
5 |
6 | const mode = process.env.NODE_ENV;
7 | const dev = mode === 'development';
8 |
9 | const config = {
10 | plugins: [
11 | autoprefixer(),
12 | tailwindcssNesting(),
13 | tailwindcss(),
14 | !dev &&
15 | cssnano({
16 | preset: 'default',
17 | }),
18 | ],
19 | };
20 |
21 | module.exports = config;
22 |
--------------------------------------------------------------------------------
/scripts/audit-tailwind-colors/to-rows.ts:
--------------------------------------------------------------------------------
1 | import { type Result } from './types';
2 | import { getProjectRoot } from '../get-project-root';
3 |
4 | export const toRow = (result: Result) => {
5 | return [
6 | result.path.replace(getProjectRoot(), ''),
7 | result.line,
8 | result.class,
9 | result.variant || '',
10 | result.utility || '',
11 | result.color || '',
12 | result.shade || '',
13 | ].join(',');
14 | };
15 |
16 | export const toRows = (results: Result[]) => {
17 | return results.reduce((rows, result) => {
18 | return rows + toRow(result) + '\n';
19 | }, 'File,Line Number,Class,Variant,Utility,Color,Shade\n');
20 | };
21 |
--------------------------------------------------------------------------------
/scripts/audit-tailwind-colors/types.ts:
--------------------------------------------------------------------------------
1 | export type TailwindClass = {
2 | variant: string | null;
3 | utility: string | null;
4 | color: string | null;
5 | shade: string | null;
6 | };
7 |
8 | export type Result = {
9 | path: string;
10 | line: number;
11 | class: string;
12 | } & TailwindClass;
13 |
--------------------------------------------------------------------------------
/scripts/get-project-root.ts:
--------------------------------------------------------------------------------
1 | import { existsSync } from 'fs';
2 | import { dirname, join } from 'path';
3 | import { fileURLToPath } from 'url';
4 |
5 | export const getProjectRoot = (): string => {
6 | let currentDirectory = dirname(fileURLToPath(import.meta.url));
7 |
8 | while (currentDirectory !== '/') {
9 | if (existsSync(join(currentDirectory, 'package.json'))) {
10 | return currentDirectory;
11 | }
12 | currentDirectory = dirname(currentDirectory);
13 | }
14 |
15 | throw new Error('Project root not found.');
16 | };
17 |
--------------------------------------------------------------------------------
/scripts/start-codec-server.ts:
--------------------------------------------------------------------------------
1 | import yargs from 'yargs/yargs';
2 |
3 | import {
4 | type CodecServerOptions,
5 | createCodecServer,
6 | } from '../temporal/codec-server';
7 |
8 | const args = yargs(process.argv.slice(2)).parse();
9 |
10 | const options: CodecServerOptions = {
11 | port: args['port'],
12 | };
13 |
14 | const server = await createCodecServer(options);
15 |
16 | server.start().catch(async (error) => {
17 | console.error(error);
18 | await server.stop();
19 | process.exit(1);
20 | });
21 |
22 | process.on('beforeExit', () => {
23 | if (server) server.stop();
24 | });
25 |
--------------------------------------------------------------------------------
/scripts/start-temporal-server.ts:
--------------------------------------------------------------------------------
1 | import yargs from 'yargs/yargs';
2 |
3 | import {
4 | createTemporalServer,
5 | type TemporalServer,
6 | type TemporalServerOptions,
7 | } from '../utilities/temporal-server';
8 |
9 | const args = yargs(process.argv.slice(2)).parse();
10 |
11 | const options: TemporalServerOptions = {
12 | port: args['port'],
13 | uiPort: args['uiPort'] ?? args['ui-port'],
14 | path: args['path'],
15 | logLevel: args['logLevel'] ?? args['log-level'],
16 | codecEndpoint: args['codecEndpoint'] ?? args['codec-endpoint'],
17 | dbFilename: args['dbFilename'] ?? args['db-filename'],
18 | };
19 |
20 | const server: TemporalServer = await createTemporalServer(options);
21 |
22 | await server.ready();
23 |
24 | process.on('beforeExit', async () => {
25 | await server.shutdown();
26 | });
27 |
--------------------------------------------------------------------------------
/scripts/start-ui-server.ts:
--------------------------------------------------------------------------------
1 | import { createUIServer, UIServer } from '../utilities/ui-server';
2 |
3 | const server: UIServer = await createUIServer();
4 |
5 | await server.ready();
6 |
7 | process.on('beforeExit', async () => {
8 | await server.shutdown();
9 | });
10 |
--------------------------------------------------------------------------------
/scripts/workflows.ts:
--------------------------------------------------------------------------------
1 | import { connect, startWorkflows } from '../temporal/client';
2 | import { runWorkerUntil } from '../temporal/workers';
3 |
4 | async function main() {
5 | const client = await connect();
6 | const results = startWorkflows(client);
7 | await runWorkerUntil(results);
8 | }
9 |
10 | main().catch((error) => {
11 | console.error(error);
12 | process.exit(1);
13 | });
14 |
--------------------------------------------------------------------------------
/server/Makefile:
--------------------------------------------------------------------------------
1 | .ONESHELL:
2 | .PHONY:
3 |
4 | all: build
5 |
6 | ##### Variables ######
7 |
8 | ifndef GOPATH
9 | GOPATH := $(shell go env GOPATH)
10 | endif
11 |
12 | GOBIN := $(if $(shell go env GOBIN),$(shell go env GOBIN),$(GOPATH)/bin)
13 | PATH := $(GOBIN):$(PATH)
14 |
15 | COLOR := "\e[1;36m%s\e[0m\n"
16 |
17 | ##### Build #####
18 | build: build-server
19 |
20 | build-server:
21 | go mod tidy
22 | go build -o ui-server ./cmd/server/main.go
23 |
24 | ##### Test #####
25 | test: clean-test-results
26 | @printf $(COLOR) "Running unit tests..."
27 | go test ./... -race
28 |
29 | clean-test-results:
30 | @rm -f test.log
31 | @go clean -testcache
32 |
--------------------------------------------------------------------------------
/server/README.md:
--------------------------------------------------------------------------------
1 | # ui-server
2 |
3 | [](https://github.com/temporalio/ui-server/actions/workflows/docker.yml)
4 |
5 | ## Development
6 |
7 | https://github.com/temporalio/ui-server is automatically updated to mirror
8 | changes to https://github.com/temporalio/ui/tree/main/server; commits should be
9 | made to the UI repository.
10 |
11 | For contributions follow UI's development guide https://github.com/temporalio/ui
12 |
13 |
14 | ## To View gRPC routes:
15 | [Temporal API Workflowservice](https://github.com/temporalio/api/blob/master/temporal/api/workflowservice/v1/service.proto)
16 |
--------------------------------------------------------------------------------
/server/config/base.yaml:
--------------------------------------------------------------------------------
1 | temporalGrpcAddress: 127.0.0.1:7233
2 | port: 8233
3 |
--------------------------------------------------------------------------------
/server/config/e2e.yaml:
--------------------------------------------------------------------------------
1 | temporalGrpcAddress: 127.0.0.1:7233
2 | port: 8080
3 | codec:
4 | endpoint: http://localhost:8888
5 |
--------------------------------------------------------------------------------
/server/docker/start-ui-server.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu -o pipefail
4 |
5 | if [ -f ./config/config-template.yaml ]; then
6 | >&2 echo "Custom config templates should now be mounted at: /home/ui-server/config/docker.yaml"
7 | >&2 echo "Please see the README for details on config templating support"
8 | dockerize -template ./config-template.yaml:./config/docker.yaml
9 | fi
10 |
11 | # Run bash instead of ui-server if "bash" is passed as an argument (convenient to debug docker image).
12 | for arg in "$@" ; do [[ ${arg} == "bash" ]] && bash && exit 0 ; done
13 |
14 | exec ./ui-server --env docker start
15 |
--------------------------------------------------------------------------------
/server/ui/embed.go:
--------------------------------------------------------------------------------
1 | package ui
2 |
3 | import (
4 | "embed"
5 | "io/fs"
6 | )
7 |
8 | //go:embed all:assets
9 | var assets embed.FS
10 |
11 | func Assets() (fs.FS, error) {
12 | return fs.Sub(assets, "assets")
13 | }
14 |
--------------------------------------------------------------------------------
/src/app.css:
--------------------------------------------------------------------------------
1 | @import '@fontsource-variable/inter';
2 |
3 | @import '@fontsource/noto-sans-mono';
4 |
5 | @import 'tailwindcss/base';
6 | @import 'tailwindcss/components';
7 | @import 'tailwindcss/utilities';
8 |
9 | @layer base {
10 | *,
11 | html,
12 | body {
13 | @apply box-border;
14 | }
15 |
16 | body {
17 | @apply body-normal surface-background relative overscroll-none;
18 | }
19 |
20 | input[type='search']::-webkit-search-cancel-button {
21 | @apply hidden;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/app.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | ///
3 |
4 | declare namespace App {
5 | interface Locals {}
6 |
7 | interface Platform {}
8 |
9 | interface Session {}
10 |
11 | interface PageData {
12 | workflow?: import('$types').WorkflowExecution;
13 | settings?: import('$types').Settings;
14 | workers?: import('$types').GetPollersResponse;
15 | cluster?: import('$types').ClusterInformation;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %sveltekit.head%
7 |
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | type Vitest = import('vitest');
4 |
5 | interface ImportMetaEnv {
6 | readonly VITE_TEMPORAL_UI_BUILD_TARGET: string;
7 | readonly VITE_API: string;
8 | readonly VITE_DARK_MODE: boolean;
9 | }
10 |
11 | interface ImportMeta {
12 | readonly env: ImportMetaEnv;
13 | readonly vitest: Vitest;
14 | }
15 |
--------------------------------------------------------------------------------
/src/fixtures/event-groups.continued-as-new.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/fixtures/event-groups.continued-as-new.json
--------------------------------------------------------------------------------
/src/fixtures/raw-events.ascending.continued-as-new.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/fixtures/raw-events.ascending.continued-as-new.json
--------------------------------------------------------------------------------
/src/fixtures/raw-events.descending.continued-as-new.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/fixtures/raw-events.descending.continued-as-new.json
--------------------------------------------------------------------------------
/src/fixtures/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Auth": {
3 | "Enabled": false,
4 | "Options": null
5 | },
6 | "BannerText": "",
7 | "DefaultNamespace": "default",
8 | "ShowTemporalSystemNamespace": false,
9 | "FeedbackURL": "",
10 | "NotifyOnNewVersion": true,
11 | "Codec": {
12 | "Endpoint": "",
13 | "PassAccessToken": true
14 | },
15 | "Version": "2.0.0"
16 | }
17 |
--------------------------------------------------------------------------------
/src/fixtures/stacktrace-query.ts-sdk.json:
--------------------------------------------------------------------------------
1 | {
2 | "queryResult": {
3 | "payloads": [
4 | {
5 | "metadata": {
6 | "encoding": "anNvbi9wbGFpbg=="
7 | },
8 | "data": " at Promise.then ()\n at global.setTimeout (/Users/user/Desktop/ts-sdk/example/node_modules/@temporalio/workflow/src/worker-interface.ts:85:7)\n at setTimeout (/Users/user/Desktop/ts-sdk/example/src/workflows.ts:10:33)\n at new Promise ()\n at delay (/Users/user/Desktop/ts-sdk/example/src/workflows.ts:10:9)\n at delay (/Users/user/Desktop/ts-sdk/example/src/workflows.ts:16:8)\n\n at delay (/Users/user/Desktop/ts-sdk/example/src/workflows.ts:16:8)"
9 | }
10 | ]
11 | },
12 | "queryRejected": null
13 | }
14 |
--------------------------------------------------------------------------------
/src/global.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '@sveltejs/svelte-virtual-list';
4 |
5 | declare namespace svelte.JSX {
6 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
7 | interface HTMLAttributes {
8 | 'onclick-outside': (e: CustomEvent) => void;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/hooks.server.ts:
--------------------------------------------------------------------------------
1 | import type { Handle } from '@sveltejs/kit';
2 |
3 | export const handle: Handle = async ({ event, resolve }) => {
4 | const response = await resolve(event, {});
5 |
6 | return response;
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/components/advanced-visibility-guard.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 | {#if $supportsAdvancedVisibility}
6 |
7 | {:else}
8 |
9 | {/if}
10 |
--------------------------------------------------------------------------------
/src/lib/components/auto-refresh-workflow.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
16 |
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/detail-list/detail-list-column.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
14 | {@render children()}
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/components/detail-list/detail-list-label.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | {@render children()}
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/detail-list/detail-list.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 | {@render children()}
18 |
19 |
--------------------------------------------------------------------------------
/src/lib/components/detail-list/index.ts:
--------------------------------------------------------------------------------
1 | export { default as DetailList } from './detail-list.svelte';
2 | export { default as DetailListLabel } from './detail-list-label.svelte';
3 | export { default as DetailListValue } from './detail-list-value.svelte';
4 | export { default as DetailListTextValue } from './detail-list-text-value.svelte';
5 | export { default as DetailListLinkValue } from './detail-list-link-value.svelte';
6 | export { default as DetailListColumn } from './detail-list-column.svelte';
7 |
--------------------------------------------------------------------------------
/src/lib/components/event/event-empty-row.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 | {#if loading}
12 |
13 | {:else}
14 |
15 | {/if}
16 |
--------------------------------------------------------------------------------
/src/lib/components/event/event-metadata-expanded.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
Summary
13 |
18 |
19 | {decodedValue}
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/feature-guard.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 | {#if enabled}
6 |
7 | {:else}
8 |
9 | {/if}
10 |
--------------------------------------------------------------------------------
/src/lib/components/feedback-button.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 | Give Feedback
15 |
16 |
17 |
18 |
27 |
--------------------------------------------------------------------------------
/src/lib/components/is-cloud-guard.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {#if isCloud || $page.data?.settings?.runtimeEnvironment?.isCloud}
8 |
9 | {:else}
10 |
11 | {/if}
12 |
--------------------------------------------------------------------------------
/src/lib/components/is-legacy-cloud-guard.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 | {#if isCloud && isLegacyCloud}
12 |
13 | {:else}
14 |
15 | {/if}
16 |
--------------------------------------------------------------------------------
/src/lib/components/is-oss-guard.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {#if isCloud || $page.data?.settings?.runtimeEnvironment?.isCloud}
8 |
9 | {:else}
10 |
11 | {/if}
12 |
--------------------------------------------------------------------------------
/src/lib/components/is-temporal-server-version-guard.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 | {#if $isCloud || minimumVersionRequired(minimumVersion, $temporalVersion)}
10 |
11 | {:else}
12 |
13 | {/if}
14 |
--------------------------------------------------------------------------------
/src/lib/components/lines-and-dots/svg/text-link.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 | goto(href)}
15 | on:keydown={(e) => {
16 | if (e.key === 'Enter') {
17 | goto(href);
18 | }
19 | }}
20 | class="cursor-pointer select-none outline-none"
21 | {x}
22 | {y}
23 | font-size={fontSize}
24 | >
25 |
26 |
27 |
28 |
37 |
--------------------------------------------------------------------------------
/src/lib/components/login-button.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | goto(routeForLoginPage())}
10 | >
11 | Login
12 |
13 |
14 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/nexus-guard.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {#if nexusEnabled}
8 |
9 | {:else}
10 |
11 | {/if}
12 |
--------------------------------------------------------------------------------
/src/lib/components/page-title.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | {title}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/panel.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
18 |
--------------------------------------------------------------------------------
/src/lib/components/poller-icon.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
15 |
--------------------------------------------------------------------------------
/src/lib/components/schedule/schedule-day-of-week-view.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 | {translate('schedules.recurring-days-heading')}
16 |
17 |
18 | {translate('schedules.recurring-days-description')}
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/schedule/schedule-error.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | {translate('schedules.error-title')}
10 |
11 | {error}
12 |
13 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/schedule/schedule-frequency-panel.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 | {translate('schedules.schedule-spec')}
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/lib/components/schedule/schedule-input.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/schedule/schedule-notes.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
{translate('common.notes')}
9 |
{notes}
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/components/search-attribute-filter/close-filter-button.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
18 |
--------------------------------------------------------------------------------
/src/lib/components/search.stories.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/lib/components/skip-nav.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
11 | {translate('common.skip-nav')}
12 |
13 |
--------------------------------------------------------------------------------
/src/lib/components/workflow-versioning-header.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 | {translate('workers.buildId')}
17 |
18 |
--------------------------------------------------------------------------------
/src/lib/components/workflow/dropdown-filter/conditional.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
(conditional = '=')}>
7 |
8 | Is
9 |
10 |
11 |
(conditional = '!=')}>
12 |
13 | Is Not
14 |
15 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/workflow/workflow-count-refresh.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 | ($refresh = Date.now())}
13 | >
14 | {#if count > 0}
15 | +{count.toLocaleString()}
16 | {:else if count < 0}
17 | {count.toLocaleString()}
18 | {/if}
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/workflow/workflows-summary-configurable-table/table-header-cell.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | {label}
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/components/workflow/workflows-summary-table.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | Workflows
10 |
11 | Status
12 | Workflow ID
13 | Type
14 | Start
15 | End
16 | Summary
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/holocene/README.md:
--------------------------------------------------------------------------------
1 | # Holocene
2 |
3 | Temporal's UI Component Library
4 |
5 | Run `pnpm stories:dev` to open Storybook
6 |
--------------------------------------------------------------------------------
/src/lib/holocene/accordion/accordion-group.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/lib/holocene/card.stories.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
15 |
16 |
17 |
18 |
19 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut cupiditate
20 | exercitationem quia quibusdam excepturi rem saepe dolore quas, odit vero
21 | sed rerum necessitatibus minima nobis, ullam minus inventore voluptates
22 | itaque?
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/lib/holocene/card.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | {@render children?.()}
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/holocene/error-boundary.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 | {#snippet failed(error, reset)}
8 |
9 | {/snippet}
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/holocene/feature-tag.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 | {#if hide}
11 |
12 | {:else}
13 |
14 | {/if}
15 |
16 |
25 |
--------------------------------------------------------------------------------
/src/lib/holocene/file-input.stories.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/icon.story.md:
--------------------------------------------------------------------------------
1 | # Icon
2 |
3 | The ` ` component allows for rendering of SVG Icons in our app. It is designed to support SVG's with 24x24 viewboxes only! To add a new icon, follow these steps:
4 |
5 | 1. Obtain the SVG markup from a designer. Make sure it is 24x24px!
6 | 2. Create a new Svelte component in `src/lib/holocene/icon/svg` with the following contents. _Note: It's important to spread `$$props` here!_
7 |
8 | ```
9 |
13 |
14 |
15 | ```
16 |
17 | 3. Take the ` ` element(s) from your SVG markup, and paste them in the default slot of the ` ` Component.
18 | 4. Add your new icon to the `icons` object in `src/lib/holocene/icon/paths.ts`.
19 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/icon.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 | {#if icon}
13 |
21 | {/if}
22 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/index.ts:
--------------------------------------------------------------------------------
1 | import Icon from './icon.svelte';
2 |
3 | export { type IconName, iconNames } from './paths';
4 |
5 | export default Icon;
6 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
19 | {title}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/activity.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/add.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/archives.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/arrow-down.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/arrow-left.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/arrow-right.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/arrow-up.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/ascending.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/book-sparkles.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/bookmark.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/calendar-plus.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/calendar.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/chart-ascending.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/chart.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/checkmark.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/chevron-down.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/chevron-left.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/chevron-right.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/chevron-selector-vertical.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/chevron-up.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/close.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/connection.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/converter-down.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/converter-up.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/copy.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/credit-card.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/descending.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/exit.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/expand.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/external-link.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/feed.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/file-import.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/filter-solid.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/filter.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/fire-extinguisher.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/flag.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/graph.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/heartbeat.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/hyphen.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/import.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/json.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/keyboard.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/labs.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/lightning-bolt.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/lock.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/logout.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/merge.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/minimize.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/namespace.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/nexus.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/office-buildings.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/pause.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/play.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/relationship.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/retry.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/schedules.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/sliders.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/spinner-solid.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/star-filled.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/summary.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/table.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
12 |
13 |
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/terminal.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/timeline.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/toolbox.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/transcoder-off.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/transcoder-on.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/trash.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/trending-down.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
12 |
20 |
29 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/trending-up.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
12 |
20 |
29 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/update.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/vertical-ellipsis.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/warning.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/holocene/icon/svg/xmark-filled.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/holocene/keyboard-shortcut/arrow-down.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 | {title}
15 |
--------------------------------------------------------------------------------
/src/lib/holocene/keyboard-shortcut/arrow-left.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 | {title}
15 |
--------------------------------------------------------------------------------
/src/lib/holocene/keyboard-shortcut/arrow-right.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
12 | {title}
16 |
--------------------------------------------------------------------------------
/src/lib/holocene/keyboard-shortcut/arrow-up.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 | {title}
15 |
--------------------------------------------------------------------------------
/src/lib/holocene/labs-mode-guard.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 | {#if $labsMode}
18 |
19 | {:else}
20 |
21 | {/if}
22 |
--------------------------------------------------------------------------------
/src/lib/holocene/menu/index.ts:
--------------------------------------------------------------------------------
1 | import MenuButton from './menu-button.svelte';
2 | import MenuContainer from './menu-container.svelte';
3 | import MenuDivider from './menu-divider.svelte';
4 | import MenuItem from './menu-item.svelte';
5 | import Menu from './menu.svelte';
6 |
7 | export { MenuContainer, Menu, MenuItem, MenuButton, MenuDivider };
8 |
--------------------------------------------------------------------------------
/src/lib/holocene/menu/menu-divider.svelte:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/lib/holocene/orderable-list/orderable-list.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 | Items
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
25 |
--------------------------------------------------------------------------------
/src/lib/holocene/outside-click.ts:
--------------------------------------------------------------------------------
1 | import type { Action } from 'svelte/action';
2 |
3 | export const clickoutside: Action void> = (
4 | node: Element,
5 | handler: (event: MouseEvent) => void,
6 | ): { destroy: () => void } => {
7 | const handleClick = (event: MouseEvent) => {
8 | if (
9 | node &&
10 | !node.contains(event.target as HTMLElement) &&
11 | !event.defaultPrevented
12 | ) {
13 | handler(event);
14 | }
15 | };
16 |
17 | document.addEventListener('click', handleClick, true);
18 |
19 | return {
20 | destroy() {
21 | document.removeEventListener('click', handleClick, true);
22 | },
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/src/lib/holocene/page-transition.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/holocene/pill-container/pill-container.stories.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
17 |
18 |
19 |
20 | Pill A
21 | Pill B
22 | Pill C
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/lib/holocene/progress-bar.stories.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/holocene/radio-input/index.ts:
--------------------------------------------------------------------------------
1 | import RadioGroup, { RADIO_GROUP_CONTEXT } from './radio-group.svelte';
2 | import RadioInput from './radio-input.svelte';
3 |
4 | export type { RadioGroupContext, RadioInputProps } from './types';
5 |
6 | export { RADIO_GROUP_CONTEXT, RadioGroup, RadioInput };
7 |
--------------------------------------------------------------------------------
/src/lib/holocene/radio-input/types.ts:
--------------------------------------------------------------------------------
1 | import type { HTMLAttributes, HTMLInputAttributes } from 'svelte/elements';
2 | import type { Writable } from 'svelte/store';
3 |
4 | export interface RadioInputProps extends HTMLInputAttributes {
5 | value: T;
6 | id: string;
7 | label: string;
8 | labelHidden?: boolean;
9 | description?: string;
10 | group?: Writable;
11 | name?: string;
12 | 'data-testid'?: string;
13 | class?: string;
14 | }
15 |
16 | export interface RadioGroupProps extends HTMLAttributes {
17 | name: string;
18 | group: Writable;
19 | description?: string;
20 | }
21 |
22 | export type RadioGroupContext = {
23 | name: string;
24 | group: Writable;
25 | };
26 |
--------------------------------------------------------------------------------
/src/lib/holocene/scroll-to-bottom.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/src/lib/holocene/scroll-to-top.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/holocene/select/option-group.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | {label}
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/holocene/select/simple-option.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {value}
8 |
--------------------------------------------------------------------------------
/src/lib/holocene/skeleton/index.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
14 |
15 |
32 |
--------------------------------------------------------------------------------
/src/lib/holocene/skeleton/skeleton.stories.svelte:
--------------------------------------------------------------------------------
1 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/lib/holocene/tab-buttons/tab-buttons.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/lib/holocene/tab/tab-list.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
22 |
23 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/src/lib/holocene/tab/tab-panel.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/lib/holocene/table/table-header-row.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/lib/holocene/table/table-row.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/holocene/test-utilities.ts:
--------------------------------------------------------------------------------
1 | import type { Story } from '@storybook/addon-svelte-csf';
2 | import { expect, within } from '@storybook/test';
3 |
4 | type PlayFunction = Story['$$prop_def']['play'];
5 |
6 | export const shouldNotBeTransparent = (
7 | fn: (canvas: ReturnType) => PlayFunction,
8 | ) => {
9 | return ({ canvasElement }) => {
10 | const canvas = within(canvasElement);
11 | const element = fn(canvas);
12 | expect(element).not.toHaveStyle({ backgroundColor: 'rgba(0,0,0,0)' });
13 | };
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/holocene/toggle-button/toggle-buttons.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/lib/holocene/user-menu-mobile.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 | {#if $authUser.accessToken}
10 |
11 |
18 |
25 | {/if}
26 |
--------------------------------------------------------------------------------
/src/lib/i18n/locales/en/date-picker.ts:
--------------------------------------------------------------------------------
1 | export const Namespace = 'date-picker' as const;
2 |
3 | export const Strings = {
4 | 'next-month': 'Next Month',
5 | 'previous-month': 'Previous Month',
6 | } as const;
7 |
--------------------------------------------------------------------------------
/src/lib/i18n/locales/index.ts:
--------------------------------------------------------------------------------
1 | import { EN, English } from './en';
2 |
3 | export default {
4 | [EN]: English,
5 | };
6 |
--------------------------------------------------------------------------------
/src/lib/i18n/translate.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 | {#if translated !== key}
19 | {translated}
20 | {:else}
21 |
22 | {/if}
23 |
--------------------------------------------------------------------------------
/src/lib/i18n/translate.ts:
--------------------------------------------------------------------------------
1 | import { t } from 'i18next';
2 |
3 | import type { I18nKey, I18nReplace, I18nResources } from '.';
4 |
5 | const translateGeneric = (
6 | key: I18nKey,
7 | replace: I18nReplace = {},
8 | ): string => {
9 | const [namespace, ...keys] = key.split('.');
10 |
11 | if (namespace && keys.length > 0) {
12 | const k = keys.join('.');
13 | return t(`${namespace}:${k}`, replace);
14 | }
15 | };
16 |
17 | export const createTranslate = () => {
18 | return translateGeneric;
19 | };
20 |
21 | export const translate = createTranslate();
22 |
--------------------------------------------------------------------------------
/src/lib/layouts/workflow-padded-layout.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/lib/models/core-user.ts:
--------------------------------------------------------------------------------
1 | // Actions an authenticated user can do
2 | // Continue to add to Interface as more actions are added in core
3 | export interface CoreUser {
4 | namespaceWriteDisabled: (namespace: string) => boolean;
5 | }
6 |
7 | // Set context with this key
8 | export const CoreUserKey = 'CoreUser' as const;
9 |
--------------------------------------------------------------------------------
/src/lib/models/event-groups/get-group-for-event.ts:
--------------------------------------------------------------------------------
1 | import type { WorkflowEvent } from '$lib/types/events';
2 |
3 | import type { EventGroup, EventGroups } from './event-groups';
4 |
5 | export const getGroupForEvent = (
6 | event: WorkflowEvent,
7 | groups: EventGroups,
8 | ): EventGroup => {
9 | const eventId = event.id;
10 |
11 | for (const group of groups) {
12 | if (eventId === group.id) return group;
13 | for (const id of group.eventIds) {
14 | if (eventId === id) {
15 | return group;
16 | }
17 | }
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/src/lib/models/event-groups/get-last-event.ts:
--------------------------------------------------------------------------------
1 | import type { WorkflowEvent } from '$lib/types/events';
2 |
3 | import type { EventGroup } from './event-groups';
4 |
5 | export const getLastEvent = ({ events }: EventGroup): WorkflowEvent => {
6 | let latestEventKey = 0;
7 | let result: WorkflowEvent;
8 |
9 | for (const event of events.values()) {
10 | const k = Number(event.id);
11 | if (k >= latestEventKey) {
12 | latestEventKey = k;
13 | result = event;
14 | }
15 | }
16 |
17 | return result;
18 | };
19 |
--------------------------------------------------------------------------------
/src/lib/models/search-attribute-filters.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | SearchAttributes,
3 | SearchAttributeType,
4 | } from '$lib/types/workflows';
5 |
6 | export type SearchAttributeFilter = {
7 | attribute: Extract;
8 | type: SearchAttributeType;
9 | value: string;
10 | operator: string;
11 | parenthesis: string;
12 | conditional: string;
13 | customDate?: boolean;
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/models/workflow-actions.ts:
--------------------------------------------------------------------------------
1 | export enum Action {
2 | Cancel,
3 | Reset,
4 | Terminate,
5 | }
6 |
--------------------------------------------------------------------------------
/src/lib/models/workflow-status.ts:
--------------------------------------------------------------------------------
1 | import type { WorkflowStatus } from '$lib/types/workflows';
2 |
3 | export type WorkflowFilters = readonly (WorkflowStatus | 'All')[];
4 |
5 | export const workflowStatuses: Readonly = [
6 | 'Running',
7 | 'TimedOut',
8 | 'Completed',
9 | 'Failed',
10 | 'ContinuedAsNew',
11 | 'Canceled',
12 | 'Terminated',
13 | ] as const;
14 |
15 | export function isWorkflowStatusType(value: string): value is WorkflowStatus {
16 | return workflowStatuses.includes(value as WorkflowStatus);
17 | }
18 |
19 | export const workflowStatusFilters: WorkflowFilters = [
20 | 'All',
21 | ...workflowStatuses,
22 | ] as const;
23 |
--------------------------------------------------------------------------------
/src/lib/pages/workflow-history-json.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/pages/workflow-history.svelte:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/src/lib/services/settings-service.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest';
2 |
3 | import { isCloudMatch } from './settings-service';
4 |
5 | describe('isCloudMatch', () => {
6 | it('should return true for tmprl.cloud', () => {
7 | expect(isCloudMatch.test('tmprl.cloud')).toBe(true);
8 | });
9 |
10 | it('should return true for tmprl-test.cloud', () => {
11 | expect(isCloudMatch.test('tmprl.cloud')).toBe(true);
12 | });
13 |
14 | it('should return false for non Temporal domains', () => {
15 | expect(isCloudMatch.test(undefined as unknown as string)).toBe(false);
16 | expect(isCloudMatch.test('xxx.xxx')).toBe(false);
17 | expect(isCloudMatch.test('localhost:3000')).toBe(false);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/src/lib/stores/auth-user.ts:
--------------------------------------------------------------------------------
1 | import { get } from 'svelte/store';
2 |
3 | import { persistStore } from '$lib/stores/persist-store';
4 | import type { User } from '$lib/types/global';
5 |
6 | export const authUser = persistStore('AuthUser', {});
7 |
8 | export const getAuthUser = (): User => get(authUser);
9 |
10 | export const setAuthUser = (user: User) => {
11 | const { accessToken, idToken, name, email, picture } = user;
12 |
13 | if (!accessToken) {
14 | throw new Error('No access token');
15 | }
16 |
17 | authUser.set({
18 | accessToken,
19 | idToken,
20 | name,
21 | email,
22 | picture,
23 | });
24 | };
25 |
26 | export const clearAuthUser = () => {
27 | authUser.set({});
28 | };
29 |
--------------------------------------------------------------------------------
/src/lib/stores/batch-operations.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | import { pollBatchOperation } from '$lib/services/batch-service';
4 | import { persistStore } from '$lib/stores/persist-store';
5 |
6 | export const inProgressBatchOperation = writable<{
7 | namespace: string;
8 | jobId: string;
9 | }>();
10 |
11 | inProgressBatchOperation.subscribe(async (operation) => {
12 | if (operation) {
13 | await pollBatchOperation(operation).then(() =>
14 | inProgressBatchOperation.set(undefined),
15 | );
16 | }
17 | });
18 |
19 | export const autoRefresh = persistStore(
20 | 'auto-refresh-batch-operation',
21 | false,
22 | );
23 |
--------------------------------------------------------------------------------
/src/lib/stores/bulk-actions.ts:
--------------------------------------------------------------------------------
1 | import { derived } from 'svelte/store';
2 |
3 | import { bulkActionsEnabled } from '$lib/utilities/bulk-actions-enabled';
4 | import { isVersionNewer } from '$lib/utilities/version-check';
5 |
6 | import { isCloud, supportsAdvancedVisibility } from './advanced-visibility';
7 | import { settings } from './settings';
8 | import { temporalVersion } from './versions';
9 |
10 | export const supportsBulkActions = derived(
11 | [temporalVersion, supportsAdvancedVisibility, settings, isCloud],
12 | ([$temporalVersion, $supportsAdvancedVisibility, $settings, $isCloud]) =>
13 | ($isCloud ? true : isVersionNewer($temporalVersion, '1.18.0')) &&
14 | $supportsAdvancedVisibility &&
15 | bulkActionsEnabled($settings),
16 | );
17 |
--------------------------------------------------------------------------------
/src/lib/stores/capability-enablement.ts:
--------------------------------------------------------------------------------
1 | import { derived } from 'svelte/store';
2 |
3 | import { page } from '$app/stores';
4 |
5 | import { minimumVersionRequired } from '$lib/utilities/version-check';
6 |
7 | import { temporalVersion } from './versions';
8 |
9 | export const prefixSearchEnabled = derived(
10 | [page, temporalVersion],
11 | ([$page, $temporalVersion]) => {
12 | const serverVersionEnabled = minimumVersionRequired(
13 | '1.23.0',
14 | $temporalVersion,
15 | );
16 | const capabilitiesEnabled = Boolean(
17 | $page.data?.systemInfo?.capabilities?.prefixSearch,
18 | );
19 | return serverVersionEnabled || capabilitiesEnabled;
20 | },
21 | );
22 |
--------------------------------------------------------------------------------
/src/lib/stores/cluster.ts:
--------------------------------------------------------------------------------
1 | import { derived } from 'svelte/store';
2 |
3 | import { page } from '$app/stores';
4 |
5 | export const cluster = derived([page], ([$page]) => {
6 | return $page.data?.cluster;
7 | });
8 |
--------------------------------------------------------------------------------
/src/lib/stores/column-width.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | export const workflowEventsColumnWidth = writable(0);
4 | export const workflowEventsResponsiveColumnWidth = writable(0);
5 |
--------------------------------------------------------------------------------
/src/lib/stores/core-user.ts:
--------------------------------------------------------------------------------
1 | import { readable, type Readable } from 'svelte/store';
2 |
3 | import { getContext, hasContext } from 'svelte';
4 |
5 | import { type CoreUser, CoreUserKey } from '$lib/models/core-user';
6 |
7 | export const defaultCoreUserStore: Readable = readable({
8 | namespaceWriteDisabled: () => false,
9 | });
10 |
11 | export const coreUserStore = (): Readable => {
12 | if (!hasContext(CoreUserKey)) return defaultCoreUserStore;
13 | return getContext(CoreUserKey);
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/stores/data-converter-config.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | import type { DataEncoderStatus } from '$lib/types/global';
4 |
5 | export const lastDataConverterStatus =
6 | writable('notRequested');
7 |
8 | export function setLastDataConverterFailure(error?: string): void {
9 | lastDataConverterStatus.set('error');
10 | if (error) console.error(error);
11 | }
12 |
13 | export function setLastDataConverterSuccess(): void {
14 | lastDataConverterStatus.set('success');
15 | }
16 |
17 | export function resetLastDataConverterSuccess(): void {
18 | lastDataConverterStatus.set('notRequested');
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/stores/error.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | import type { NetworkError } from '$lib/types/global';
4 |
5 | export const networkError = writable(null);
6 |
--------------------------------------------------------------------------------
/src/lib/stores/import-events.test.ts:
--------------------------------------------------------------------------------
1 | import { get } from 'svelte/store';
2 |
3 | import { describe, expect, it } from 'vitest';
4 |
5 | import { importEventGroups, importEvents } from './import-events';
6 |
7 | describe('ImportEvents', () => {
8 | it('should get default values', () => {
9 | expect(get(importEvents)).toEqual([]);
10 | expect(get(importEventGroups)).toEqual([]);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/src/lib/stores/import-events.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | import type { EventGroups } from '$lib/models/event-groups/event-groups';
4 | import type { WorkflowEvents } from '$lib/types/events';
5 |
6 | export const importEvents = writable([]);
7 | export const importEventGroups = writable([]);
8 |
--------------------------------------------------------------------------------
/src/lib/stores/labs-mode.ts:
--------------------------------------------------------------------------------
1 | import { persistStore } from './persist-store';
2 |
3 | export const labsMode = persistStore('labsMode', false, true);
4 |
--------------------------------------------------------------------------------
/src/lib/stores/namespaces.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | import type { DescribeNamespaceResponse } from '$lib/types';
4 |
5 | import { persistStore } from './persist-store';
6 |
7 | export const lastUsedNamespace = persistStore('lastNamespace', 'default', true);
8 |
9 | export const namespaces = writable([]);
10 |
--------------------------------------------------------------------------------
/src/lib/stores/nav-open.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | import { persistStore } from './persist-store';
4 |
5 | export const navOpen = persistStore('navOpen', false);
6 |
7 | export const namespaceSelectorOpen = writable();
8 |
--------------------------------------------------------------------------------
/src/lib/stores/new-feature-tags.ts:
--------------------------------------------------------------------------------
1 | import { get } from 'svelte/store';
2 |
3 | import { persistStore } from './persist-store';
4 |
5 | export const viewedFeatureTags = persistStore('viewedFeatureTags', null);
6 |
7 | export const viewFeature = (feature: string): void => {
8 | let featureTags: string[] = get(viewedFeatureTags) ?? [];
9 | if (!featureTags.includes(feature)) {
10 | featureTags = [...featureTags, feature];
11 | viewedFeatureTags.set(featureTags);
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/lib/stores/previous-events.ts:
--------------------------------------------------------------------------------
1 | import { writable, type Writable } from 'svelte/store';
2 |
3 | import type { FetchEventsParameters } from '$lib/services/events-service';
4 |
5 | const emptyPrevious: FetchEventsParameters = {
6 | namespace: null,
7 | workflowId: null,
8 | runId: null,
9 | rawPayloads: null,
10 | sort: null,
11 | };
12 |
13 | export const previous: Writable =
14 | writable(emptyPrevious);
15 |
16 | export const clearPreviousEventParameters = (): void => {
17 | previous.set(emptyPrevious);
18 | };
19 |
--------------------------------------------------------------------------------
/src/lib/stores/reset-workflows.ts:
--------------------------------------------------------------------------------
1 | import { persistStore } from './persist-store';
2 |
3 | export const resetWorkflows = persistStore>(
4 | 'resetWorkflows',
5 | {},
6 | );
7 |
--------------------------------------------------------------------------------
/src/lib/stores/settings.ts:
--------------------------------------------------------------------------------
1 | import { derived } from 'svelte/store';
2 |
3 | import { page } from '$app/stores';
4 |
5 | export const settings = derived([page], ([$page]) => $page.data.settings);
6 |
--------------------------------------------------------------------------------
/src/lib/stores/task-queue-view.ts:
--------------------------------------------------------------------------------
1 | import { persistStore } from '$lib/stores/persist-store';
2 | import type { TaskQueueView } from '$lib/types/events';
3 |
4 | export const taskQueueView = persistStore(
5 | 'taskQueueView',
6 | 'workers',
7 | true,
8 | );
9 |
--------------------------------------------------------------------------------
/src/lib/stores/versions.ts:
--------------------------------------------------------------------------------
1 | import { derived } from 'svelte/store';
2 |
3 | import { cluster } from './cluster';
4 | import { settings } from './settings';
5 |
6 | export const temporalVersion = derived([cluster], ([$cluster]) => {
7 | return $cluster?.serverVersion;
8 | });
9 |
10 | export const uiVersion = derived([settings], ([$settings]) => {
11 | return $settings?.version;
12 | });
13 |
--------------------------------------------------------------------------------
/src/lib/svelte-mocks/app/environment.ts:
--------------------------------------------------------------------------------
1 | export function browser(): boolean {
2 | return true;
3 | }
4 |
--------------------------------------------------------------------------------
/src/lib/svelte-mocks/app/paths.ts:
--------------------------------------------------------------------------------
1 | export const base = '';
2 |
--------------------------------------------------------------------------------
/src/lib/theme/preset.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss';
2 |
3 | import temporal, { textStyles } from './plugin';
4 |
5 | const config = {
6 | content: ['./src/**/*.{html,js,svelte,ts}'],
7 | plugins: [temporal, textStyles],
8 | } satisfies Config;
9 |
10 | export default config;
11 |
--------------------------------------------------------------------------------
/src/lib/theme/types.d.ts:
--------------------------------------------------------------------------------
1 | type PaletteColor = import('./colors').PaletteColor;
2 | type Palette = import('./colors').Palette;
3 |
4 | type RGB = `${number} ${number} ${number}`;
5 | type HexColor = `#${string}`;
6 |
7 | type CSSVariable = `--${string}`;
8 | type ColorVariables = Readonly<
9 | Record
10 | >;
11 |
12 | type Shade =
13 | | 50
14 | | 100
15 | | 200
16 | | 300
17 | | 400
18 | | 500
19 | | 600
20 | | 700
21 | | 800
22 | | 900
23 | | 950
24 | | 'DEFAULT';
25 |
26 | type Shades = Record;
27 |
28 | type Color = [PaletteColor, Shade | undefined] | HexColor;
29 |
30 | type ColorName =
31 | | Exclude
32 | | `${PaletteColor}.${Shade}`;
33 |
--------------------------------------------------------------------------------
/src/lib/types/holocene.ts:
--------------------------------------------------------------------------------
1 | export type DataAttributes = {
2 | // [index: `data-${string}`]: any;
3 | 'data-testid'?: string;
4 | };
5 |
6 | export type ToastVariant = 'success' | 'error' | 'info' | 'warning' | 'primary';
7 |
8 | export type ToastPosition =
9 | | 'top-left'
10 | | 'top-center'
11 | | 'top-right'
12 | | 'bottom-left'
13 | | 'bottom-center'
14 | | 'bottom-right';
15 |
16 | export interface Toast {
17 | message: string;
18 | variant?: ToastVariant;
19 | id?: string;
20 | duration?: number;
21 | link?: string;
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/types/nexus.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | CallbackInfo,
3 | Endpoint,
4 | EndpointSpec,
5 | Callback as ICallback,
6 | } from '$lib/types';
7 |
8 | import type { EventLink } from './events';
9 |
10 | export interface NexusEndpointSpec extends EndpointSpec {
11 | descriptionString?: string;
12 | allowedCallerNamespaces?: string[];
13 | }
14 | export interface NexusEndpoint extends Endpoint {
15 | asyncOperationId?: string;
16 | state?: string;
17 | spec?: NexusEndpointSpec;
18 | }
19 |
20 | export interface Callback extends CallbackInfo {
21 | blockedReason?: string;
22 | callback?: CallbackWithLinks;
23 | }
24 | interface CallbackWithLinks extends ICallback {
25 | links?: EventLink[];
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/utilities/advanced-visibility-enabled.ts:
--------------------------------------------------------------------------------
1 | import type { ClusterInformation } from '$lib/types/global';
2 |
3 | import { isVersionNewer } from './version-check';
4 |
5 | export const advancedVisibilityEnabled = (
6 | cluster: ClusterInformation,
7 | version: string,
8 | ) => {
9 | return (
10 | cluster?.visibilityStore?.includes('elasticsearch') ||
11 | isVersionNewer(version, '1.19')
12 | );
13 | };
14 |
15 | export const advancedVisibilityEnabledWithOrderBy = (
16 | cluster: ClusterInformation,
17 | ) => {
18 | return cluster?.visibilityStore?.includes('elasticsearch');
19 | };
20 |
--------------------------------------------------------------------------------
/src/lib/utilities/btoa.ts:
--------------------------------------------------------------------------------
1 | import { BROWSER } from 'esm-env';
2 |
3 | export const base64EncodeUnicode = (str: string) => {
4 | return window.btoa(
5 | encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (_, p1) =>
6 | String.fromCharCode(parseInt(p1, 16)),
7 | ),
8 | );
9 | };
10 |
11 | export const btoa = (str: string, isBrowser = BROWSER): string => {
12 | if (!isBrowser) return str;
13 | return base64EncodeUnicode(str);
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/utilities/bulk-actions-enabled.ts:
--------------------------------------------------------------------------------
1 | import type { Settings } from '$lib/types/global';
2 |
3 | const ALLOWED_BULK_ACTIONS: (keyof Pick<
4 | Settings,
5 | | 'workflowSignalDisabled'
6 | | 'workflowCancelDisabled'
7 | | 'workflowResetDisabled'
8 | | 'workflowTerminateDisabled'
9 | >)[] = ['workflowCancelDisabled', 'workflowTerminateDisabled'];
10 |
11 | export const bulkActionsEnabled = (settings: Settings) => {
12 | if (settings.disableWriteActions) return false;
13 | if (settings.batchActionsDisabled) return false;
14 |
15 | return ALLOWED_BULK_ACTIONS.some((action) => !settings[action]);
16 | };
17 |
--------------------------------------------------------------------------------
/src/lib/utilities/cancel-in-progress.ts:
--------------------------------------------------------------------------------
1 | import type { WorkflowEvents } from '$lib/types/events';
2 | import type { WorkflowStatus } from '$lib/types/workflows';
3 |
4 | export const isCancelInProgress = (
5 | status: WorkflowStatus,
6 | eventHistory: WorkflowEvents,
7 | ) => {
8 | const isRunning = status === 'Running';
9 | const workflowCancelRequested = eventHistory?.some(
10 | (event) => event?.eventType === 'WorkflowExecutionCancelRequested',
11 | );
12 | return isRunning && workflowCancelRequested;
13 | };
14 |
--------------------------------------------------------------------------------
/src/lib/utilities/copy-to-clipboard.ts:
--------------------------------------------------------------------------------
1 | import { type Writable, writable } from 'svelte/store';
2 |
3 | type CopiedToClipboardReturnValue = {
4 | copy: (event: Event, content: string) => Promise;
5 | copied: Writable;
6 | };
7 |
8 | export const copyToClipboard = (
9 | timeout = 2000,
10 | ): CopiedToClipboardReturnValue => {
11 | const copied = writable(false);
12 |
13 | const copy = async (event: Event, content: string) => {
14 | event.preventDefault();
15 | event.stopPropagation();
16 | try {
17 | await navigator.clipboard.writeText(content);
18 | copied.set(true);
19 | setTimeout(() => {
20 | copied.set(false);
21 | }, timeout);
22 | } catch (error) {
23 | console.error(error);
24 | }
25 | };
26 |
27 | return { copy, copied };
28 | };
29 |
--------------------------------------------------------------------------------
/src/lib/utilities/dark-mode/dark-mode.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/lib/utilities/dark-mode/index.ts:
--------------------------------------------------------------------------------
1 | import DarkMode from './dark-mode.svelte';
2 |
3 | export default DarkMode;
4 | export {
5 | useDarkMode,
6 | useDarkModePreference,
7 | getNextDarkModePreference,
8 | } from './dark-mode';
9 |
10 | export type { DarkModePreference } from './dark-mode';
11 |
--------------------------------------------------------------------------------
/src/lib/utilities/encode-uri.ts:
--------------------------------------------------------------------------------
1 | export function encodeURIForSvelte(uri: string): string {
2 | if (uri) return encodeURIComponent(uri);
3 | return uri;
4 | }
5 |
6 | export function decodeURIForSvelte(uri: string): string {
7 | if (uri) return decodeURIComponent(uri);
8 | return uri;
9 | }
10 |
--------------------------------------------------------------------------------
/src/lib/utilities/event-formatting.ts:
--------------------------------------------------------------------------------
1 | import type { EventSortOrder } from '$lib/stores/event-view';
2 | import type { BooleanString } from '$lib/types/global';
3 |
4 | type DateFilterOptions = {
5 | compact: boolean;
6 | sortOrder: EventSortOrder;
7 | showElapsed: BooleanString;
8 | };
9 |
10 | export const getDateFilterValue = ({
11 | compact,
12 | sortOrder,
13 | showElapsed,
14 | }: DateFilterOptions) => {
15 | const isDefaultSortOrder = compact || sortOrder === 'descending';
16 | const isNotElapsedTime = showElapsed === 'false';
17 | const allDefaults = isDefaultSortOrder && isNotElapsedTime;
18 |
19 | if (allDefaults) {
20 | return undefined;
21 | }
22 |
23 | return `${sortOrder}:${showElapsed}`;
24 | };
25 |
--------------------------------------------------------------------------------
/src/lib/utilities/export-workflows.ts:
--------------------------------------------------------------------------------
1 | import type { WorkflowExecution } from '@temporalio/common';
2 |
3 | import { stringifyWithBigInt } from './parse-with-big-int';
4 |
5 | export const exportWorkflows = (
6 | workflows: WorkflowExecution[],
7 | page: number,
8 | ) => {
9 | const content = stringifyWithBigInt({ workflows }, null, 2);
10 | const fileName = `workflows-${workflows.length}-${page}-${Date.now()}.json`;
11 | download(content, fileName, 'text/plain');
12 |
13 | function download(content: string, fileName: string, contentType: string) {
14 | const a = document.createElement('a');
15 | const file = new Blob([content], { type: contentType });
16 | a.href = URL.createObjectURL(file);
17 | a.download = fileName;
18 | a.click();
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/src/lib/utilities/format-bytes.ts:
--------------------------------------------------------------------------------
1 | export const formatBytes = (bytes: number, decimals = 2) => {
2 | if (!+bytes) return '0 Bytes';
3 |
4 | const k = 1024;
5 | const dm = decimals < 0 ? 0 : decimals;
6 | const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
7 |
8 | const i = Math.floor(Math.log(bytes) / Math.log(k));
9 |
10 | return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
11 | };
12 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-api-origin.ts:
--------------------------------------------------------------------------------
1 | import { BROWSER } from 'esm-env';
2 |
3 | export function getApiOrigin(isBrowser = BROWSER): string | null {
4 | const endpoint = import.meta.env.VITE_API;
5 | const isRelative = !endpoint.startsWith('http');
6 |
7 | let origin = '';
8 |
9 | if (isRelative) {
10 | origin = isBrowser ? window.location.origin + endpoint : '';
11 | } else {
12 | origin = endpoint;
13 | }
14 |
15 | if (origin.endsWith('/')) origin = origin.slice(0, -1);
16 |
17 | return origin;
18 | }
19 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-clusters.ts:
--------------------------------------------------------------------------------
1 | import type { DescribeNamespaceResponse } from '$lib/types';
2 |
3 | export const getClusters = (namespace: DescribeNamespaceResponse): string => {
4 | const clusters = namespace?.replicationConfig?.clusters;
5 | const activeCluster = namespace?.replicationConfig?.activeClusterName;
6 | if (clusters?.length) {
7 | return clusters
8 | .map(({ clusterName }) => {
9 | if (clusterName === activeCluster) {
10 | return `${clusterName} (active)`;
11 | }
12 | return clusterName;
13 | })
14 | .join(', ');
15 | }
16 | return 'Unknown';
17 | };
18 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-context.ts:
--------------------------------------------------------------------------------
1 | import { getContext } from 'svelte';
2 |
3 | export function getAppContext(key: 'group'): boolean;
4 | export function getAppContext(key: string): unknown {
5 | return getContext(key);
6 | }
7 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-environment.ts:
--------------------------------------------------------------------------------
1 | export function getEnvironment(): string | null {
2 | return import.meta.env.VITE_TEMPORAL_UI_BUILD_TARGET ?? null;
3 | }
4 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-float-style.ts:
--------------------------------------------------------------------------------
1 | export const getFloatStyle = ({
2 | width,
3 | height,
4 | screenWidth,
5 | breakpoint = 1279, // 'xl' max-width breakpoint in tailwindcss
6 | }: {
7 | width?: number;
8 | height?: number;
9 | screenWidth: number;
10 | breakpoint?: number;
11 | }): string => {
12 | return width && height && screenWidth > breakpoint
13 | ? `position: absolute; right: ${width + 20}px; top: -${height}px`
14 | : '';
15 | };
16 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-group-status-and-count.ts:
--------------------------------------------------------------------------------
1 | import { workflowStatuses } from '$lib/models/workflow-status';
2 | import type { WorkflowStatus } from '$lib/types/workflows';
3 |
4 | import { decodePayload } from './decode-payload';
5 |
6 | export const getStatusAndCountOfGroup = (groups = []) => {
7 | return groups
8 | .map((group) => {
9 | const status = decodePayload(
10 | group?.groupValues[0],
11 | ) as unknown as WorkflowStatus;
12 | const count = parseInt(group.count);
13 | return {
14 | status,
15 | count,
16 | };
17 | })
18 | .sort((a, b) => {
19 | return (
20 | workflowStatuses.indexOf(a.status) - workflowStatuses.indexOf(b.status)
21 | );
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-namespace.ts:
--------------------------------------------------------------------------------
1 | import type { DescribeNamespaceResponse } from '$lib/types';
2 |
3 | type GetNamespaceParameters = {
4 | namespace?: string;
5 | defaultNamespace: string;
6 | namespaces: DescribeNamespaceResponse[];
7 | };
8 |
9 | export const getNamespace = ({
10 | namespace,
11 | defaultNamespace,
12 | namespaces,
13 | }: GetNamespaceParameters): string | undefined => {
14 | if (!namespace) return defaultNamespace;
15 | if (!namespaces?.length) return defaultNamespace;
16 |
17 | if (namespaces.find((ns) => ns?.namespaceInfo?.name === namespace)) {
18 | return namespace;
19 | }
20 |
21 | return undefined;
22 | };
23 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-query-types-from-error.ts:
--------------------------------------------------------------------------------
1 | export const getQueryTypesFromError = (message: string): { name: string }[] => {
2 | const indexOfOpeningBracket = message.indexOf('[');
3 | const indexOfClosingBracket = message.indexOf(']');
4 |
5 | return message
6 | .slice(indexOfOpeningBracket + 1, indexOfClosingBracket)
7 | .split(' ')
8 | .filter((query: string) => query !== '__stack_trace')
9 | .map((query: string) => {
10 | if (query.endsWith(',')) {
11 | return { name: query.slice(0, query.length - 1) };
12 | } else {
13 | return { name: query };
14 | }
15 | });
16 | };
17 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-truncated-word.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest';
2 |
3 | import { getTruncatedWord } from './get-truncated-word';
4 |
5 | describe('getTruncatedWord', () => {
6 | it('should return same word if the width is wider than word', () => {
7 | expect(getTruncatedWord('Running', 100)).toBe('Running');
8 | });
9 | it('should return truncated word if the width is shorter than word', () => {
10 | expect(getTruncatedWord('Running', 50)).toBe('Ru...');
11 | });
12 | it('should return "..." if the width is zero', () => {
13 | expect(getTruncatedWord('Running', 0)).toBe('...');
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-truncated-word.ts:
--------------------------------------------------------------------------------
1 | export const getTruncatedWord = (word: string, width: number): string => {
2 | if (word.length * 8.15 > width) {
3 | const truncLength = Math.floor(width / 8.15) - 4;
4 | if (truncLength > 0) {
5 | const trunc = word.slice(0, truncLength);
6 | return `${trunc}...`;
7 | } else {
8 | return '...';
9 | }
10 | }
11 | return word;
12 | };
13 |
--------------------------------------------------------------------------------
/src/lib/utilities/get-workflow-status-filter-code.ts:
--------------------------------------------------------------------------------
1 | import type { WorkflowStatus } from '$lib/types/workflows';
2 |
3 | type ExecutionStatusCodes = '1' | '2' | '3' | '4' | '5' | '6' | '7';
4 |
5 | export const getStatusFilterCode = (
6 | status: WorkflowStatus,
7 | ): ExecutionStatusCodes => {
8 | if (status === 'Running') return '1';
9 | if (status === 'Completed') return '2';
10 | if (status === 'Failed') return '3';
11 | if (status === 'Canceled') return '4';
12 | if (status === 'Terminated') return '5';
13 | if (status === 'ContinuedAsNew') return '6';
14 | if (status === 'TimedOut') return '7';
15 | };
16 |
--------------------------------------------------------------------------------
/src/lib/utilities/has.ts:
--------------------------------------------------------------------------------
1 | import { isObject } from './is';
2 |
3 | export const has = , V = unknown>(
4 | target: unknown,
5 | ...properties: K
6 | ): target is Record => {
7 | if (!hasAnyProperties(target)) return false;
8 | for (const property of properties) {
9 | if (!Object.prototype.hasOwnProperty.call(target, property)) return false;
10 | }
11 | return true;
12 | };
13 |
14 | export const hasAnyProperties = (
15 | obj: unknown,
16 | ): obj is ReturnType => {
17 | if (!isObject(obj)) return false;
18 | return !!Object.getOwnPropertyNames(obj).length;
19 | };
20 |
--------------------------------------------------------------------------------
/src/lib/utilities/is-authorized.ts:
--------------------------------------------------------------------------------
1 | import type { Settings, User } from '$lib/types/global';
2 |
3 | export const isAuthorized = (settings: Settings, user: User): boolean => {
4 | return !settings.auth.enabled || Boolean(user?.accessToken);
5 | };
6 |
--------------------------------------------------------------------------------
/src/lib/utilities/is-email.ts:
--------------------------------------------------------------------------------
1 | // http://emailregex.com/
2 | export const isEmail = (value: string): boolean => {
3 | return /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
4 | value,
5 | );
6 | };
7 |
--------------------------------------------------------------------------------
/src/lib/utilities/is-function.ts:
--------------------------------------------------------------------------------
1 | export const isFunction = (fn: unknown): fn is T => {
2 | return typeof fn === 'function';
3 | };
4 |
--------------------------------------------------------------------------------
/src/lib/utilities/is-http.ts:
--------------------------------------------------------------------------------
1 | export const validateHttps = (endpoint: string): boolean => {
2 | return endpoint?.substring(0, 8) === 'https://';
3 | };
4 |
5 | export const validateHttp = (endpoint: string): boolean => {
6 | return endpoint?.substring(0, 7) === 'http://';
7 | };
8 |
9 | export const validateHttpOrHttps = (endpoint: string): boolean => {
10 | return validateHttp(endpoint) || validateHttps(endpoint);
11 | };
12 |
--------------------------------------------------------------------------------
/src/lib/utilities/is-network-error.ts:
--------------------------------------------------------------------------------
1 | import type { NetworkError } from '$lib/types/global';
2 |
3 | import { has } from './has';
4 |
5 | export function isNetworkError(
6 | error: unknown | NetworkError,
7 | ): error is NetworkError {
8 | if (!error) return false;
9 | return has(error, 'statusCode', 'statusText', 'response');
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/utilities/is-pending-activity.ts:
--------------------------------------------------------------------------------
1 | import type { PendingActivity, PendingNexusOperation } from '$lib/types/events';
2 |
3 | import { has } from './has';
4 |
5 | export const isPendingActivity = (event: unknown): event is PendingActivity => {
6 | if (event === null) return false;
7 | if (typeof event !== 'object') return false;
8 | if (Array.isArray(event)) return false;
9 | if (has(event, 'activityType')) return true;
10 | return false;
11 | };
12 |
13 | export const isPendingNexusOperation = (
14 | event: unknown,
15 | ): event is PendingNexusOperation => {
16 | if (event === null) return false;
17 | if (typeof event !== 'object') return false;
18 | if (Array.isArray(event)) return false;
19 | if (has(event, 'operation') && has(event, 'endpoint')) return true;
20 | return false;
21 | };
22 |
--------------------------------------------------------------------------------
/src/lib/utilities/merge.ts:
--------------------------------------------------------------------------------
1 | type KeyValue = { [key: string]: string | number | boolean };
2 |
3 | export const merge = (
4 | first: T = {} as T,
5 | second: T = {} as T,
6 | ): T => {
7 | const result = { ...first };
8 |
9 | for (const key of Object.keys(second)) {
10 | const value = result[key];
11 |
12 | if (Array.isArray(value)) {
13 | result[key] = result[key].concat(second[key]);
14 | } else if (typeof value === 'object' && !Array.isArray(value)) {
15 | result[key] = merge(result[key], second[key]);
16 | } else {
17 | result[key] = second[key];
18 | }
19 | }
20 |
21 | return result;
22 | };
23 |
--------------------------------------------------------------------------------
/src/lib/utilities/namespace-url-pattern.ts:
--------------------------------------------------------------------------------
1 | import UrlPattern from 'url-pattern';
2 |
3 | // The default for this lib doesn't include .-_ which are all valid characters for a cloud namespace
4 | const urlPatternOpts = { segmentValueCharset: '.a-zA-Z0-9_-' };
5 |
6 | export const namespaceUrlPattern = new UrlPattern(
7 | '/namespaces/:namespace/*',
8 | urlPatternOpts,
9 | );
10 |
11 | export const workflowRoutePattern = new UrlPattern(
12 | '/namespaces/:namespace/workflows*',
13 | urlPatternOpts,
14 | );
15 |
--------------------------------------------------------------------------------
/src/lib/utilities/nexus-enabled.ts:
--------------------------------------------------------------------------------
1 | import type { Capabilities } from '$lib/types';
2 |
3 | export const nexusEnabled = (capabilities: Capabilities): boolean => {
4 | return capabilities?.nexus;
5 | };
6 |
--------------------------------------------------------------------------------
/src/lib/utilities/omit.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest';
2 |
3 | import { omit } from './omit';
4 |
5 | describe('omit', () => {
6 | it('should remove a key from an object', () => {
7 | const obj = { a: 1, b: 2 };
8 | const result = omit(obj, 'b');
9 |
10 | expect(result).toEqual({ a: 1 });
11 | });
12 |
13 | it('should not modify an object if given an invalid key', () => {
14 | const obj = { a: 1, b: 2 };
15 | const result = omit(obj, 'c');
16 |
17 | expect(result).toEqual({ a: 1, b: 2 });
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/src/lib/utilities/omit.ts:
--------------------------------------------------------------------------------
1 | type Omit = {
2 | // eslint-disable-next-line @typescript-eslint/ban-types
3 | (
4 | obj: Source,
5 | ...keys: KeysToOmit
6 | ): {
7 | [RemainingKey in Exclude<
8 | keyof Source,
9 | KeysToOmit[number]
10 | >]: Source[RemainingKey];
11 | };
12 | };
13 |
14 | export const omit: Omit = (object, ...keys) => {
15 | const result = {} as {
16 | [K in keyof typeof object]: (typeof object)[K];
17 | };
18 |
19 | for (const key of Object.keys(object)) {
20 | if (!keys.includes(key)) {
21 | result[key] = object[key];
22 | }
23 | }
24 |
25 | return result;
26 | };
27 |
--------------------------------------------------------------------------------
/src/lib/utilities/parse-with-big-int.ts:
--------------------------------------------------------------------------------
1 | import JSONbig from 'json-bigint';
2 |
3 | const JSONBigNative = JSONbig({
4 | useNativeBigInt: true,
5 | constructorAction: 'preserve',
6 | });
7 |
8 | export const parseWithBigInt = (content: string) => {
9 | try {
10 | return JSONBigNative.parse(content);
11 | } catch (e) {
12 | return JSON.parse(content);
13 | }
14 | };
15 |
16 | export const stringifyWithBigInt = (
17 | value: T,
18 | replacer?: (key: string, value: T) => T,
19 | space?: string | number,
20 | ) => JSONBigNative.stringify(value, replacer, space);
21 |
--------------------------------------------------------------------------------
/src/lib/utilities/payload-to-string.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest';
2 |
3 | import { payloadToString } from './payload-to-string';
4 |
5 | describe('payloadToString', () => {
6 | it('should combine payloads into a string if it is an array of payloads', () => {
7 | expect(payloadToString(['a'])).toBe('a');
8 | expect(payloadToString(['a', 'b', 'c'])).toBe('a, b, c');
9 | });
10 |
11 | it('should return the payload if the payload is not an array of payloads', () => {
12 | expect(payloadToString('a')).toBe('a');
13 | expect(payloadToString(['a, b, c'])).toBe('a, b, c');
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/src/lib/utilities/payload-to-string.ts:
--------------------------------------------------------------------------------
1 | import type { Payload } from '$lib/types';
2 |
3 | export const payloadToString = (value: Payload) => {
4 | if (Array.isArray(value)) return value.join(', ');
5 |
6 | return value;
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/utilities/pick.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest';
2 |
3 | import { pick } from './pick';
4 |
5 | describe('pick', () => {
6 | it('should only keep the keys specified', () => {
7 | const source = { a: 1, b: 2, c: 3 };
8 | expect(pick(source, 'a', 'c')).toEqual({ a: 1, c: 3 });
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/src/lib/utilities/pick.ts:
--------------------------------------------------------------------------------
1 | export const pick = (
2 | source: T,
3 | ...keys: K[]
4 | ): Pick => {
5 | const result: Partial> = {};
6 | for (const key of keys) {
7 | result[key] = source[key];
8 | }
9 | return result as Pick;
10 | };
11 |
--------------------------------------------------------------------------------
/src/lib/utilities/pluralize.ts:
--------------------------------------------------------------------------------
1 | export const pluralize = (word: string, count: number): string => {
2 | if (count === 1) {
3 | return word;
4 | }
5 | return `${word}s`;
6 | };
7 |
--------------------------------------------------------------------------------
/src/lib/utilities/query/is-search-attribute.ts:
--------------------------------------------------------------------------------
1 | import { get } from 'svelte/store';
2 |
3 | import { searchAttributes } from '$lib/stores/search-attributes';
4 |
5 | import { isString } from '../is';
6 |
7 | export const isSearchAttribute = (
8 | attribute: string,
9 | attributes = searchAttributes,
10 | ): attribute is string => {
11 | if (!isString(attribute)) return false;
12 | return !!get(attributes)[attribute];
13 | };
14 |
--------------------------------------------------------------------------------
/src/lib/utilities/refresh-rate.ts:
--------------------------------------------------------------------------------
1 | export const getExponentialBackoffSeconds = (
2 | initialIntervalSeconds: number,
3 | attempt: number,
4 | maxAttempts: number,
5 | ): number => {
6 | const maxIntervalSeconds = 3600;
7 | const growthFactor = Math.pow(
8 | maxIntervalSeconds / initialIntervalSeconds,
9 | 1 / maxAttempts,
10 | );
11 | const exponentialBackoff =
12 | initialIntervalSeconds * Math.pow(growthFactor, attempt);
13 | const intervalSeconds = Math.min(
14 | maxIntervalSeconds,
15 | Math.round(exponentialBackoff),
16 | );
17 | return intervalSeconds;
18 | };
19 |
--------------------------------------------------------------------------------
/src/lib/utilities/search-type-parameter.ts:
--------------------------------------------------------------------------------
1 | import { isString } from './is';
2 |
3 | type SearchType = 'basic' | 'advanced';
4 |
5 | export const isValidSearchType = (
6 | parameter: unknown,
7 | ): parameter is SearchType => {
8 | if (!isString(parameter)) return false;
9 | if (parameter === 'basic') return true;
10 | if (parameter === 'advanced') return true;
11 | return false;
12 | };
13 |
14 | export const getSearchType = (url: URL): SearchType => {
15 | const searchType = url.searchParams.get('search');
16 |
17 | if (isValidSearchType(searchType)) return searchType;
18 |
19 | url.searchParams.set('search', 'basic');
20 |
21 | return 'basic';
22 | };
23 |
--------------------------------------------------------------------------------
/src/lib/utilities/stack-trace/get-file-paths-from-stack-trace.ts:
--------------------------------------------------------------------------------
1 | import { getFilePathsFromGoStackTrace } from './get-file-paths-from-go-stack-trace';
2 | import { getFilePathsFromTypeScriptStackTrace } from './get-file-paths-from-typescript-stack-trace';
3 | import { isFromGoSDK } from './is-from-go-sdk';
4 | import { isFromTypeScriptSDK } from './is-from-typescript-sdk';
5 |
6 | export const getFilePathsFromStackTrace = (
7 | stackTraceText: string,
8 | ): { filePath: string; codeLine: number; character: number }[] => {
9 | if (isFromTypeScriptSDK(stackTraceText)) {
10 | return getFilePathsFromTypeScriptStackTrace(stackTraceText);
11 | } else if (isFromGoSDK(stackTraceText)) {
12 | return getFilePathsFromGoStackTrace(stackTraceText);
13 | } else return undefined;
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/utilities/stack-trace/get-sdk-origin.ts:
--------------------------------------------------------------------------------
1 | // The function takes a decoded StackTraceQuery response as a string
2 | // and returns the name of the SDK the response came from
3 |
4 | import { isFromGoSDK } from './is-from-go-sdk';
5 | import { isFromJavaSDK } from './is-from-java-sdk';
6 | import { isFromTypeScriptSDK } from './is-from-typescript-sdk';
7 |
8 | export const getSDKOrigin = (stackTraceText: string): string => {
9 | if (isFromTypeScriptSDK(stackTraceText)) return 'typescript';
10 | else if (isFromGoSDK(stackTraceText)) return 'go';
11 | else if (isFromJavaSDK(stackTraceText)) return 'java';
12 | else return null;
13 | };
14 |
--------------------------------------------------------------------------------
/src/lib/utilities/stack-trace/is-from-go-sdk.ts:
--------------------------------------------------------------------------------
1 | // The function takes a decoded StackTraceQuery response as a string
2 | // It returns true if the response came from the GoSDK and false otherwise
3 |
4 | export const isFromGoSDK = (stackTraceText: string): boolean => {
5 | return /\w.go:\d/.test(stackTraceText); //contains '.go:' followed by a digit
6 | };
7 |
--------------------------------------------------------------------------------
/src/lib/utilities/stack-trace/is-from-java-sdk.ts:
--------------------------------------------------------------------------------
1 | // The function takes a decoded StackTraceQuery response as a string
2 | // It returns true if the response came from the JavaSDK and false otherwise
3 |
4 | export const isFromJavaSDK = (stackTraceText: string): boolean => {
5 | return /\w.java:\d/.test(stackTraceText); //contains '.java:' followed by a digit
6 | };
7 |
--------------------------------------------------------------------------------
/src/lib/utilities/stack-trace/is-from-typescript-sdk.ts:
--------------------------------------------------------------------------------
1 | // The function takes a decoded StackTraceQuery response as a string
2 | // It returns true if the response came from the TypeScriptSDK and false otherwise
3 |
4 | export const isFromTypeScriptSDK = (stackTraceText: string): boolean => {
5 | return /\w.ts:\d/.test(stackTraceText); //contains '.ts:' followed by a digit
6 | };
7 |
--------------------------------------------------------------------------------
/src/lib/utilities/to-time-difference.ts:
--------------------------------------------------------------------------------
1 | import type { Timestamp } from '$lib/types';
2 |
3 | export const toTimeDifference = ({
4 | date,
5 | now = Date.now(),
6 | negativeDefault,
7 | }: {
8 | date: Timestamp;
9 | now?: number;
10 | negativeDefault?: string;
11 | }): string => {
12 | if (!date) return '';
13 | const start = String(date);
14 |
15 | try {
16 | const scheduled = Number(new Date(start));
17 | const timeFromNow = (scheduled - now) / 1000;
18 |
19 | if (negativeDefault && timeFromNow < 0) {
20 | return negativeDefault;
21 | }
22 |
23 | return !isNaN(timeFromNow) ? `${timeFromNow.toFixed(0)}s` : '';
24 | } catch (error) {
25 | return '';
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/src/lib/utilities/to-url.ts:
--------------------------------------------------------------------------------
1 | export const toURL = (
2 | url: string,
3 | params?: URLSearchParams | Record,
4 | hash?: string,
5 | ): string => {
6 | const isURLSearchParams = params instanceof URLSearchParams;
7 | if (params && !isURLSearchParams) params = new URLSearchParams(params);
8 | if (params) url = `${url}?${params}`;
9 | if (hash) url = `${url}#${hash}`;
10 | return url;
11 | };
12 |
--------------------------------------------------------------------------------
/src/lib/utilities/trim-trailing-slash.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest';
2 |
3 | import { trimTrailingSlash } from './trim-trailing-slash';
4 |
5 | describe('trimTrailingSlash', () => {
6 | it('should remove trailing slash from a string', () => {
7 | expect(trimTrailingSlash('http://cats.meow/')).toEqual('http://cats.meow');
8 | });
9 | it('should return original string if no trailing slash', () => {
10 | expect(trimTrailingSlash('http://cats.meow')).toEqual('http://cats.meow');
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/src/lib/utilities/trim-trailing-slash.ts:
--------------------------------------------------------------------------------
1 | export const trimTrailingSlash = (x: string): string => {
2 | return x.replace(/\/+$/, '');
3 | };
4 |
--------------------------------------------------------------------------------
/src/lib/utilities/unique.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest';
2 |
3 | import { unique } from './unique';
4 |
5 | describe('unique', () => {
6 | it('should remove duplicate values from an array', () => {
7 | expect([1, 2, 2, 3].filter(unique)).toEqual([1, 2, 3]);
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/src/lib/utilities/unique.ts:
--------------------------------------------------------------------------------
1 | export const unique = (value: T, index: number, self: T[]): boolean =>
2 | self.indexOf(value) === index;
3 |
--------------------------------------------------------------------------------
/src/lib/utilities/workflow-cancel-enabled.ts:
--------------------------------------------------------------------------------
1 | import type { CoreUser } from '$lib/models/core-user';
2 | import type { Settings } from '$lib/types/global';
3 |
4 | export const workflowCancelEnabled = (
5 | settings: Settings,
6 | coreUser: CoreUser,
7 | namespace: string,
8 | ): boolean => {
9 | return (
10 | !settings.disableWriteActions &&
11 | !settings.workflowCancelDisabled &&
12 | !coreUser.namespaceWriteDisabled(namespace)
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/utilities/workflow-create-disabled.ts:
--------------------------------------------------------------------------------
1 | import { get } from 'svelte/store';
2 |
3 | import type { Page } from '@sveltejs/kit';
4 |
5 | import { coreUserStore } from '$lib/stores/core-user';
6 |
7 | export const workflowCreateDisabled = (
8 | page: Page,
9 | namespace?: string,
10 | ): boolean => {
11 | const coreUser = coreUserStore();
12 | const namespaceWriteDisabled = get(coreUser).namespaceWriteDisabled(
13 | namespace ?? page.params.namespace,
14 | );
15 | if (page?.data?.settings?.disableWriteActions) return true;
16 | if (page?.data?.settings?.startWorkflowDisabled) return true;
17 |
18 | return namespaceWriteDisabled;
19 | };
20 |
--------------------------------------------------------------------------------
/src/lib/utilities/workflow-reset-enabled.ts:
--------------------------------------------------------------------------------
1 | import type { CoreUser } from '$lib/models/core-user';
2 | import type { Settings } from '$lib/types/global';
3 |
4 | export const workflowResetEnabled = (
5 | settings: Settings,
6 | coreUser: CoreUser,
7 | namespace: string,
8 | ): boolean => {
9 | return (
10 | !settings.disableWriteActions &&
11 | !settings.workflowResetDisabled &&
12 | !coreUser.namespaceWriteDisabled(namespace)
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/utilities/workflow-signal-enabled.ts:
--------------------------------------------------------------------------------
1 | import type { CoreUser } from '$lib/models/core-user';
2 | import type { Settings } from '$lib/types/global';
3 |
4 | export const workflowSignalEnabled = (
5 | settings: Settings,
6 | coreUser: CoreUser,
7 | namespace: string,
8 | ): boolean => {
9 | return (
10 | !settings.disableWriteActions &&
11 | !settings.workflowSignalDisabled &&
12 | !coreUser.namespaceWriteDisabled(namespace)
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/utilities/workflow-terminate-enabled.ts:
--------------------------------------------------------------------------------
1 | import type { CoreUser } from '$lib/models/core-user';
2 | import type { Settings } from '$lib/types/global';
3 |
4 | export const workflowTerminateEnabled = (
5 | settings: Settings,
6 | coreUser: CoreUser,
7 | namespace: string,
8 | ): boolean => {
9 | return (
10 | !settings.disableWriteActions &&
11 | !settings.workflowTerminateDisabled &&
12 | !coreUser.namespaceWriteDisabled(namespace)
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/utilities/workflow-update-enabled.ts:
--------------------------------------------------------------------------------
1 | import type { CoreUser } from '$lib/models/core-user';
2 | import type { Settings } from '$lib/types/global';
3 |
4 | export const workflowUpdateEnabled = (
5 | settings: Settings,
6 | coreUser: CoreUser,
7 | namespace: string,
8 | ): boolean => {
9 | return (
10 | !settings.disableWriteActions &&
11 | !settings.workflowUpdateDisabled &&
12 | !coreUser.namespaceWriteDisabled(namespace)
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/utilities/write-actions-are-allowed.ts:
--------------------------------------------------------------------------------
1 | import { get } from 'svelte/store';
2 |
3 | import { settings } from '$lib/stores/settings';
4 |
5 | export const writeActionsAreAllowed = (store = settings): boolean => {
6 | const isDisabled = get(store).disableWriteActions;
7 | return !isDisabled;
8 | };
9 |
--------------------------------------------------------------------------------
/src/lib/vendor/Temporal_Logo_Animation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/Temporal_Logo_Animation.gif
--------------------------------------------------------------------------------
/src/lib/vendor/Temporal_Logo_Animation.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/Temporal_Logo_Animation.mp4
--------------------------------------------------------------------------------
/src/lib/vendor/Temporal_Logo_Animation.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/Temporal_Logo_Animation.webm
--------------------------------------------------------------------------------
/src/lib/vendor/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/android-chrome-192x192.png
--------------------------------------------------------------------------------
/src/lib/vendor/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/android-chrome-512x512.png
--------------------------------------------------------------------------------
/src/lib/vendor/andromeda.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/andromeda.png
--------------------------------------------------------------------------------
/src/lib/vendor/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/apple-touch-icon.png
--------------------------------------------------------------------------------
/src/lib/vendor/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/banner.png
--------------------------------------------------------------------------------
/src/lib/vendor/empty-state-dark_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/empty-state-dark_2x.png
--------------------------------------------------------------------------------
/src/lib/vendor/empty-state-dark_4x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/empty-state-dark_4x.png
--------------------------------------------------------------------------------
/src/lib/vendor/empty-state-light_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/empty-state-light_2x.png
--------------------------------------------------------------------------------
/src/lib/vendor/empty-state-light_4x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/empty-state-light_4x.png
--------------------------------------------------------------------------------
/src/lib/vendor/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/favicon-16x16.png
--------------------------------------------------------------------------------
/src/lib/vendor/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/favicon-32x32.png
--------------------------------------------------------------------------------
/src/lib/vendor/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/favicon.ico
--------------------------------------------------------------------------------
/src/lib/vendor/sdk-logos/dot-net-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/sdk-logos/dot-net-logo.png
--------------------------------------------------------------------------------
/src/lib/vendor/sdk-logos/go-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/sdk-logos/go-logo.png
--------------------------------------------------------------------------------
/src/lib/vendor/sdk-logos/java-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/sdk-logos/java-logo.png
--------------------------------------------------------------------------------
/src/lib/vendor/sdk-logos/php-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/sdk-logos/php-logo.png
--------------------------------------------------------------------------------
/src/lib/vendor/sdk-logos/python-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/sdk-logos/python-logo.png
--------------------------------------------------------------------------------
/src/lib/vendor/sdk-logos/ruby-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/sdk-logos/ruby-logo.png
--------------------------------------------------------------------------------
/src/lib/vendor/sdk-logos/rust-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/sdk-logos/rust-logo.png
--------------------------------------------------------------------------------
/src/lib/vendor/sdk-logos/ts-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/lib/vendor/sdk-logos/ts-logo.png
--------------------------------------------------------------------------------
/src/lib/vendor/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Temporal Web UI",
3 | "short_name": "Temporal",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/src/routes/(app)/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { routeForWorkflows } from '$lib/utilities/route-for';
6 |
7 | export const load: PageLoad = async ({ parent }) => {
8 | const data = await parent();
9 |
10 | const defaultNamespace = data?.settings?.defaultNamespace;
11 | const isCloud = data.settings.runtimeEnvironment?.isCloud;
12 |
13 | if (isCloud) {
14 | redirect(
15 | 302,
16 | routeForWorkflows({
17 | namespace: defaultNamespace,
18 | }),
19 | );
20 | }
21 |
22 | return { defaultNamespace };
23 | };
24 |
--------------------------------------------------------------------------------
/src/routes/(app)/import/+layout.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/routes/(app)/import/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { routeForEventHistoryImport } from '$lib/utilities/route-for';
6 |
7 | export const load: PageLoad = async () => {
8 | const redirectPath = routeForEventHistoryImport();
9 |
10 | redirect(302, redirectPath);
11 | };
12 |
--------------------------------------------------------------------------------
/src/routes/(app)/import/events/+page.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/routes/(app)/import/events/[namespace]/[workflow]/[run]/history/+layout.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/routes/(app)/import/events/[namespace]/[workflow]/[run]/history/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { routeForEventHistoryImport } from '$lib/utilities/route-for';
6 |
7 | export const load: PageLoad = async function () {
8 | const redirectPath = routeForEventHistoryImport('feed');
9 | redirect(302, redirectPath);
10 | };
11 |
--------------------------------------------------------------------------------
/src/routes/(app)/import/events/[namespace]/[workflow]/[run]/history/json/+page.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/+layout.ts:
--------------------------------------------------------------------------------
1 | import type { LayoutData, LayoutLoad } from './$types';
2 |
3 | import { fetchSearchAttributesForNamespace } from '$lib/services/search-attributes-service';
4 | import { allSearchAttributes } from '$lib/stores/search-attributes';
5 |
6 | export const load: LayoutLoad = async ({
7 | params,
8 | parent,
9 | fetch,
10 | }): Promise => {
11 | await parent();
12 | const attributes = await fetchSearchAttributesForNamespace(
13 | params.namespace,
14 | fetch,
15 | );
16 |
17 | allSearchAttributes.set(attributes);
18 | };
19 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/+page.ts:
--------------------------------------------------------------------------------
1 | import type { PageLoad } from './$types';
2 |
3 | import { fetchNamespace } from '$lib/services/namespaces-service';
4 | import { getClusters } from '$lib/utilities/get-clusters';
5 |
6 | export const load: PageLoad = async function ({ params, parent, url }) {
7 | const { searchParams } = url;
8 |
9 | if (searchParams.has('time-range')) searchParams.delete('time-range');
10 |
11 | await parent();
12 | const namespace = await fetchNamespace(params.namespace);
13 | const clusters = getClusters(namespace);
14 |
15 | return {
16 | namespace,
17 | clusters,
18 | };
19 | };
20 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/batch-operations/+page.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/batch-operations/[jobId]/+page.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/schedules/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/schedules/[schedule]/+page.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/schedules/[schedule]/edit/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/schedules/create/+page.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/task-queues/+layout.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | {translate('common.task-queue')}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/task-queues/+page.svelte:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/routes/(app)/namespaces/[namespace]/task-queues/+page.svelte
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/task-queues/[queue]/+page.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/worker-deployments/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/worker-deployments/[deployment]/+layout.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/worker-deployments/[deployment]/+page.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/+page.ts:
--------------------------------------------------------------------------------
1 | export const ssr = false;
2 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/+page.ts:
--------------------------------------------------------------------------------
1 | import { error, redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { fetchWorkflowForRunId } from '$lib/services/workflow-service';
6 |
7 | export const load: PageLoad = async function ({ url, params }) {
8 | const { namespace, workflow: workflowId } = params;
9 | const { runId } = await fetchWorkflowForRunId({ namespace, workflowId });
10 |
11 | if (runId) {
12 | redirect(302, `${url.pathname}/${runId}`);
13 | } else {
14 | error(404);
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/+layout.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/+page.svelte:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/+page.svelte
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | export const load: PageLoad = async function ({ url }) {
6 | redirect(302, `${url.pathname}/history`);
7 | };
8 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/call-stack/+page.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/history.json/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { getEndpointForRawHistory } from '$lib/services/events-service';
6 |
7 | export const load: PageLoad = async function ({ parent, params }) {
8 | await parent();
9 |
10 | const { namespace, workflow, run } = params;
11 | const route = getEndpointForRawHistory({
12 | namespace,
13 | workflowId: workflow,
14 | runId: run,
15 | });
16 | redirect(302, route);
17 | };
18 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/history/+page.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { routeForEventHistory } from '$lib/utilities/route-for';
6 |
7 | export const load: PageLoad = async function ({ params }) {
8 | const { namespace, workflow, run } = params;
9 | const route = routeForEventHistory({
10 | namespace,
11 | workflow,
12 | run,
13 | });
14 | redirect(302, route);
15 | };
16 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/history/events/[id]/+page.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/history/feed/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { routeForEventHistory } from '$lib/utilities/route-for';
6 |
7 | export const load: PageLoad = async function ({ params }) {
8 | const { namespace, workflow, run } = params;
9 | const route = routeForEventHistory({
10 | namespace,
11 | workflow,
12 | run,
13 | });
14 | redirect(302, route);
15 | };
16 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/history/json/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { routeForEventHistory } from '$lib/utilities/route-for';
6 |
7 | export const load: PageLoad = async function ({ params }) {
8 | const { namespace, workflow, run } = params;
9 | const route = routeForEventHistory({
10 | namespace,
11 | workflow,
12 | run,
13 | });
14 | redirect(302, route);
15 | };
16 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/metadata/+page.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/pending-activities/+page.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/query/+page.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/relationships/+page.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/[workflow]/[run]/stack-trace/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { routeForCallStack } from '$lib/utilities/route-for';
6 |
7 | export const load: PageLoad = async function ({ params }) {
8 | redirect(302, routeForCallStack(params));
9 | };
10 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/start-workflow/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/routes/(app)/namespaces/[namespace]/workflows/start-workflow/+page.ts:
--------------------------------------------------------------------------------
1 | import { redirect } from '@sveltejs/kit';
2 |
3 | import type { PageLoad } from './$types';
4 |
5 | import { routeForWorkflows } from '$lib/utilities/route-for';
6 |
7 | export const load: PageLoad = async function ({ params, parent }) {
8 | const data = await parent();
9 | const disabled =
10 | data?.settings?.disableWriteActions ||
11 | data?.settings?.startWorkflowDisabled;
12 |
13 | if (disabled) {
14 | const { namespace } = params;
15 | redirect(302, routeForWorkflows({ namespace }));
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/src/routes/(app)/nexus/+layout.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 | Sorry, this feature is not available in this version of Temporal. Please
9 | enable Nexus or upgrade to a newer version.
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/routes/(app)/nexus/+page.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/routes/(app)/nexus/+page.ts:
--------------------------------------------------------------------------------
1 | import { fetchNexusEndpoints } from '$lib/services/nexus-service.js';
2 |
3 | import type { PageLoad } from '../$types';
4 |
5 | export const load: PageLoad = async ({ fetch, url }) => {
6 | const search = url.searchParams.get('search') || '';
7 | const endpoints = await fetchNexusEndpoints(search, fetch);
8 | return {
9 | endpoints,
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/src/routes/(app)/nexus/[id]/+layout.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 | {#if !endpoint}
13 |
20 | {:else}
21 |
22 | {/if}
23 |
--------------------------------------------------------------------------------
/src/routes/(app)/nexus/[id]/+page.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
19 |
20 |
--------------------------------------------------------------------------------
/src/routes/(login)/+layout.svelte:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/routes/(login)/+layout.ts:
--------------------------------------------------------------------------------
1 | import '../../app.css';
2 |
3 | import { error } from '@sveltejs/kit';
4 |
5 | import type { LayoutLoad } from './$types';
6 |
7 | import { fetchSettings } from '$lib/services/settings-service';
8 | import type { Settings } from '$lib/types/global';
9 |
10 | export const ssr = false;
11 |
12 | export const load: LayoutLoad = async function ({ fetch }) {
13 | const settings: Settings = await fetchSettings(fetch);
14 |
15 | if (!settings.auth.enabled) {
16 | error(404);
17 | }
18 |
19 | return {
20 | settings,
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/src/routes/+layout.ts:
--------------------------------------------------------------------------------
1 | import i18next from 'i18next';
2 | import LanguageDetector from 'i18next-browser-languagedetector';
3 |
4 | import type { LayoutData, LayoutLoad } from './$types';
5 |
6 | import { i18nNamespaces } from '$lib/i18n';
7 | import resources from '$lib/i18n/locales';
8 |
9 | export const ssr = false;
10 |
11 | export const load: LayoutLoad = async function (): LayoutData {
12 | i18next.use(LanguageDetector).init({
13 | fallbackLng: 'en',
14 | load: 'languageOnly',
15 | ns: i18nNamespaces,
16 | defaultNS: 'common',
17 | detection: {
18 | order: ['querystring', 'localStorage', 'navigator'],
19 | caches: ['localStorage'],
20 | lookupQuerystring: 'lng',
21 | lookupLocalStorage: 'locale',
22 | },
23 | resources,
24 | });
25 | };
26 |
--------------------------------------------------------------------------------
/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/ui/48ac8fe4f222c5af9b8663047cae46adfccd379e/static/favicon.ico
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss';
2 | import { fontFamily } from 'tailwindcss/defaultTheme';
3 |
4 | import temporal, { textStyles } from './src/lib/theme/plugin';
5 |
6 | const config = {
7 | content: ['./src/**/*.{html,js,svelte,ts}'],
8 | darkMode: ['selector', '[data-theme="dark"]'],
9 | theme: {
10 | fontFamily: {
11 | sans: ['Inter', ...fontFamily.sans],
12 | mono: ['Noto Sans Mono', ...fontFamily.mono],
13 | },
14 | extend: {
15 | animation: {
16 | 'spin-slow': 'spin 3s linear infinite',
17 | },
18 | zIndex: {
19 | 100: '100',
20 | },
21 | },
22 | },
23 | plugins: [temporal, textStyles],
24 | } satisfies Config;
25 |
26 | export default config;
27 |
--------------------------------------------------------------------------------
/temporal/activities/double.ts:
--------------------------------------------------------------------------------
1 | export default async function (value: number): Promise {
2 | return value * 2;
3 | }
4 |
--------------------------------------------------------------------------------
/temporal/activities/echo.ts:
--------------------------------------------------------------------------------
1 | export default async function (input: string): Promise {
2 | return `Received ${input}`;
3 | }
4 |
--------------------------------------------------------------------------------
/temporal/activities/index.ts:
--------------------------------------------------------------------------------
1 | export { default as echo } from './echo';
2 | export { default as double } from './double';
3 |
--------------------------------------------------------------------------------
/temporal/data-converter.ts:
--------------------------------------------------------------------------------
1 | import type { DataConverter } from '@temporalio/common';
2 |
3 | import { PayloadCodec } from './payload-codec';
4 |
5 | let dataConverter: DataConverter;
6 |
7 | export function getDataConverter(): DataConverter {
8 | if (!dataConverter) {
9 | dataConverter = createDataConverter();
10 | }
11 | return dataConverter;
12 | }
13 |
14 | function createDataConverter(): DataConverter {
15 | return {
16 | payloadCodecs: [new PayloadCodec()],
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/tests/e2e/storageState.json:
--------------------------------------------------------------------------------
1 | {
2 | "cookies": [],
3 | "origins": []
4 | }
--------------------------------------------------------------------------------
/tests/global-teardown.ts:
--------------------------------------------------------------------------------
1 | import { FullConfig } from '@playwright/test';
2 |
3 | import { disconnect, stopWorkflows } from '../temporal/client';
4 | import { getCodecServer } from '../temporal/codec-server';
5 | import { stopWorker } from '../temporal/workers';
6 | import { getTemporalServer } from '../utilities/temporal-server';
7 | import { getUIServer } from '../utilities/ui-server';
8 |
9 | export default async function (config: FullConfig) {
10 | if (config.metadata.mode === 'e2e') {
11 | const temporal = getTemporalServer();
12 | const codecServer = getCodecServer();
13 | const uiServer = getUIServer();
14 |
15 | await stopWorkflows();
16 | await stopWorker();
17 | await disconnect();
18 | await codecServer.stop();
19 | await uiServer.shutdown();
20 | await temporal.shutdown();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tests/integration/storageState.json:
--------------------------------------------------------------------------------
1 | {
2 | "cookies": [],
3 | "origins": []
4 | }
--------------------------------------------------------------------------------
/tests/test-utilities/accessibility-reporter/unique.ts:
--------------------------------------------------------------------------------
1 | export const unique = (items: T[]) =>
2 | items.reduce((acc: T[], current: T) => {
3 | const x = acc.find((item) => item.id === current.id);
4 | if (!x) {
5 | return acc.concat([current]);
6 | } else {
7 | return acc;
8 | }
9 | }, []);
10 |
--------------------------------------------------------------------------------
/tests/test-utilities/custom-matchers.ts:
--------------------------------------------------------------------------------
1 | import { expect } from '@playwright/test';
2 |
3 | expect.extend({
4 | async toHaveLocalStorageItem(page, key: string, expected: string) {
5 | const stored = await page.evaluate((key) => localStorage.getItem(key), key);
6 | const pass = stored === JSON.stringify(expected);
7 | return {
8 | pass,
9 | message: () =>
10 | pass
11 | ? `Expected local storage at key "${key}" not to have value "${JSON.stringify(expected)}"`
12 | : `Expected local storage at key "${key}" to have value ${JSON.stringify(expected)}, but got ${stored}`,
13 | };
14 | },
15 | });
16 |
17 | declare module '@playwright/test' {
18 | interface Matchers {
19 | toHaveLocalStorageItem(key: string, expected: string): Promise;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/test-utilities/mock-date.ts:
--------------------------------------------------------------------------------
1 | export const mockDate = () => {
2 | const _Date = window.Date;
3 |
4 | class FakeDate extends _Date {
5 | constructor(
6 | date:
7 | | number
8 | | string
9 | | Date = 'Wed Sept 19 2012 12:00:00 GMT-0600 (Mountain Daylight Time)',
10 | ) {
11 | super();
12 | return new _Date(date);
13 | }
14 | }
15 |
16 | window.Date = FakeDate as DateConstructor;
17 | };
18 |
--------------------------------------------------------------------------------
/tests/test-utilities/mock-local-storage.ts:
--------------------------------------------------------------------------------
1 | import type { Page } from '@playwright/test';
2 |
3 | export const setLocalStorage = async (
4 | key: string,
5 | value: string,
6 | page: Page,
7 | ) => {
8 | await page.addInitScript(
9 | (item) => {
10 | window.localStorage.setItem(item.key, item.value);
11 | },
12 | { key, value },
13 | );
14 | await page.reload();
15 | };
16 |
17 | export const removeLocalStorageItem = async (
18 | key: string,
19 | page: Page,
20 | ): Promise => {
21 | await page.addInitScript((key) => window.localStorage.removeItem(key), key);
22 | await page.reload();
23 | };
24 |
--------------------------------------------------------------------------------
/tests/test-utilities/mocks/batch-operations.ts:
--------------------------------------------------------------------------------
1 | import { Page } from '@playwright/test';
2 |
3 | export const CREATE_BATCH_OPERATION_API =
4 | '**/api/v1/namespaces/*/batch-operations*';
5 |
6 | export const DESCRIBE_BATCH_OPERATION_API =
7 | '**/api/v1/namespaces/*/batch-operations/*';
8 |
9 | export const mockCreateBatchOperationApi = (page: Page) => {
10 | return page.route(CREATE_BATCH_OPERATION_API, (route) => {
11 | route.fulfill({ json: {} });
12 | });
13 | };
14 |
15 | export const mockDescribeBatchOperationApi = (page: Page) => {
16 | return page.route(DESCRIBE_BATCH_OPERATION_API, (route) => {
17 | route.fulfill({ json: { state: 'COMPLETED', completeOperationCount: 10 } });
18 | });
19 | };
20 |
--------------------------------------------------------------------------------
/tests/test-utilities/mocks/query.ts:
--------------------------------------------------------------------------------
1 | import { Page } from '@playwright/test';
2 |
3 | const json = {
4 | queryResult: {
5 | payloads: [
6 | {
7 | an: 'error',
8 | },
9 | ],
10 | },
11 | queryRejected: null,
12 | };
13 |
14 | export default async function mockQueryApiWithStackTraceError(page: Page) {
15 | await page.route(
16 | '**/api/v1/namespaces/default/workflows/*/runs/*/query*',
17 | async (route) => {
18 | route.fulfill({ json });
19 | },
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/tests/test-utilities/mocks/task-queues.ts:
--------------------------------------------------------------------------------
1 | import type { Page } from '@playwright/test';
2 |
3 | export const TASK_QUEUES_API = '**/api/v1/namespaces/*/task-queues/*?*';
4 |
5 | const mockTaskQueues = {
6 | pollers: [
7 | {
8 | lastAccessTime: '2022-05-05T21:42:46.576609378Z',
9 | identity: '@poller',
10 | ratePerSecond: 100000,
11 | },
12 | ],
13 | taskQueueStatus: null,
14 | };
15 |
16 | export const mockTaskQueuesApi = (page: Page) => {
17 | return page.route(TASK_QUEUES_API, (route) => {
18 | return route.fulfill({ json: mockTaskQueues });
19 | });
20 | };
21 |
--------------------------------------------------------------------------------
/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "$src/*": ["../src/*"],
6 | "~/*": ["./*"]
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "rewrites": [
3 | {
4 | "source": "/(.*)",
5 | "destination": "/"
6 | }
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------