├── .devcontainer ├── devcontainer.json └── docker-compose.yml ├── .docker_env ├── .dockerignore ├── .eslintrc.js ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ └── docker_publish.yml ├── .gitignore ├── .prettierrc ├── .vscode ├── component-styles.code-snippets └── settings.json ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── NOTICE ├── README.md ├── docker-compose-backend-services.yml ├── docker-compose.yml ├── jest.config.ts ├── jest ├── browser │ ├── jest.config.ts │ ├── jest.resolver.js │ ├── jest.setup.ts │ └── jest.snapshot-resolver.js └── node │ ├── jest.config.ts │ └── jest.setup.ts ├── next.config.mjs ├── package-lock.json ├── package.json ├── public ├── next.svg └── vercel.svg ├── scripts ├── __tests__ │ └── update-server-host.node.ts └── update-server-host.ts ├── src ├── app │ ├── (Home) │ │ ├── (Domain) │ │ │ └── domains │ │ │ │ ├── [domain] │ │ │ │ └── [cluster] │ │ │ │ │ ├── [domainTab] │ │ │ │ │ ├── error.tsx │ │ │ │ │ ├── loading.tsx │ │ │ │ │ └── page.tsx │ │ │ │ │ └── layout.tsx │ │ │ │ └── error.tsx │ │ ├── (Domains) │ │ │ └── domains │ │ │ │ ├── error.tsx │ │ │ │ └── page.tsx │ │ ├── (Task List) │ │ │ └── domains │ │ │ │ └── [domain] │ │ │ │ └── [cluster] │ │ │ │ └── task-lists │ │ │ │ └── [taskListName] │ │ │ │ ├── error.tsx │ │ │ │ └── page.tsx │ │ ├── (Workflow) │ │ │ └── domains │ │ │ │ └── [domain] │ │ │ │ └── [cluster] │ │ │ │ └── workflows │ │ │ │ └── [workflowId] │ │ │ │ ├── [runId] │ │ │ │ ├── [workflowTab] │ │ │ │ │ ├── error.tsx │ │ │ │ │ ├── loading.tsx │ │ │ │ │ └── page.tsx │ │ │ │ └── layout.tsx │ │ │ │ └── error.tsx │ │ ├── error.tsx │ │ ├── layout.tsx │ │ ├── loading.tsx │ │ └── redirects │ │ │ └── domain │ │ │ └── [...domainParams] │ │ │ ├── error.tsx │ │ │ ├── loading.tsx │ │ │ ├── not-found.tsx │ │ │ └── page.tsx │ ├── api │ │ ├── clusters │ │ │ └── [cluster] │ │ │ │ └── route.ts │ │ ├── config │ │ │ └── route.ts │ │ ├── domains │ │ │ └── [domain] │ │ │ │ └── [cluster] │ │ │ │ ├── route.ts │ │ │ │ ├── task-list │ │ │ │ └── [taskListName] │ │ │ │ │ └── route.ts │ │ │ │ ├── update │ │ │ │ └── route.ts │ │ │ │ ├── workflows-basic │ │ │ │ └── route.ts │ │ │ │ └── workflows │ │ │ │ ├── [workflowId] │ │ │ │ └── [runId] │ │ │ │ │ ├── (actions) │ │ │ │ │ ├── cancel │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── reset │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── restart │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── signal │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── terminate │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── history │ │ │ │ │ └── route.ts │ │ │ │ │ ├── query │ │ │ │ │ ├── [queryName] │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ └── log │ │ │ └── route.ts │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ ├── not-found.tsx │ ├── page.tsx │ └── registry.tsx ├── assets │ ├── cadence-logo-black.svg │ ├── cadence-logo.svg │ └── error-icon.svg ├── components │ ├── app-nav-bar │ │ ├── app-nav-bar.styles.tsx │ │ └── app-nav-bar.tsx │ ├── async-props-loader │ │ ├── __test__ │ │ │ └── async-props-loader.test.tsx │ │ ├── async-props-loader.tsx │ │ └── async-props-loader.types.ts │ ├── copy-text-button │ │ ├── __tests__ │ │ │ └── copy-text-button.test.tsx │ │ ├── copy-text-button.tsx │ │ └── copy-text-button.types.ts │ ├── date-filter-v2 │ │ ├── __tests__ │ │ │ └── date-filter-v2.test.tsx │ │ ├── date-filter-v2.constants.ts │ │ ├── date-filter-v2.styles.ts │ │ ├── date-filter-v2.tsx │ │ ├── date-filter-v2.types.ts │ │ └── helpers │ │ │ ├── __tests__ │ │ │ ├── get-dayjs-from-date-filter-value.test.ts │ │ │ ├── is-relative-date-filter-value.test.ts │ │ │ ├── parse-date-filter-value.test.ts │ │ │ └── stringify-date-filter-value.test.ts │ │ │ ├── get-dayjs-from-date-filter-value.ts │ │ │ ├── is-relative-date-filter-value.ts │ │ │ ├── parse-date-filter-value.ts │ │ │ └── stringify-date-filter-value.ts │ ├── date-filter │ │ ├── __tests__ │ │ │ └── date-filter.test.tsx │ │ ├── date-filter.constants.ts │ │ ├── date-filter.styles.ts │ │ ├── date-filter.tsx │ │ └── date-filter.types.ts │ ├── error-boundary │ │ ├── __tests__ │ │ │ └── error-boundary.test.tsx │ │ ├── error-boundary.tsx │ │ └── error-boundary.types.ts │ ├── error-panel │ │ ├── __tests__ │ │ │ └── error-panel.test.tsx │ │ ├── error-panel.styles.ts │ │ ├── error-panel.tsx │ │ └── error-panel.types.ts │ ├── formatted-date │ │ ├── formatted-date.styles.ts │ │ ├── formatted-date.tsx │ │ └── formatted-date.types.ts │ ├── link │ │ ├── link.styles.ts │ │ ├── link.tsx │ │ └── link.types.ts │ ├── list-filter-multi │ │ ├── __tests__ │ │ │ └── list-filter-multi.test.tsx │ │ ├── list-filter-multi.styles.ts │ │ ├── list-filter-multi.tsx │ │ └── list-filter-multi.types.ts │ ├── list-filter │ │ ├── __tests__ │ │ │ └── list-filter.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── get-options-from-label-map.test.ts │ │ │ └── get-options-from-label-map.ts │ │ ├── list-filter.styles.ts │ │ ├── list-filter.tsx │ │ └── list-filter.types.ts │ ├── list-table-nested │ │ ├── __tests__ │ │ │ └── list-table-nested.test.tsx │ │ ├── list-table-nested.styles.ts │ │ ├── list-table-nested.tsx │ │ ├── list-table-nested.types.ts │ │ └── sublist-table │ │ │ ├── __tests__ │ │ │ └── sublist-table.test.tsx │ │ │ ├── sublist-table.styles.ts │ │ │ ├── sublist-table.tsx │ │ │ └── sublist-table.types.ts │ ├── list-table │ │ ├── __tests__ │ │ │ └── list-table.test.tsx │ │ ├── list-table.styles.ts │ │ ├── list-table.tsx │ │ └── list-table.types.ts │ ├── page-filters │ │ ├── __fixtures__ │ │ │ └── page-filters.fixtures.ts │ │ ├── __tests__ │ │ │ └── page-filters.test.tsx │ │ ├── hooks │ │ │ └── use-page-filters.ts │ │ ├── page-filters-fields │ │ │ ├── __tests__ │ │ │ │ └── page-filters-fields.test.tsx │ │ │ ├── page-filters-fields.styles.ts │ │ │ ├── page-filters-fields.tsx │ │ │ └── page-filters-fields.types.ts │ │ ├── page-filters-search │ │ │ ├── __tests__ │ │ │ │ └── page-filters-search.test.tsx │ │ │ ├── page-filters-search.styles.ts │ │ │ ├── page-filters-search.tsx │ │ │ └── page-filters-search.types.ts │ │ ├── page-filters-toggle │ │ │ ├── __tests__ │ │ │ │ └── page-filters-toggle.test.tsx │ │ │ ├── page-filters-toggle.styles.ts │ │ │ ├── page-filters-toggle.tsx │ │ │ └── page-filters-toggle.types.ts │ │ ├── page-filters.styles.ts │ │ ├── page-filters.tsx │ │ └── page-filters.types.ts │ ├── page-section │ │ ├── __test__ │ │ │ └── page-section.test.tsx │ │ ├── page-section.styles.ts │ │ └── page-section.tsx │ ├── page-tabs │ │ ├── __tests__ │ │ │ └── page-tabs.test.tsx │ │ ├── page-tabs.styles.ts │ │ ├── page-tabs.tsx │ │ └── page-tabs.types.ts │ ├── panel-section │ │ ├── panel-section.styles.ts │ │ ├── panel-section.tsx │ │ └── panel-section.types.ts │ ├── pretty-json-skeleton │ │ ├── pretty-json-skeleton.styles.ts │ │ ├── pretty-json-skeleton.tsx │ │ └── pretty-json-skeleton.types.ts │ ├── pretty-json │ │ ├── pretty-json.styles.ts │ │ ├── pretty-json.tsx │ │ └── pretty-json.types.tsx │ ├── section-loading-indicator │ │ ├── section-loading-indicator.styles.ts │ │ └── section-loading-indicator.tsx │ ├── segmented-control-rounded │ │ ├── __tests__ │ │ │ └── segmented-control-rounded.test.tsx │ │ ├── segmented-control-rounded.styles.ts │ │ ├── segmented-control-rounded.tsx │ │ └── segmented-control-rounded.types.ts │ ├── snackbar-provider │ │ ├── snackbar-provider.styles.ts │ │ ├── snackbar-provider.tsx │ │ └── snackbar-provider.types.ts │ ├── table-virtualized │ │ ├── __tests__ │ │ │ └── table-virtualized.test.tsx │ │ ├── table-virtualized.tsx │ │ └── table-virtualized.types.ts │ ├── table │ │ ├── __tests__ │ │ │ └── table.test.tsx │ │ ├── table-body-cell │ │ │ ├── table-body-cell.styles.ts │ │ │ └── table-body-cell.tsx │ │ ├── table-footer-message │ │ │ ├── table-footer-message.styles.ts │ │ │ └── table-footer-message.tsx │ │ ├── table-head-cell │ │ │ ├── __tests__ │ │ │ │ └── table-head-cell.test.tsx │ │ │ ├── table-head-cell.styles.ts │ │ │ ├── table-head-cell.tsx │ │ │ └── table-head-cell.types.ts │ │ ├── table-infinite-scroll-loader │ │ │ ├── __tests__ │ │ │ │ └── table-infinite-scroll-loader.test.tsx │ │ │ ├── table-infinite-scroll-loader.styles.ts │ │ │ ├── table-infinite-scroll-loader.tsx │ │ │ └── table-infinite-scroll-loader.types.ts │ │ ├── table-root │ │ │ ├── table-root.styles.ts │ │ │ └── table-root.tsx │ │ ├── table.tsx │ │ └── table.types.ts │ └── timeline │ │ ├── timeline.tsx │ │ └── timeline.types.ts ├── config │ ├── dynamic │ │ ├── dynamic.config.ts │ │ └── resolvers │ │ │ ├── clusters-public.ts │ │ │ ├── clusters-public.types.ts │ │ │ ├── clusters.ts │ │ │ ├── clusters.types.ts │ │ │ ├── extended-domain-info-enabled.ts │ │ │ ├── extended-domain-info-enabled.types.ts │ │ │ ├── schemas │ │ │ └── resolver-schemas.ts │ │ │ ├── workflow-actions-disabled-values.config.ts │ │ │ ├── workflow-actions-enabled.ts │ │ │ └── workflow-actions-enabled.types.ts │ ├── grpc │ │ ├── grpc-proto-dir-base-path.ts │ │ └── grpc-services-config.ts │ └── theme │ │ ├── base-web-icons-overrides.config.ts │ │ ├── theme-light.config.ts │ │ └── theme-provider-overrides.config.ts ├── hooks │ ├── __tests__ │ │ └── use-throttled-state.test.tsx │ ├── use-config-value │ │ ├── __tests__ │ │ │ └── use-config-value.test.ts │ │ ├── use-config-value.ts │ │ └── use-config-value.types.ts │ ├── use-merged-infinite-queries │ │ ├── __tests__ │ │ │ └── use-merged-infinite-queries.test.ts │ │ ├── helpers │ │ │ ├── get-merged-fetch-next-page.ts │ │ │ └── get-merged-query-status.ts │ │ ├── use-merged-infinite-queries-error.ts │ │ ├── use-merged-infinite-queries.ts │ │ └── use-merged-infinite-queries.types.ts │ ├── use-page-query-params │ │ ├── __fixtures__ │ │ │ └── page-query-params.fixtures.ts │ │ ├── __tests__ │ │ │ ├── use-page-query-params.test.tsx │ │ │ └── use-page-query-params.tst.ts │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ ├── get-array-val-for-multi-val-params.test.ts │ │ │ │ ├── get-page-query-params-values.test.ts │ │ │ │ └── get-updated-url-search.test.ts │ │ │ ├── get-array-val-for-multi-val-params.ts │ │ │ ├── get-page-query-params-values.ts │ │ │ └── get-updated-url-search.ts │ │ ├── use-page-query-params.tsx │ │ └── use-page-query-params.types.ts │ ├── use-previous-value.tsx │ ├── use-server-component-page-params.tsx │ ├── use-styletron-classes.tsx │ └── use-throttled-state.tsx ├── instrumentation.ts ├── providers │ ├── react-query-provider.tsx │ └── styletron-provider.tsx ├── route-handlers │ ├── cancel-workflow │ │ ├── __tests__ │ │ │ └── cancel-workflow.node.ts │ │ ├── cancel-workflow.ts │ │ ├── cancel-workflow.types.ts │ │ └── schemas │ │ │ └── cancel-workflow-request-body-schema.ts │ ├── describe-cluster │ │ ├── __tests__ │ │ │ └── describe-cluster.node.ts │ │ ├── describe-cluster.ts │ │ └── describe-cluster.types.ts │ ├── describe-domain │ │ ├── describe-domain.ts │ │ └── describe-domain.types.ts │ ├── describe-task-list │ │ ├── __fixtures__ │ │ │ └── mock-task-list-response.ts │ │ ├── describe-task-list.ts │ │ ├── describe-task-list.types.ts │ │ └── helpers │ │ │ ├── __tests__ │ │ │ └── get-workers-for-task-list.test.ts │ │ │ └── get-workers-for-task-list.ts │ ├── describe-workflow │ │ ├── describe-workflow.ts │ │ └── describe-workflow.types.ts │ ├── fetch-workflow-query-types │ │ ├── fetch-workflow-query-types.ts │ │ ├── fetch-workflow-query-types.types.ts │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── parse-error-message-for-query-types.test.ts │ │ │ └── parse-error-message-for-query-types.ts │ │ └── schemas │ │ │ └── query-types-data-schema.ts │ ├── get-config │ │ ├── __tests__ │ │ │ └── get-config.node.ts │ │ ├── get-config.ts │ │ ├── get-config.types.ts │ │ └── schemas │ │ │ └── get-config-query-params-schema.ts │ ├── get-workflow-history │ │ ├── get-workflow-history.ts │ │ ├── get-workflow-history.types.ts │ │ └── schemas │ │ │ └── get-workflow-history-query-params-schema.ts │ ├── list-workflows-basic │ │ ├── list-workflows-basic.ts │ │ ├── list-workflows-basic.types.ts │ │ └── schemas │ │ │ └── list-workflows-basic-query-params-schema.ts │ ├── list-workflows │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ ├── get-list-workflow-executions-query.test.ts │ │ │ │ └── map-executions-to-workflows.test.ts │ │ │ ├── get-list-workflow-executions-query.ts │ │ │ └── map-executions-to-workflows.ts │ │ ├── list-workflows.ts │ │ ├── list-workflows.types.ts │ │ └── schemas │ │ │ └── list-workflows-query-params-schema.ts │ ├── log-to-server │ │ ├── log-to-server.ts │ │ ├── log-to-server.types.ts │ │ └── schemas │ │ │ └── log-to-server-payload-schema.ts │ ├── query-workflow │ │ ├── query-workflow.ts │ │ ├── query-workflow.types.ts │ │ └── schemas │ │ │ └── valid-query-input-schema.ts │ ├── reset-workflow │ │ ├── __tests__ │ │ │ └── reset-workflow.node.ts │ │ ├── reset-workflow.ts │ │ ├── reset-workflow.types.ts │ │ └── schemas │ │ │ └── reset-workflow-request-body-schema.ts │ ├── restart-workflow │ │ ├── __tests__ │ │ │ └── restart-workflow.node.ts │ │ ├── restart-workflow.ts │ │ ├── restart-workflow.types.ts │ │ └── schemas │ │ │ └── restart-workflow-request-body-schema.ts │ ├── signal-workflow │ │ ├── __tests__ │ │ │ └── signal-workflow.node.ts │ │ ├── schemas │ │ │ ├── signal-workflow-input-schema.ts │ │ │ └── signal-workflow-request-body-schema.ts │ │ ├── signal-workflow.ts │ │ └── signal-workflow.types.ts │ ├── terminate-workflow │ │ ├── __tests__ │ │ │ └── terminate-workflow.node.ts │ │ ├── schemas │ │ │ └── terminate-workflow-request-body-schema.ts │ │ ├── terminate-workflow.ts │ │ └── terminate-workflow.types.ts │ └── update-domain │ │ ├── schemas │ │ └── update-domain-values-schema.ts │ │ ├── update-domain.ts │ │ └── update-domain.types.ts ├── styletron.ts ├── test-utils │ ├── msw-mock-handlers │ │ ├── helper │ │ │ └── msw-mock-endpoints.ts │ │ ├── msw-mock-handlers.tsx │ │ └── msw-mock-handlers.types.tsx │ ├── rtl.tsx │ ├── rtl.types.tsx │ ├── test-provider.tsx │ └── test-provider.types.tsx ├── utils │ ├── __tests__ │ │ ├── decode-url-params.test.ts │ │ ├── download-json.test.ts │ │ ├── global-ref.node.ts │ │ ├── lossless-json-parse.test.ts │ │ ├── lossless-json-stringify.test.ts │ │ ├── merge-sorted-arrays.test.ts │ │ └── sort-by.test.ts │ ├── config │ │ ├── __fixtures__ │ │ │ └── resolved-config-values.ts │ │ ├── __mocks__ │ │ │ └── get-config-value.ts │ │ ├── __tests__ │ │ │ ├── get-config-value.node.ts │ │ │ ├── get-config-value.test.ts │ │ │ ├── get-transformed-configs.test.ts │ │ │ └── transform-configs.test.ts │ │ ├── config.types.ts │ │ ├── get-config-value.ts │ │ ├── get-transformed-configs.ts │ │ ├── global-configs-ref.ts │ │ └── transform-configs.ts │ ├── data-formatters │ │ ├── __tests__ │ │ │ ├── format-date.test.ts │ │ │ ├── format-duration-to-seconds.test.ts │ │ │ ├── format-duration.test.ts │ │ │ ├── format-enum.test.ts │ │ │ ├── format-failure-details.test.ts │ │ │ ├── format-input-payload.test.ts │ │ │ ├── format-payload-map.test.ts │ │ │ ├── format-payload.test.ts │ │ │ ├── format-prev-auto-reset-points.test.ts │ │ │ ├── format-retry-policy.test.ts │ │ │ ├── format-timestamp-to-datetime.test.ts │ │ │ ├── format-workflow-event-id.test.ts │ │ │ ├── format-workflow-history-event-type.test.ts │ │ │ └── format-workflow-history.test.ts │ │ ├── format-date.ts │ │ ├── format-duration-to-seconds.ts │ │ ├── format-duration.ts │ │ ├── format-enum.ts │ │ ├── format-failure-details.ts │ │ ├── format-input-payload.ts │ │ ├── format-payload-map.ts │ │ ├── format-payload.ts │ │ ├── format-pending-workflow-history-event │ │ │ ├── __tests__ │ │ │ │ ├── index.test.ts │ │ │ │ └── index.test.ts.snapshot │ │ │ ├── format-pending-activity-start-event.ts │ │ │ ├── format-pending-decision-start-event.ts │ │ │ └── index.ts │ │ ├── format-prev-auto-reset-points.ts │ │ ├── format-retry-policy.ts │ │ ├── format-timestamp-to-datetime.ts │ │ ├── format-workflow-event-id.ts │ │ ├── format-workflow-history-event-type.ts │ │ ├── format-workflow-history-event │ │ │ ├── __tests__ │ │ │ │ ├── index.test.ts │ │ │ │ └── index.test.ts.snapshot │ │ │ ├── format-activity-task-cancel-requested-event.ts │ │ │ ├── format-activity-task-canceled-event.ts │ │ │ ├── format-activity-task-completed-event.ts │ │ │ ├── format-activity-task-failed-event.ts │ │ │ ├── format-activity-task-scheduled-event.ts │ │ │ ├── format-activity-task-started-event.ts │ │ │ ├── format-activity-task-timed-out-event.ts │ │ │ ├── format-cancel-timer-failed-event.ts │ │ │ ├── format-child-workflow-execution-canceled-event.ts │ │ │ ├── format-child-workflow-execution-canceled-terminated.ts │ │ │ ├── format-child-workflow-execution-completed-event.ts │ │ │ ├── format-child-workflow-execution-failed-event.ts │ │ │ ├── format-child-workflow-execution-started-event.ts │ │ │ ├── format-child-workflow-execution-timed-out-event.ts │ │ │ ├── format-decision-task-completed-event.ts │ │ │ ├── format-decision-task-failed-event.ts │ │ │ ├── format-decision-task-scheduled-event.ts │ │ │ ├── format-decision-task-started-event.ts │ │ │ ├── format-decision-timed-out-event.ts │ │ │ ├── format-external-workflow-execution-cancel-requested-event.ts │ │ │ ├── format-external-workflow-execution-signaled-event.ts │ │ │ ├── format-format-marker-recorded-event.ts │ │ │ ├── format-request-cancel-activity-task-failed-event.ts │ │ │ ├── format-request-cancel-external-workflow-execution-failed-event.ts │ │ │ ├── format-request-cancel-external-workflow-execution-initiated-event.ts │ │ │ ├── format-signal-external-workflow-execution-failed-event.ts │ │ │ ├── format-signal-external-workflow-execution-initiated-event.ts │ │ │ ├── format-start-child-workflow-execution-failed-event.ts │ │ │ ├── format-start-child-workflow-execution-initiated-event.ts │ │ │ ├── format-timer-canceled-event.ts │ │ │ ├── format-timer-fired-event.ts │ │ │ ├── format-timer-started-event.ts │ │ │ ├── format-upsert-workflow-search-attributes-event.ts │ │ │ ├── format-workflow-common-event-fields.ts │ │ │ ├── format-workflow-execution-cancel-requested-event.ts │ │ │ ├── format-workflow-execution-canceled-event.ts │ │ │ ├── format-workflow-execution-completed-event.ts │ │ │ ├── format-workflow-execution-continued-as-new-event.ts │ │ │ ├── format-workflow-execution-failed-event.ts │ │ │ ├── format-workflow-execution-signaled-event.ts │ │ │ ├── format-workflow-execution-started-event.ts │ │ │ ├── format-workflow-execution-terminated-event.ts │ │ │ ├── format-workflow-execution-timed-out-event.ts │ │ │ ├── format-workflow-history-event.type.ts │ │ │ └── index.ts │ │ ├── format-workflow-history.ts │ │ └── schema │ │ │ ├── format-history-event-schema.ts │ │ │ ├── format-history-pending-event-schema.ts │ │ │ ├── history-event-schema.ts │ │ │ └── pending-history-event-schema.ts │ ├── datetime │ │ ├── __tests__ │ │ │ ├── dayjs.test.ts │ │ │ ├── get-grpc-timestamp-from-iso.test.ts │ │ │ ├── parse-date-query-param.test.ts │ │ │ └── parse-grpc-timestamp.test.ts │ │ ├── dayjs.ts │ │ ├── get-grpc-timestamp-from-iso.ts │ │ ├── parse-date-query-param.ts │ │ └── parse-grpc-timestamp.ts │ ├── decode-url-params.ts │ ├── download-json.ts │ ├── global-ref.ts │ ├── grpc │ │ ├── grpc-client.ts │ │ ├── grpc-error.ts │ │ └── grpc-service.ts │ ├── logger │ │ ├── console │ │ │ ├── __tests__ │ │ │ │ └── register-console-logger.node.ts │ │ │ ├── helpers │ │ │ │ └── strip-escapes-from-next-log.ts │ │ │ ├── register-console-logger.constants.ts │ │ │ ├── register-console-logger.ts │ │ │ └── register-console-logger.types.ts │ │ ├── index.ts │ │ ├── logger-register.ts │ │ ├── logger.types.ts │ │ └── pino │ │ │ ├── helpers │ │ │ └── get-log-body.ts │ │ │ ├── pino.config.ts │ │ │ ├── pino.ts │ │ │ └── pino.types.ts │ ├── lossless-json-parse.ts │ ├── lossless-json-stringify.ts │ ├── media-query │ │ ├── __tests__ │ │ │ ├── get-media-queries-for-breakpoints.test.ts │ │ │ └── get-media-queries-margins.test.ts │ │ ├── get-media-queries-for-breakpoints.ts │ │ └── get-media-queries-margins.ts │ ├── merge-sorted-arrays.ts │ ├── msw │ │ └── node.ts │ ├── otel │ │ ├── otel-register.ts │ │ └── otel.types.ts │ ├── request │ │ ├── __tests__ │ │ │ ├── request.node.ts │ │ │ └── request.test.ts │ │ ├── index.ts │ │ ├── request-error.ts │ │ └── request.ts │ ├── route-handlers-middleware │ │ ├── __tests__ │ │ │ └── route-handler-with-middlewares.test.ts │ │ ├── config │ │ │ └── route-handlers-default-middlewares.config.ts │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── is-object-of-string-key-value.test.ts │ │ │ └── is-object-of-string-key-value.ts │ │ ├── index.ts │ │ ├── middlewares │ │ │ ├── __mocks__ │ │ │ │ └── grpc-cluster-methods.ts │ │ │ ├── __tests__ │ │ │ │ └── grpc-cluster-methods.test.ts │ │ │ └── grpc-cluster-methods.ts │ │ ├── route-handler-with-middlewares.ts │ │ └── route-handlers-middleware.types.ts │ └── sort-by.ts └── views │ ├── domain-page │ ├── __fixtures__ │ │ ├── domain-description.ts │ │ ├── domain-metadata.ts │ │ ├── domain-page-help-menu-config.ts │ │ └── domain-page-query-params.ts │ ├── config │ │ ├── domain-page-header-info-items.config.ts │ │ ├── domain-page-help-menu.config.ts │ │ ├── domain-page-metadata-extended-table.config.ts │ │ ├── domain-page-metadata-table.config.ts │ │ ├── domain-page-query-params.config.ts │ │ ├── domain-page-settings-form.config.ts │ │ └── domain-page-tabs.config.ts │ ├── domain-page-cluster-selector │ │ ├── __tests__ │ │ │ └── domain-page-cluster-selector.test.tsx │ │ ├── domain-page-cluster-selector.styles.ts │ │ └── domain-page-cluster-selector.tsx │ ├── domain-page-content │ │ ├── __tests__ │ │ │ └── domain-page-content.test.tsx │ │ ├── domain-page-content.styles.ts │ │ ├── domain-page-content.tsx │ │ └── domain-page-content.types.ts │ ├── domain-page-context-provider │ │ ├── domain-page-context-provider.tsx │ │ └── domain-page-context-provider.types.tsx │ ├── domain-page-error │ │ ├── __tests__ │ │ │ └── domain-page-error.test.tsx │ │ ├── domain-page-error.tsx │ │ └── domain-page-error.types.ts │ ├── domain-page-header-info-item │ │ ├── __tests__ │ │ │ └── domain-page-header-info-item.test.tsx │ │ ├── domain-page-header-info-item.styles.ts │ │ ├── domain-page-header-info-item.tsx │ │ └── domain-page-header-info-item.types.ts │ ├── domain-page-header-info-loader │ │ ├── __tests__ │ │ │ └── domain-page-header-info-loader.test.tsx │ │ ├── domain-page-header-info-loader.tsx │ │ └── domain-page-header-info-loader.types.ts │ ├── domain-page-header-info │ │ ├── __tests__ │ │ │ └── domain-page-header-info.test.tsx │ │ ├── domain-page-header-info.styles.ts │ │ ├── domain-page-header-info.tsx │ │ └── domain-page-header-info.types.ts │ ├── domain-page-header-status-tag │ │ ├── __tests__ │ │ │ └── domain-page-header-status-tag.test.tsx │ │ ├── domain-page-header-status-tag.tsx │ │ └── domain-page-header-status-tag.types.ts │ ├── domain-page-header │ │ ├── domain-page-header.styles.ts │ │ ├── domain-page-header.tsx │ │ └── domain-page-header.types.ts │ ├── domain-page-help-item-button │ │ ├── __tests__ │ │ │ └── domain-page-help-item-button.test.tsx │ │ ├── domain-page-help-item-button.styles.ts │ │ ├── domain-page-help-item-button.tsx │ │ └── domain-page-help-item-button.types.ts │ ├── domain-page-help │ │ ├── __tests__ │ │ │ └── domain-page-help.test.tsx │ │ ├── domain-page-help.styles.ts │ │ ├── domain-page-help.tsx │ │ └── domain-page-help.types.ts │ ├── domain-page-metadata-clusters │ │ ├── __tests__ │ │ │ └── domain-page-metadata-clusters.test.tsx │ │ ├── domain-page-metadata-clusters.styles.ts │ │ └── domain-page-metadata-clusters.tsx │ ├── domain-page-metadata-description │ │ ├── __tests__ │ │ │ └── domain-page-metadata-description.test.tsx │ │ ├── domain-page-metadata-description.styles.ts │ │ ├── domain-page-metadata-description.tsx │ │ └── domain-page-metadata-description.types.ts │ ├── domain-page-metadata-table │ │ ├── __tests__ │ │ │ └── domain-page-metadata-table.test.tsx │ │ ├── domain-page-metadata-table.styles.ts │ │ ├── domain-page-metadata-table.tsx │ │ └── domain-page-metadata-table.types.ts │ ├── domain-page-metadata-view-json │ │ ├── __tests__ │ │ │ └── domain-page-metadata-view-json.test.tsx │ │ ├── domain-page-metadata-view-json.styles.ts │ │ ├── domain-page-metadata-view-json.tsx │ │ └── domain-page-metadata-view-json.types.ts │ ├── domain-page-metadata │ │ ├── __tests__ │ │ │ └── domain-page-metadata.test.tsx │ │ ├── domain-page-metadata.tsx │ │ └── domain-page-metadata.types.ts │ ├── domain-page-settings-retention-period │ │ ├── __tests__ │ │ │ └── domain-page-settings-retention-period.test.tsx │ │ ├── domain-page-settings-retention-period.constants.ts │ │ ├── domain-page-settings-retention-period.styles.ts │ │ └── domain-page-settings-retention-period.tsx │ ├── domain-page-settings │ │ ├── __tests__ │ │ │ └── domain-page-settings.test.tsx │ │ ├── domain-page-settings.constants.ts │ │ ├── domain-page-settings.styles.ts │ │ ├── domain-page-settings.tsx │ │ └── domain-page-settings.types.ts │ ├── domain-page-tabs-error │ │ ├── __tests__ │ │ │ └── domain-page-tabs-error.test.tsx │ │ ├── domain-page-tabs-error.tsx │ │ └── domain-page-tabs-error.types.ts │ ├── domain-page-tabs │ │ ├── __tests__ │ │ │ └── domain-page-tabs.test.tsx │ │ ├── domain-page-tabs.styles.ts │ │ ├── domain-page-tabs.tsx │ │ └── domain-page-tabs.types.ts │ ├── domain-page.tsx │ ├── domain-page.types.ts │ └── hooks │ │ └── use-is-extended-metadata-enabled │ │ ├── get-is-extended-metadata-enabled-query-options.ts │ │ └── use-suspense-is-extended-metadata-enabled.ts │ ├── domain-workflows-archival │ ├── __tests__ │ │ └── domain-workflows-archival.test.tsx │ ├── config │ │ ├── domain-workflows-archival-disabled-panel.config.ts │ │ ├── domain-workflows-archival-filters.config.ts │ │ └── domain-workflows-archival-page-size.config.ts │ ├── domain-workflows-archival-disabled-panel │ │ ├── __tests__ │ │ │ └── domain-workflows-archival-disabled-panel.test.tsx │ │ ├── domain-workflows-archival-disabled-panel.styles.ts │ │ ├── domain-workflows-archival-disabled-panel.tsx │ │ └── domain-workflows-archival-disabled-panel.types.ts │ ├── domain-workflows-archival-header │ │ ├── __tests__ │ │ │ └── domain-workflows-archival-header.test.tsx │ │ ├── domain-workflows-archival-header.tsx │ │ └── domain-workflows-archival-header.types.ts │ ├── domain-workflows-archival-table │ │ ├── __tests__ │ │ │ └── domain-workflows-archival-table.test.tsx │ │ ├── domain-workflows-archival-table.tsx │ │ ├── domain-workflows-archival-table.types.ts │ │ └── helpers │ │ │ ├── __tests__ │ │ │ └── get-archival-error-panel-props.test.ts │ │ │ └── get-archival-error-panel-props.ts │ └── domain-workflows-archival.tsx │ ├── domain-workflows-basic │ ├── config │ │ ├── domain-workflows-basic-filters.config.ts │ │ ├── domain-workflows-basic-page-size.config.ts │ │ └── domain-workflows-basic-search-debounce-ms.config.ts │ ├── domain-workflows-basic-filters │ │ ├── __tests__ │ │ │ └── domain-workflows-basic-filters.test.tsx │ │ ├── domain-workflows-basic-filters.constants.ts │ │ ├── domain-workflows-basic-filters.styles.ts │ │ ├── domain-workflows-basic-filters.tsx │ │ ├── domain-workflows-basic-filters.types.ts │ │ └── helpers │ │ │ ├── __tests__ │ │ │ └── is-workflow-status-basic-visibility.test.ts │ │ │ └── is-workflow-status-basic-visibility.ts │ ├── domain-workflows-basic-table │ │ ├── __tests__ │ │ │ └── domain-workflows-basic-table.test.tsx │ │ ├── domain-workflows-basic-table.tsx │ │ ├── domain-workflows-basic-table.types.ts │ │ └── helpers │ │ │ ├── __tests__ │ │ │ └── get-workflows-basic-error-panel-props.test.ts │ │ │ └── get-workflows-basic-error-panel-props.ts │ ├── domain-workflows-basic.tsx │ ├── domain-workflows-basic.types.ts │ └── hooks │ │ ├── helpers │ │ ├── __tests__ │ │ │ ├── compare-basic-visibility-workflows.test.ts │ │ │ └── get-list-workflows-basic-query-options.test.ts │ │ ├── compare-basic-visibility-workflows.ts │ │ └── get-list-workflows-basic-query-options.ts │ │ └── use-list-workflows-basic.ts │ ├── domain-workflows │ ├── __tests__ │ │ └── domain-workflows.test.tsx │ ├── config │ │ ├── domain-workflows-filters.config.ts │ │ └── domain-workflows-page-size.config.ts │ ├── domain-workflows-advanced │ │ ├── __tests__ │ │ │ └── domain-workflows-advanced.test.tsx │ │ ├── domain-workflows-advanced.tsx │ │ └── domain-workflows-advanced.types.ts │ ├── domain-workflows-header │ │ ├── domain-workflows-header.tsx │ │ └── domain-workflows-header.types.ts │ ├── domain-workflows-table │ │ ├── __tests__ │ │ │ └── domain-workflows-table.test.tsx │ │ ├── domain-workflows-table.tsx │ │ ├── domain-workflows-table.types.ts │ │ └── helpers │ │ │ ├── __tests__ │ │ │ └── get-workflows-error-panel-props.test.ts │ │ │ └── get-workflows-error-panel-props.ts │ ├── domain-workflows.tsx │ └── helpers │ │ ├── __tests__ │ │ └── is-cluster-advanced-visibility-enabled.test.ts │ │ └── is-cluster-advanced-visibility-enabled.ts │ ├── domains-page │ ├── __fixtures__ │ │ └── domains.ts │ ├── config │ │ ├── domains-page-error-banner.config.ts │ │ ├── domains-page-filters.config.ts │ │ ├── domains-page-query-params.config.ts │ │ └── domains-table-columns.config.ts │ ├── domains-page-context-provider │ │ ├── domains-page-context-provider.tsx │ │ └── domains-page-context-provider.types.tsx │ ├── domains-page-error-banner │ │ ├── __tests__ │ │ │ └── domains-page-error-banner.test.tsx │ │ ├── domains-page-error-banner.styles.ts │ │ ├── domains-page-error-banner.tsx │ │ └── domains-page-error-banner.types.ts │ ├── domains-page-filters-cluster-name │ │ ├── domains-page-filters-cluster-name.styles.ts │ │ ├── domains-page-filters-cluster-name.tsx │ │ └── domains-page-filters-cluster-name.types.ts │ ├── domains-page-filters-deprecated │ │ ├── __tests__ │ │ │ └── domains-page-filters-deprecated.test.tsx │ │ ├── domains-page-filters-deprecated.styles.ts │ │ ├── domains-page-filters-deprecated.tsx │ │ └── domains-page-filters-deprecated.types.ts │ ├── domains-page-filters │ │ ├── domains-page-filters.tsx │ │ └── domains-page-filters.types.ts │ ├── domains-page-title-badge │ │ ├── domains-page-title-badge.styles.ts │ │ ├── domains-page-title-badge.tsx │ │ └── domains-page-title-badge.types.ts │ ├── domains-page-title │ │ ├── __tests__ │ │ │ └── domains-page-title.test.tsx │ │ ├── domains-page-title.styles.ts │ │ ├── domains-page-title.tsx │ │ └── domains-page-title.types.ts │ ├── domains-page.tsx │ ├── domains-page.types.ts │ ├── domains-table-cluster-cell │ │ ├── __tests__ │ │ │ └── domains-table-cluster-cell.test.tsx │ │ ├── domains-table-cluster-cell.styles.ts │ │ └── domains-table-cluster-cell.tsx │ ├── domains-table-domain-name-cell │ │ ├── __tests__ │ │ │ └── domains-table-domain-name-cell.test.tsx │ │ ├── domains-table-domain-name-cell.styles.ts │ │ └── domains-table-domain-name-cell.tsx │ ├── domains-table │ │ ├── domains-table.tsx │ │ └── domains-table.types.ts │ └── helpers │ │ ├── __tests__ │ │ ├── filter-irrelevant-domains.test.ts │ │ └── get-unique-domains.test.ts │ │ ├── filter-irrelevant-domains.ts │ │ ├── get-all-domains.ts │ │ └── get-unique-domains.ts │ ├── redirect-domain │ ├── __tests__ │ │ └── redirect-domain.node.ts │ ├── redirect-domain-error │ │ ├── redirect-domain-error.tsx │ │ └── redirect-domain-error.types.ts │ ├── redirect-domain-not-found │ │ └── redirect-domain-not-found.tsx │ ├── redirect-domain.tsx │ └── redirect-domain.types.ts │ ├── shared │ ├── domain-status-tag │ │ ├── __tests__ │ │ │ └── domain-status-tag.test.tsx │ │ ├── domain-status-tag.constants.ts │ │ ├── domain-status-tag.styles.ts │ │ ├── domain-status-tag.tsx │ │ └── domain-status-tag.types.ts │ ├── hooks │ │ ├── use-domain-description │ │ │ ├── get-domain-description-query-options.ts │ │ │ ├── use-domain-description.types.ts │ │ │ └── use-suspense-domain-description.ts │ │ ├── use-list-workflows.ts │ │ ├── use-list-workflows.types.ts │ │ └── use-suspense-cluster-config.ts │ ├── settings-form │ │ ├── __fixtures__ │ │ │ └── settings-form.fixtures.ts │ │ ├── __tests__ │ │ │ └── settings-form.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── get-initial-values.test.ts │ │ │ └── get-initial-values.ts │ │ ├── settings-form.styles.ts │ │ ├── settings-form.tsx │ │ └── settings-form.types.ts │ ├── task-list-label │ │ ├── __tests__ │ │ │ └── task-list-label.test.tsx │ │ ├── task-list-label.styles.ts │ │ ├── task-list-label.tsx │ │ └── task-list-label.types.ts │ ├── workflow-event-details-execution-link │ │ ├── __tests__ │ │ │ └── workflow-event-details-execution-link.test.tsx │ │ ├── workflow-event-details-execution-link.tsx │ │ └── workflow-event-details-execution-link.types.ts │ ├── workflow-history-event-details-task-list-link │ │ ├── __tests__ │ │ │ └── workflow-history-event-details-task-list-link.test.tsx │ │ ├── workflow-history-event-details-task-list-link.tsx │ │ └── workflow-history-event-details-task-list-link.types.ts │ ├── workflow-status-tag │ │ ├── __tests__ │ │ │ └── workflow-status-tag.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── is-workflow-status.test.ts │ │ │ └── is-workflow-status.ts │ │ ├── workflow-status-tag-icon │ │ │ ├── __tests__ │ │ │ │ └── workflow-status-tag-icon.test.tsx │ │ │ ├── workflow-status-tag-icon.styles.ts │ │ │ ├── workflow-status-tag-icon.tsx │ │ │ └── workflow-status-tag-icon.types.ts │ │ ├── workflow-status-tag.constants.ts │ │ ├── workflow-status-tag.styles.ts │ │ ├── workflow-status-tag.tsx │ │ └── workflow-status-tag.types.ts │ ├── workflows-header │ │ ├── __tests__ │ │ │ └── workflows-header.test.tsx │ │ ├── config │ │ │ ├── workflows-query-tooltip.config.ts │ │ │ └── workflows-search-debounce-ms.config.ts │ │ ├── workflows-header.styles.ts │ │ ├── workflows-header.tsx │ │ ├── workflows-header.types.ts │ │ ├── workflows-query-input │ │ │ ├── __tests__ │ │ │ │ └── workflows-query-input.test.tsx │ │ │ ├── workflows-query-input.styles.ts │ │ │ ├── workflows-query-input.tsx │ │ │ └── workflows-query-input.types.ts │ │ └── workflows-query-label │ │ │ ├── __tests__ │ │ │ └── workflows-query-label.test.tsx │ │ │ ├── workflows-query-label.styles.ts │ │ │ ├── workflows-query-label.tsx │ │ │ └── workflows-query-label.types.ts │ └── workflows-table │ │ ├── config │ │ ├── workflows-table-non-sortable.config.ts │ │ └── workflows-table-sortable.config.ts │ │ ├── workflows-table.tsx │ │ └── workflows-table.types.ts │ ├── task-list-page │ ├── __fixtures__ │ │ ├── mock-task-list-page-query-params-values.ts │ │ └── mock-task-list.tsx │ ├── config │ │ ├── task-list-filters.config.ts │ │ ├── task-list-page-query-params.config.ts │ │ └── task-list-workers-table.config.ts │ ├── helpers │ │ ├── __tests__ │ │ │ └── is-valid-table-column.test.ts │ │ └── is-valid-table-column.ts │ ├── task-list-error │ │ ├── __tests__ │ │ │ └── task-list-error.test.tsx │ │ ├── task-list-error.tsx │ │ └── task-list-error.types.ts │ ├── task-list-filters-handlers │ │ ├── __tests__ │ │ │ └── task-list-filters-handlers.test.tsx │ │ ├── task-list-filters-handlers.constants.ts │ │ ├── task-list-filters-handlers.styles.ts │ │ ├── task-list-filters-handlers.tsx │ │ └── task-list-filters-handlers.types.ts │ ├── task-list-filters │ │ ├── __tests__ │ │ │ └── task-list-filters.test.tsx │ │ ├── task-list-filters.styles.ts │ │ └── task-list-filters.tsx │ ├── task-list-loader │ │ ├── __tests__ │ │ │ └── task-list-loader.test.tsx │ │ ├── task-list-loader.constants.ts │ │ ├── task-list-loader.styles.ts │ │ ├── task-list-loader.tsx │ │ └── task-list-loader.types.ts │ ├── task-list-page.tsx │ ├── task-list-page.types.ts │ ├── task-list-workers-table-handler-icon │ │ ├── __tests__ │ │ │ ├── task-list-workers-table-handler-icon.test.tsx │ │ │ └── task-list-workers-table-handler-icon.test.tsx.snapshot │ │ ├── task-list-workers-table-handler-icon.styles.ts │ │ └── task-list-workers-table-handler-icon.tsx │ └── task-list-workers-table │ │ ├── __tests__ │ │ └── task-list-workers-table.test.tsx │ │ ├── helpers │ │ ├── __tests__ │ │ │ └── filter-workers.test.ts │ │ └── filter-workers.ts │ │ ├── task-list-workers-table.styles.ts │ │ ├── task-list-workers-table.tsx │ │ └── task-list-workers-table.types.ts │ ├── workflow-actions │ ├── __fixtures__ │ │ └── workflow-actions-config.tsx │ ├── __tests__ │ │ └── workflow-actions.test.tsx │ ├── config │ │ ├── workflow-actions-disabled-reasons.config.ts │ │ ├── workflow-actions-non-runnable-reasons.config.ts │ │ ├── workflow-actions-non-runnable-statuses.config.ts │ │ └── workflow-actions.config.ts │ ├── workflow-action-new-run-success-msg │ │ ├── __tests__ │ │ │ └── workflow-action-new-run-success-msg.test.tsx │ │ ├── workflow-action-new-run-success-msg.tsx │ │ └── workflow-action-new-run-success-msg.types.tsx │ ├── workflow-action-reset-form │ │ ├── __tests__ │ │ │ └── workflow-action-reset-form.test.tsx │ │ ├── schemas │ │ │ └── reset-workflow-form-schema.ts │ │ ├── workflow-action-reset-form.styles.ts │ │ ├── workflow-action-reset-form.tsx │ │ └── workflow-action-reset-form.types.ts │ ├── workflow-action-signal-form │ │ ├── __tests__ │ │ │ └── workflow-action-signal-form.test.tsx │ │ ├── schemas │ │ │ └── signal-workflow-form-schema.ts │ │ ├── workflow-action-signal-form.styles.ts │ │ ├── workflow-action-signal-form.tsx │ │ └── workflow-action-signal-form.types.ts │ ├── workflow-actions-menu │ │ ├── __tests__ │ │ │ └── workflow-actions-menu.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── get-action-disabled-reason.test.ts │ │ │ └── get-action-disabled-reason.ts │ │ ├── workflow-actions-menu.styles.ts │ │ ├── workflow-actions-menu.tsx │ │ └── workflow-actions-menu.types.ts │ ├── workflow-actions-modal-content │ │ ├── __tests__ │ │ │ └── workflow-actions-modal-content.test.tsx │ │ ├── workflow-actions-modal-content.styles.ts │ │ ├── workflow-actions-modal-content.tsx │ │ └── workflow-actions-modal-content.types.ts │ ├── workflow-actions-modal │ │ ├── __tests__ │ │ │ └── workflow-actions-modal.test.tsx │ │ ├── workflow-actions-modal.styles.ts │ │ ├── workflow-actions-modal.tsx │ │ └── workflow-actions-modal.types.ts │ ├── workflow-actions.styles.ts │ ├── workflow-actions.tsx │ └── workflow-actions.types.ts │ ├── workflow-history │ ├── __fixtures__ │ │ ├── all-workflow-event-types-attributes.ts │ │ ├── all-workflow-event-types.ts │ │ ├── mock-workflow-history-details-entries.ts │ │ ├── workflow-history-activity-events.ts │ │ ├── workflow-history-child-workflow-events.ts │ │ ├── workflow-history-decision-events.ts │ │ ├── workflow-history-event-groups.ts │ │ ├── workflow-history-pending-events.ts │ │ ├── workflow-history-request-cancel-external-workflow-events.ts │ │ ├── workflow-history-singal-external-workflow-events.ts │ │ ├── workflow-history-single-events.ts │ │ ├── workflow-history-timer-events.ts │ │ └── workflow-page-url-params.ts │ ├── __tests__ │ │ └── workflow-history.test.tsx │ ├── config │ │ ├── workflow-history-event-details.config.ts │ │ ├── workflow-history-filters.config.ts │ │ └── workflow-history-should-shorten-group-labels.config.ts │ ├── helpers │ │ ├── __tests__ │ │ │ ├── get-common-history-group-fields.test.ts │ │ │ ├── get-visible-groups-has-missing-events.test.ts │ │ │ └── group-history-events.test.ts │ │ ├── check-history-event-group │ │ │ ├── __tests__ │ │ │ │ ├── is-child-workflow-execution-event.test.ts │ │ │ │ ├── is-extended-activity-event.test.ts │ │ │ │ ├── is-extended-decision-event.test.ts │ │ │ │ ├── is-request-cancel-external-workflow-execution-event.test.ts │ │ │ │ ├── is-signal-external-workflow-execution-event.test.ts │ │ │ │ ├── is-signle-event.test.ts │ │ │ │ └── is-timer-event.test.ts │ │ │ ├── is-child-workflow-execution-event.ts │ │ │ ├── is-extended-activity-event.ts │ │ │ ├── is-extended-decision-event.ts │ │ │ ├── is-request-cancel-external-workflow-execution-event.ts │ │ │ ├── is-signal-external-workflow-execution-event.ts │ │ │ ├── is-single-event.ts │ │ │ └── is-timer-event.ts │ │ ├── get-common-history-group-fields.ts │ │ ├── get-history-event-group-id.ts │ │ ├── get-history-group-from-events │ │ │ ├── __tests__ │ │ │ │ ├── get-activity-group-from-events.test.ts │ │ │ │ ├── get-child-workflow-execution-group-from-events.test.ts │ │ │ │ ├── get-decision-group-from-events.test.ts │ │ │ │ ├── get-request-cancel-external-workflow-execution-group-from-events.test.ts │ │ │ │ ├── get-signal-external-workflow-execution-group-from-events.test.ts │ │ │ │ ├── get-single-event-group-from-events.test.ts │ │ │ │ └── get-timer-group-from-events.test.ts │ │ │ ├── get-activity-group-from-events.ts │ │ │ ├── get-child-workflow-execution-group-from-events.ts │ │ │ ├── get-decision-group-from-events.ts │ │ │ ├── get-request-cancel-external-workflow-execution-group-from-events.ts │ │ │ ├── get-signal-external-workflow-execution-group-from-events.ts │ │ │ ├── get-single-event-group-from-events.ts │ │ │ └── get-timer-group-from-events.ts │ │ ├── get-visible-groups-has-missing-events.ts │ │ ├── group-history-events.ts │ │ ├── pending-activities-info-to-events.ts │ │ ├── pending-decision-info-to-event.ts │ │ └── place-event-in-group-events.ts │ ├── hooks │ │ ├── __tests__ │ │ │ ├── use-event-expansion-toggle.test.ts │ │ │ ├── use-initial-selected-event.test.ts │ │ │ └── use-keep-loading-events.test.ts │ │ ├── use-event-expansion-toggle.ts │ │ ├── use-event-expansion-toggle.types.ts │ │ ├── use-initial-selected-event.ts │ │ ├── use-initial-selected-event.types.ts │ │ ├── use-keep-loading-events.ts │ │ └── use-keep-loading-events.types.ts │ ├── workflow-history-compact-event-card │ │ ├── __tests__ │ │ │ └── workflow-history-compact-event-card.test.tsx │ │ ├── workflow-history-compact-event-card.styles.ts │ │ ├── workflow-history-compact-event-card.tsx │ │ └── workflow-history-compact-event-card.types.ts │ ├── workflow-history-event-details-entry │ │ ├── __tests__ │ │ │ └── workflow-history-event-details-entry.test.tsx │ │ ├── workflow-history-event-details-entry.tsx │ │ └── workflow-history-event-details-entry.types.ts │ ├── workflow-history-event-details-group │ │ ├── __tests__ │ │ │ └── workflow-history-event-details-group.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── get-details-field-label.test.ts │ │ │ └── get-details-field-label.ts │ │ ├── workflow-history-event-details-group.styles.ts │ │ ├── workflow-history-event-details-group.tsx │ │ └── workflow-history-event-details-group.types.ts │ ├── workflow-history-event-details-json │ │ ├── __tests__ │ │ │ └── workflow-history-event-details-json.test.tsx │ │ ├── workflow-history-event-details-json.styles.ts │ │ ├── workflow-history-event-details-json.tsx │ │ └── workflow-history-event-details-json.types.ts │ ├── workflow-history-event-details-placeholder-text │ │ ├── __tests__ │ │ │ └── workflow-history-event-details-placeholder-text.test.tsx │ │ ├── workflow-history-event-details-placeholder-text.styles.ts │ │ ├── workflow-history-event-details-placeholder-text.tsx │ │ └── workflow-history-event-details-placeholder-text.types.ts │ ├── workflow-history-event-details │ │ ├── __tests__ │ │ │ └── workflow-history-event-details.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ ├── generate-history-event-details.test.ts │ │ │ │ └── is-pending-history-event.test.ts │ │ │ ├── generate-history-event-details.ts │ │ │ ├── get-history-event-field-render-config.ts │ │ │ └── is-pending-history-event.ts │ │ ├── workflow-history-event-details.styles.ts │ │ ├── workflow-history-event-details.tsx │ │ └── workflow-history-event-details.types.ts │ ├── workflow-history-event-status-badge │ │ ├── __tests__ │ │ │ ├── workflow-history-tab-event-status-badge.test.tsx │ │ │ └── workflow-history-tab-event-status-badge.test.tsx.snapshot │ │ ├── helpers │ │ │ ├── get-badge-container-size.ts │ │ │ └── get-badge-icon-size.ts │ │ ├── workflow-history-event-status-badge.constants.ts │ │ ├── workflow-history-event-status-badge.styles.ts │ │ ├── workflow-history-event-status-badge.tsx │ │ └── workflow-history-event-status-badge.types.ts │ ├── workflow-history-events-card │ │ ├── __tests__ │ │ │ └── workflow-history-events-card.test.tsx │ │ ├── workflow-history-events-card.styles.ts │ │ ├── workflow-history-events-card.tsx │ │ └── workflow-history-events-card.types.ts │ ├── workflow-history-events-duration-badge │ │ ├── __tests__ │ │ │ └── workflow-history-events-duration-badge.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── get-formatted-events-duration.test.ts │ │ │ └── get-formatted-events-duration.ts │ │ ├── workflow-history-events-duration-badge.styles.ts │ │ ├── workflow-history-events-duration-badge.tsx │ │ └── workflow-history-events-duration-badge.types.ts │ ├── workflow-history-expand-all-events-button │ │ ├── __tests__ │ │ │ └── workflow-history-expand-all-events-button.test.tsx │ │ ├── workflow-history-expand-all-events-button.tsx │ │ └── workflow-history-expand-all-events-button.types.ts │ ├── workflow-history-export-json-button │ │ ├── __tests__ │ │ │ └── workflow-history-export-json-button.test.tsx │ │ ├── workflow-history-export-json-button.tsx │ │ └── workflow-history-export-json-button.types.ts │ ├── workflow-history-filters-status │ │ ├── __tests__ │ │ │ └── workflow-history-filters-status.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── filter-events-by-event-status.test.ts │ │ │ └── filter-events-by-event-status.ts │ │ ├── workflow-history-filters-status.constants.ts │ │ ├── workflow-history-filters-status.styles.ts │ │ ├── workflow-history-filters-status.tsx │ │ └── workflow-history-filters-status.types.ts │ ├── workflow-history-filters-type │ │ ├── __tests__ │ │ │ └── workflow-history-filters-type.test.tsx │ │ ├── helpers │ │ │ └── filter-events-by-event-type.ts │ │ ├── workflow-history-filters-type.constants.ts │ │ ├── workflow-history-filters-type.styles.ts │ │ ├── workflow-history-filters-type.tsx │ │ └── workflow-history-filters-type.types.ts │ ├── workflow-history-group-label │ │ ├── __tests__ │ │ │ └── workflow-history-group-label.test.tsx │ │ ├── workflow-history-group-label.tsx │ │ └── workflow-history-group-label.types.ts │ ├── workflow-history-timeline-chart │ │ ├── __tests__ │ │ │ └── workflow-history-timeline-chart.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ ├── convert-event-group-to-timeline-item.test.ts │ │ │ │ ├── get-class-name-for-event-group.test.ts │ │ │ │ └── is-valid-class-name-key.test.ts │ │ │ ├── convert-event-group-to-timeline-item.ts │ │ │ ├── get-class-name-for-event-group.ts │ │ │ └── is-valid-class-name-key.ts │ │ ├── workflow-history-timeline-chart.styles.ts │ │ ├── workflow-history-timeline-chart.tsx │ │ └── workflow-history-timeline-chart.types.ts │ ├── workflow-history-timeline-group │ │ ├── __tests__ │ │ │ └── workflow-history-timeline-group.test.tsx │ │ ├── workflow-history-timeline-group.styles.ts │ │ ├── workflow-history-timeline-group.tsx │ │ └── workflow-history-timeline-group.types.ts │ ├── workflow-history-timeline-load-more │ │ ├── __tests__ │ │ │ └── workflow-history-timeline-load-more.test.tsx │ │ ├── workflow-history-timeline-load-more.styles.ts │ │ ├── workflow-history-timeline-load-more.tsx │ │ └── workflow-history-timeline-load-more.types.ts │ ├── workflow-history-timeline-reset-button │ │ ├── __tests__ │ │ │ └── workflow-history-timeline-reset-button.test.tsx │ │ ├── workflow-history-timeline-reset-button.tsx │ │ └── workflow-history-timeline-reset-button.types.ts │ ├── workflow-history.styles.ts │ ├── workflow-history.tsx │ └── workflow-history.types.ts │ ├── workflow-page │ ├── __fixtures__ │ │ ├── describe-workflow-response.ts │ │ └── workflow-details-params.ts │ ├── __tests__ │ │ └── workflow-page.test.tsx │ ├── config │ │ ├── workflow-page-cli-commands-groups.config.ts │ │ ├── workflow-page-cli-commands.config.ts │ │ ├── workflow-page-query-params.config.ts │ │ ├── workflow-page-status-refetch-interval.config.ts │ │ ├── workflow-page-tabs-contents-map.config.ts │ │ ├── workflow-page-tabs-error.config.ts │ │ └── workflow-page-tabs.config.ts │ ├── helpers │ │ ├── __tests__ │ │ │ ├── get-workflow-is-completed.test.ts │ │ │ ├── get-workflow-page-error-config.test.ts │ │ │ └── get-workflow-status-tag-props.test.ts │ │ ├── get-workflow-is-completed.ts │ │ ├── get-workflow-page-error-config.ts │ │ └── get-workflow-status-tag-props.ts │ ├── hooks │ │ ├── use-describe-workflow.ts │ │ └── use-describe-workflow.types.ts │ ├── workflow-page-cli-commands-button │ │ ├── __tests__ │ │ │ └── workflow-page-cli-commands-button.test.tsx │ │ └── workflow-page-cli-commands-button.tsx │ ├── workflow-page-cli-commands-modal │ │ ├── __tests__ │ │ │ └── workflow-page-cli-commands-modal.test.tsx │ │ ├── workflow-page-cli-commands-modal.styles.ts │ │ ├── workflow-page-cli-commands-modal.tsx │ │ └── workflow-page-cli-commands-modal.types.ts │ ├── workflow-page-error │ │ ├── __tests__ │ │ │ └── workflow-page-error.test.tsx │ │ ├── workflow-page-error.tsx │ │ └── workflow-page-error.types.ts │ ├── workflow-page-header │ │ ├── __tests__ │ │ │ └── workflow-page-header.test.tsx │ │ ├── workflow-page-header.styles.ts │ │ ├── workflow-page-header.tsx │ │ └── workflow-page-header.types.ts │ ├── workflow-page-pending-events-badge │ │ ├── __tests__ │ │ │ └── workflow-page-pending-events-badge.test.tsx │ │ ├── workflow-page-pending-events-badge.styles.ts │ │ └── workflow-page-pending-events-badge.tsx │ ├── workflow-page-status-tag │ │ └── workflow-page-status-tag.tsx │ ├── workflow-page-tab-content │ │ ├── __tests__ │ │ │ └── workflow-page-tab-content.test.tsx │ │ ├── workflow-page-tab-content.styles.ts │ │ ├── workflow-page-tab-content.tsx │ │ └── workflow-page-tab-content.types.ts │ ├── workflow-page-tabs-error │ │ ├── __tests__ │ │ │ └── workflow-page-tabs-error.test.tsx │ │ ├── workflow-page-tabs-error.tsx │ │ └── workflow-page-tabs-error.types.ts │ ├── workflow-page-tabs │ │ ├── __tests__ │ │ │ └── workflow-page-tabs.test.tsx │ │ ├── workflow-page-tabs.styles.ts │ │ ├── workflow-page-tabs.tsx │ │ └── workflow-page-tabs.types.ts │ ├── workflow-page.tsx │ └── workflow-page.types.ts │ ├── workflow-queries │ ├── __tests__ │ │ └── workflow-queries.test.tsx │ ├── config │ │ └── workflow-queries-empty-panel.config.ts │ ├── helpers │ │ ├── __tests__ │ │ │ └── get-workflow-query-status.test.ts │ │ └── get-workflow-query-status.ts │ ├── hooks │ │ └── use-workflow-queries.ts │ ├── workflow-queries-result-json │ │ ├── __tests__ │ │ │ └── workflow-queries-result-json.test.tsx │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ └── get-query-json-content.test.ts │ │ │ └── get-query-json-content.ts │ │ ├── workflow-queries-result-json.styles.ts │ │ ├── workflow-queries-result-json.tsx │ │ └── workflow-queries-result-json.types.ts │ ├── workflow-queries-status-icon │ │ ├── __tests__ │ │ │ └── workflow-queries-status-icon.test.tsx │ │ ├── workflow-queries-status-icon.tsx │ │ └── workflow-queries-status-icon.types.ts │ ├── workflow-queries-tile-input │ │ ├── __tests__ │ │ │ └── workflow-queries-tile-input.test.tsx │ │ ├── workflow-queries-tile-input.styles.ts │ │ ├── workflow-queries-tile-input.tsx │ │ └── workflow-queries-tile-input.types.ts │ ├── workflow-queries-tile │ │ ├── __tests__ │ │ │ └── workflow-queries-tile.test.tsx │ │ ├── workflow-queries-tile.styles.ts │ │ ├── workflow-queries-tile.tsx │ │ └── workflow-queries-tile.types.ts │ ├── workflow-queries.constants.ts │ ├── workflow-queries.styles.ts │ ├── workflow-queries.tsx │ └── workflow-queries.types.ts │ ├── workflow-stack-trace │ ├── __tests__ │ │ └── workflow-stack-trace.test.tsx │ ├── workflow-stack-trace.styles.ts │ └── workflow-stack-trace.tsx │ └── workflow-summary-tab │ ├── __tests__ │ └── workflow-summary-tab.test.tsx │ ├── config │ └── workflow-summary-tab-details.config.ts │ ├── helpers │ ├── __tests__ │ │ └── get-workflow-result-json.test.ts │ └── get-workflow-result-json.ts │ ├── workflow-summary-tab-details │ ├── __tests__ │ │ └── workflow-summary-tab-details.test.tsx │ ├── workflow-summary-tab-details.styles.ts │ ├── workflow-summary-tab-details.tsx │ └── workflow-summary-tab-details.types.ts │ ├── workflow-summary-tab-json-view │ ├── __tests__ │ │ └── workflow-summary-tab-json-view.test.tsx │ ├── workflow-summary-tab-json-view.constants.tsx │ ├── workflow-summary-tab-json-view.styles.ts │ ├── workflow-summary-tab-json-view.tsx │ └── workflow-summary-tab-json-view.types.ts │ ├── workflow-summary-tab.styles.ts │ └── workflow-summary-tab.tsx └── tsconfig.json /.docker_env: -------------------------------------------------------------------------------- 1 | CADENCE_CLUSTERS_NAMES=cluster0 2 | CADENCE_GRPC_PEERS="127.0.0.1:7833" 3 | CADENCE_GRPC_SERVICES_NAMES=cadence-frontend 4 | CADENCE_WEB_PORT=8088 5 | CADENCE_WEB_HOSTNAME=0.0.0.0 6 | CADENCE_ADMIN_SECURITY_TOKEN="" 7 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for more information: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | # https://containers.dev/guide/dependabot 6 | 7 | version: 2 8 | updates: 9 | - package-ecosystem: "devcontainers" 10 | directory: "/" 11 | schedule: 12 | interval: weekly 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | #generated 39 | src/__generated__ 40 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "jsxBracketSameLine": false 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "editor.tabSize": 2, 4 | "editor.insertSpaces": true, 5 | "editor.codeActionsOnSave": { 6 | "source.fixAll": "explicit" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Developing Cadence's Web UI 2 | 3 | This doc is intended for contributors to `cadence-web` 4 | 5 | **Note:** All contributors will be asked to sign [Uber Contributor License Agreement](http://t.uber.com/cla) during the PR process. 6 | 7 | ## Development Environment 8 | 9 | Node.js. Check [package.json](https://github.com/cadence-workflow/cadence-web/blob/master/package.json) for the current (engines > node) version required. 10 | 11 | For development check the [Building & developing cadence-web](./README.md#building-&-developing-cadence-web)section 12 | 13 | ## Working with the source code 14 | 15 | Follow [this great guide](https://gist.github.com/Chaser324/ce0505fbed06b947d962) on how to work with a GitHub fork and submit a pull request. 16 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | cadence_web: 4 | container_name: cadence_web 5 | build: 6 | context: . #if your Dockerfile is not at the same level change the path here (./cadence_web) 7 | target: dev 8 | restart: always 9 | command: npm run dev 10 | environment: 11 | - NODE_ENV=development 12 | #if you're using Windows, you may need to uncomment the next line 13 | #- WATCHPACK_POLLING=true 14 | volumes: 15 | - .:/app 16 | - /app/node_modules 17 | - /app/.next 18 | ports: 19 | - 8088:8088 -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | const config = { 2 | collectCoverage: true, 3 | coverageDirectory: 'coverage', 4 | coveragePathIgnorePatterns: [ 5 | '/node_modules/', 6 | 'src/test-utils', 7 | '\\.config\\.ts$', 8 | ], 9 | coverageProvider: 'v8', 10 | coverageThreshold: { 11 | global: { 12 | branches: 85, 13 | functions: 85, 14 | lines: 85, 15 | statements: 85, 16 | }, 17 | }, 18 | projects: [ 19 | '/jest/browser/jest.config.ts', 20 | '/jest/node/jest.config.ts', 21 | ], 22 | }; 23 | export default config; 24 | -------------------------------------------------------------------------------- /jest/browser/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | 3 | import { server } from '@/utils/msw/node'; 4 | 5 | beforeAll(() => { 6 | // Enable API mocking before all the tests. 7 | server.listen() 8 | }) 9 | 10 | afterEach(() => { 11 | // Reset the request handlers between each test. 12 | // This way the handlers we add on a per-test basis 13 | // do not leak to other, irrelevant tests. 14 | server.resetHandlers() 15 | }) 16 | 17 | afterAll(() => { 18 | // Finally, disable API mocking after the tests are done. 19 | server.close() 20 | }) -------------------------------------------------------------------------------- /jest/browser/jest.snapshot-resolver.js: -------------------------------------------------------------------------------- 1 | const snapshotExtension = '.snapshot'; 2 | 3 | module.exports = { 4 | resolveSnapshotPath: (testPath) => 5 | testPath + snapshotExtension, 6 | 7 | resolveTestPath: (snapshotFilePath) => 8 | snapshotFilePath.slice(0, -snapshotExtension.length), 9 | 10 | // Example test path, used for preflight consistency check of the implementation above 11 | testPathForConsistencyCheck: 'views/component/__tests__/component.test.js', 12 | }; 13 | -------------------------------------------------------------------------------- /jest/node/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | 3 | import { server } from '@/utils/msw/node'; 4 | 5 | beforeAll(() => { 6 | // Enable API mocking before all the tests. 7 | server.listen() 8 | }) 9 | 10 | afterEach(() => { 11 | // Reset the request handlers between each test. 12 | // This way the handlers we add on a per-test basis 13 | // do not leak to other, irrelevant tests. 14 | server.resetHandlers() 15 | }) 16 | 17 | afterAll(() => { 18 | // Finally, disable API mocking after the tests are done. 19 | server.close() 20 | }) -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/(Home)/(Domain)/domains/[domain]/[cluster]/[domainTab]/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import DomainPageTabsError from '@/views/domain-page/domain-page-tabs-error/domain-page-tabs-error'; 3 | 4 | export default DomainPageTabsError; 5 | -------------------------------------------------------------------------------- /src/app/(Home)/(Domain)/domains/[domain]/[cluster]/[domainTab]/loading.tsx: -------------------------------------------------------------------------------- 1 | import SectionLoadingIndicator from '@/components/section-loading-indicator/section-loading-indicator'; 2 | 3 | export default SectionLoadingIndicator; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/(Domain)/domains/[domain]/[cluster]/[domainTab]/page.tsx: -------------------------------------------------------------------------------- 1 | import DomainPageContent from '@/views/domain-page/domain-page-content/domain-page-content'; 2 | 3 | export default DomainPageContent; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/(Domain)/domains/[domain]/[cluster]/layout.tsx: -------------------------------------------------------------------------------- 1 | import DomainPage from '@/views/domain-page/domain-page'; 2 | 3 | export default DomainPage; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/(Domain)/domains/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import DomainPageError from '@/views/domain-page/domain-page-error/domain-page-error'; 3 | 4 | export default DomainPageError; 5 | -------------------------------------------------------------------------------- /src/app/(Home)/(Domains)/domains/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import ErrorPanel from '@/components/error-panel/error-panel'; 3 | 4 | export default function DomainsPageError({ 5 | error, 6 | reset, 7 | }: Readonly<{ 8 | error: Error; 9 | reset: () => void; 10 | }>) { 11 | return ( 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/app/(Home)/(Domains)/domains/page.tsx: -------------------------------------------------------------------------------- 1 | import DomainsPage from '@/views/domains-page/domains-page'; 2 | 3 | export const dynamic = 'force-dynamic'; // prevent executing the page during build 4 | 5 | export default DomainsPage; 6 | -------------------------------------------------------------------------------- /src/app/(Home)/(Task List)/domains/[domain]/[cluster]/task-lists/[taskListName]/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import TaskListError from '@/views/task-list-page/task-list-error/task-list-error'; 3 | 4 | export default TaskListError; 5 | -------------------------------------------------------------------------------- /src/app/(Home)/(Task List)/domains/[domain]/[cluster]/task-lists/[taskListName]/page.tsx: -------------------------------------------------------------------------------- 1 | import TaskListPage from '@/views/task-list-page/task-list-page'; 2 | 3 | export default TaskListPage; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/(Workflow)/domains/[domain]/[cluster]/workflows/[workflowId]/[runId]/[workflowTab]/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import WorkflowPageTabsError from '@/views/workflow-page/workflow-page-tabs-error/workflow-page-tabs-error'; 3 | 4 | export default WorkflowPageTabsError; 5 | -------------------------------------------------------------------------------- /src/app/(Home)/(Workflow)/domains/[domain]/[cluster]/workflows/[workflowId]/[runId]/[workflowTab]/loading.tsx: -------------------------------------------------------------------------------- 1 | import SectionLoadingIndicator from '@/components/section-loading-indicator/section-loading-indicator'; 2 | 3 | export default SectionLoadingIndicator; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/(Workflow)/domains/[domain]/[cluster]/workflows/[workflowId]/[runId]/[workflowTab]/page.tsx: -------------------------------------------------------------------------------- 1 | import WorkflowPageTabContent from '@/views/workflow-page/workflow-page-tab-content/workflow-page-tab-content'; 2 | 3 | export default WorkflowPageTabContent; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/(Workflow)/domains/[domain]/[cluster]/workflows/[workflowId]/[runId]/layout.tsx: -------------------------------------------------------------------------------- 1 | import WorkflowPage from '@/views/workflow-page/workflow-page'; 2 | 3 | export default WorkflowPage; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/(Workflow)/domains/[domain]/[cluster]/workflows/[workflowId]/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import WorkflowPageError from '@/views/workflow-page/workflow-page-error/workflow-page-error'; 3 | 4 | export default WorkflowPageError; 5 | -------------------------------------------------------------------------------- /src/app/(Home)/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import ErrorPanel from '@/components/error-panel/error-panel'; 3 | 4 | export default function HomePageError({ 5 | error, 6 | reset, 7 | }: Readonly<{ 8 | error: Error; 9 | reset: () => void; 10 | }>) { 11 | return ( 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/app/(Home)/layout.tsx: -------------------------------------------------------------------------------- 1 | import AppNavBar from '@/components/app-nav-bar/app-nav-bar'; 2 | 3 | export default function HomeLayout({ 4 | children, 5 | }: Readonly<{ 6 | children: React.ReactNode; 7 | }>) { 8 | return ( 9 | <> 10 | 11 |
{children}
12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/app/(Home)/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { ProgressBar, type ProgressBarOverrides } from 'baseui/progress-bar'; 3 | 4 | const progressOverrides = { 5 | BarContainer: { 6 | style: { margin: 0 }, 7 | }, 8 | } satisfies ProgressBarOverrides; 9 | 10 | export default function HomePageLoading() { 11 | return ; 12 | } 13 | -------------------------------------------------------------------------------- /src/app/(Home)/redirects/domain/[...domainParams]/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import RedirectDomainError from '@/views/redirect-domain/redirect-domain-error/redirect-domain-error'; 3 | 4 | export default RedirectDomainError; 5 | -------------------------------------------------------------------------------- /src/app/(Home)/redirects/domain/[...domainParams]/loading.tsx: -------------------------------------------------------------------------------- 1 | import SectionLoadingIndicator from '@/components/section-loading-indicator/section-loading-indicator'; 2 | 3 | export default SectionLoadingIndicator; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/redirects/domain/[...domainParams]/not-found.tsx: -------------------------------------------------------------------------------- 1 | import RedirectDomainNotFound from '@/views/redirect-domain/redirect-domain-not-found/redirect-domain-not-found'; 2 | 3 | export default RedirectDomainNotFound; 4 | -------------------------------------------------------------------------------- /src/app/(Home)/redirects/domain/[...domainParams]/page.tsx: -------------------------------------------------------------------------------- 1 | import RedirectDomain from '@/views/redirect-domain/redirect-domain'; 2 | 3 | export default RedirectDomain; 4 | -------------------------------------------------------------------------------- /src/app/api/clusters/[cluster]/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import { describeCluster } from '@/route-handlers/describe-cluster/describe-cluster'; 4 | import type { RouteParams } from '@/route-handlers/describe-domain/describe-domain.types'; 5 | import { routeHandlerWithMiddlewares } from '@/utils/route-handlers-middleware'; 6 | import routeHandlersDefaultMiddlewares from '@/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config'; 7 | 8 | export async function GET( 9 | request: NextRequest, 10 | options: { params: RouteParams } 11 | ) { 12 | return routeHandlerWithMiddlewares( 13 | describeCluster, 14 | request, 15 | options, 16 | routeHandlersDefaultMiddlewares 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/api/config/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import getConfig from '@/route-handlers/get-config/get-config'; 4 | 5 | export async function GET(request: NextRequest) { 6 | return getConfig(request); 7 | } 8 | -------------------------------------------------------------------------------- /src/app/api/domains/[domain]/[cluster]/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import { describeDomain } from '@/route-handlers/describe-domain/describe-domain'; 4 | import type { RouteParams } from '@/route-handlers/describe-domain/describe-domain.types'; 5 | import { routeHandlerWithMiddlewares } from '@/utils/route-handlers-middleware'; 6 | import routeHandlersDefaultMiddlewares from '@/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config'; 7 | 8 | export async function GET( 9 | request: NextRequest, 10 | options: { params: RouteParams } 11 | ) { 12 | return routeHandlerWithMiddlewares( 13 | describeDomain, 14 | request, 15 | options, 16 | routeHandlersDefaultMiddlewares 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/api/domains/[domain]/[cluster]/task-list/[taskListName]/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import { describeTaskList } from '@/route-handlers/describe-task-list/describe-task-list'; 4 | import { type RouteParams } from '@/route-handlers/describe-task-list/describe-task-list.types'; 5 | import { routeHandlerWithMiddlewares } from '@/utils/route-handlers-middleware'; 6 | import routeHandlersDefaultMiddlewares from '@/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config'; 7 | 8 | export async function GET( 9 | request: NextRequest, 10 | options: { params: RouteParams } 11 | ) { 12 | return routeHandlerWithMiddlewares( 13 | describeTaskList, 14 | request, 15 | options, 16 | routeHandlersDefaultMiddlewares 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/api/domains/[domain]/[cluster]/update/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import { updateDomain } from '@/route-handlers/update-domain/update-domain'; 4 | import { type RouteParams } from '@/route-handlers/update-domain/update-domain.types'; 5 | import { routeHandlerWithMiddlewares } from '@/utils/route-handlers-middleware'; 6 | import routeHandlersDefaultMiddlewares from '@/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config'; 7 | 8 | export async function POST( 9 | request: NextRequest, 10 | options: { params: RouteParams } 11 | ) { 12 | return routeHandlerWithMiddlewares( 13 | updateDomain, 14 | request, 15 | options, 16 | routeHandlersDefaultMiddlewares 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/api/domains/[domain]/[cluster]/workflows-basic/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import { listWorkflowsBasic } from '@/route-handlers/list-workflows-basic/list-workflows-basic'; 4 | import type { RouteParams } from '@/route-handlers/list-workflows-basic/list-workflows-basic.types'; 5 | import { routeHandlerWithMiddlewares } from '@/utils/route-handlers-middleware'; 6 | import routeHandlersDefaultMiddlewares from '@/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config'; 7 | 8 | export async function GET( 9 | request: NextRequest, 10 | options: { params: RouteParams } 11 | ) { 12 | return routeHandlerWithMiddlewares( 13 | listWorkflowsBasic, 14 | request, 15 | options, 16 | routeHandlersDefaultMiddlewares 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/api/domains/[domain]/[cluster]/workflows/[workflowId]/[runId]/(actions)/reset/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import { resetWorkflow } from '@/route-handlers/reset-workflow/reset-workflow'; 4 | import { type RouteParams } from '@/route-handlers/reset-workflow/reset-workflow.types'; 5 | import { routeHandlerWithMiddlewares } from '@/utils/route-handlers-middleware'; 6 | import routeHandlersDefaultMiddlewares from '@/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config'; 7 | 8 | export async function POST( 9 | request: NextRequest, 10 | options: { params: RouteParams } 11 | ) { 12 | return routeHandlerWithMiddlewares( 13 | resetWorkflow, 14 | request, 15 | options, 16 | routeHandlersDefaultMiddlewares 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/api/domains/[domain]/[cluster]/workflows/[workflowId]/[runId]/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import describeWorkflow from '@/route-handlers/describe-workflow/describe-workflow'; 4 | import { type RouteParams } from '@/route-handlers/describe-workflow/describe-workflow.types'; 5 | import { routeHandlerWithMiddlewares } from '@/utils/route-handlers-middleware'; 6 | import routeHandlersDefaultMiddlewares from '@/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config'; 7 | 8 | export async function GET( 9 | request: NextRequest, 10 | options: { params: RouteParams } 11 | ) { 12 | return routeHandlerWithMiddlewares( 13 | describeWorkflow, 14 | request, 15 | options, 16 | routeHandlersDefaultMiddlewares 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/api/domains/[domain]/[cluster]/workflows/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import { listWorkflows } from '@/route-handlers/list-workflows/list-workflows'; 4 | import type { RouteParams } from '@/route-handlers/list-workflows/list-workflows.types'; 5 | import { routeHandlerWithMiddlewares } from '@/utils/route-handlers-middleware'; 6 | import routeHandlersDefaultMiddlewares from '@/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config'; 7 | 8 | export async function GET( 9 | request: NextRequest, 10 | options: { params: RouteParams } 11 | ) { 12 | return routeHandlerWithMiddlewares( 13 | listWorkflows, 14 | request, 15 | options, 16 | routeHandlersDefaultMiddlewares 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/api/log/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest } from 'next/server'; 2 | 3 | import { logToServer } from '@/route-handlers/log-to-server/log-to-server'; 4 | 5 | export async function POST(request: NextRequest) { 6 | return logToServer(request); 7 | } 8 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadence-workflow/cadence-web/abb519253bb342d1b6057751526c4609ceac1b87/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | padding: 0; 4 | margin: 0; 5 | } 6 | 7 | html, 8 | body { 9 | display: flex; 10 | flex-direction: column; 11 | max-width: 100vw; 12 | height: 100%; 13 | } 14 | 15 | body main { 16 | display: contents; 17 | } -------------------------------------------------------------------------------- /src/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { usePathname } from 'next/navigation'; 3 | 4 | import ErrorPanel from '@/components/error-panel/error-panel'; 5 | 6 | export default function NotFound() { 7 | const path = usePathname(); 8 | 9 | return ( 10 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation'; 2 | 3 | export default function Home() { 4 | redirect('/domains'); 5 | return null; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/app-nav-bar/app-nav-bar.styles.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | StyletronCSSObject, 3 | StyletronCSSObjectOf, 4 | } from '@/hooks/use-styletron-classes'; 5 | 6 | const cssStylesObj = { 7 | titleIcon: { 8 | display: 'flex', 9 | height: '1em', 10 | }, 11 | } satisfies StyletronCSSObject; 12 | 13 | export const cssStyles: StyletronCSSObjectOf = 14 | cssStylesObj; 15 | -------------------------------------------------------------------------------- /src/components/async-props-loader/async-props-loader.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | type AsyncLoaderComponent, 3 | type Props, 4 | } from './async-props-loader.types'; 5 | 6 | export default async function AsyncPropsLoader({ 7 | component, 8 | getAsyncProps, 9 | }: Props) { 10 | const asyncProps = await getAsyncProps(); 11 | const Component = component; 12 | return ; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/async-props-loader/async-props-loader.types.ts: -------------------------------------------------------------------------------- 1 | import { type JSX } from 'react'; 2 | 3 | export type AsyncLoaderComponent = 4 | | keyof JSX.IntrinsicElements 5 | | React.JSXElementConstructor; 6 | 7 | export type Props = { 8 | component: Component; 9 | getAsyncProps: () => Promise>; 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/copy-text-button/copy-text-button.types.ts: -------------------------------------------------------------------------------- 1 | import { type ButtonProps } from 'baseui/button'; 2 | 3 | export type Props = { 4 | textToCopy: string; 5 | } & ButtonProps; 6 | -------------------------------------------------------------------------------- /src/components/date-filter-v2/date-filter-v2.types.ts: -------------------------------------------------------------------------------- 1 | import { type DATE_FILTER_RELATIVE_VALUES } from './date-filter-v2.constants'; 2 | 3 | export type RelativeDurationConfig = { 4 | label: string; 5 | durationSeconds: number; 6 | }; 7 | 8 | export type RelativeDateFilterValue = keyof typeof DATE_FILTER_RELATIVE_VALUES; 9 | 10 | export type DateFilterValue = Date | 'now' | RelativeDateFilterValue; 11 | 12 | export type DateFilterRange = { 13 | start: DateFilterValue | undefined; 14 | end: DateFilterValue | undefined; 15 | }; 16 | 17 | export type Props = { 18 | label: string; 19 | placeholder: string; 20 | dates: DateFilterRange; 21 | onChangeDates: (v: DateFilterRange) => void; 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/date-filter-v2/helpers/get-dayjs-from-date-filter-value.ts: -------------------------------------------------------------------------------- 1 | import dayjs from '@/utils/datetime/dayjs'; 2 | 3 | import { DATE_FILTER_RELATIVE_VALUES } from '../date-filter-v2.constants'; 4 | import { type DateFilterValue } from '../date-filter-v2.types'; 5 | 6 | export default function getDayjsFromDateFilterValue( 7 | v: DateFilterValue, 8 | now: dayjs.Dayjs 9 | ) { 10 | if (v instanceof Date) { 11 | return dayjs(v); 12 | } 13 | 14 | if (v === 'now') { 15 | return now; 16 | } 17 | 18 | return now.subtract( 19 | DATE_FILTER_RELATIVE_VALUES[v].durationSeconds, 20 | 'seconds' 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/components/date-filter-v2/helpers/is-relative-date-filter-value.ts: -------------------------------------------------------------------------------- 1 | import { DATE_FILTER_RELATIVE_VALUES } from '../date-filter-v2.constants'; 2 | import { type RelativeDateFilterValue } from '../date-filter-v2.types'; 3 | 4 | export default function isRelativeDateFilterValue( 5 | v: any 6 | ): v is RelativeDateFilterValue { 7 | return Object.hasOwn(DATE_FILTER_RELATIVE_VALUES, v); 8 | } 9 | -------------------------------------------------------------------------------- /src/components/date-filter-v2/helpers/parse-date-filter-value.ts: -------------------------------------------------------------------------------- 1 | import dayjs from '@/utils/datetime/dayjs'; 2 | 3 | import { type DateFilterValue } from '../date-filter-v2.types'; 4 | 5 | import isRelativeDateFilterValue from './is-relative-date-filter-value'; 6 | 7 | export default function parseDateFilterValue( 8 | v: string, 9 | fallback: DateFilterValue 10 | ): DateFilterValue { 11 | if (isRelativeDateFilterValue(v)) return v; 12 | const day = dayjs(v); 13 | return day.isValid() ? day.toDate() : fallback; 14 | } 15 | -------------------------------------------------------------------------------- /src/components/date-filter-v2/helpers/stringify-date-filter-value.ts: -------------------------------------------------------------------------------- 1 | import dayjs from '@/utils/datetime/dayjs'; 2 | 3 | import { type DateFilterValue } from '../date-filter-v2.types'; 4 | 5 | export default function stringifyDateFilterValue( 6 | v: DateFilterValue, 7 | prettyPrint?: 'pretty' 8 | ): string { 9 | const now = dayjs(); 10 | 11 | if (v instanceof Date) { 12 | const dayValue = dayjs(v); 13 | return prettyPrint === 'pretty' 14 | ? dayValue.format( 15 | dayValue.isSame(now, 'year') 16 | ? 'DD MMM, HH:mm:ss z' 17 | : 'DD MMM YYYY, HH:mm:ss z' 18 | ) 19 | : v.toISOString(); 20 | } 21 | 22 | return v; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/date-filter/date-filter.constants.ts: -------------------------------------------------------------------------------- 1 | export const DATE_FORMAT = 'dd MMM yyyy, HH:mm:ss z'; 2 | 3 | export const QUICK_SELECT_OPTIONS = [ 4 | { label: 'Last 5 minutes', durationSeconds: 5 * 60 }, 5 | { label: 'Last 15 minutes', durationSeconds: 15 * 60 }, 6 | { label: 'Last 1 hour', durationSeconds: 1 * 60 * 60 }, 7 | { label: 'Last 6 hours', durationSeconds: 6 * 60 * 60 }, 8 | { label: 'Last 12 hours', durationSeconds: 12 * 60 * 60 }, 9 | { label: 'Last 1 day', durationSeconds: 1 * 24 * 60 * 60 }, 10 | { label: 'Last 7 days', durationSeconds: 7 * 24 * 60 * 60 }, 11 | ] as const satisfies Array<{ label: string; durationSeconds: number }>; 12 | -------------------------------------------------------------------------------- /src/components/date-filter/date-filter.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import type { FormControlOverrides } from 'baseui/form-control/types'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | dateFormControl: { 7 | Label: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | ...$theme.typography.LabelXSmall, 10 | }), 11 | }, 12 | ControlContainer: { 13 | style: (): StyleObject => ({ 14 | margin: '0px', 15 | }), 16 | }, 17 | } satisfies FormControlOverrides, 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/date-filter/date-filter.types.ts: -------------------------------------------------------------------------------- 1 | export type DateRange = { 2 | start: Date | undefined; 3 | end: Date | undefined; 4 | }; 5 | 6 | export type Props = { 7 | label: string; 8 | placeholder: string; 9 | dates: DateRange; 10 | onChangeDates: (v: DateRange) => void; 11 | clearable?: boolean; 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/error-boundary/error-boundary.types.ts: -------------------------------------------------------------------------------- 1 | import { type ErrorBoundaryProps } from 'react-error-boundary'; 2 | 3 | export type Props = ErrorBoundaryProps & { 4 | omitLogging?: boolean | ((err: Error) => boolean); 5 | }; 6 | -------------------------------------------------------------------------------- /src/components/error-panel/error-panel.types.ts: -------------------------------------------------------------------------------- 1 | type BaseAction = { 2 | kind: string; 3 | label: string; 4 | }; 5 | 6 | type RetryAction = BaseAction & { 7 | kind: 'retry'; 8 | }; 9 | 10 | type InternalLinkAction = BaseAction & { 11 | kind: 'link-internal'; 12 | link: string; 13 | }; 14 | 15 | type ExternalLinkAction = BaseAction & { 16 | kind: 'link-external'; 17 | link: string; 18 | }; 19 | 20 | export type ErrorAction = RetryAction | InternalLinkAction | ExternalLinkAction; 21 | 22 | export type Props = { 23 | error?: Error; 24 | message: string; 25 | actions?: Array; 26 | reset?: () => void; 27 | omitLogging?: boolean; 28 | }; 29 | -------------------------------------------------------------------------------- /src/components/formatted-date/formatted-date.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled, type Theme } from 'baseui'; 2 | export const styled = { 3 | GrayText: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ 4 | color: $theme.colors.contentTertiary, 5 | })), 6 | }; 7 | -------------------------------------------------------------------------------- /src/components/formatted-date/formatted-date.tsx: -------------------------------------------------------------------------------- 1 | import formatDate from '@/utils/data-formatters/format-date'; 2 | 3 | import { styled } from './formatted-date.styles'; 4 | import { type Props } from './formatted-date.types'; 5 | 6 | export default function FormattedDate({ 7 | timestampMs, 8 | placeholderText = 'Ongoing', 9 | }: Props) { 10 | if (!timestampMs) { 11 | return {placeholderText}; 12 | } 13 | 14 | return
{formatDate(timestampMs)}
; 15 | } 16 | -------------------------------------------------------------------------------- /src/components/formatted-date/formatted-date.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | timestampMs: number | null | undefined; 3 | placeholderText?: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/components/link/link.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import NextLink from 'next/link'; 4 | 5 | import { styled } from './link.styles'; 6 | import { type Props } from './link.types'; 7 | 8 | export default function Link({ 9 | href, 10 | children, 11 | prefetch = false, 12 | ...restProps 13 | }: Props) { 14 | return ( 15 | 22 | {children} 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /src/components/link/link.types.ts: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | 3 | import { type StyledLink } from 'baseui/link'; 4 | import type NextLink from 'next/link'; 5 | 6 | type LinkProps = React.ComponentProps & 7 | React.ComponentProps; 8 | 9 | export type Props = Omit & { 10 | color?: LinkProps['color'] | 'contentPrimary' | 'contentInversePrimary'; 11 | }; 12 | -------------------------------------------------------------------------------- /src/components/list-filter-multi/list-filter-multi.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import type { FormControlOverrides } from 'baseui/form-control/types'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | selectFormControl: { 7 | Label: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | ...$theme.typography.LabelXSmall, 10 | }), 11 | }, 12 | ControlContainer: { 13 | style: (): StyleObject => ({ 14 | margin: '0px', 15 | }), 16 | }, 17 | } satisfies FormControlOverrides, 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/list-filter-multi/list-filter-multi.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | values: Array | undefined; 3 | onChangeValues: (values: Array | undefined) => void; 4 | labelMap: Record; 5 | label: string; 6 | placeholder: string; 7 | }; 8 | -------------------------------------------------------------------------------- /src/components/list-filter/helpers/__tests__/get-options-from-label-map.test.ts: -------------------------------------------------------------------------------- 1 | import getOptionsFromLabelMap from '../get-options-from-label-map'; 2 | 3 | const MOCK_LABEL_MAP = { 4 | opt1: 'Option 1', 5 | opt2: 'Option 2', 6 | opt3: 'Option 3', 7 | }; 8 | 9 | describe(getOptionsFromLabelMap.name, () => { 10 | it('returns array of id-label pairs for a label map', () => { 11 | expect(getOptionsFromLabelMap(MOCK_LABEL_MAP)).toEqual([ 12 | { 13 | id: 'opt1', 14 | label: 'Option 1', 15 | }, 16 | { 17 | id: 'opt2', 18 | label: 'Option 2', 19 | }, 20 | { 21 | id: 'opt3', 22 | label: 'Option 3', 23 | }, 24 | ]); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/components/list-filter/helpers/get-options-from-label-map.ts: -------------------------------------------------------------------------------- 1 | export default function getOptionsFromLabelMap( 2 | labelMap: Record 3 | ) { 4 | return Object.entries(labelMap).map(([key, value]) => ({ 5 | id: key, 6 | label: value, 7 | })); 8 | } 9 | -------------------------------------------------------------------------------- /src/components/list-filter/list-filter.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import type { FormControlOverrides } from 'baseui/form-control/types'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | selectFormControl: { 7 | Label: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | ...$theme.typography.LabelXSmall, 10 | }), 11 | }, 12 | ControlContainer: { 13 | style: (): StyleObject => ({ 14 | margin: '0px', 15 | }), 16 | }, 17 | } satisfies FormControlOverrides, 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/list-filter/list-filter.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | value: T | undefined; 3 | onChangeValue: (value: T | undefined) => void; 4 | labelMap: Record; 5 | label: string; 6 | placeholder: string; 7 | }; 8 | -------------------------------------------------------------------------------- /src/components/list-table-nested/sublist-table/sublist-table.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from './sublist-table.styles'; 2 | import { type Props } from './sublist-table.types'; 3 | 4 | export default function SublistTable({ items }: Props) { 5 | return ( 6 | 7 | {items.map((sublistItem) => ( 8 | 9 | 10 | {sublistItem.label}: 11 | 12 | {sublistItem.value} 13 | 14 | ))} 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/list-table-nested/sublist-table/sublist-table.types.ts: -------------------------------------------------------------------------------- 1 | export type SublistItem = { 2 | key: string; 3 | label: string; 4 | value: React.ReactNode; 5 | }; 6 | 7 | export type Props = { 8 | items: Array; 9 | }; 10 | -------------------------------------------------------------------------------- /src/components/list-table/list-table.types.ts: -------------------------------------------------------------------------------- 1 | export type ListTableItem = { 2 | key: string; 3 | label: string; 4 | renderValue: React.ComponentType | ((props: T) => React.ReactNode); 5 | }; 6 | 7 | export type Props = { 8 | data: T; 9 | listTableConfig: Array>; 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/page-filters/page-filters-fields/page-filters-fields.types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type PageQueryParamSetter, 3 | type PageQueryParamValues, 4 | type PageQueryParams, 5 | } from '@/hooks/use-page-query-params/use-page-query-params.types'; 6 | 7 | import { type PageFilterConfig } from '../page-filters.types'; 8 | 9 | export type Props

= { 10 | pageFiltersConfig: Array>; 11 | resetAllFilters: () => void; 12 | queryParams: PageQueryParamValues

; 13 | setQueryParams: PageQueryParamSetter

; 14 | }; 15 | -------------------------------------------------------------------------------- /src/components/page-filters/page-filters-search/page-filters-search.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import { type InputOverrides } from 'baseui/input'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | searchInput: { 7 | Root: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | height: $theme.sizing.scale950, 10 | }), 11 | }, 12 | Input: { 13 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 14 | ...$theme.typography.ParagraphSmall, 15 | }), 16 | }, 17 | } satisfies InputOverrides, 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/page-filters/page-filters-search/page-filters-search.types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type PageQueryParamKeys, 3 | type PageQueryParamValues, 4 | type PageQueryParams, 5 | } from '@/hooks/use-page-query-params/use-page-query-params.types'; 6 | 7 | export type Props< 8 | P extends PageQueryParams, 9 | K extends PageQueryParamKeys

, 10 | > = { 11 | pageQueryParamsConfig: P; 12 | searchQueryParamKey: PageQueryParamValues

[K] extends string ? K : never; 13 | searchPlaceholder: string; 14 | searchTrimRegExp?: RegExp; 15 | inputDebounceDurationMs?: number; 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/page-filters/page-filters-toggle/page-filters-toggle.styles.ts: -------------------------------------------------------------------------------- 1 | import type { ButtonOverrides } from 'baseui/button'; 2 | 3 | export const overrides = { 4 | filtersButton: { 5 | Root: { 6 | style: { 7 | whiteSpace: 'nowrap', 8 | }, 9 | }, 10 | } satisfies ButtonOverrides, 11 | }; 12 | -------------------------------------------------------------------------------- /src/components/page-filters/page-filters-toggle/page-filters-toggle.types.ts: -------------------------------------------------------------------------------- 1 | import { type ButtonProps } from 'baseui/button'; 2 | 3 | export type Props = { 4 | onClick: ButtonProps['onClick']; 5 | activeFiltersCount: number; 6 | isActive: boolean; 7 | }; 8 | -------------------------------------------------------------------------------- /src/components/page-section/page-section.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme, styled as createStyled } from 'baseui'; 2 | 3 | import { getMediaQueryMargins } from '@/utils/media-query/get-media-queries-margins'; 4 | 5 | export const styled = { 6 | PageSection: createStyled('section', ({ $theme }: { $theme: Theme }) => ({ 7 | width: '100%', 8 | margin: '0 auto', 9 | paddingLeft: $theme.sizing.scale600, 10 | paddingRight: $theme.sizing.scale600, 11 | // override default styles by media query specific styles 12 | ...getMediaQueryMargins($theme, (margin) => ({ 13 | maxWidth: `${$theme.grid.maxWidth + 2 * margin}px`, 14 | paddingRight: `${margin}px`, 15 | paddingLeft: `${margin}px`, 16 | })), 17 | })), 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/page-section/page-section.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { styled } from './page-section.styles'; 3 | 4 | const PageSection = styled.PageSection; 5 | 6 | export default PageSection; 7 | -------------------------------------------------------------------------------- /src/components/page-tabs/page-tabs.types.ts: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | 3 | import { type IconProps } from 'baseui/icon'; 4 | import { type TabsProps } from 'baseui/tabs-motion'; 5 | 6 | export type PageTab = { 7 | key: string; 8 | title: string; 9 | endEnhancer?: React.ComponentType>; 10 | artwork?: React.ComponentType<{ 11 | size: IconProps['size']; 12 | color: IconProps['color']; 13 | }>; 14 | }; 15 | 16 | export type PageTabsList = Array; 17 | 18 | export type Props = { 19 | tabList: PageTabsList; 20 | selectedTab: React.Key; 21 | setSelectedTab: (value: React.Key) => void; 22 | endEnhancer?: TabsProps['endEnhancer']; 23 | }; 24 | -------------------------------------------------------------------------------- /src/components/panel-section/panel-section.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled, type Theme } from 'baseui'; 2 | 3 | export const styled = { 4 | PanelSectionContainer: createStyled( 5 | 'section', 6 | ({ $theme }: { $theme: Theme }) => ({ 7 | display: 'flex', 8 | alignItems: 'center', 9 | flex: 1, 10 | flexDirection: 'column', 11 | gap: $theme.sizing.scale600, 12 | paddingTop: $theme.sizing.scale900, 13 | paddingBottom: $theme.sizing.scale1200, 14 | paddingLeft: $theme.sizing.scale600, 15 | paddingRight: $theme.sizing.scale600, 16 | }) 17 | ), 18 | Spacer: createStyled<'div', { $height: string }>('div', ({ $height }) => ({ 19 | flex: `1 1 ${$height}`, 20 | })), 21 | }; 22 | -------------------------------------------------------------------------------- /src/components/panel-section/panel-section.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from './panel-section.styles'; 2 | import { type Props } from './panel-section.types'; 3 | 4 | export default function PanelSection({ children }: Props) { 5 | return ( 6 | 7 | 8 | {children} 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /src/components/panel-section/panel-section.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | children: React.ReactNode; 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/pretty-json-skeleton/pretty-json-skeleton.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | width: string; 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/pretty-json/pretty-json.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { JsonView, allExpanded } from 'react-json-view-lite'; 3 | 4 | import useStyletronClasses from '@/hooks/use-styletron-classes'; 5 | 6 | import { cssStyles } from './pretty-json.styles'; 7 | import type { Props } from './pretty-json.types'; 8 | 9 | export default function PrettyJson({ json }: Props) { 10 | const { cls } = useStyletronClasses(cssStyles); 11 | 12 | return ( 13 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/components/pretty-json/pretty-json.types.tsx: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | json: PrettyJsonValue; 3 | }; 4 | 5 | export type PrettyJsonValue = 6 | | string 7 | | number 8 | | boolean 9 | | null 10 | | undefined 11 | | JsonObject 12 | | JsonArray 13 | | bigint; 14 | 15 | type JsonObject = { [key: string]: PrettyJsonValue }; 16 | type JsonArray = PrettyJsonValue[]; 17 | -------------------------------------------------------------------------------- /src/components/section-loading-indicator/section-loading-indicator.styles.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | StyletronCSSObject, 3 | StyletronCSSObjectOf, 4 | } from '@/hooks/use-styletron-classes'; 5 | 6 | const cssStylesObj = { 7 | spinnerContainer: (theme) => ({ 8 | padding: `${theme.sizing.scale1200} 0px`, 9 | display: 'flex', 10 | alignItems: 'center', 11 | justifyContent: 'center', 12 | }), 13 | } satisfies StyletronCSSObject; 14 | 15 | export const cssStyles: StyletronCSSObjectOf = 16 | cssStylesObj; 17 | -------------------------------------------------------------------------------- /src/components/section-loading-indicator/section-loading-indicator.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { Spinner, SIZE, type SpinnerProps } from 'baseui/spinner'; 3 | 4 | import useStyletronClasses from '@/hooks/use-styletron-classes'; 5 | 6 | import { cssStyles } from './section-loading-indicator.styles'; 7 | 8 | export default function SectionLoadingIndicator(props: SpinnerProps) { 9 | const { cls } = useStyletronClasses(cssStyles); 10 | 11 | return ( 12 |

13 | 14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/segmented-control-rounded/segmented-control-rounded.types.ts: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | 3 | import type { 4 | SegmentProps, 5 | SegmentedControlProps, 6 | } from 'baseui/segmented-control'; 7 | 8 | export type SegmentControlRoundedOption = Omit & { 9 | key: React.Key; // make key required 10 | }; 11 | export type Props = Pick< 12 | SegmentedControlProps, 13 | 'activeKey' | 'disabled' | 'onChange' 14 | > & { 15 | options: Array; 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/snackbar-provider/snackbar-provider.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import { type SnackbarElementOverrides } from 'baseui/snackbar'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | snackbar: { 7 | Root: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | backgroundColor: $theme.colors.contentPositive, 10 | }), 11 | }, 12 | } satisfies SnackbarElementOverrides, 13 | }; 14 | -------------------------------------------------------------------------------- /src/components/snackbar-provider/snackbar-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { 3 | SnackbarProvider as BaseSnackbarProvider, 4 | PLACEMENT, 5 | DURATION, 6 | } from 'baseui/snackbar'; 7 | 8 | import { overrides } from './snackbar-provider.styles'; 9 | import { type Props } from './snackbar-provider.types'; 10 | 11 | export default function SnackbarProvider({ children }: Props) { 12 | return ( 13 | 18 | {children} 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/components/snackbar-provider/snackbar-provider.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | children: React.ReactNode; 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/table/table-body-cell/table-body-cell.styles.ts: -------------------------------------------------------------------------------- 1 | import { withStyle } from 'baseui'; 2 | import { StyledTableBodyCell } from 'baseui/table-semantic'; 3 | 4 | export const styled = { 5 | TableBodyCell: withStyle(StyledTableBodyCell, { 6 | verticalAlign: 'middle', 7 | wordBreak: 'break-word', 8 | }), 9 | }; 10 | -------------------------------------------------------------------------------- /src/components/table/table-body-cell/table-body-cell.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from './table-body-cell.styles'; 2 | 3 | export default styled.TableBodyCell; 4 | -------------------------------------------------------------------------------- /src/components/table/table-footer-message/table-footer-message.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme, withStyle } from 'baseui'; 2 | import { StyledTableLoadingMessage } from 'baseui/table-semantic'; 3 | 4 | export const styled = { 5 | TableFooterMessage: withStyle( 6 | StyledTableLoadingMessage, 7 | ({ $theme }: { $theme: Theme }) => ({ 8 | display: 'flex', 9 | justifyContent: 'center', 10 | justifySelf: 'stretch', 11 | // The base StyledTableLoadingMessage uses the shorthand property for padding 12 | // https://styletron.org/concepts#shorthand-and-longhand-properties 13 | padding: `${$theme.sizing.scale600} 0`, 14 | }) 15 | ), 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/table/table-footer-message/table-footer-message.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from './table-footer-message.styles'; 2 | 3 | export default styled.TableFooterMessage; 4 | -------------------------------------------------------------------------------- /src/components/table/table-head-cell/table-head-cell.types.ts: -------------------------------------------------------------------------------- 1 | import { type SortOrder } from '@/utils/sort-by'; 2 | 3 | export type Props = { 4 | name: string; 5 | columnID: string; 6 | width: string; 7 | sortColumn?: string; 8 | sortOrder?: SortOrder; 9 | isSortable?: boolean; 10 | onSort?: (column: string) => void; 11 | }; 12 | -------------------------------------------------------------------------------- /src/components/table/table-infinite-scroll-loader/table-infinite-scroll-loader.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled, withStyle } from 'baseui'; 2 | import { StyledLink } from 'baseui/link'; 3 | 4 | export const styled = { 5 | EndMessageContainer: createStyled<'div', { $isError?: boolean }>( 6 | 'div', 7 | ({ $theme, $isError }) => ({ 8 | ...$theme.typography.LabelSmall, 9 | color: $isError 10 | ? $theme.colors.contentNegative 11 | : $theme.colors.contentTertiary, 12 | }) 13 | ), 14 | RetryLink: withStyle(StyledLink, ({ $theme }) => ({ 15 | color: $theme.colors.contentNegative, 16 | cursor: 'pointer', 17 | })), 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/table/table-infinite-scroll-loader/table-infinite-scroll-loader.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | hasData: boolean; 3 | error: Error | null; 4 | fetchNextPage: () => void; 5 | hasNextPage: boolean; 6 | isFetchingNextPage: boolean; 7 | }; 8 | -------------------------------------------------------------------------------- /src/components/table/table-root/table-root.styles.ts: -------------------------------------------------------------------------------- 1 | import { withStyle } from 'baseui'; 2 | import { StyledRoot } from 'baseui/accordion'; 3 | 4 | export const styled = { 5 | TableRoot: withStyle(StyledRoot, { 6 | alignSelf: 'center', 7 | flex: '1 1 0', 8 | overflow: 'visible', 9 | width: '100%', 10 | }), 11 | }; 12 | -------------------------------------------------------------------------------- /src/components/table/table-root/table-root.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from './table-root.styles'; 2 | 3 | export default styled.TableRoot; 4 | -------------------------------------------------------------------------------- /src/components/timeline/timeline.tsx: -------------------------------------------------------------------------------- 1 | // @ts-expect-error: react-visjs-timeline does not have type declarations available 2 | import VisJSTimeline from 'react-visjs-timeline'; 3 | 4 | import type { Props } from './timeline.types'; 5 | 6 | export default function Timeline({ 7 | items, 8 | height = '400px', 9 | onClickItem, 10 | }: Props) { 11 | return ( 12 | { 19 | if (item !== null) onClickItem(item); 20 | }} 21 | /> 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /src/components/timeline/timeline.types.ts: -------------------------------------------------------------------------------- 1 | export type TimelineItem = { 2 | id: number; 3 | start: Date; 4 | end?: Date; 5 | content: string; 6 | title?: string; 7 | type: 'box' | 'point' | 'range' | 'background'; 8 | className: string; 9 | }; 10 | 11 | export type Props = { 12 | items: Array; 13 | height?: string; 14 | onClickItem: (itemId: number) => void; 15 | }; 16 | -------------------------------------------------------------------------------- /src/config/dynamic/resolvers/clusters-public.ts: -------------------------------------------------------------------------------- 1 | import clusters from './clusters'; 2 | 3 | export default function clustersPublic() { 4 | const originalClusters = clusters(); 5 | return originalClusters.map((cluster) => { 6 | return { 7 | clusterName: cluster.clusterName, 8 | }; 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /src/config/dynamic/resolvers/clusters-public.types.ts: -------------------------------------------------------------------------------- 1 | import { type ClusterConfig } from './clusters.types'; 2 | 3 | export type PublicClusterConfig = Pick; 4 | 5 | export type PublicClustersConfigs = Array; 6 | -------------------------------------------------------------------------------- /src/config/dynamic/resolvers/clusters.types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type GRPCRequestConfig, 3 | type GRPCServiceConfig, 4 | } from '@/utils/grpc/grpc-service'; 5 | 6 | export type ClusterConfig = { 7 | clusterName: string; 8 | grpc: GRPCRequestConfig & Pick; 9 | }; 10 | 11 | export type ClustersConfigs = Array; 12 | -------------------------------------------------------------------------------- /src/config/dynamic/resolvers/extended-domain-info-enabled.ts: -------------------------------------------------------------------------------- 1 | import { type ExtendedDomainInfoEnabledConfig } from './extended-domain-info-enabled.types'; 2 | 3 | export default async function extendedDomainInfoEnabled(): Promise { 4 | return { 5 | metadata: false, 6 | issues: false, 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /src/config/dynamic/resolvers/extended-domain-info-enabled.types.ts: -------------------------------------------------------------------------------- 1 | export type ExtendedDomainInfoEnabledConfig = { 2 | metadata: boolean; 3 | issues: boolean; 4 | }; 5 | -------------------------------------------------------------------------------- /src/config/dynamic/resolvers/workflow-actions-disabled-values.config.ts: -------------------------------------------------------------------------------- 1 | const WORKFLOW_ACTIONS_DISABLED_VALUES_CONFIG = [ 2 | 'DISABLED_DEFAULT', 3 | 'DISABLED_UNAUTHORIZED', 4 | ] as const satisfies Array<`DISABLED_${string}`>; 5 | 6 | export default WORKFLOW_ACTIONS_DISABLED_VALUES_CONFIG; 7 | -------------------------------------------------------------------------------- /src/config/dynamic/resolvers/workflow-actions-enabled.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type WorkflowActionsEnabledConfig, 3 | type WorkflowActionsEnabledResolverParams, 4 | } from './workflow-actions-enabled.types'; 5 | 6 | /** 7 | * If you have authentication enabled for users, override this resolver 8 | * to control whether users can access workflow actions in the UI 9 | */ 10 | export default async function workflowActionsEnabled( 11 | _: WorkflowActionsEnabledResolverParams 12 | ): Promise { 13 | return { 14 | terminate: 'ENABLED', 15 | cancel: 'ENABLED', 16 | restart: 'ENABLED', 17 | reset: 'ENABLED', 18 | signal: 'ENABLED', 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/config/dynamic/resolvers/workflow-actions-enabled.types.ts: -------------------------------------------------------------------------------- 1 | import type WORKFLOW_ACTIONS_DISABLED_VALUES_CONFIG from './workflow-actions-disabled-values.config'; 2 | 3 | export type WorkflowActionID = 4 | | 'cancel' 5 | | 'terminate' 6 | | 'restart' 7 | | 'reset' 8 | | 'signal'; 9 | 10 | export type WorkflowActionsEnabledResolverParams = { 11 | domain: string; 12 | cluster: string; 13 | }; 14 | 15 | export type WorkflowActionDisabledValue = 16 | (typeof WORKFLOW_ACTIONS_DISABLED_VALUES_CONFIG)[number]; 17 | 18 | export type WorkflowActionEnabledConfigValue = 19 | | 'ENABLED' 20 | | WorkflowActionDisabledValue; 21 | 22 | export type WorkflowActionsEnabledConfig = Record< 23 | WorkflowActionID, 24 | WorkflowActionEnabledConfigValue 25 | >; 26 | -------------------------------------------------------------------------------- /src/config/grpc/grpc-proto-dir-base-path.ts: -------------------------------------------------------------------------------- 1 | const GRPC_PROTO_DIR_BASE_PATH = 'src/__generated__/idl/proto'; 2 | 3 | export default GRPC_PROTO_DIR_BASE_PATH; 4 | -------------------------------------------------------------------------------- /src/config/grpc/grpc-services-config.ts: -------------------------------------------------------------------------------- 1 | const GRPC_SERVICES_CONFIGS = { 2 | adminServiceConfig: { 3 | schemaPath: 'uber/cadence/admin/v1/service.proto', 4 | servicePath: 'uber.cadence.admin.v1.AdminAPI', 5 | }, 6 | domainServiceConfig: { 7 | schemaPath: 'uber/cadence/api/v1/service_domain.proto', 8 | servicePath: 'uber.cadence.api.v1.DomainAPI', 9 | }, 10 | visibilityServiceConfig: { 11 | schemaPath: 'uber/cadence/api/v1/service_visibility.proto', 12 | servicePath: 'uber.cadence.api.v1.VisibilityAPI', 13 | }, 14 | workflowServiceConfig: { 15 | schemaPath: 'uber/cadence/api/v1/service_workflow.proto', 16 | servicePath: 'uber.cadence.api.v1.WorkflowAPI', 17 | }, 18 | }; 19 | 20 | export default GRPC_SERVICES_CONFIGS; 21 | -------------------------------------------------------------------------------- /src/config/theme/base-web-icons-overrides.config.ts: -------------------------------------------------------------------------------- 1 | import { type ComponentType } from 'react'; 2 | 3 | import { type IconProps } from 'baseui/icon'; 4 | import { type Icon } from 'baseui/styles'; 5 | import { MdFilterList, MdSearch } from 'react-icons/md'; 6 | 7 | const baseWebIconsOverrides = { 8 | // IconProps needed by Baseweb is a super type of IconBaseProps from react-icons, so no issues should happen from casting 9 | Search: MdSearch as ComponentType, 10 | Filter: MdFilterList as ComponentType, 11 | } satisfies Icon; 12 | 13 | export default baseWebIconsOverrides; 14 | -------------------------------------------------------------------------------- /src/config/theme/theme-light.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type DeepPartial, 3 | type MakeExtendable, 4 | type Theme, 5 | } from 'baseui/styles'; 6 | 7 | import baseWebIconsOverrides from './base-web-icons-overrides.config'; 8 | 9 | const themeLight = { 10 | grid: { maxWidth: 1580 }, 11 | icons: baseWebIconsOverrides, 12 | colors: { 13 | borderOpaque: '#F3F3F3', 14 | backgroundSecondary: '#F3F3F3', 15 | backgroundTertiary: '#E8E8E8', 16 | backgroundWarningLight: '#FDF2DC', 17 | backgroundPositive: '#0E8345', 18 | }, 19 | borders: { 20 | buttonBorderRadiusMini: '8px', 21 | popoverBorderRadius: '12px', 22 | }, 23 | } satisfies DeepPartial>; 24 | 25 | export default themeLight; 26 | -------------------------------------------------------------------------------- /src/config/theme/theme-provider-overrides.config.ts: -------------------------------------------------------------------------------- 1 | import { type BaseProviderOverrides } from 'baseui'; 2 | 3 | const themeProviderOverrides: BaseProviderOverrides = { 4 | AppContainer: { 5 | style: { 6 | display: 'flex', 7 | flexDirection: 'column', 8 | flex: 1, 9 | }, 10 | }, 11 | }; 12 | 13 | export default themeProviderOverrides; 14 | -------------------------------------------------------------------------------- /src/hooks/use-config-value/use-config-value.types.ts: -------------------------------------------------------------------------------- 1 | import { type UseQueryResult } from '@tanstack/react-query'; 2 | 3 | import { 4 | type GetConfigKeys, 5 | type GetConfigResponse, 6 | } from '@/route-handlers/get-config/get-config.types'; 7 | import { type RequestError } from '@/utils/request/request-error'; 8 | 9 | export type UseConfigValueResult = UseQueryResult< 10 | GetConfigResponse, 11 | RequestError 12 | >; 13 | -------------------------------------------------------------------------------- /src/hooks/use-merged-infinite-queries/use-merged-infinite-queries-error.ts: -------------------------------------------------------------------------------- 1 | export class UseMergedInfiniteQueriesError extends Error { 2 | errors: Array; 3 | constructor(message: string, errors: Array, options?: ErrorOptions) { 4 | super(message, options); 5 | this.errors = errors; 6 | this.name = 'UseMergedInfiniteQueriesError'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/hooks/use-previous-value.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from 'react'; 2 | 3 | function usePreviousValue(value: T) { 4 | const ref = useRef(); 5 | useEffect(() => { 6 | ref.current = value; 7 | }); 8 | return ref.current; 9 | } 10 | 11 | export default usePreviousValue; 12 | -------------------------------------------------------------------------------- /src/hooks/use-server-component-page-params.tsx: -------------------------------------------------------------------------------- 1 | import getPageQueryParamsValues from './use-page-query-params/helpers/get-page-query-params-values'; 2 | import type { 3 | ParsedQuery, 4 | PageQueryParams, 5 | } from './use-page-query-params/use-page-query-params.types'; 6 | 7 | export function useServerComponentQueryParams

( 8 | config: P, 9 | searchQueryParams: ParsedQuery 10 | ) { 11 | return getPageQueryParamsValues(config, searchQueryParams); 12 | } 13 | -------------------------------------------------------------------------------- /src/route-handlers/cancel-workflow/cancel-workflow.types.ts: -------------------------------------------------------------------------------- 1 | import { type RequestCancelWorkflowExecutionResponse } from '@/__generated__/proto-ts/uber/cadence/api/v1/RequestCancelWorkflowExecutionResponse'; 2 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 3 | 4 | export type RouteParams = { 5 | domain: string; 6 | cluster: string; 7 | workflowId: string; 8 | runId: string; 9 | }; 10 | 11 | export type RequestParams = { 12 | params: RouteParams; 13 | }; 14 | 15 | export type CancelWorkflowResponse = RequestCancelWorkflowExecutionResponse; 16 | 17 | export type Context = DefaultMiddlewaresContext; 18 | -------------------------------------------------------------------------------- /src/route-handlers/cancel-workflow/schemas/cancel-workflow-request-body-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | const cancelWorkflowRequestBodySchema = z.object({ 4 | cause: z 5 | .string() 6 | .optional() 7 | .default('Requesting workflow cancellation from cadence-web UI'), 8 | }); 9 | 10 | export default cancelWorkflowRequestBodySchema; 11 | -------------------------------------------------------------------------------- /src/route-handlers/describe-cluster/describe-cluster.types.ts: -------------------------------------------------------------------------------- 1 | import { type DescribeClusterResponse as OriginalDescribeClusterResponse } from '@/__generated__/proto-ts/uber/cadence/admin/v1/DescribeClusterResponse'; 2 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 3 | 4 | export type RouteParams = { 5 | cluster: string; 6 | }; 7 | 8 | export type RequestParams = { 9 | params: RouteParams; 10 | }; 11 | 12 | export type Context = DefaultMiddlewaresContext; 13 | export type DescribeClusterResponse = Omit< 14 | OriginalDescribeClusterResponse, 15 | 'membershipInfo' 16 | >; 17 | -------------------------------------------------------------------------------- /src/route-handlers/describe-domain/describe-domain.types.ts: -------------------------------------------------------------------------------- 1 | import { type Domain } from '@/__generated__/proto-ts/uber/cadence/api/v1/Domain'; 2 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 3 | 4 | export type RouteParams = { 5 | domain: string; 6 | cluster: string; 7 | }; 8 | 9 | export type RequestParams = { 10 | params: RouteParams; 11 | }; 12 | 13 | export type Context = DefaultMiddlewaresContext; 14 | export type DescribeDomainResponse = Domain; 15 | -------------------------------------------------------------------------------- /src/route-handlers/fetch-workflow-query-types/fetch-workflow-query-types.types.ts: -------------------------------------------------------------------------------- 1 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 2 | 3 | export type RouteParams = { 4 | domain: string; 5 | cluster: string; 6 | workflowId: string; 7 | runId: string; 8 | }; 9 | 10 | export type RequestParams = { 11 | params: RouteParams; 12 | }; 13 | 14 | export type FetchWorkflowQueryTypesResponse = { 15 | queryTypes: Array; 16 | }; 17 | 18 | export type Context = DefaultMiddlewaresContext; 19 | -------------------------------------------------------------------------------- /src/route-handlers/fetch-workflow-query-types/helpers/parse-error-message-for-query-types.ts: -------------------------------------------------------------------------------- 1 | export default function parseErrorMessageForQueryTypes( 2 | message: string 3 | ): Array | undefined { 4 | const knownTypesErrorMatch = message.match( 5 | /(KnownQueryTypes|knownTypes)=\[(.*)?\]/ 6 | ); 7 | 8 | if (!knownTypesErrorMatch) { 9 | return undefined; 10 | } 11 | 12 | const queryTypes = knownTypesErrorMatch[2]; 13 | 14 | return queryTypes ? queryTypes.split(/, | /).filter(Boolean) : []; 15 | } 16 | -------------------------------------------------------------------------------- /src/route-handlers/fetch-workflow-query-types/schemas/query-types-data-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | export const queryTypesDataSchema = z.string().transform((d): Array => { 4 | const parsedJSON = JSON.parse(Buffer.from(d, 'base64').toString('utf-8')); 5 | return z.array(z.string()).parse(parsedJSON); 6 | }); 7 | -------------------------------------------------------------------------------- /src/route-handlers/get-workflow-history/get-workflow-history.types.ts: -------------------------------------------------------------------------------- 1 | import { type GetWorkflowExecutionHistoryResponse } from '@/__generated__/proto-ts/uber/cadence/api/v1/GetWorkflowExecutionHistoryResponse'; 2 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 3 | 4 | export type RouteParams = { 5 | domain: string; 6 | cluster: string; 7 | workflowId: string; 8 | runId: string; 9 | }; 10 | 11 | export type RequestParams = { 12 | params: RouteParams; 13 | }; 14 | 15 | export type GetWorkflowHistoryResponse = GetWorkflowExecutionHistoryResponse; 16 | 17 | export type Context = DefaultMiddlewaresContext; 18 | -------------------------------------------------------------------------------- /src/route-handlers/get-workflow-history/schemas/get-workflow-history-query-params-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | const getWorkflowHistoryQueryParamsSchema = z.object({ 4 | pageSize: z 5 | .string() 6 | .transform((val) => parseInt(val, 10)) 7 | .pipe( 8 | z.number().positive({ message: 'Page size must be a positive integer' }) 9 | ), 10 | nextPage: z.string().optional(), 11 | waitForNewEvent: z 12 | .string() 13 | .toLowerCase() 14 | .transform((x) => x === 'true') 15 | .pipe(z.boolean()) 16 | .optional(), 17 | }); 18 | 19 | export default getWorkflowHistoryQueryParamsSchema; 20 | -------------------------------------------------------------------------------- /src/route-handlers/log-to-server/log-to-server.types.ts: -------------------------------------------------------------------------------- 1 | import { type z } from 'zod'; 2 | 3 | import type logToServerPayloadSchema from './schemas/log-to-server-payload-schema'; 4 | 5 | export type LogToServerBody = z.infer; 6 | -------------------------------------------------------------------------------- /src/route-handlers/log-to-server/schemas/log-to-server-payload-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | import { LOG_LEVELS, type LogLevel } from '@/utils/logger'; 4 | 5 | const logToServerPayloadSchema = z.object({ 6 | level: z.custom( 7 | (v) => LOG_LEVELS.includes(v), 8 | 'Invalid log level: expected one of ' + LOG_LEVELS.toString() 9 | ), 10 | message: z.string(), 11 | payload: z.any(), 12 | }); 13 | 14 | export default logToServerPayloadSchema; 15 | -------------------------------------------------------------------------------- /src/route-handlers/query-workflow/query-workflow.types.ts: -------------------------------------------------------------------------------- 1 | import { type QueryRejected } from '@/__generated__/proto-ts/uber/cadence/api/v1/QueryRejected'; 2 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 3 | 4 | export type RouteParams = { 5 | domain: string; 6 | cluster: string; 7 | workflowId: string; 8 | runId: string; 9 | queryName: string; 10 | }; 11 | 12 | export type RequestParams = { 13 | params: RouteParams; 14 | }; 15 | 16 | export type QueryWorkflowResponse = { 17 | result: any; 18 | rejected: QueryRejected | null; 19 | }; 20 | 21 | export type Context = DefaultMiddlewaresContext; 22 | -------------------------------------------------------------------------------- /src/route-handlers/query-workflow/schemas/valid-query-input-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | const validQueryInputSchema = z.string().superRefine((str, ctx) => { 4 | if (str === '') return true; 5 | 6 | try { 7 | return JSON.parse(str); 8 | } catch { 9 | ctx.addIssue({ code: 'custom', message: 'Invalid JSON' }); 10 | return z.NEVER; 11 | } 12 | }); 13 | 14 | export default validQueryInputSchema; 15 | -------------------------------------------------------------------------------- /src/route-handlers/reset-workflow/reset-workflow.types.ts: -------------------------------------------------------------------------------- 1 | import { type ResetWorkflowExecutionResponse } from '@/__generated__/proto-ts/uber/cadence/api/v1/ResetWorkflowExecutionResponse'; 2 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 3 | 4 | export type RouteParams = { 5 | domain: string; 6 | cluster: string; 7 | workflowId: string; 8 | runId: string; 9 | }; 10 | 11 | export type RequestParams = { 12 | params: RouteParams; 13 | }; 14 | 15 | export type ResetWorkflowResponse = ResetWorkflowExecutionResponse; 16 | 17 | export type Context = DefaultMiddlewaresContext; 18 | -------------------------------------------------------------------------------- /src/route-handlers/reset-workflow/schemas/reset-workflow-request-body-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | const resetWorkflowRequestBodySchema = z.object({ 4 | reason: z 5 | .string() 6 | .optional() 7 | .default('Resetting workflow from cadence-web UI'), 8 | decisionFinishEventId: z.union([z.string(), z.number()]), 9 | requestId: z.string().optional(), 10 | skipSignalReapply: z.boolean().optional(), 11 | }); 12 | 13 | export default resetWorkflowRequestBodySchema; 14 | -------------------------------------------------------------------------------- /src/route-handlers/restart-workflow/restart-workflow.types.ts: -------------------------------------------------------------------------------- 1 | import { type RestartWorkflowExecutionResponse } from '@/__generated__/proto-ts/uber/cadence/api/v1/RestartWorkflowExecutionResponse'; 2 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 3 | 4 | export type RouteParams = { 5 | domain: string; 6 | cluster: string; 7 | workflowId: string; 8 | runId: string; 9 | }; 10 | 11 | export type RequestParams = { 12 | params: RouteParams; 13 | }; 14 | 15 | export type RestartWorkflowResponse = RestartWorkflowExecutionResponse; 16 | 17 | export type Context = DefaultMiddlewaresContext; 18 | -------------------------------------------------------------------------------- /src/route-handlers/restart-workflow/schemas/restart-workflow-request-body-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | const restartWorkflowRequestBodySchema = z.object({ 4 | reason: z 5 | .string() 6 | .optional() 7 | .default('Restarting workflow from cadence-web UI'), 8 | }); 9 | 10 | export default restartWorkflowRequestBodySchema; 11 | -------------------------------------------------------------------------------- /src/route-handlers/signal-workflow/schemas/signal-workflow-input-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | import losslessJsonParse from '@/utils/lossless-json-parse'; 4 | 5 | const signalWorkflowInputSchema = z.string().superRefine((str, ctx) => { 6 | if (!str) return undefined; 7 | 8 | try { 9 | return losslessJsonParse(str); 10 | } catch { 11 | ctx.addIssue({ code: 'custom', message: 'Invalid JSON' }); 12 | return z.NEVER; 13 | } 14 | }); 15 | 16 | export default signalWorkflowInputSchema; 17 | -------------------------------------------------------------------------------- /src/route-handlers/signal-workflow/schemas/signal-workflow-request-body-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | import signalWorkflowInputSchema from './signal-workflow-input-schema'; 4 | 5 | const signalWorkflowRequestBodySchema = z.object({ 6 | signalName: z.string().min(1), 7 | signalInput: signalWorkflowInputSchema.optional(), 8 | }); 9 | 10 | export default signalWorkflowRequestBodySchema; 11 | -------------------------------------------------------------------------------- /src/route-handlers/signal-workflow/signal-workflow.types.ts: -------------------------------------------------------------------------------- 1 | import { type z } from 'zod'; 2 | 3 | import { type GRPCClusterMethods } from '@/utils/grpc/grpc-client'; 4 | 5 | import type signalWorkflowRequestBodySchema from './schemas/signal-workflow-request-body-schema'; 6 | 7 | export type RequestParams = { 8 | params: { 9 | domain: string; 10 | cluster: string; 11 | workflowId: string; 12 | runId: string; 13 | }; 14 | }; 15 | 16 | export type SignalWorkflowRequestBody = z.infer< 17 | typeof signalWorkflowRequestBodySchema 18 | >; 19 | 20 | export type Context = { 21 | grpcClusterMethods: GRPCClusterMethods; 22 | }; 23 | -------------------------------------------------------------------------------- /src/route-handlers/terminate-workflow/schemas/terminate-workflow-request-body-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | const terminateWorkflowRequestBodySchema = z.object({ 4 | reason: z 5 | .string() 6 | .optional() 7 | .default('Terminating workflow from cadence-web UI'), 8 | }); 9 | 10 | export default terminateWorkflowRequestBodySchema; 11 | -------------------------------------------------------------------------------- /src/route-handlers/terminate-workflow/terminate-workflow.types.ts: -------------------------------------------------------------------------------- 1 | import { type TerminateWorkflowExecutionResponse } from '@/__generated__/proto-ts/uber/cadence/api/v1/TerminateWorkflowExecutionResponse'; 2 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 3 | 4 | export type RouteParams = { 5 | domain: string; 6 | cluster: string; 7 | workflowId: string; 8 | runId: string; 9 | }; 10 | 11 | export type RequestParams = { 12 | params: RouteParams; 13 | }; 14 | 15 | export type TerminateWorkflowResponse = TerminateWorkflowExecutionResponse; 16 | 17 | export type Context = DefaultMiddlewaresContext; 18 | -------------------------------------------------------------------------------- /src/route-handlers/update-domain/update-domain.types.ts: -------------------------------------------------------------------------------- 1 | import { type Domain } from '@/__generated__/proto-ts/uber/cadence/api/v1/Domain'; 2 | import { type UpdateDomainRequest__Input } from '@/__generated__/proto-ts/uber/cadence/api/v1/UpdateDomainRequest'; 3 | import { type DefaultMiddlewaresContext } from '@/utils/route-handlers-middleware'; 4 | 5 | export type RouteParams = { 6 | domain: string; 7 | cluster: string; 8 | }; 9 | 10 | export type RequestParams = { 11 | params: RouteParams; 12 | }; 13 | 14 | export type UpdateDomainFields = Omit< 15 | UpdateDomainRequest__Input, 16 | 'securityToken' | 'name' | 'updateMask' 17 | >; 18 | 19 | export type UpdateDomainResponse = Domain; 20 | 21 | export type Context = DefaultMiddlewaresContext; 22 | -------------------------------------------------------------------------------- /src/styletron.ts: -------------------------------------------------------------------------------- 1 | import { Client, Server } from 'styletron-engine-monolithic'; 2 | import { DebugEngine } from 'styletron-react'; 3 | 4 | const getHydrateClass = () => 5 | document.getElementsByClassName('_styletron_hydrate_'); 6 | 7 | export const styletron = 8 | typeof window === 'undefined' 9 | ? new Server() 10 | : new Client({ 11 | hydrate: getHydrateClass(), 12 | }); 13 | 14 | export const debug = 15 | process.env.NODE_ENV === 'production' ? void 0 : new DebugEngine(); 16 | -------------------------------------------------------------------------------- /src/test-utils/msw-mock-handlers/msw-mock-handlers.tsx: -------------------------------------------------------------------------------- 1 | import { memo } from 'react'; 2 | 3 | import mswMockEndpoints from './helper/msw-mock-endpoints'; 4 | import { type Props } from './msw-mock-handlers.types'; 5 | 6 | export default memo(function MSWMockHandlers({ endpointsMocks }: Props) { 7 | if (endpointsMocks) mswMockEndpoints(endpointsMocks); 8 | 9 | return null; 10 | }); 11 | -------------------------------------------------------------------------------- /src/test-utils/msw-mock-handlers/msw-mock-handlers.types.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | type Path, 3 | type http, 4 | type HttpResponseResolver, 5 | type JsonBodyType, 6 | } from 'msw'; 7 | 8 | export type HttpEndpointMock = { 9 | path: Path; 10 | httpMethod: Uppercase; 11 | jsonResponse?: JsonBodyType; 12 | httpResolver?: HttpResponseResolver; 13 | mockOnce?: boolean; 14 | }; 15 | 16 | export type Props = { 17 | endpointsMocks?: Array; 18 | }; 19 | -------------------------------------------------------------------------------- /src/test-utils/rtl.types.tsx: -------------------------------------------------------------------------------- 1 | import type { JSXElementConstructor, ReactNode } from 'react'; 2 | 3 | import type { Props as TestProviderProps } from './test-provider.types'; 4 | 5 | export type PublicProviderProps = Omit; 6 | 7 | export type RenderHookOptions = { 8 | initialProps?: T; 9 | wrapper?: JSXElementConstructor<{ 10 | children: ReactNode; 11 | }>; 12 | }; 13 | -------------------------------------------------------------------------------- /src/test-utils/test-provider.types.tsx: -------------------------------------------------------------------------------- 1 | import { type ReactElement } from 'react'; 2 | 3 | import { type QueryClientConfig } from '@tanstack/react-query'; 4 | 5 | import type { Props as MSWMocksHandlersProps } from './msw-mock-handlers/msw-mock-handlers.types'; 6 | 7 | export type Props = { 8 | children?: ReactElement; 9 | router?: { 10 | initialUrl?: string; 11 | pathnames?: string[]; 12 | }; 13 | queryClientConfig?: QueryClientConfig; 14 | endpointsMocks?: MSWMocksHandlersProps['endpointsMocks']; 15 | enableAnimations?: boolean; 16 | isSnapshotTest?: boolean; 17 | }; 18 | -------------------------------------------------------------------------------- /src/utils/config/__mocks__/get-config-value.ts: -------------------------------------------------------------------------------- 1 | import mockResolvedConfigValues from '../__fixtures__/resolved-config-values'; 2 | import { type LoadedConfigResolvedValues } from '../config.types'; 3 | 4 | export default jest.fn(function ( 5 | key: K 6 | ) { 7 | return Promise.resolve(mockResolvedConfigValues[key]); 8 | }); 9 | -------------------------------------------------------------------------------- /src/utils/config/__tests__/get-config-value.test.ts: -------------------------------------------------------------------------------- 1 | import getConfigValue from '../get-config-value'; 2 | 3 | jest.mock('../global-configs-ref', () => ({ 4 | loadedGlobalConfigs: { 5 | CADENCE_WEB_PORT: 'someValue', 6 | }, 7 | })); 8 | 9 | describe('getConfigValue', () => { 10 | beforeEach(() => { 11 | jest.clearAllMocks(); 12 | }); 13 | 14 | it('throws an error when invoked in the browser', async () => { 15 | (global as any).window = {}; 16 | await expect(getConfigValue('CADENCE_WEB_PORT', undefined)).rejects.toThrow( 17 | 'getConfigValue cannot be invoked on browser' 18 | ); 19 | delete (global as any).window; 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/utils/config/get-transformed-configs.ts: -------------------------------------------------------------------------------- 1 | import 'server-only'; 2 | 3 | import configDefinitions from '../../config/dynamic/dynamic.config'; 4 | import resolverSchemas from '../../config/dynamic/resolvers/schemas/resolver-schemas'; 5 | 6 | import type { LoadedConfigs } from './config.types'; 7 | import transformConfigs from './transform-configs'; 8 | 9 | export default async function getTransformedConfigs(): Promise { 10 | return await transformConfigs(configDefinitions, resolverSchemas); 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/config/global-configs-ref.ts: -------------------------------------------------------------------------------- 1 | import GlobalRef from '../global-ref'; 2 | 3 | import { type LoadedConfigs } from './config.types'; 4 | 5 | const globalConfigRef = new GlobalRef('cadence-config'); 6 | const setLoadedGlobalConfigs = (c: LoadedConfigs): void => { 7 | globalConfigRef.value = c; 8 | }; 9 | 10 | const getLoadedGlobalConfigs = (): LoadedConfigs => { 11 | return globalConfigRef.value; 12 | }; 13 | 14 | export { getLoadedGlobalConfigs, setLoadedGlobalConfigs }; 15 | -------------------------------------------------------------------------------- /src/utils/data-formatters/__tests__/format-date.test.ts: -------------------------------------------------------------------------------- 1 | import formatDate from '../format-date'; 2 | 3 | jest.useFakeTimers().setSystemTime(new Date('2023-05-25')); 4 | 5 | describe(formatDate.name, () => { 6 | it('returns formatted date for the current year', () => { 7 | expect(formatDate(new Date('2023-01-01T12:34:56').getTime())).toEqual( 8 | '01 Jan, 12:34:56 UTC' 9 | ); 10 | }); 11 | 12 | it('returns formatted date for a prior year', () => { 13 | expect(formatDate(new Date('2022-01-01T12:34:56').getTime())).toEqual( 14 | '01 Jan 2022, 12:34:56 UTC' 15 | ); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-date.ts: -------------------------------------------------------------------------------- 1 | import dayjs from '@/utils/datetime/dayjs'; 2 | 3 | export default function formatDate(timestampMs: number) { 4 | const date = dayjs(timestampMs); 5 | const now = dayjs(); 6 | return date.format( 7 | date.isSame(now, 'year') ? 'DD MMM, HH:mm:ss z' : 'DD MMM YYYY, HH:mm:ss z' 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-duration-to-seconds.ts: -------------------------------------------------------------------------------- 1 | import { type Duration } from '@/__generated__/proto-ts/google/protobuf/Duration'; 2 | 3 | const formatDurationToSeconds = ( 4 | duration?: Pick | null 5 | ) => (duration ? parseInt(String(duration.seconds)) : null); 6 | 7 | export default formatDurationToSeconds; 8 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-failure-details.ts: -------------------------------------------------------------------------------- 1 | import { type Failure } from '@/__generated__/proto-ts/uber/cadence/api/v1/Failure'; 2 | 3 | const formatFailureDetails = (failure: Pick | null) => { 4 | if (!failure?.details) { 5 | return null; 6 | } 7 | 8 | const decodedFailureDetails = atob(failure.details); 9 | 10 | try { 11 | return JSON.parse(decodedFailureDetails); 12 | } catch { 13 | return decodedFailureDetails; 14 | } 15 | }; 16 | 17 | export default formatFailureDetails; 18 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-payload-map.ts: -------------------------------------------------------------------------------- 1 | import formatPayload from './format-payload'; 2 | 3 | const formatPayloadMap = ( 4 | map: { [key in K]: any } | null | undefined, 5 | fieldKey: K 6 | ) => { 7 | if (!map?.[fieldKey]) { 8 | return null; 9 | } 10 | 11 | return { 12 | [fieldKey]: Object.keys(map[fieldKey]) 13 | .map((key) => ({ 14 | [key]: formatPayload(map[fieldKey][key]), 15 | })) 16 | .reduce( 17 | (accumulator, value) => ({ 18 | ...accumulator, 19 | ...value, 20 | }), 21 | {} 22 | ), 23 | } as { [key in K]: any }; 24 | }; 25 | 26 | export default formatPayloadMap; 27 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-prev-auto-reset-points.ts: -------------------------------------------------------------------------------- 1 | import { type ResetPoints } from '@/__generated__/proto-ts/uber/cadence/api/v1/ResetPoints'; 2 | 3 | import formatTimestampToDatetime from './format-timestamp-to-datetime'; 4 | 5 | const formatPrevAutoResetPoints = (prevAutoResetPoints: ResetPoints | null) => { 6 | const points = prevAutoResetPoints?.points; 7 | 8 | if (!points) { 9 | return null; 10 | } 11 | 12 | return { 13 | points: points.map(({ createdTime, expiringTime, ...point }) => ({ 14 | ...point, 15 | createdTimeNano: formatTimestampToDatetime(createdTime), 16 | expiringTimeNano: formatTimestampToDatetime(expiringTime), 17 | })), 18 | }; 19 | }; 20 | 21 | export default formatPrevAutoResetPoints; 22 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-retry-policy.ts: -------------------------------------------------------------------------------- 1 | import type { RetryPolicy } from '@/__generated__/proto-ts/uber/cadence/api/v1/RetryPolicy'; 2 | 3 | import formatDurationToSeconds from './format-duration-to-seconds'; 4 | 5 | const formatRetryPolicy = (retryPolicy: RetryPolicy | null | undefined) => { 6 | if (!retryPolicy) { 7 | return null; 8 | } 9 | 10 | const { expirationInterval, initialInterval, maximumInterval, ...rest } = 11 | retryPolicy; 12 | 13 | return { 14 | expirationIntervalInSeconds: formatDurationToSeconds(expirationInterval), 15 | initialIntervalInSeconds: formatDurationToSeconds(initialInterval), 16 | maximumIntervalInSeconds: formatDurationToSeconds(maximumInterval), 17 | ...rest, 18 | }; 19 | }; 20 | 21 | export default formatRetryPolicy; 22 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-timestamp-to-datetime.ts: -------------------------------------------------------------------------------- 1 | const formatTimestampToDatetime = ( 2 | timestamp: 3 | | { seconds: number | string; nanos: number | string } 4 | | null 5 | | undefined 6 | ) => 7 | timestamp 8 | ? new Date( 9 | parseInt(String(timestamp.seconds)) * 1000 + 10 | parseInt(String(timestamp.nanos)) / 1e6 11 | ) 12 | : null; 13 | 14 | export default formatTimestampToDatetime; 15 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-event-id.ts: -------------------------------------------------------------------------------- 1 | import toNumber from 'lodash/toNumber'; 2 | 3 | const formatWorkflowEventId = (input: string | number | null | undefined) => { 4 | if (input === null || input === undefined || input === '') return null; 5 | const parsedNumber = toNumber(input); 6 | return isNaN(parsedNumber) ? input : parsedNumber; 7 | }; 8 | 9 | export default formatWorkflowEventId; 10 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-activity-task-cancel-requested-event.ts: -------------------------------------------------------------------------------- 1 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 2 | import { type ActivityTaskCancelRequestedEvent } from './format-workflow-history-event.type'; 3 | 4 | const formatActivityTaskCancelRequestedEvent = ({ 5 | activityTaskCancelRequestedEventAttributes: { 6 | decisionTaskCompletedEventId, 7 | ...eventAttributes 8 | }, 9 | ...eventFields 10 | }: ActivityTaskCancelRequestedEvent) => { 11 | return { 12 | ...formatWorkflowCommonEventFields(eventFields), 13 | ...eventAttributes, 14 | decisionTaskCompletedEventId: parseInt(decisionTaskCompletedEventId), 15 | }; 16 | }; 17 | 18 | export default formatActivityTaskCancelRequestedEvent; 19 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-cancel-timer-failed-event.ts: -------------------------------------------------------------------------------- 1 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 2 | import { type CancelTimerFailedEvent } from './format-workflow-history-event.type'; 3 | 4 | const formatCancelTimerFailedEvent = ({ 5 | cancelTimerFailedEventAttributes: { 6 | decisionTaskCompletedEventId, 7 | ...eventAttributes 8 | }, 9 | ...eventFields 10 | }: CancelTimerFailedEvent) => { 11 | return { 12 | ...formatWorkflowCommonEventFields(eventFields), 13 | ...eventAttributes, 14 | decisionTaskCompletedEventId: parseInt(decisionTaskCompletedEventId), 15 | }; 16 | }; 17 | 18 | export default formatCancelTimerFailedEvent; 19 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-decision-task-completed-event.ts: -------------------------------------------------------------------------------- 1 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 2 | import { type DecisionTaskCompletedEvent } from './format-workflow-history-event.type'; 3 | 4 | const formatDecisionTaskCompletedEvent = ({ 5 | decisionTaskCompletedEventAttributes: { ...eventAttributes }, 6 | ...eventFields 7 | }: DecisionTaskCompletedEvent) => { 8 | return { 9 | ...formatWorkflowCommonEventFields(eventFields), 10 | ...eventAttributes, 11 | }; 12 | }; 13 | 14 | export default formatDecisionTaskCompletedEvent; 15 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-decision-task-started-event.ts: -------------------------------------------------------------------------------- 1 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 2 | import { type DecisionTaskStartedEvent } from './format-workflow-history-event.type'; 3 | 4 | const formatDecisionTaskStartedEvent = ({ 5 | decisionTaskStartedEventAttributes: { scheduledEventId, ...eventAttributes }, 6 | ...eventFields 7 | }: DecisionTaskStartedEvent) => { 8 | return { 9 | ...formatWorkflowCommonEventFields(eventFields), 10 | ...eventAttributes, 11 | scheduledEventId: parseInt(scheduledEventId), 12 | }; 13 | }; 14 | 15 | export default formatDecisionTaskStartedEvent; 16 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-timer-canceled-event.ts: -------------------------------------------------------------------------------- 1 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 2 | import { type TimerCanceledEvent } from './format-workflow-history-event.type'; 3 | 4 | const formatTimerCanceledEvent = ({ 5 | timerCanceledEventAttributes: { 6 | decisionTaskCompletedEventId, 7 | startedEventId, 8 | ...eventAttributes 9 | }, 10 | ...eventFields 11 | }: TimerCanceledEvent) => { 12 | return { 13 | ...formatWorkflowCommonEventFields(eventFields), 14 | ...eventAttributes, 15 | decisionTaskCompletedEventId: parseInt(decisionTaskCompletedEventId), 16 | startedEventId: parseInt(startedEventId), 17 | }; 18 | }; 19 | 20 | export default formatTimerCanceledEvent; 21 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-timer-fired-event.ts: -------------------------------------------------------------------------------- 1 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 2 | import { type TimerFiredEvent } from './format-workflow-history-event.type'; 3 | 4 | const formatTimerFiredEvent = ({ 5 | timerFiredEventAttributes: { startedEventId, ...eventAttributes }, 6 | ...eventFields 7 | }: TimerFiredEvent) => { 8 | return { 9 | ...formatWorkflowCommonEventFields(eventFields), 10 | ...eventAttributes, 11 | startedEventId: parseInt(startedEventId), 12 | }; 13 | }; 14 | 15 | export default formatTimerFiredEvent; 16 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-workflow-execution-signaled-event.ts: -------------------------------------------------------------------------------- 1 | import formatInputPayload from '../format-input-payload'; 2 | 3 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 4 | import { type WorkflowExecutionSignaledEvent } from './format-workflow-history-event.type'; 5 | 6 | const formatWorkflowExecutionSignaledEvent = ({ 7 | workflowExecutionSignaledEventAttributes: { input, ...eventAttributes }, 8 | ...eventFields 9 | }: WorkflowExecutionSignaledEvent) => { 10 | return { 11 | ...formatWorkflowCommonEventFields(eventFields), 12 | ...eventAttributes, 13 | input: formatInputPayload(input), 14 | }; 15 | }; 16 | 17 | export default formatWorkflowExecutionSignaledEvent; 18 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-workflow-execution-terminated-event.ts: -------------------------------------------------------------------------------- 1 | import formatPayload from '../format-payload'; 2 | 3 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 4 | import { type WorkflowExecutionTerminatedEvent } from './format-workflow-history-event.type'; 5 | 6 | const formatWorkflowExecutionTerminatedEvent = ({ 7 | workflowExecutionTerminatedEventAttributes: { details, ...eventAttributes }, 8 | ...eventFields 9 | }: WorkflowExecutionTerminatedEvent) => { 10 | return { 11 | ...formatWorkflowCommonEventFields(eventFields), 12 | ...eventAttributes, 13 | details: formatPayload(details), 14 | }; 15 | }; 16 | 17 | export default formatWorkflowExecutionTerminatedEvent; 18 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/format-workflow-execution-timed-out-event.ts: -------------------------------------------------------------------------------- 1 | import formatWorkflowCommonEventFields from './format-workflow-common-event-fields'; 2 | import { type WorkflowExecutionTimedOutEvent } from './format-workflow-history-event.type'; 3 | 4 | const formatWorkflowExecutionTimedOutEvent = ({ 5 | workflowExecutionTimedOutEventAttributes: { ...eventAttributes }, 6 | ...eventFields 7 | }: WorkflowExecutionTimedOutEvent) => { 8 | return { 9 | ...formatWorkflowCommonEventFields(eventFields), 10 | ...eventAttributes, 11 | }; 12 | }; 13 | 14 | export default formatWorkflowExecutionTimedOutEvent; 15 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history-event/index.ts: -------------------------------------------------------------------------------- 1 | import type { HistoryEvent } from '@/__generated__/proto-ts/uber/cadence/api/v1/HistoryEvent'; 2 | import logger from '@/utils/logger'; 3 | 4 | import { 5 | type FormattedHistoryEvent, 6 | getFormatHistoryEventSchema, 7 | } from '../schema/format-history-event-schema'; 8 | 9 | export default function formatWorkflowHistoryEvent( 10 | event: HistoryEvent 11 | ): FormattedHistoryEvent | null { 12 | const schema = getFormatHistoryEventSchema(event); 13 | if (schema) { 14 | const { data, error } = schema.safeParse(event); 15 | if (error) { 16 | logger.warn({ error: error }, 'Failed to format workflow event'); 17 | return null; 18 | } 19 | return data ?? null; 20 | } 21 | return null; 22 | } 23 | -------------------------------------------------------------------------------- /src/utils/data-formatters/format-workflow-history.ts: -------------------------------------------------------------------------------- 1 | import { type GetWorkflowHistoryResponse } from '@/route-handlers/get-workflow-history/get-workflow-history.types'; 2 | 3 | import formatWorkflowHistoryEvent from './format-workflow-history-event'; 4 | 5 | const formatWorkflowHistory = ({ 6 | archived, 7 | history, 8 | rawHistory, 9 | ...response 10 | }: GetWorkflowHistoryResponse) => ({ 11 | ...response, 12 | archived: archived || null, 13 | history: { 14 | events: (history?.events || []).map(formatWorkflowHistoryEvent), 15 | }, 16 | rawHistory: rawHistory?.length ? rawHistory : null, 17 | }); 18 | 19 | export default formatWorkflowHistory; 20 | -------------------------------------------------------------------------------- /src/utils/datetime/__tests__/get-grpc-timestamp-from-iso.test.ts: -------------------------------------------------------------------------------- 1 | import getGrpcTimestampFromIso from '../get-grpc-timestamp-from-iso'; 2 | 3 | describe(getGrpcTimestampFromIso.name, () => { 4 | it('should get a GRPC Timestamp object given the ISO 8601 date', () => { 5 | expect(getGrpcTimestampFromIso('2024-04-02T22:15:00.000Z')).toEqual({ 6 | seconds: 1712096100, 7 | nanos: 0, 8 | }); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/utils/datetime/__tests__/parse-grpc-timestamp.test.ts: -------------------------------------------------------------------------------- 1 | import parseGrpcTimestamp from '../parse-grpc-timestamp'; 2 | 3 | describe('parseGrpcTimestamp', () => { 4 | it('should parse GRPC timestamp correctly', () => { 5 | const time = { seconds: '1717408148', nanos: 258000000 }; 6 | const parsedTimestamp = parseGrpcTimestamp(time); 7 | expect(parsedTimestamp).toEqual(1717408148258); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/utils/datetime/dayjs.ts: -------------------------------------------------------------------------------- 1 | import { default as dayjs } from 'dayjs'; 2 | import advancedFormat from 'dayjs/plugin/advancedFormat'; 3 | import duration from 'dayjs/plugin/duration'; 4 | import relativeTime from 'dayjs/plugin/relativeTime'; 5 | import timezone from 'dayjs/plugin/timezone'; 6 | import utc from 'dayjs/plugin/utc'; 7 | 8 | dayjs.extend(relativeTime); 9 | dayjs.extend(duration); 10 | dayjs.extend(utc); 11 | dayjs.extend(timezone); 12 | dayjs.extend(advancedFormat); 13 | 14 | export default dayjs; 15 | -------------------------------------------------------------------------------- /src/utils/datetime/get-grpc-timestamp-from-iso.ts: -------------------------------------------------------------------------------- 1 | import type { Timestamp__Input } from '@/__generated__/proto-ts/google/protobuf/Timestamp'; 2 | 3 | export default function getGrpcTimestampFromIso( 4 | isoDate: string 5 | ): Timestamp__Input { 6 | const date = new Date(isoDate); 7 | return { 8 | seconds: date.getTime() / 1000, 9 | nanos: date.getUTCMilliseconds() * 1000000, 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/datetime/parse-date-query-param.ts: -------------------------------------------------------------------------------- 1 | export default function parseDateQueryParam( 2 | dateString: string 3 | ): Date | undefined { 4 | const date = new Date(dateString); 5 | return isNaN(date.getTime()) ? undefined : date; 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/datetime/parse-grpc-timestamp.ts: -------------------------------------------------------------------------------- 1 | import { type Duration } from '@/__generated__/proto-ts/google/protobuf/Duration'; 2 | import type { Timestamp } from '@/__generated__/proto-ts/google/protobuf/Timestamp'; 3 | 4 | export default function parseGrpcTimestamp(time: Timestamp | Duration): number { 5 | return parseInt(time.seconds) * 1000 + time.nanos / 1000000; 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/decode-url-params.ts: -------------------------------------------------------------------------------- 1 | export default function decodeUrlParams( 2 | params: Params 3 | ): Params { 4 | return Object.fromEntries( 5 | Object.entries(params).map(([key, value]) => [ 6 | key, 7 | decodeURIComponent(value), 8 | ]) 9 | ) as Params; // shrink object type to include only keys from params 10 | } 11 | -------------------------------------------------------------------------------- /src/utils/download-json.ts: -------------------------------------------------------------------------------- 1 | import losslessJsonStringify from './lossless-json-stringify'; 2 | 3 | export default function downloadJson(jsonData: any, filename: string) { 4 | if (typeof window === 'undefined') { 5 | return; 6 | } 7 | 8 | const blob = new Blob([losslessJsonStringify(jsonData, null, '\t')], { 9 | type: 'application/json', 10 | }); 11 | const url = window.URL.createObjectURL(blob); 12 | const a = document.createElement('a'); 13 | a.href = url; 14 | a.download = `${filename}.json`; 15 | document.body.appendChild(a); 16 | a.click(); 17 | document.body.removeChild(a); 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/global-ref.ts: -------------------------------------------------------------------------------- 1 | export default class GlobalRef { 2 | private readonly sym: symbol; 3 | 4 | constructor(uniqueName: string, defaultValue?: T) { 5 | this.sym = Symbol.for(uniqueName); 6 | const g = global as any; 7 | if (g[this.sym] === undefined) g[this.sym] = defaultValue; 8 | } 9 | 10 | get value() { 11 | return (global as any)[this.sym] as T; 12 | } 13 | 14 | set value(value: T) { 15 | (global as any)[this.sym] = value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/logger/console/helpers/strip-escapes-from-next-log.ts: -------------------------------------------------------------------------------- 1 | export default function stripEscapesFromNextLog(str: string): string { 2 | // This regex matches all ANSI escape sequences that next.js likes to put in the console logs 3 | return str.replace( 4 | /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, 5 | '' 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/logger/console/register-console-logger.constants.ts: -------------------------------------------------------------------------------- 1 | import { type LogLevel } from '..'; 2 | 3 | import { type ConsoleLogLevel } from './register-console-logger.types'; 4 | 5 | export const NEXTJS_ERROR_PREFIX = '⨯'; 6 | 7 | export const CONSOLE_LOG_LEVEL_TO_LOG_LEVEL_MAP: Record< 8 | ConsoleLogLevel, 9 | LogLevel 10 | > = { 11 | error: 'error', 12 | warn: 'warn', 13 | info: 'info', 14 | log: 'info', 15 | debug: 'debug', 16 | }; 17 | -------------------------------------------------------------------------------- /src/utils/logger/console/register-console-logger.types.ts: -------------------------------------------------------------------------------- 1 | export type ConsoleLogLevel = 'error' | 'info' | 'warn' | 'debug' | 'log'; 2 | -------------------------------------------------------------------------------- /src/utils/logger/index.ts: -------------------------------------------------------------------------------- 1 | // Logger 2 | import logger from './pino/pino'; 3 | 4 | // Register logger 5 | export { registerLoggers } from './logger-register'; 6 | 7 | // Constants 8 | export const LOG_LEVELS = Object.values(logger.levels.labels); 9 | 10 | // Types 11 | export { type LogLevel as LogLevel } from './pino/pino.types'; 12 | export * from './logger.types'; 13 | 14 | export default logger; 15 | -------------------------------------------------------------------------------- /src/utils/logger/logger-register.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | /* Registering console loggers in this file */ 3 | 4 | import logger from '.'; 5 | import registerConsoleLogger from './console/register-console-logger'; 6 | 7 | export function registerLoggers() { 8 | if (process.env.NEXT_RUNTIME === 'nodejs') { 9 | const consoleLogger = logger.child({ name: 'console' }); 10 | console.error = registerConsoleLogger(consoleLogger, 'error'); 11 | console.log = registerConsoleLogger(consoleLogger, 'log'); 12 | console.info = registerConsoleLogger(consoleLogger, 'info'); 13 | console.warn = registerConsoleLogger(consoleLogger, 'warn'); 14 | console.debug = registerConsoleLogger(consoleLogger, 'debug'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/utils/logger/logger.types.ts: -------------------------------------------------------------------------------- 1 | import type logger from '.'; 2 | 3 | export type Logger = typeof logger; 4 | 5 | export type RouteHandlerErrorPayload = { 6 | error?: any; 7 | requestParams?: object; 8 | queryParams?: object; 9 | }; 10 | -------------------------------------------------------------------------------- /src/utils/logger/pino/pino.ts: -------------------------------------------------------------------------------- 1 | import { pino } from 'pino'; 2 | 3 | import LOGGER_CONFIG from './pino.config'; 4 | import { type CustomLevels } from './pino.types'; 5 | 6 | const logger = pino(LOGGER_CONFIG); 7 | 8 | export default logger; 9 | -------------------------------------------------------------------------------- /src/utils/logger/pino/pino.types.ts: -------------------------------------------------------------------------------- 1 | import { type Level } from 'pino'; 2 | 3 | // To add custom levels, change this to a union type with your custom levels 4 | export type CustomLevels = never; 5 | 6 | export type LogLevel = Level | CustomLevels; 7 | -------------------------------------------------------------------------------- /src/utils/lossless-json-parse.ts: -------------------------------------------------------------------------------- 1 | import { parse, isSafeNumber, isInteger, type Reviver } from 'lossless-json'; 2 | 3 | export default function losslessJsonParse( 4 | json: string, 5 | reviver?: Reviver | null | undefined 6 | ) { 7 | return parse(json, reviver, (value) => { 8 | if (!isSafeNumber(value)) { 9 | return BigInt(value); 10 | } 11 | if (isInteger(value)) { 12 | return parseInt(value); 13 | } 14 | return parseFloat(value); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /src/utils/lossless-json-stringify.ts: -------------------------------------------------------------------------------- 1 | import { stringify, type Reviver } from 'lossless-json'; 2 | 3 | export default function losslessJsonStringify( 4 | json: unknown, 5 | reviver?: Reviver | null | undefined, 6 | space?: string | number | undefined 7 | ) { 8 | const stringified = stringify(json, reviver, space, [ 9 | { 10 | test: (value) => typeof value === 'bigint', 11 | stringify: (value) => (value || '').toString(), 12 | }, 13 | ]); 14 | 15 | return stringified || ''; 16 | } 17 | -------------------------------------------------------------------------------- /src/utils/media-query/__tests__/get-media-queries-for-breakpoints.test.ts: -------------------------------------------------------------------------------- 1 | import { getMediaQueriesForBreakpoints } from '../get-media-queries-for-breakpoints'; 2 | 3 | describe('getMediaQueriesForBreakpoints', () => { 4 | it('should return an array of media queries sorted in ascending order', () => { 5 | const breakpoints = { 6 | small: 480, 7 | medium: 768, 8 | large: 1024, 9 | }; 10 | const expectedMediaQueries = [ 11 | '@media screen and (min-width: 480px)', 12 | '@media screen and (min-width: 768px)', 13 | '@media screen and (min-width: 1024px)', 14 | ]; 15 | expect(getMediaQueriesForBreakpoints(breakpoints)).toEqual( 16 | expectedMediaQueries 17 | ); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/utils/media-query/get-media-queries-for-breakpoints.ts: -------------------------------------------------------------------------------- 1 | import type { Breakpoints } from 'baseui/themes'; 2 | 3 | const getMediaQuery = (breakpoint: number): string => 4 | `@media screen and (min-width: ${breakpoint}px)`; 5 | 6 | export const getMediaQueriesForBreakpoints = ( 7 | breakpoints: Breakpoints 8 | ): string[] => 9 | Object.keys(breakpoints) 10 | .map((key) => breakpoints[key as keyof Breakpoints]) 11 | .sort((a, b) => a - b) 12 | .map(getMediaQuery); 13 | -------------------------------------------------------------------------------- /src/utils/msw/node.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | export const server = setupServer(); 4 | -------------------------------------------------------------------------------- /src/utils/otel/otel.types.ts: -------------------------------------------------------------------------------- 1 | import { type GrpcInstrumentationConfig } from '@opentelemetry/instrumentation-grpc'; 2 | import { type NodeSDKConfiguration } from '@opentelemetry/sdk-node'; 3 | 4 | export type OtelRegisterConfig = Partial & { 5 | grpcInstrumentationConfig?: GrpcInstrumentationConfig; 6 | }; 7 | -------------------------------------------------------------------------------- /src/utils/request/index.ts: -------------------------------------------------------------------------------- 1 | import request from './request'; 2 | 3 | export default request; 4 | -------------------------------------------------------------------------------- /src/utils/request/request-error.ts: -------------------------------------------------------------------------------- 1 | import { type ZodIssue } from 'zod'; 2 | 3 | export class RequestError extends Error { 4 | url: string; 5 | status: number; 6 | validationErrors: Array | undefined; 7 | constructor( 8 | message: string, 9 | url: string, 10 | status: number, 11 | validationErrors?: Array, 12 | options?: ErrorOptions 13 | ) { 14 | super(message, options); 15 | this.url = url; 16 | this.status = status; 17 | if (validationErrors?.length) { 18 | this.validationErrors = validationErrors; 19 | } 20 | this.name = 'RequestError'; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/utils/route-handlers-middleware/config/route-handlers-default-middlewares.config.ts: -------------------------------------------------------------------------------- 1 | import { type GRPCClusterMethods } from '@/utils/grpc/grpc-client'; 2 | 3 | import grpcClusterMethodsMiddleware from '../middlewares/grpc-cluster-methods'; 4 | import { type MiddlewareFunction } from '../route-handlers-middleware.types'; 5 | 6 | const routeHandlersDefaultMiddlewares: [ 7 | MiddlewareFunction<['grpcClusterMethods', GRPCClusterMethods]>, 8 | ] = [grpcClusterMethodsMiddleware]; 9 | 10 | export default routeHandlersDefaultMiddlewares; 11 | -------------------------------------------------------------------------------- /src/utils/route-handlers-middleware/helpers/is-object-of-string-key-value.ts: -------------------------------------------------------------------------------- 1 | import isPlainObject from 'lodash/isPlainObject'; 2 | 3 | export default function isObjectOfStringKeyValue( 4 | v: any 5 | ): v is Record { 6 | return ( 7 | isPlainObject(v) && 8 | Reflect.ownKeys(v).every((k) => typeof k === 'string') && 9 | Object.values(v).every((v) => typeof v === 'string') 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/route-handlers-middleware/index.ts: -------------------------------------------------------------------------------- 1 | export { default as routeHandlerWithMiddlewares } from './route-handler-with-middlewares'; 2 | 3 | export { type DefaultMiddlewaresContext } from './route-handlers-middleware.types'; 4 | -------------------------------------------------------------------------------- /src/views/domain-page/__fixtures__/domain-metadata.ts: -------------------------------------------------------------------------------- 1 | import { type DomainMetadata } from '../domain-page-metadata/domain-page-metadata.types'; 2 | 3 | import { mockDomainDescription } from './domain-description'; 4 | 5 | export const mockDomainMetadata = { 6 | domainDescription: mockDomainDescription, 7 | isExtendedMetadataEnabled: false, 8 | } as const satisfies DomainMetadata; 9 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-content/domain-page-content.styles.ts: -------------------------------------------------------------------------------- 1 | import { withStyle } from 'baseui'; 2 | 3 | import PageSection from '@/components/page-section/page-section'; 4 | 5 | export const styled = { 6 | PageSection: withStyle(PageSection, () => ({ 7 | display: 'flex', 8 | flexDirection: 'column', 9 | flex: 1, 10 | })), 11 | }; 12 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-content/domain-page-content.types.ts: -------------------------------------------------------------------------------- 1 | import { type DomainPageTabName } from '../domain-page-tabs/domain-page-tabs.types'; 2 | 3 | export type DomainPageContentParams = { 4 | domain: string; 5 | cluster: string; 6 | domainTab: DomainPageTabName; 7 | }; 8 | 9 | export type Props = { 10 | params: DomainPageContentParams; 11 | }; 12 | 13 | export type DomainPageTabContentProps = { 14 | domain: string; 15 | cluster: string; 16 | }; 17 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-context-provider/domain-page-context-provider.types.tsx: -------------------------------------------------------------------------------- 1 | import { type PublicLoadedConfig } from '@/utils/config/config.types'; 2 | 3 | export type DomainPageContextType = { 4 | pageConfig: Pick; 5 | }; 6 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-error/domain-page-error.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | error: Error; 3 | reset: () => void; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-header-info-item/domain-page-header-info-item.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | title: string; 3 | loading: boolean; 4 | content?: React.ReactNode; 5 | placeholderSize: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-header-info-loader/domain-page-header-info-loader.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import React from 'react'; 3 | 4 | import useSuspenseDomainDescription from '@/views/shared/hooks/use-domain-description/use-suspense-domain-description'; 5 | 6 | import DomainPageHeaderInfo from '../domain-page-header-info/domain-page-header-info'; 7 | 8 | import { type Props } from './domain-page-header-info-loader.types'; 9 | 10 | export default function DomainPageHeaderInfoLoader(props: Props) { 11 | const { data: domainDescription } = useSuspenseDomainDescription(props); 12 | 13 | return ( 14 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-header-info-loader/domain-page-header-info-loader.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-header-info/domain-page-header-info.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled } from 'baseui'; 2 | 3 | export const styled = { 4 | DomainDetailsContainer: createStyled('div', ({ $theme }) => ({ 5 | display: 'flex', 6 | flexDirection: 'column', 7 | flexWrap: 'wrap', 8 | columnGap: $theme.sizing.scale850, 9 | rowGap: $theme.sizing.scale500, 10 | [$theme.mediaQuery.medium]: { 11 | flexDirection: 'row', 12 | }, 13 | })), 14 | }; 15 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-header-status-tag/domain-page-header-status-tag.tsx: -------------------------------------------------------------------------------- 1 | import DomainStatusTag from '@/views/shared/domain-status-tag/domain-status-tag'; 2 | import useSuspenseDomainDescription from '@/views/shared/hooks/use-domain-description/use-suspense-domain-description'; 3 | 4 | import { type Props } from './domain-page-header-status-tag.types'; 5 | 6 | export default function DomainPageHeaderStatusTag(props: Props) { 7 | const { data: domainDescription } = useSuspenseDomainDescription(props); 8 | 9 | if (domainDescription.status === 'DOMAIN_STATUS_REGISTERED') { 10 | return null; 11 | } 12 | 13 | return ; 14 | } 15 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-header-status-tag/domain-page-header-status-tag.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-header/domain-page-header.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled } from 'baseui'; 2 | 3 | export const styled = { 4 | HeaderContainer: createStyled('div', ({ $theme }) => ({ 5 | display: 'flex', 6 | flexDirection: 'row', 7 | gap: $theme.sizing.scale700, 8 | marginTop: $theme.sizing.scale1000, 9 | })), 10 | DomainInfoContainer: createStyled('div', ({ $theme }) => ({ 11 | display: 'flex', 12 | flexDirection: 'column', 13 | gap: $theme.sizing.scale500, 14 | })), 15 | DomainNameLabel: createStyled('div', ({ $theme }) => ({ 16 | display: 'flex', 17 | flexDirection: 'row', 18 | alignItems: 'center', 19 | gap: $theme.sizing.scale600, 20 | ...$theme.typography.HeadingSmall, 21 | })), 22 | }; 23 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-header/domain-page-header.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-help/domain-page-help.types.ts: -------------------------------------------------------------------------------- 1 | import { type DomainPageHelpItem } from '../domain-page-help-item-button/domain-page-help-item-button.types'; 2 | 3 | export type DomainPageHelpGroup = { 4 | title: string; 5 | items: Array; 6 | }; 7 | 8 | export type DomainPageHelpMenuConfig = Array; 9 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-metadata-clusters/domain-page-metadata-clusters.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled, type Theme } from 'baseui'; 2 | 3 | export const styled = { 4 | ClusterTextContainer: createStyled( 5 | 'div', 6 | ({ $theme }: { $theme: Theme }) => ({ 7 | ...$theme.typography.ParagraphSmall, 8 | }) 9 | ), 10 | }; 11 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-metadata-description/domain-page-metadata-description.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled } from 'baseui'; 2 | 3 | export const styled = { 4 | DescriptionContainer: createStyled('div', ({ $theme }) => ({ 5 | display: 'flex', 6 | flexDirection: 'column', 7 | alignItems: 'flex-start', 8 | gap: $theme.sizing.scale500, 9 | })), 10 | DescriptionPlaceholder: createStyled('div', ({ $theme }) => ({ 11 | color: $theme.colors.contentTertiary, 12 | })), 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-metadata-description/domain-page-metadata-description.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | description: string; 3 | }; 4 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-metadata-table/domain-page-metadata-table.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled, type Theme } from 'baseui'; 2 | 3 | export const styled = { 4 | MetadataContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ 5 | paddingTop: $theme.sizing.scale800, 6 | })), 7 | }; 8 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-metadata-view-json/domain-page-metadata-view-json.types.ts: -------------------------------------------------------------------------------- 1 | import { type DomainDescription } from '../domain-page.types'; 2 | 3 | export type Props = { 4 | domainDescription: DomainDescription; 5 | }; 6 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-metadata/domain-page-metadata.types.ts: -------------------------------------------------------------------------------- 1 | import { type DomainDescription } from '../domain-page.types'; 2 | 3 | export type DomainMetadata = { 4 | domainDescription: DomainDescription; 5 | isExtendedMetadataEnabled: boolean; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-settings-retention-period/domain-page-settings-retention-period.constants.ts: -------------------------------------------------------------------------------- 1 | export const NUM_SECONDS_IN_DAY = 86400; 2 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-settings-retention-period/domain-page-settings-retention-period.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import type { InputOverrides } from 'baseui/input'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | input: { 7 | Root: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | ...$theme.typography.ParagraphSmall, 10 | maxWidth: '160px', 11 | }), 12 | }, 13 | } satisfies InputOverrides, 14 | }; 15 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-settings/domain-page-settings.constants.ts: -------------------------------------------------------------------------------- 1 | export const SETTINGS_UPDATE_TOAST_DURATION_MS = 5000; 2 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-settings/domain-page-settings.types.ts: -------------------------------------------------------------------------------- 1 | import { type z } from 'zod'; 2 | 3 | import { type domainPageSettingsFormSchema } from '../config/domain-page-settings-form.config'; 4 | 5 | export type SettingsValues = z.infer; 6 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-tabs-error/domain-page-tabs-error.types.ts: -------------------------------------------------------------------------------- 1 | import { type Props as ErrorPanelProps } from '@/components/error-panel/error-panel.types'; 2 | 3 | export type DomainPageTabErrorConfig = Omit; 4 | 5 | export type Props = { 6 | error: Error; 7 | reset: () => void; 8 | }; 9 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page-tabs/domain-page-tabs.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled, type Theme } from 'baseui'; 2 | 3 | export const styled = { 4 | PageTabsContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ 5 | marginTop: $theme.sizing.scale950, 6 | })), 7 | }; 8 | -------------------------------------------------------------------------------- /src/views/domain-page/domain-page.types.ts: -------------------------------------------------------------------------------- 1 | import { type DescribeDomainResponse } from '@/route-handlers/describe-domain/describe-domain.types'; 2 | import type { WorkflowStatus } from '@/views/shared/workflow-status-tag/workflow-status-tag.types'; 3 | 4 | export type Props = { 5 | params: { domain: string; cluster: string }; 6 | children: React.ReactNode; 7 | }; 8 | 9 | export type DomainDescription = DescribeDomainResponse; 10 | 11 | export type DomainWorkflow = { 12 | workflowID: string; 13 | runID: string; 14 | workflowName: string; 15 | status: WorkflowStatus; 16 | startTime: number; 17 | closeTime: number | null | undefined; 18 | }; 19 | -------------------------------------------------------------------------------- /src/views/domain-page/hooks/use-is-extended-metadata-enabled/use-suspense-is-extended-metadata-enabled.ts: -------------------------------------------------------------------------------- 1 | import { useSuspenseQuery } from '@tanstack/react-query'; 2 | 3 | import getIsExtendedMetadataEnabledQueryOptions from './get-is-extended-metadata-enabled-query-options'; 4 | 5 | export default function useSuspenseIsExtendedMetadataEnabled() { 6 | return useSuspenseQuery(getIsExtendedMetadataEnabledQueryOptions()); 7 | } 8 | -------------------------------------------------------------------------------- /src/views/domain-workflows-archival/config/domain-workflows-archival-disabled-panel.config.ts: -------------------------------------------------------------------------------- 1 | import { type ArchivalDisabledPanelConfig } from '../domain-workflows-archival-disabled-panel/domain-workflows-archival-disabled-panel.types'; 2 | 3 | const domainWorkflowsArchivalDisabledPanelConfig = { 4 | title: 'Archival not enabled for domain', 5 | details: [ 6 | 'This domain currently does not have history archival and/or visibility archival enabled.', 7 | ], 8 | links: [ 9 | { 10 | text: 'Check out the docs', 11 | href: 'https://cadenceworkflow.io/docs/concepts/archival', 12 | }, 13 | ], 14 | } as const satisfies ArchivalDisabledPanelConfig; 15 | 16 | export default domainWorkflowsArchivalDisabledPanelConfig; 17 | -------------------------------------------------------------------------------- /src/views/domain-workflows-archival/config/domain-workflows-archival-page-size.config.ts: -------------------------------------------------------------------------------- 1 | const DOMAIN_WORKFLOWS_ARCHIVAL_PAGE_SIZE = 20; 2 | 3 | export default DOMAIN_WORKFLOWS_ARCHIVAL_PAGE_SIZE; 4 | -------------------------------------------------------------------------------- /src/views/domain-workflows-archival/domain-workflows-archival-disabled-panel/domain-workflows-archival-disabled-panel.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | isHistoryArchivalEnabled: boolean; 3 | isVisibilityArchivalEnabled: boolean; 4 | }; 5 | 6 | export type ArchivalDisabledPanelConfig = { 7 | title: string; 8 | details: Array; 9 | links: Array<{ 10 | href: string; 11 | text: string; 12 | }>; 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/domain-workflows-archival/domain-workflows-archival-header/domain-workflows-archival-header.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowStatus } from '@/views/shared/workflow-status-tag/workflow-status-tag.types'; 2 | 3 | export type Props = { 4 | domain: string; 5 | cluster: string; 6 | timeRangeStart: string; 7 | timeRangeEnd: string; 8 | }; 9 | 10 | export type WorkflowStatusClosed = Exclude< 11 | WorkflowStatus, 12 | 'WORKFLOW_EXECUTION_CLOSE_STATUS_INVALID' 13 | >; 14 | -------------------------------------------------------------------------------- /src/views/domain-workflows-archival/domain-workflows-archival-table/domain-workflows-archival-table.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | timeRangeStart: string; 5 | timeRangeEnd: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/domain-workflows-basic/config/domain-workflows-basic-page-size.config.ts: -------------------------------------------------------------------------------- 1 | const DOMAIN_WORKFLOWS_BASIC_PAGE_SIZE = 20; 2 | 3 | export default DOMAIN_WORKFLOWS_BASIC_PAGE_SIZE; 4 | -------------------------------------------------------------------------------- /src/views/domain-workflows-basic/config/domain-workflows-basic-search-debounce-ms.config.ts: -------------------------------------------------------------------------------- 1 | const DOMAIN_WORKFLOWS_BASIC_SEARCH_DEBOUNCE_MS = 250; 2 | 3 | export default DOMAIN_WORKFLOWS_BASIC_SEARCH_DEBOUNCE_MS; 4 | -------------------------------------------------------------------------------- /src/views/domain-workflows-basic/domain-workflows-basic-filters/domain-workflows-basic-filters.constants.ts: -------------------------------------------------------------------------------- 1 | import { WORKFLOW_STATUS_NAMES } from '@/views/shared/workflow-status-tag/workflow-status-tag.constants'; 2 | 3 | import { type WorkflowStatusBasicVisibility } from './domain-workflows-basic-filters.types'; 4 | 5 | export const WORKFLOW_STATUS_NAMES_BASIC_VISIBILITY = { 6 | ALL_CLOSED: 'Closed', 7 | ...WORKFLOW_STATUS_NAMES, 8 | } as const satisfies Record; 9 | -------------------------------------------------------------------------------- /src/views/domain-workflows-basic/domain-workflows-basic-filters/domain-workflows-basic-filters.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowStatus } from '@/views/shared/workflow-status-tag/workflow-status-tag.types'; 2 | 3 | export type WorkflowStatusBasicVisibility = WorkflowStatus | 'ALL_CLOSED'; 4 | -------------------------------------------------------------------------------- /src/views/domain-workflows-basic/domain-workflows-basic-filters/helpers/is-workflow-status-basic-visibility.ts: -------------------------------------------------------------------------------- 1 | import { WORKFLOW_STATUS_NAMES_BASIC_VISIBILITY } from '../domain-workflows-basic-filters.constants'; 2 | import { type WorkflowStatusBasicVisibility } from '../domain-workflows-basic-filters.types'; 3 | 4 | export default function isWorkflowStatusBasicVisibility( 5 | value: any 6 | ): value is WorkflowStatusBasicVisibility { 7 | return value in WORKFLOW_STATUS_NAMES_BASIC_VISIBILITY; 8 | } 9 | -------------------------------------------------------------------------------- /src/views/domain-workflows-basic/domain-workflows-basic-table/domain-workflows-basic-table.types.ts: -------------------------------------------------------------------------------- 1 | import { type TableColumn } from '@/components/table/table.types'; 2 | import { type DomainWorkflow } from '@/views/domain-page/domain-page.types'; 3 | 4 | export type Props = { 5 | domain: string; 6 | cluster: string; 7 | }; 8 | 9 | export type DomainWorkflowsBasicTableConfig = Array< 10 | Omit, 'sortable'> 11 | >; 12 | -------------------------------------------------------------------------------- /src/views/domain-workflows-basic/domain-workflows-basic.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { type DomainPageTabContentProps } from '@/views/domain-page/domain-page-content/domain-page-content.types'; 4 | 5 | import DomainWorkflowsBasicFilters from './domain-workflows-basic-filters/domain-workflows-basic-filters'; 6 | import DomainWorkflowsBasicTable from './domain-workflows-basic-table/domain-workflows-basic-table'; 7 | 8 | export default function DomainWorkflowsBasic(props: DomainPageTabContentProps) { 9 | return ( 10 | <> 11 | 12 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/views/domain-workflows-basic/domain-workflows-basic.types.ts: -------------------------------------------------------------------------------- 1 | import { type RouteParams as ListWorkflowsBasicRouteParams } from '@/route-handlers/list-workflows-basic/list-workflows-basic.types'; 2 | 3 | export type UseListWorkflowsBasicParams = ListWorkflowsBasicRouteParams & { 4 | pageSize?: number; 5 | }; 6 | -------------------------------------------------------------------------------- /src/views/domain-workflows/config/domain-workflows-page-size.config.ts: -------------------------------------------------------------------------------- 1 | const DOMAIN_WORKFLOWS_PAGE_SIZE = 20; 2 | 3 | export default DOMAIN_WORKFLOWS_PAGE_SIZE; 4 | -------------------------------------------------------------------------------- /src/views/domain-workflows/domain-workflows-advanced/domain-workflows-advanced.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/domain-workflows/domain-workflows-header/domain-workflows-header.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | timeRangeStart: string; 5 | timeRangeEnd: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/domain-workflows/domain-workflows-table/domain-workflows-table.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | timeRangeStart: string; 5 | timeRangeEnd: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/domain-workflows/helpers/is-cluster-advanced-visibility-enabled.ts: -------------------------------------------------------------------------------- 1 | import type { DescribeClusterResponse } from '@/route-handlers/describe-cluster/describe-cluster.types'; 2 | 3 | export default function isClusterAdvancedVisibilityEnabled( 4 | cluster: DescribeClusterResponse 5 | ) { 6 | const clusterVisibilityFeatures = 7 | cluster.persistenceInfo?.visibilityStore?.features || []; 8 | 9 | const advancedVisibilityEnabledFeature = clusterVisibilityFeatures.find( 10 | ({ key }) => key === 'advancedVisibilityEnabled' 11 | ); 12 | 13 | return advancedVisibilityEnabledFeature?.enabled ?? false; 14 | } 15 | -------------------------------------------------------------------------------- /src/views/domains-page/config/domains-page-error-banner.config.ts: -------------------------------------------------------------------------------- 1 | import { MdWarning } from 'react-icons/md'; 2 | 3 | import { type Props } from '../domains-page-error-banner/domains-page-error-banner.types'; 4 | 5 | const domainsPageErrorBannerConfig = { 6 | icon: MdWarning, 7 | getErrorMessage: ({ failedClusters }: Props) => 8 | `Failed to fetch domains for following clusters: ${failedClusters.join(', ')}`, 9 | }; 10 | 11 | export default domainsPageErrorBannerConfig; 12 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-context-provider/domains-page-context-provider.types.tsx: -------------------------------------------------------------------------------- 1 | import { type PublicLoadedConfig } from '@/utils/config/config.types'; 2 | 3 | export type DomainsPageContextType = { 4 | pageConfig: Pick; 5 | }; 6 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-error-banner/domains-page-error-banner.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import type { BannerOverrides } from 'baseui/banner'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | banner: { 7 | Root: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | backgroundColor: $theme.colors.backgroundWarningLight, 10 | marginLeft: 0, 11 | marginRight: 0, 12 | }), 13 | }, 14 | Message: { 15 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 16 | ...$theme.typography.LabelSmall, 17 | }), 18 | }, 19 | } satisfies BannerOverrides, 20 | }; 21 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-error-banner/domains-page-error-banner.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | failedClusters: Array; 3 | }; 4 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-filters-cluster-name/domains-page-filters-cluster-name.types.ts: -------------------------------------------------------------------------------- 1 | export type DomainsPageFiltersClusterNameValue = { 2 | clusterName: string | undefined; 3 | }; 4 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-filters-deprecated/domains-page-filters-deprecated.types.ts: -------------------------------------------------------------------------------- 1 | export type DomainsPageFiltersDeprecatedValue = { 2 | showDeprecated: boolean | undefined; 3 | }; 4 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-filters/domains-page-filters.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import PageFilters from '@/components/page-filters/page-filters'; 3 | import PageSection from '@/components/page-section/page-section'; 4 | 5 | import domainsPageFiltersConfig from '../config/domains-page-filters.config'; 6 | import domainsPageQueryParamsConfig from '../config/domains-page-query-params.config'; 7 | 8 | export default function DomainsPageFilters() { 9 | return ( 10 | 11 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-title-badge/domains-page-title-badge.styles.ts: -------------------------------------------------------------------------------- 1 | import type { Theme } from 'baseui'; 2 | import type { BadgeOverrides } from 'baseui/badge'; 3 | import type { StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | badge: { 7 | Badge: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | color: $theme.colors.contentPrimary, 10 | backgroundColor: $theme.colors.backgroundTertiary, 11 | borderRadius: '20px', 12 | padding: `${$theme.sizing.scale0} ${$theme.sizing.scale300}`, 13 | ...$theme.typography.LabelXSmall, 14 | }), 15 | }, 16 | } satisfies BadgeOverrides, 17 | }; 18 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-title-badge/domains-page-title-badge.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import React from 'react'; 3 | 4 | import { Badge } from 'baseui/badge'; 5 | 6 | import { overrides } from './domains-page-title-badge.styles'; 7 | import type { Props } from './domains-page-title-badge.types'; 8 | 9 | export default function DomainsPageTitleBadge({ content }: Props) { 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-title-badge/domains-page-title-badge.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | content: string | number; 3 | }; 4 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-title/__tests__/domains-page-title.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { render, screen } from '@/test-utils/rtl'; 4 | 5 | import DomainsPageTitle from '../domains-page-title'; 6 | 7 | describe('DomainsPageTitle', () => { 8 | it('should render title', async () => { 9 | render(); 10 | await screen.findByText('All domains'); 11 | }); 12 | 13 | it('should render passed count badge', async () => { 14 | render(} />); 15 | await screen.findAllByTestId('count-badge'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-title/domains-page-title.styles.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | StyletronCSSObject, 3 | StyletronCSSObjectOf, 4 | } from '@/hooks/use-styletron-classes'; 5 | 6 | const cssStylesObj = { 7 | titleContainer: (theme) => ({ 8 | marginTop: theme.sizing.scale1200, 9 | marginBottom: theme.sizing.scale700, 10 | display: 'flex', 11 | gap: theme.sizing.scale300, 12 | alignItems: 'center', 13 | }), 14 | } satisfies StyletronCSSObject; 15 | 16 | export const cssStyles: StyletronCSSObjectOf = 17 | cssStylesObj; 18 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-title/domains-page-title.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { LabelLarge } from 'baseui/typography'; 3 | 4 | import PageSection from '@/components/page-section/page-section'; 5 | import useStyletronClasses from '@/hooks/use-styletron-classes'; 6 | 7 | import { cssStyles } from './domains-page-title.styles'; 8 | import { type Props } from './domains-page-title.types'; 9 | 10 | export default function DomainsPageTitle({ countBadge }: Props) { 11 | const { cls } = useStyletronClasses(cssStyles); 12 | 13 | return ( 14 | 15 |

16 | All domains 17 | {countBadge} 18 |
19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page-title/domains-page-title.types.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export type Props = { 4 | countBadge: ReactNode; 5 | }; 6 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-page.types.ts: -------------------------------------------------------------------------------- 1 | import { type Domain } from '@/__generated__/proto-ts/uber/cadence/api/v1/Domain'; 2 | 3 | export type DomainData = Domain; 4 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-table-cluster-cell/domains-table-cluster-cell.styles.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | StyletronCSSObject, 3 | StyletronCSSObjectOf, 4 | } from '@/hooks/use-styletron-classes'; 5 | 6 | const cssStylesObj = { 7 | clustersLinks: (theme) => ({ 8 | display: 'flex', 9 | gap: theme.sizing.scale400, 10 | ...theme.typography.ParagraphXSmall, 11 | }), 12 | } satisfies StyletronCSSObject; 13 | 14 | export const cssStyles: StyletronCSSObjectOf = 15 | cssStylesObj; 16 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-table-domain-name-cell/domains-table-domain-name-cell.styles.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | StyletronCSSObject, 3 | StyletronCSSObjectOf, 4 | } from '@/hooks/use-styletron-classes'; 5 | 6 | const cssStylesObj = { 7 | domainNameCell: (theme) => ({ 8 | display: 'flex', 9 | alignItems: 'center', 10 | gap: theme.sizing.scale400, 11 | ...theme.typography.ParagraphSmall, 12 | }), 13 | } satisfies StyletronCSSObject; 14 | 15 | export const cssStyles: StyletronCSSObjectOf = 16 | cssStylesObj; 17 | -------------------------------------------------------------------------------- /src/views/domains-page/domains-table/domains-table.types.ts: -------------------------------------------------------------------------------- 1 | import type { TableConfig } from '@/components/table/table.types'; 2 | 3 | import type { DomainData } from '../domains-page.types'; 4 | 5 | export type DomainsTableColumns = TableConfig; 6 | 7 | export type Props = { 8 | domains: Array; 9 | tableColumns?: DomainsTableColumns; 10 | }; 11 | -------------------------------------------------------------------------------- /src/views/domains-page/helpers/filter-irrelevant-domains.ts: -------------------------------------------------------------------------------- 1 | import type { DomainData } from '../domains-page.types'; 2 | 3 | export default function filterIrrelevantDomains( 4 | clusterName: string, 5 | domains: DomainData[] 6 | ) { 7 | return (domains || []).filter((domain) => { 8 | if ( 9 | domain.status === 'DOMAIN_STATUS_INVALID' || 10 | domain.status === 'DOMAIN_STATUS_DELETED' 11 | ) 12 | return false; 13 | 14 | if (!domain.clusters.some(({ clusterName: c }) => clusterName === c)) 15 | return false; 16 | 17 | return true; 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /src/views/domains-page/helpers/get-unique-domains.ts: -------------------------------------------------------------------------------- 1 | import { type DomainData } from '../domains-page.types'; 2 | 3 | export default function getUniqueDomains(domains: DomainData[]) { 4 | const allUniqueDomains: Record = {}; 5 | return domains.filter((d: DomainData) => { 6 | if (allUniqueDomains[`${d.id}-${d.name}-${d.activeClusterName}`]) 7 | return false; 8 | 9 | allUniqueDomains[`${d.id}-${d.name}-${d.activeClusterName}`] = true; 10 | return true; 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /src/views/redirect-domain/redirect-domain-error/redirect-domain-error.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | error: Error; 3 | }; 4 | -------------------------------------------------------------------------------- /src/views/redirect-domain/redirect-domain-not-found/redirect-domain-not-found.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { useParams } from 'next/navigation'; 3 | 4 | import ErrorPanel from '@/components/error-panel/error-panel'; 5 | 6 | import { type RouteParams } from '../redirect-domain.types'; 7 | 8 | export default function RedirectDomainNotFound() { 9 | const { domainParams } = useParams(); 10 | 11 | const domain = decodeURIComponent(domainParams[0]); 12 | 13 | return ( 14 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/views/redirect-domain/redirect-domain.types.ts: -------------------------------------------------------------------------------- 1 | export type RouteParams = { 2 | domainParams: Array; 3 | }; 4 | 5 | export type Props = { 6 | params: RouteParams; 7 | searchParams?: { [key: string]: string | string[] | undefined }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/views/shared/domain-status-tag/domain-status-tag.constants.ts: -------------------------------------------------------------------------------- 1 | import { type DomainStatus } from './domain-status-tag.types'; 2 | 3 | export const DOMAIN_STATUS_NAMES = { 4 | DOMAIN_STATUS_INVALID: 'Invalid', 5 | DOMAIN_STATUS_REGISTERED: 'Registered', 6 | DOMAIN_STATUS_DEPRECATED: 'Deprecated', 7 | DOMAIN_STATUS_DELETED: 'Deleted', 8 | } as const satisfies Record; 9 | -------------------------------------------------------------------------------- /src/views/shared/domain-status-tag/domain-status-tag.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Tag } from 'baseui/tag'; 4 | import { MdWarning } from 'react-icons/md'; 5 | 6 | import { DOMAIN_STATUS_NAMES } from './domain-status-tag.constants'; 7 | import { overrides } from './domain-status-tag.styles'; 8 | import { type Props } from './domain-status-tag.types'; 9 | 10 | export default function DomainStatusTag(props: Props) { 11 | return ( 12 | 13 | 14 | {DOMAIN_STATUS_NAMES[props.status]} 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/views/shared/domain-status-tag/domain-status-tag.types.ts: -------------------------------------------------------------------------------- 1 | import { type DomainStatus as DomainStatusProto } from '@/__generated__/proto-ts/uber/cadence/api/v1/DomainStatus'; 2 | 3 | export type DomainStatus = DomainStatusProto; 4 | 5 | export type Props = { 6 | status: DomainStatus; 7 | }; 8 | -------------------------------------------------------------------------------- /src/views/shared/hooks/use-domain-description/use-domain-description.types.ts: -------------------------------------------------------------------------------- 1 | export type UseDomainDescriptionParams = { 2 | domain: string; 3 | cluster: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/shared/hooks/use-domain-description/use-suspense-domain-description.ts: -------------------------------------------------------------------------------- 1 | import { useSuspenseQuery } from '@tanstack/react-query'; 2 | 3 | import getDomainDescriptionQueryOptions from './get-domain-description-query-options'; 4 | import { type UseDomainDescriptionParams } from './use-domain-description.types'; 5 | 6 | export default function useSuspenseDomainDescription( 7 | params: UseDomainDescriptionParams 8 | ) { 9 | return useSuspenseQuery(getDomainDescriptionQueryOptions(params)); 10 | } 11 | -------------------------------------------------------------------------------- /src/views/shared/settings-form/helpers/__tests__/get-initial-values.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | mockData, 3 | mockFormConfig, 4 | } from '../../__fixtures__/settings-form.fixtures'; 5 | import getInitialValues from '../get-initial-values'; 6 | 7 | describe(getInitialValues.name, () => { 8 | it('returns expected values', () => { 9 | const result = getInitialValues({ 10 | data: mockData, 11 | formConfig: mockFormConfig, 12 | }); 13 | 14 | expect(result).toEqual({ 15 | field1: 'mock_data_A', 16 | field2: 1234, 17 | field3: true, 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/views/shared/settings-form/helpers/get-initial-values.ts: -------------------------------------------------------------------------------- 1 | import { type z } from 'zod'; 2 | 3 | import { 4 | type SettingsFormValues, 5 | type SettingsFormConfig, 6 | } from '../settings-form.types'; 7 | 8 | export default function getInitialValues< 9 | D extends object, 10 | Z extends z.ZodTypeAny, 11 | >({ 12 | data, 13 | formConfig, 14 | }: { 15 | data: D; 16 | formConfig: SettingsFormConfig; 17 | }): SettingsFormValues { 18 | return Object.fromEntries( 19 | formConfig.map((field) => [field.path, field.getInitialValue(data)]) 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/views/shared/task-list-label/task-list-label.tsx: -------------------------------------------------------------------------------- 1 | import { Tag, KIND, VARIANT } from 'baseui/tag'; 2 | 3 | import { styled, overrides } from './task-list-label.styles'; 4 | import { type Props } from './task-list-label.types'; 5 | 6 | export default function TaskListLabel(props: Props) { 7 | const numWorkers = props.taskList.workers.length; 8 | return ( 9 | 10 | {props.taskList.name} 11 | 17 | {`${numWorkers} ${numWorkers === 1 ? 'worker' : 'workers'}`} 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/views/shared/task-list-label/task-list-label.types.ts: -------------------------------------------------------------------------------- 1 | import { type TaskList } from '@/route-handlers/describe-task-list/describe-task-list.types'; 2 | 3 | export type Props = { 4 | taskList: TaskList; 5 | isHighlighted?: boolean; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/shared/workflow-event-details-execution-link/workflow-event-details-execution-link.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | cluster: string; 3 | domain: string; 4 | workflowId: string; 5 | runId: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/shared/workflow-history-event-details-task-list-link/workflow-history-event-details-task-list-link.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | cluster: string; 3 | domain: string; 4 | taskList: { name: string | null; kind: 'NORMAL' | 'STICKY' | null } | null; 5 | }; 6 | -------------------------------------------------------------------------------- /src/views/shared/workflow-status-tag/helpers/is-workflow-status.ts: -------------------------------------------------------------------------------- 1 | import { WORKFLOW_STATUS_NAMES } from '../workflow-status-tag.constants'; 2 | import { type WorkflowStatus } from '../workflow-status-tag.types'; 3 | 4 | export default function isWorkflowStatus(value: any): value is WorkflowStatus { 5 | return value in WORKFLOW_STATUS_NAMES; 6 | } 7 | -------------------------------------------------------------------------------- /src/views/shared/workflow-status-tag/workflow-status-tag-icon/workflow-status-tag-icon.styles.ts: -------------------------------------------------------------------------------- 1 | import { withStyle } from 'baseui'; 2 | import { Spinner } from 'baseui/spinner'; 3 | 4 | export const styled = { 5 | Spinner: withStyle(Spinner, ({ $theme }) => ({ 6 | width: $theme.sizing.scale300, 7 | height: $theme.sizing.scale300, 8 | borderWidth: '2px', 9 | marginRight: '1px', 10 | borderRightColor: $theme.colors.accent200, 11 | borderLeftColor: $theme.colors.accent200, 12 | borderBottomColor: $theme.colors.accent200, 13 | })), 14 | }; 15 | -------------------------------------------------------------------------------- /src/views/shared/workflow-status-tag/workflow-status-tag-icon/workflow-status-tag-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { WORKFLOW_STATUSES } from '../workflow-status-tag.constants'; 4 | 5 | import { styled } from './workflow-status-tag-icon.styles'; 6 | import { type Props } from './workflow-status-tag-icon.types'; 7 | 8 | export default function WorkflowStatusTagIcon(props: Props) { 9 | switch (props.kind) { 10 | case 'start': 11 | if (props.isArchived) return null; 12 | if (props.status === WORKFLOW_STATUSES.running) { 13 | return ; 14 | } 15 | case 'end': 16 | // if there is a link, return the styled link 17 | } 18 | return null; 19 | } 20 | -------------------------------------------------------------------------------- /src/views/shared/workflow-status-tag/workflow-status-tag-icon/workflow-status-tag-icon.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowStatus } from '../workflow-status-tag.types'; 2 | 3 | export type WorkflowStatusTagIconKind = 'start' | 'end'; 4 | 5 | export type Props = { 6 | kind: WorkflowStatusTagIconKind; 7 | status: WorkflowStatus; 8 | link?: string; 9 | isArchived?: boolean; 10 | }; 11 | -------------------------------------------------------------------------------- /src/views/shared/workflow-status-tag/workflow-status-tag.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowExecutionCloseStatus } from '@/__generated__/proto-ts/uber/cadence/api/v1/WorkflowExecutionCloseStatus'; 2 | 3 | export type WorkflowStatus = WorkflowExecutionCloseStatus; 4 | 5 | export type Props = { 6 | status: WorkflowStatus; 7 | link?: string; 8 | isArchived?: boolean; 9 | }; 10 | 11 | export type OverridesArgs = { 12 | status: WorkflowStatus; 13 | link?: string; 14 | isArchived?: boolean; 15 | }; 16 | -------------------------------------------------------------------------------- /src/views/shared/workflows-header/config/workflows-search-debounce-ms.config.ts: -------------------------------------------------------------------------------- 1 | const WORKFLOWS_SEARCH_DEBOUNCE_MS = 250; 2 | 3 | export default WORKFLOWS_SEARCH_DEBOUNCE_MS; 4 | -------------------------------------------------------------------------------- /src/views/shared/workflows-header/workflows-query-input/workflows-query-input.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | value: string; 3 | setValue: (v: string | undefined) => void; 4 | refetchQuery: () => void; 5 | isQueryRunning: boolean; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/shared/workflows-header/workflows-query-label/workflows-query-label.types.ts: -------------------------------------------------------------------------------- 1 | export type ExampleQuery = { 2 | label: string; 3 | text: string; 4 | }; 5 | 6 | export type WorkflowsQueryTooltipConfig = { 7 | title: string; 8 | subtitle: string; 9 | supportedOperators: Array; 10 | docsCta: string; 11 | exampleQueriesTitle: string; 12 | exampleQueries: Array; 13 | docsButtonText: string; 14 | docsLink: string; 15 | }; 16 | -------------------------------------------------------------------------------- /src/views/shared/workflows-table/workflows-table.types.ts: -------------------------------------------------------------------------------- 1 | import { type TableColumn } from '@/components/table/table.types'; 2 | import { type SortOrder } from '@/utils/sort-by'; 3 | import { type DomainWorkflow } from '@/views/domain-page/domain-page.types'; 4 | 5 | type SortParams = { 6 | onSort: (column: string) => void; 7 | sortColumn: string; 8 | sortOrder: SortOrder; 9 | }; 10 | 11 | export type Props = { 12 | workflows: Array; 13 | isLoading: boolean; 14 | error: Error | null; 15 | hasNextPage: boolean; 16 | fetchNextPage: () => void; 17 | isFetchingNextPage: boolean; 18 | sortParams?: SortParams; 19 | }; 20 | 21 | export type WorkflowsTableNonSortableConfig = Array< 22 | Omit, 'sortable'> 23 | >; 24 | -------------------------------------------------------------------------------- /src/views/task-list-page/__fixtures__/mock-task-list-page-query-params-values.ts: -------------------------------------------------------------------------------- 1 | import { type PageQueryParamValues } from '@/hooks/use-page-query-params/use-page-query-params.types'; 2 | 3 | import type taskListPageQueryParamsConfig from '../config/task-list-page-query-params.config'; 4 | 5 | export const mockTaskListPageQueryParamsValues: PageQueryParamValues< 6 | typeof taskListPageQueryParamsConfig 7 | > = { 8 | taskListSearch: '', 9 | handlerType: undefined, 10 | sortColumn: 'lastAccessTime', 11 | sortOrder: 'DESC', 12 | }; 13 | -------------------------------------------------------------------------------- /src/views/task-list-page/helpers/is-valid-table-column.ts: -------------------------------------------------------------------------------- 1 | import taskListWorkersTableConfig from '../config/task-list-workers-table.config'; 2 | import { type TaskListWorkerTableColumnID } from '../task-list-workers-table/task-list-workers-table.types'; 3 | 4 | export default function isValidTableColumn( 5 | column: string 6 | ): column is TaskListWorkerTableColumnID { 7 | return ( 8 | taskListWorkersTableConfig.find((config) => config.id === column) !== 9 | undefined 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-error/task-list-error.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | error: Error; 3 | reset: () => void; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-filters-handlers/task-list-filters-handlers.constants.ts: -------------------------------------------------------------------------------- 1 | import { type TaskListHandlerTypeOption } from './task-list-filters-handlers.types'; 2 | 3 | export const TASK_LIST_HANDLERS_OPTIONS = [ 4 | { id: 'TASK_LIST_TYPE_ACTIVITY', label: 'Activity' }, 5 | { id: 'TASK_LIST_TYPE_DECISION', label: 'Decision' }, 6 | ] as const satisfies Array; 7 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-filters-handlers/task-list-filters-handlers.types.ts: -------------------------------------------------------------------------------- 1 | import { type TaskListType } from '@/__generated__/proto-ts/uber/cadence/api/v1/TaskListType'; 2 | 3 | export type TaskListHandlerTypeOption = { 4 | id: TaskListType; 5 | label: string; 6 | }; 7 | 8 | export type TaskListFiltersHandlersValue = { 9 | handlerType: TaskListType | undefined; 10 | }; 11 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-filters/__tests__/task-list-filters.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { render } from '@/test-utils/rtl'; 4 | 5 | import { mockQueryParamsValues } from '@/components/page-filters/__fixtures__/page-filters.fixtures'; 6 | 7 | import TaskListFilters from '../task-list-filters'; 8 | 9 | const mockSetQueryParams = jest.fn(); 10 | jest.mock('@/hooks/use-page-query-params/use-page-query-params', () => 11 | jest.fn(() => [mockQueryParamsValues, mockSetQueryParams]) 12 | ); 13 | 14 | describe(TaskListFilters.name, () => { 15 | it('renders without errors', () => { 16 | render(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-filters/task-list-filters.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled, type Theme } from 'baseui'; 2 | 3 | export const styled = { 4 | FiltersContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ 5 | marginTop: $theme.sizing.scale600, 6 | })), 7 | }; 8 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-filters/task-list-filters.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import PageFilters from '@/components/page-filters/page-filters'; 3 | 4 | import taskListFiltersConfig from '../config/task-list-filters.config'; 5 | import taskListPageQueryParamsConfig from '../config/task-list-page-query-params.config'; 6 | 7 | import { styled } from './task-list-filters.styles'; 8 | 9 | export default function TaskListFilters() { 10 | return ( 11 | 12 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-loader/task-list-loader.constants.ts: -------------------------------------------------------------------------------- 1 | export const TASK_LIST_REFETCH_INTERVAL_MS = 60000; 2 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-loader/task-list-loader.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled } from 'baseui'; 2 | 3 | export const styled = { 4 | TaskListContainer: createStyled('div', ({ $theme }) => ({ 5 | display: 'flex', 6 | flexDirection: 'column', 7 | paddingTop: $theme.sizing.scale800, 8 | rowGap: $theme.sizing.scale600, 9 | })), 10 | TaskListHeaderContainer: createStyled('div', ({ $theme }) => ({ 11 | display: 'flex', 12 | flexDirection: 'row', 13 | columnGap: $theme.sizing.scale400, 14 | })), 15 | }; 16 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-loader/task-list-loader.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | taskListName: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-page.tsx: -------------------------------------------------------------------------------- 1 | import React, { Suspense } from 'react'; 2 | 3 | import decodeUrlParams from '@/utils/decode-url-params'; 4 | 5 | import TaskListLoader from './task-list-loader/task-list-loader'; 6 | import { type RouteParams, type Props } from './task-list-page.types'; 7 | 8 | export default function TaskListPage(props: Props) { 9 | const decodedParams = decodeUrlParams(props.params) as RouteParams; 10 | 11 | return ( 12 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-page.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | params: RouteParams; 3 | }; 4 | 5 | export type RouteParams = { 6 | domain: string; 7 | cluster: string; 8 | taskListName: string; 9 | }; 10 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-workers-table-handler-icon/task-list-workers-table-handler-icon.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled } from 'baseui'; 2 | 3 | export const styled = { 4 | IconContainer: createStyled<'div', { $hasHandler: boolean }>( 5 | 'div', 6 | ({ $theme, $hasHandler }) => ({ 7 | // Note: this green does not correspond to the Green available in Baseweb 8 | color: $hasHandler ? '#009A51' : $theme.colors.contentInverseSecondary, 9 | display: 'block', 10 | }) 11 | ), 12 | }; 13 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-workers-table-handler-icon/task-list-workers-table-handler-icon.tsx: -------------------------------------------------------------------------------- 1 | import { useStyletron } from 'baseui'; 2 | import { MdCheckCircleOutline, MdRadioButtonUnchecked } from 'react-icons/md'; 3 | 4 | import { styled } from './task-list-workers-table-handler-icon.styles'; 5 | 6 | export default function TaskListWorkersTableHandlerIcon(props: { 7 | hasHandler: boolean; 8 | }) { 9 | const [_, theme] = useStyletron(); 10 | const Icon = props.hasHandler ? MdCheckCircleOutline : MdRadioButtonUnchecked; 11 | 12 | return ( 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-workers-table/task-list-workers-table.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled } from 'baseui'; 2 | 3 | export const styled = { 4 | EndMessageContainer: createStyled('div', ({ $theme }) => ({ 5 | ...$theme.typography.LabelSmall, 6 | color: $theme.colors.contentTertiary, 7 | })), 8 | }; 9 | -------------------------------------------------------------------------------- /src/views/task-list-page/task-list-workers-table/task-list-workers-table.types.ts: -------------------------------------------------------------------------------- 1 | import { type TaskList } from '@/route-handlers/describe-task-list/describe-task-list.types'; 2 | 3 | import type taskListWorkersTableConfig from '../config/task-list-workers-table.config'; 4 | 5 | export type TaskListWorkerTableColumnID = 6 | (typeof taskListWorkersTableConfig)[number]['id']; 7 | 8 | export type Props = { taskList: TaskList }; 9 | -------------------------------------------------------------------------------- /src/views/workflow-actions/config/workflow-actions-disabled-reasons.config.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowActionDisabledValue } from '@/config/dynamic/resolvers/workflow-actions-enabled.types'; 2 | 3 | const WORKFLOW_ACTIONS_DISABLED_REASONS_CONFIG = { 4 | DISABLED_DEFAULT: 'Workflow action has been disabled', 5 | DISABLED_UNAUTHORIZED: 'Not authorized to perform this action', 6 | } as const satisfies Record; 7 | 8 | export default WORKFLOW_ACTIONS_DISABLED_REASONS_CONFIG; 9 | -------------------------------------------------------------------------------- /src/views/workflow-actions/config/workflow-actions-non-runnable-reasons.config.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowActionNonRunnableStatus } from '../workflow-actions.types'; 2 | 3 | const WORKFLOW_ACTIONS_NON_RUNNABLE_REASONS_CONFIG = { 4 | NOT_RUNNABLE_WORKFLOW_CLOSED: 'Workflow is already closed', 5 | } as const satisfies Record; 6 | 7 | export default WORKFLOW_ACTIONS_NON_RUNNABLE_REASONS_CONFIG; 8 | -------------------------------------------------------------------------------- /src/views/workflow-actions/config/workflow-actions-non-runnable-statuses.config.ts: -------------------------------------------------------------------------------- 1 | const WORKFLOW_ACTIONS_NON_RUNNABLE_STATUSES_CONFIG = [ 2 | 'NOT_RUNNABLE_WORKFLOW_CLOSED', 3 | ] as const satisfies Array<`NOT_RUNNABLE_${string}`>; 4 | 5 | export default WORKFLOW_ACTIONS_NON_RUNNABLE_STATUSES_CONFIG; 6 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-action-new-run-success-msg/workflow-action-new-run-success-msg.types.tsx: -------------------------------------------------------------------------------- 1 | import { type WorkflowActionSuccessMessageProps } from '../workflow-actions.types'; 2 | 3 | export type Props = WorkflowActionSuccessMessageProps< 4 | any, 5 | { runId: string } 6 | > & { 7 | successMessage: string; 8 | }; 9 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-action-reset-form/schemas/reset-workflow-form-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | const baseSchema = z.object({ 4 | reason: z.string().min(1), 5 | skipSignalReapply: z.boolean().optional(), 6 | }); 7 | 8 | const eventIdSchema = baseSchema.extend({ 9 | resetType: z.literal('EventId'), 10 | decisionFinishEventId: z.string().min(1), 11 | }); 12 | 13 | const binaryChecksumSchema = baseSchema.extend({ 14 | resetType: z.literal('BinaryChecksum'), 15 | binaryChecksumFirstDecisionCompletedId: z.string().min(1), 16 | }); 17 | 18 | export const resetWorkflowFormSchema = z.discriminatedUnion('resetType', [ 19 | eventIdSchema, 20 | binaryChecksumSchema, 21 | ]); 22 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-action-reset-form/workflow-action-reset-form.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import { type CheckboxOverrides } from 'baseui/checkbox'; 3 | import { type RadioOverrides } from 'baseui/radio'; 4 | import { type StyleObject } from 'styletron-react'; 5 | 6 | export const overrides = { 7 | radio: { 8 | Label: { 9 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 10 | ...$theme.typography.LabelSmall, 11 | }), 12 | }, 13 | } satisfies RadioOverrides, 14 | checkbox: { 15 | Label: { 16 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 17 | ...$theme.typography.LabelSmall, 18 | alignSelf: 'center', 19 | }), 20 | }, 21 | } satisfies CheckboxOverrides, 22 | }; 23 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-action-reset-form/workflow-action-reset-form.types.ts: -------------------------------------------------------------------------------- 1 | import { type z } from 'zod'; 2 | 3 | import type resetWorkflowRequestBodySchema from '@/route-handlers/reset-workflow/schemas/reset-workflow-request-body-schema'; 4 | 5 | import { type WorkflowActionFormProps } from '../workflow-actions.types'; 6 | 7 | import { type resetWorkflowFormSchema } from './schemas/reset-workflow-form-schema'; 8 | 9 | export type Props = WorkflowActionFormProps; 10 | 11 | export type ResetWorkflowFormData = z.infer; 12 | 13 | export type ResetWorkflowSubmissionData = z.infer< 14 | typeof resetWorkflowRequestBodySchema 15 | >; 16 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-action-signal-form/schemas/signal-workflow-form-schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | import signalWorkflowInputSchema from '@/route-handlers/signal-workflow/schemas/signal-workflow-input-schema'; 4 | 5 | export const signalWorkflowFormSchema = z.object({ 6 | signalName: z.string().min(1), 7 | signalInput: signalWorkflowInputSchema.optional(), 8 | }); 9 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-action-signal-form/workflow-action-signal-form.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import { type TextareaOverrides } from 'baseui/textarea'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | jsonInput: { 7 | Input: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | ...$theme.typography.MonoParagraphSmall, 10 | '::placeholder': { 11 | ...$theme.typography.ParagraphSmall, 12 | }, 13 | }), 14 | }, 15 | } satisfies TextareaOverrides, 16 | }; 17 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-action-signal-form/workflow-action-signal-form.types.ts: -------------------------------------------------------------------------------- 1 | import { type z } from 'zod'; 2 | 3 | import type signalWorkflowRequestBodySchema from '@/route-handlers/signal-workflow/schemas/signal-workflow-request-body-schema'; 4 | 5 | import { type WorkflowActionFormProps } from '../workflow-actions.types'; 6 | 7 | import { type signalWorkflowFormSchema } from './schemas/signal-workflow-form-schema'; 8 | 9 | export type SignalWorkflowFormData = z.infer; 10 | 11 | export type Props = WorkflowActionFormProps; 12 | 13 | export type SignalWorkflowSubmissionData = z.infer< 14 | typeof signalWorkflowRequestBodySchema 15 | >; 16 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-actions-menu/workflow-actions-menu.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowActionsEnabledConfig } from '@/config/dynamic/resolvers/workflow-actions-enabled.types'; 2 | import { type DescribeWorkflowResponse } from '@/route-handlers/describe-workflow/describe-workflow.types'; 3 | 4 | import { type WorkflowAction } from '../workflow-actions.types'; 5 | 6 | export type Props = { 7 | workflow?: DescribeWorkflowResponse; 8 | actionsEnabledConfig?: WorkflowActionsEnabledConfig; 9 | onActionSelect: (action: WorkflowAction) => void; 10 | }; 11 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-actions-modal-content/workflow-actions-modal-content.types.ts: -------------------------------------------------------------------------------- 1 | import { type DefaultValues } from 'react-hook-form'; 2 | 3 | import { 4 | type WorkflowAction, 5 | type WorkflowActionInputParams, 6 | } from '../workflow-actions.types'; 7 | 8 | export type Props = { 9 | action: WorkflowAction; 10 | params: WorkflowActionInputParams; 11 | onCloseModal: () => void; 12 | initialFormValues?: DefaultValues; 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-actions-modal/workflow-actions-modal.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import { type ModalOverrides } from 'baseui/modal'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | modal: { 7 | Close: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | top: $theme.sizing.scale850, 10 | right: $theme.sizing.scale800, 11 | }), 12 | }, 13 | } satisfies ModalOverrides, 14 | }; 15 | -------------------------------------------------------------------------------- /src/views/workflow-actions/workflow-actions-modal/workflow-actions-modal.types.ts: -------------------------------------------------------------------------------- 1 | import { type DefaultValues } from 'react-hook-form'; 2 | 3 | import { type WorkflowAction } from '../workflow-actions.types'; 4 | 5 | export type Props = { 6 | domain: string; 7 | cluster: string; 8 | workflowId: string; 9 | runId: string; 10 | action: WorkflowAction | undefined; 11 | onClose: () => void; 12 | initialFormValues?: DefaultValues; 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/workflow-history/__fixtures__/workflow-page-url-params.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowPageTabsParams } from '@/views/workflow-page/workflow-page-tabs/workflow-page-tabs.types'; 2 | 3 | export const workflowPageUrlParams: WorkflowPageTabsParams = { 4 | cluster: 'testCluster', 5 | domain: 'testDomain', 6 | workflowId: 'testWorkflowId', 7 | runId: 'testRunId', 8 | workflowTab: 'history', 9 | }; 10 | -------------------------------------------------------------------------------- /src/views/workflow-history/config/workflow-history-should-shorten-group-labels.config.ts: -------------------------------------------------------------------------------- 1 | const WORKFLOW_HISTORY_SHOULD_SHORTEN_GROUP_LABELS_CONFIG: boolean = false; 2 | 3 | export default WORKFLOW_HISTORY_SHOULD_SHORTEN_GROUP_LABELS_CONFIG; 4 | -------------------------------------------------------------------------------- /src/views/workflow-history/helpers/check-history-event-group/is-extended-activity-event.ts: -------------------------------------------------------------------------------- 1 | import type { ExtendedActivityHistoryEvent } from '../../workflow-history.types'; 2 | 3 | export default function isExtendedActivityEvent(event: { 4 | attributes: string; 5 | }): event is ExtendedActivityHistoryEvent { 6 | return [ 7 | 'activityTaskScheduledEventAttributes', 8 | 'pendingActivityTaskStartEventAttributes', 9 | 'activityTaskStartedEventAttributes', 10 | 'activityTaskCompletedEventAttributes', 11 | 'activityTaskFailedEventAttributes', 12 | 'activityTaskTimedOutEventAttributes', 13 | 'activityTaskCanceledEventAttributes', 14 | ].includes(event?.attributes); 15 | } 16 | -------------------------------------------------------------------------------- /src/views/workflow-history/helpers/check-history-event-group/is-extended-decision-event.ts: -------------------------------------------------------------------------------- 1 | import type { ExtendedDecisionHistoryEvent } from '../../workflow-history.types'; 2 | 3 | export default function isExtendedDecisionEvent(event: { 4 | attributes: string; 5 | }): event is ExtendedDecisionHistoryEvent { 6 | return [ 7 | 'pendingDecisionTaskStartEventAttributes', 8 | 'decisionTaskScheduledEventAttributes', 9 | 'decisionTaskStartedEventAttributes', 10 | 'decisionTaskCompletedEventAttributes', 11 | 'decisionTaskFailedEventAttributes', 12 | 'decisionTaskTimedOutEventAttributes', 13 | ].includes(event?.attributes); 14 | } 15 | -------------------------------------------------------------------------------- /src/views/workflow-history/helpers/check-history-event-group/is-request-cancel-external-workflow-execution-event.ts: -------------------------------------------------------------------------------- 1 | import type { RequestCancelExternalWorkflowExecutionHistoryEvent } from '../../workflow-history.types'; 2 | 3 | export default function isRequestCancelExternalWorkflowExecutionEvent(event: { 4 | attributes: string; 5 | }): event is RequestCancelExternalWorkflowExecutionHistoryEvent { 6 | return [ 7 | 'requestCancelExternalWorkflowExecutionInitiatedEventAttributes', 8 | 'requestCancelExternalWorkflowExecutionFailedEventAttributes', 9 | 'externalWorkflowExecutionCancelRequestedEventAttributes', 10 | ].includes(event?.attributes); 11 | } 12 | -------------------------------------------------------------------------------- /src/views/workflow-history/helpers/check-history-event-group/is-signal-external-workflow-execution-event.ts: -------------------------------------------------------------------------------- 1 | import type { SignalExternalWorkflowExecutionHistoryEvent } from '../../workflow-history.types'; 2 | 3 | export default function isSignalExternalWorkflowExecutionEvent(event: { 4 | attributes: string; 5 | }): event is SignalExternalWorkflowExecutionHistoryEvent { 6 | return [ 7 | 'signalExternalWorkflowExecutionInitiatedEventAttributes', 8 | 'signalExternalWorkflowExecutionFailedEventAttributes', 9 | 'externalWorkflowExecutionSignaledEventAttributes', 10 | ].includes(event?.attributes); 11 | } 12 | -------------------------------------------------------------------------------- /src/views/workflow-history/helpers/check-history-event-group/is-timer-event.ts: -------------------------------------------------------------------------------- 1 | import type { TimerHistoryEvent } from '../../workflow-history.types'; 2 | 3 | export default function isTimerEvent(event: { 4 | attributes: string; 5 | }): event is TimerHistoryEvent { 6 | return [ 7 | 'timerStartedEventAttributes', 8 | 'timerFiredEventAttributes', 9 | 'timerCanceledEventAttributes', 10 | ].includes(event?.attributes); 11 | } 12 | -------------------------------------------------------------------------------- /src/views/workflow-history/helpers/place-event-in-group-events.ts: -------------------------------------------------------------------------------- 1 | import sortedIndexBy from 'lodash/sortedIndexBy'; 2 | 3 | import { type ExtendedHistoryEvent } from '../workflow-history.types'; 4 | 5 | export default function placeEventInGroupEvents( 6 | event: ExtendedHistoryEvent, 7 | events: ExtendedHistoryEvent[] 8 | ) { 9 | const sortedEvents = [...events]; 10 | sortedEvents.splice( 11 | sortedIndexBy(sortedEvents, event, (e) => 12 | e?.eventId ? parseInt(e?.eventId) : 0 13 | ), 14 | 0, 15 | event 16 | ); 17 | return sortedEvents; 18 | } 19 | -------------------------------------------------------------------------------- /src/views/workflow-history/hooks/use-event-expansion-toggle.types.ts: -------------------------------------------------------------------------------- 1 | export type EventExpansionState = Record | true; 2 | 3 | export type ToggleIsExpandAllEvents = () => void; 4 | 5 | export type GetIsEventExpanded = (eventId: string) => boolean; 6 | 7 | export type OnEventExpandToggle = (eventId: string) => void; 8 | 9 | export type ToggleIsEventExpanded = (eventId: string) => void; 10 | -------------------------------------------------------------------------------- /src/views/workflow-history/hooks/use-initial-selected-event.types.ts: -------------------------------------------------------------------------------- 1 | import { type HistoryEvent } from '@/__generated__/proto-ts/uber/cadence/api/v1/HistoryEvent'; 2 | 3 | export type UseInitialSelectedEventParams = { 4 | events: HistoryEvent[]; 5 | selectedEventId?: string; 6 | filteredEventGroupsEntries: [string, any][]; 7 | }; 8 | -------------------------------------------------------------------------------- /src/views/workflow-history/hooks/use-keep-loading-events.types.ts: -------------------------------------------------------------------------------- 1 | export type UseKeepLoadingEventsParams = { 2 | shouldKeepLoading: boolean; 3 | isLastPageEmpty: boolean; 4 | hasNextPage: boolean; 5 | fetchNextPage: () => void; 6 | isFetchingNextPage: boolean; 7 | isFetchNextPageError: boolean; 8 | stopAfterEndReached?: boolean; 9 | continueLoadingAfterError?: boolean; 10 | }; 11 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details-entry/workflow-history-event-details-entry.tsx: -------------------------------------------------------------------------------- 1 | import { type Props } from './workflow-history-event-details-entry.types'; 2 | 3 | export default function WorkflowHistoryEventDetailsEntry({ 4 | entryKey, 5 | entryPath, 6 | entryValue, 7 | renderConfig, 8 | ...decodedPageUrlParams 9 | }: Props) { 10 | const ValueComponent = renderConfig?.valueComponent; 11 | 12 | if (ValueComponent !== undefined) { 13 | return ( 14 | 20 | ); 21 | } 22 | 23 | return String(entryValue); 24 | } 25 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details-entry/workflow-history-event-details-entry.types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type WorkflowHistoryEventDetailsConfig, 3 | type WorkflowHistoryEventDetailsValueComponentProps, 4 | } from '../workflow-history-event-details/workflow-history-event-details.types'; 5 | 6 | export type Props = WorkflowHistoryEventDetailsValueComponentProps & { 7 | renderConfig: WorkflowHistoryEventDetailsConfig | null; 8 | }; 9 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details-group/workflow-history-event-details-group.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowPageTabsParams } from '@/views/workflow-page/workflow-page-tabs/workflow-page-tabs.types'; 2 | 3 | import { type WorkflowHistoryEventDetailsEntries } from '../workflow-history-event-details/workflow-history-event-details.types'; 4 | 5 | export type Props = { 6 | entries: WorkflowHistoryEventDetailsEntries; 7 | parentGroupPath?: string; 8 | decodedPageUrlParams: WorkflowPageTabsParams; 9 | }; 10 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details-json/workflow-history-event-details-json.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowHistoryEventDetailsValueComponentProps } from '../workflow-history-event-details/workflow-history-event-details.types'; 2 | 3 | export type Props = Pick< 4 | WorkflowHistoryEventDetailsValueComponentProps, 5 | 'entryValue' 6 | >; 7 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details-placeholder-text/workflow-history-event-details-placeholder-text.styles.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | StyletronCSSObject, 3 | StyletronCSSObjectOf, 4 | } from '@/hooks/use-styletron-classes'; 5 | 6 | const cssStylesObj = { 7 | placeholderText: (theme) => ({ 8 | display: 'contents', 9 | color: theme.colors.contentTertiary, 10 | fontStyle: 'italic', 11 | }), 12 | } satisfies StyletronCSSObject; 13 | 14 | export const cssStyles: StyletronCSSObjectOf = 15 | cssStylesObj; 16 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details-placeholder-text/workflow-history-event-details-placeholder-text.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import React from 'react'; 3 | 4 | import useStyletronClasses from '@/hooks/use-styletron-classes'; 5 | 6 | import { cssStyles } from './workflow-history-event-details-placeholder-text.styles'; 7 | import type { Props } from './workflow-history-event-details-placeholder-text.types'; 8 | 9 | export default function WorkflowHistoryEventDetailsPlaceholderText({ 10 | placeholderText = 'Not set', 11 | }: Props) { 12 | const { cls } = useStyletronClasses(cssStyles); 13 | return
{placeholderText}
; 14 | } 15 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details-placeholder-text/workflow-history-event-details-placeholder-text.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | placeholderText?: string; 3 | }; 4 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details/helpers/is-pending-history-event.ts: -------------------------------------------------------------------------------- 1 | import type { PendingHistoryEvent } from '../../workflow-history.types'; 2 | 3 | export default function isPendingHistoryEvent(event: { 4 | attributes: string; 5 | }): event is PendingHistoryEvent { 6 | return ( 7 | event?.attributes === 'pendingActivityTaskStartEventAttributes' || 8 | event?.attributes === 'pendingDecisionTaskStartEventAttributes' 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-details/workflow-history-event-details.styles.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | StyletronCSSObject, 3 | StyletronCSSObjectOf, 4 | } from '@/hooks/use-styletron-classes'; 5 | 6 | const cssStylesObj = { 7 | emptyDetails: (theme) => ({ 8 | ...theme.typography.LabelXSmall, 9 | color: theme.colors.contentTertiary, 10 | textAlign: 'center', 11 | padding: `${theme.sizing.scale700} 0`, 12 | }), 13 | } satisfies StyletronCSSObject; 14 | 15 | export const cssStyles: StyletronCSSObjectOf = 16 | cssStylesObj; 17 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-status-badge/helpers/get-badge-container-size.ts: -------------------------------------------------------------------------------- 1 | import type { Theme } from 'baseui'; 2 | 3 | import { type WorkflowEventStatusBadgeSize } from '../workflow-history-event-status-badge.types'; 4 | 5 | export default function getBadgeContainerSize( 6 | theme: Theme, 7 | size: WorkflowEventStatusBadgeSize 8 | ): string { 9 | const sizeMap: Record = { 10 | small: theme.sizing.scale600, 11 | medium: theme.sizing.scale800, 12 | }; 13 | 14 | return sizeMap[size]; 15 | } 16 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-status-badge/helpers/get-badge-icon-size.ts: -------------------------------------------------------------------------------- 1 | import type { Theme } from 'baseui'; 2 | 3 | import { type WorkflowEventStatusBadgeSize } from '../workflow-history-event-status-badge.types'; 4 | 5 | export default function getBadgeIconSize( 6 | theme: Theme, 7 | size: WorkflowEventStatusBadgeSize 8 | ): string { 9 | const iconSizeMap: Record = { 10 | small: theme.sizing.scale400, 11 | medium: theme.sizing.scale550, 12 | }; 13 | 14 | return iconSizeMap[size]; 15 | } 16 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-status-badge/workflow-history-event-status-badge.constants.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | WorkflowEventStatus, 3 | WorkflowEventStatusBadgeSize, 4 | } from './workflow-history-event-status-badge.types'; 5 | 6 | export const WORKFLOW_EVENT_STATUS = { 7 | COMPLETED: 'COMPLETED', 8 | FAILED: 'FAILED', 9 | CANCELED: 'CANCELED', 10 | ONGOING: 'ONGOING', 11 | WAITING: 'WAITING', 12 | } as const satisfies Record; 13 | 14 | export const WORKFLOW_EVENT_STATUS_BADGE_SIZES: Record< 15 | WorkflowEventStatusBadgeSize, 16 | WorkflowEventStatusBadgeSize 17 | > = { 18 | small: 'small', 19 | medium: 'medium', 20 | }; 21 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-event-status-badge/workflow-history-event-status-badge.types.ts: -------------------------------------------------------------------------------- 1 | export type WorkflowEventStatusBadgeSize = 'small' | 'medium'; 2 | export type WorkflowEventStatus = 3 | | 'ONGOING' 4 | | 'WAITING' 5 | | 'COMPLETED' 6 | | 'FAILED' 7 | | 'CANCELED'; 8 | 9 | export type Props = { 10 | status: WorkflowEventStatus; 11 | statusReady: boolean; 12 | size?: WorkflowEventStatusBadgeSize; 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-events-card/workflow-history-events-card.types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type GetIsEventExpanded, 3 | type ToggleIsEventExpanded, 4 | } from '../hooks/use-event-expansion-toggle.types'; 5 | import type { 6 | ExtendedHistoryEvent, 7 | HistoryGroupEventMetadata, 8 | Props as WorfklowHistoryProps, 9 | } from '../workflow-history.types'; 10 | 11 | export type Props = { 12 | events: ExtendedHistoryEvent[]; 13 | eventsMetadata: Pick[]; 14 | showEventPlaceholder?: boolean; 15 | decodedPageUrlParams: WorfklowHistoryProps['params']; 16 | getIsEventExpanded: GetIsEventExpanded; 17 | onEventToggle: ToggleIsEventExpanded; 18 | animateBorderOnEnter?: boolean; 19 | }; 20 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-events-duration-badge/workflow-history-events-duration-badge.styles.ts: -------------------------------------------------------------------------------- 1 | import { type BadgeOverrides } from 'baseui/badge/types'; 2 | import { type Theme } from 'baseui/theme'; 3 | 4 | import themeLight from '@/config/theme/theme-light.config'; 5 | 6 | export const overrides = { 7 | Badge: { 8 | Badge: { 9 | style: ({ 10 | $theme, 11 | $hierarchy, 12 | }: { 13 | $theme: Theme; 14 | $hierarchy: string; 15 | }) => ({ 16 | ...$theme.typography.LabelXSmall, 17 | ...($hierarchy === 'secondary' 18 | ? { 19 | color: $theme.colors.contentSecondary, 20 | } 21 | : null), 22 | }), 23 | }, 24 | } satisfies BadgeOverrides, 25 | }; 26 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-events-duration-badge/workflow-history-events-duration-badge.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowExecutionCloseStatus } from '@/__generated__/proto-ts/uber/cadence/api/v1/WorkflowExecutionCloseStatus'; 2 | 3 | export type Props = { 4 | startTime: Date | string | number; 5 | closeTime: Date | string | number | null | undefined; 6 | workflowIsArchived: boolean; 7 | workflowCloseStatus: WorkflowExecutionCloseStatus | null | undefined; 8 | eventsCount: number; 9 | loadingMoreEvents: boolean; 10 | hasMissingEvents: boolean; 11 | workflowCloseTime: Date | string | number | null | undefined; 12 | showOngoingOnly?: boolean; 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-expand-all-events-button/workflow-history-expand-all-events-button.types.ts: -------------------------------------------------------------------------------- 1 | import { type ToggleIsExpandAllEvents } from '../hooks/use-event-expansion-toggle.types'; 2 | 3 | export type Props = { 4 | isExpandAllEvents: boolean; 5 | toggleIsExpandAllEvents: ToggleIsExpandAllEvents; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-export-json-button/workflow-history-export-json-button.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | cluster: string; 4 | workflowId: string; 5 | runId: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-filters-status/workflow-history-filters-status.constants.ts: -------------------------------------------------------------------------------- 1 | import { type HistoryEventFilterStatus } from './workflow-history-filters-status.types'; 2 | 3 | export const HISTORY_EVENT_FILTER_STATUSES = { 4 | PENDING: 'PENDING', 5 | CANCELED: 'CANCELED', 6 | FAILED: 'FAILED', 7 | COMPLETED: 'COMPLETED', 8 | } as const satisfies Record; 9 | 10 | export const HISTORY_EVENT_FILTER_STATUS_LABELS_MAP = { 11 | PENDING: 'Pending', 12 | CANCELED: 'Canceled', 13 | FAILED: 'Failed', 14 | COMPLETED: 'Completed', 15 | } as const satisfies Record; 16 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-filters-status/workflow-history-filters-status.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import type { FormControlOverrides } from 'baseui/form-control/types'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | selectFormControl: { 7 | Label: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | ...$theme.typography.LabelXSmall, 10 | }), 11 | }, 12 | ControlContainer: { 13 | style: (): StyleObject => ({ 14 | margin: '0px', 15 | }), 16 | }, 17 | } satisfies FormControlOverrides, 18 | }; 19 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-filters-status/workflow-history-filters-status.types.ts: -------------------------------------------------------------------------------- 1 | export type HistoryEventFilterStatus = 2 | | 'COMPLETED' 3 | | 'FAILED' 4 | | 'CANCELED' 5 | | 'PENDING'; 6 | 7 | export type WorkflowHistoryFiltersStatusValue = { 8 | historyEventStatuses: HistoryEventFilterStatus[] | undefined; 9 | }; 10 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-filters-type/workflow-history-filters-type.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import type { FormControlOverrides } from 'baseui/form-control/types'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | selectFormControl: { 7 | Label: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | ...$theme.typography.LabelXSmall, 10 | }), 11 | }, 12 | ControlContainer: { 13 | style: (): StyleObject => ({ 14 | margin: '0px', 15 | }), 16 | }, 17 | } satisfies FormControlOverrides, 18 | }; 19 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-filters-type/workflow-history-filters-type.types.ts: -------------------------------------------------------------------------------- 1 | export type WorkflowHistoryEventFilteringType = 2 | | 'DECISION' 3 | | 'ACTIVITY' 4 | | 'SIGNAL' 5 | | 'TIMER' 6 | | 'DECISION' 7 | | 'CHILDWORKFLOW' 8 | | 'WORKFLOW'; 9 | 10 | export type WorkflowHistoryFiltersTypeValue = { 11 | historyEventTypes: WorkflowHistoryEventFilteringType[] | undefined; 12 | }; 13 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-group-label/workflow-history-group-label.tsx: -------------------------------------------------------------------------------- 1 | import { StatefulTooltip } from 'baseui/tooltip'; 2 | 3 | import { type Props } from './workflow-history-group-label.types'; 4 | 5 | export default function WorkflowHistoryGroupLabel({ 6 | label, 7 | shortLabel, 8 | }: Props) { 9 | if (!shortLabel) return <>{label}; 10 | 11 | return ( 12 | label} 18 | returnFocus 19 | autoFocus 20 | > 21 | {shortLabel} 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-group-label/workflow-history-group-label.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | label: string; 3 | shortLabel?: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-timeline-chart/helpers/is-valid-class-name-key.ts: -------------------------------------------------------------------------------- 1 | import { type ClsObjectFor } from '@/hooks/use-styletron-classes'; 2 | 3 | import { type cssStyles } from '../workflow-history-timeline-chart.styles'; 4 | 5 | export default function isValidClassNameKey( 6 | classes: ClsObjectFor, 7 | key: string 8 | ): key is keyof ClsObjectFor { 9 | return Object.hasOwn(classes, key); 10 | } 11 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-timeline-chart/workflow-history-timeline-chart.types.ts: -------------------------------------------------------------------------------- 1 | import { type HistoryEventsGroup } from '../workflow-history.types'; 2 | 3 | export type Props = { 4 | eventGroupsEntries: Array<[string, HistoryEventsGroup]>; 5 | selectedEventId: string | null | undefined; 6 | isLoading: boolean; 7 | hasMoreEvents: boolean; 8 | fetchMoreEvents: () => void; 9 | isFetchingMoreEvents: boolean; 10 | onClickEventGroup: (eventGroupIndex: number) => void; 11 | }; 12 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-timeline-load-more/workflow-history-timeline-load-more.types.ts: -------------------------------------------------------------------------------- 1 | import type { RequestError } from '@/utils/request/request-error'; 2 | 3 | export type Props = { 4 | error: RequestError | null; 5 | fetchNextPage: () => void; 6 | hasNextPage: boolean; 7 | isFetchingNextPage: boolean; 8 | }; 9 | -------------------------------------------------------------------------------- /src/views/workflow-history/workflow-history-timeline-reset-button/workflow-history-timeline-reset-button.types.ts: -------------------------------------------------------------------------------- 1 | type Props = { 2 | workflowId: string; 3 | runId: string; 4 | domain: string; 5 | cluster: string; 6 | onReset: () => void; 7 | }; 8 | 9 | export default Props; 10 | -------------------------------------------------------------------------------- /src/views/workflow-page/__fixtures__/workflow-details-params.ts: -------------------------------------------------------------------------------- 1 | export const mockWorkflowDetailsParams = { 2 | cluster: 'testCluster', 3 | domain: 'testDomain', 4 | workflowId: 'testWorkflowId', 5 | runId: 'testRunId', 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/workflow-page/config/workflow-page-cli-commands-groups.config.ts: -------------------------------------------------------------------------------- 1 | import { type CliCommandGroupConfig } from '../workflow-page-cli-commands-modal/workflow-page-cli-commands-modal.types'; 2 | 3 | const workflowPageCliCommandsGroupsConfig = [ 4 | { 5 | name: 'domain', 6 | title: 'Domain', 7 | }, 8 | { 9 | name: 'workflow', 10 | title: 'Workflow', 11 | }, 12 | ] as const satisfies CliCommandGroupConfig[]; 13 | 14 | export default workflowPageCliCommandsGroupsConfig; 15 | -------------------------------------------------------------------------------- /src/views/workflow-page/config/workflow-page-status-refetch-interval.config.ts: -------------------------------------------------------------------------------- 1 | const WORKFLOW_PAGE_STATUS_REFETCH_INTERVAL = 10000; 2 | 3 | export default WORKFLOW_PAGE_STATUS_REFETCH_INTERVAL; 4 | -------------------------------------------------------------------------------- /src/views/workflow-page/helpers/get-workflow-is-completed.ts: -------------------------------------------------------------------------------- 1 | const workflowCompletedAttributes = [ 2 | 'workflowExecutionCancelRequestedEventAttributes', 3 | 'workflowExecutionCanceledEventAttributes', 4 | 'workflowExecutionCompletedEventAttributes', 5 | 'workflowExecutionContinuedAsNewEventAttributes', 6 | 'workflowExecutionFailedEventAttributes', 7 | 'workflowExecutionTerminatedEventAttributes', 8 | 'workflowExecutionTimedOutEventAttributes', 9 | ]; 10 | 11 | const getWorkflowIsCompleted = (lastEventAttributes: string) => 12 | workflowCompletedAttributes.includes(lastEventAttributes); 13 | 14 | export default getWorkflowIsCompleted; 15 | -------------------------------------------------------------------------------- /src/views/workflow-page/workflow-page-error/workflow-page-error.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | error: Error; 3 | reset: () => void; 4 | }; 5 | -------------------------------------------------------------------------------- /src/views/workflow-page/workflow-page-header/workflow-page-header.types.ts: -------------------------------------------------------------------------------- 1 | export type Props = { 2 | domain: string; 3 | workflowId: string; 4 | runId: string; 5 | cluster: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/views/workflow-page/workflow-page-pending-events-badge/workflow-page-pending-events-badge.styles.ts: -------------------------------------------------------------------------------- 1 | import type { Theme } from 'baseui'; 2 | import type { BadgeOverrides } from 'baseui/badge'; 3 | import type { StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | badge: { 7 | Badge: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | color: $theme.colors.contentPrimary, 10 | backgroundColor: $theme.colors.backgroundTertiary, 11 | borderRadius: '20px', 12 | padding: `${$theme.sizing.scale0} ${$theme.sizing.scale300}`, 13 | ...$theme.typography.LabelXSmall, 14 | }), 15 | }, 16 | } satisfies BadgeOverrides, 17 | }; 18 | -------------------------------------------------------------------------------- /src/views/workflow-page/workflow-page-tab-content/workflow-page-tab-content.styles.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | StyletronCSSObject, 3 | StyletronCSSObjectOf, 4 | } from '@/hooks/use-styletron-classes'; 5 | 6 | const cssStylesObj = { 7 | tabContentContainer: (theme) => ({ 8 | display: 'flex', 9 | flexDirection: 'column', 10 | marginTop: theme.sizing.scale900, 11 | marginBottom: theme.sizing.scale900, 12 | flex: 1, 13 | }), 14 | } satisfies StyletronCSSObject; 15 | 16 | export const cssStyles: StyletronCSSObjectOf = 17 | cssStylesObj; 18 | -------------------------------------------------------------------------------- /src/views/workflow-page/workflow-page-tabs-error/workflow-page-tabs-error.types.ts: -------------------------------------------------------------------------------- 1 | import { type Props as ErrorPanelProps } from '@/components/error-panel/error-panel.types'; 2 | 3 | import { type WorkflowPageTabName } from '../workflow-page-tab-content/workflow-page-tab-content.types'; 4 | 5 | export type WorkflowPageTabErrorConfig = Omit< 6 | ErrorPanelProps, 7 | 'error' | 'reset' 8 | >; 9 | 10 | export type WorkflowPageTabsErrorConfig = Record< 11 | WorkflowPageTabName, 12 | (err: Error) => WorkflowPageTabErrorConfig 13 | >; 14 | 15 | export type Props = { 16 | error: Error; 17 | reset: () => void; 18 | }; 19 | -------------------------------------------------------------------------------- /src/views/workflow-page/workflow-page-tabs/workflow-page-tabs.styles.ts: -------------------------------------------------------------------------------- 1 | import { styled as createStyled, type Theme } from 'baseui'; 2 | 3 | export const styled = { 4 | EndButtonsContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ 5 | display: 'flex', 6 | gap: $theme.sizing.scale300, 7 | })), 8 | }; 9 | -------------------------------------------------------------------------------- /src/views/workflow-page/workflow-page-tabs/workflow-page-tabs.types.ts: -------------------------------------------------------------------------------- 1 | import type { PageTab } from '@/components/page-tabs/page-tabs.types'; 2 | 3 | import type workflowPageTabsConfig from '../config/workflow-page-tabs.config'; 4 | 5 | export type WorkflowPageTabs = Array; 6 | 7 | export type WorkflowPageTabsParams = { 8 | domain: string; 9 | cluster: string; 10 | workflowId: string; 11 | runId: string; 12 | workflowTab: (typeof workflowPageTabsConfig)[number]['key']; 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/workflow-page/workflow-page.types.ts: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | 3 | export type WorkflowPageParams = { 4 | domain: string; 5 | cluster: string; 6 | workflowId: string; 7 | runId: string; 8 | }; 9 | 10 | export type Props = { 11 | params: WorkflowPageParams; 12 | children: React.ReactNode; 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/workflow-queries/config/workflow-queries-empty-panel.config.ts: -------------------------------------------------------------------------------- 1 | import { type Props as ErrorPanelProps } from '@/components/error-panel/error-panel.types'; 2 | 3 | const workflowQueriesEmptyPanelConfig = { 4 | message: 'No queries available for this workflow', 5 | omitLogging: true, 6 | actions: [ 7 | { 8 | kind: 'link-external', 9 | label: 'Read more about workflow queries', 10 | link: 'https://cadenceworkflow.io/docs/concepts/queries', 11 | }, 12 | ], 13 | } as const satisfies ErrorPanelProps; 14 | 15 | export default workflowQueriesEmptyPanelConfig; 16 | -------------------------------------------------------------------------------- /src/views/workflow-queries/helpers/get-workflow-query-status.ts: -------------------------------------------------------------------------------- 1 | import { type QueryStatus } from '@tanstack/react-query'; 2 | 3 | import { type WorkflowQueryStatus } from '../workflow-queries-tile/workflow-queries-tile.types'; 4 | 5 | export default function getWorkflowQueryStatus({ 6 | queryStatus, 7 | isFetching, 8 | }: { 9 | queryStatus: QueryStatus; 10 | isFetching: boolean; 11 | }): WorkflowQueryStatus { 12 | if (isFetching) { 13 | return 'loading'; 14 | } 15 | 16 | switch (queryStatus) { 17 | case 'error': 18 | return 'error'; 19 | case 'success': 20 | return 'success'; 21 | case 'pending': 22 | return 'idle'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/views/workflow-queries/workflow-queries-result-json/workflow-queries-result-json.types.ts: -------------------------------------------------------------------------------- 1 | import { type PrettyJsonValue } from '@/components/pretty-json/pretty-json.types'; 2 | import { type QueryWorkflowResponse } from '@/route-handlers/query-workflow/query-workflow.types'; 3 | import { type RequestError } from '@/utils/request/request-error'; 4 | 5 | export type Props = { 6 | data?: QueryWorkflowResponse; 7 | error?: RequestError; 8 | loading?: boolean; 9 | }; 10 | 11 | export type QueryJsonContent = { 12 | content: PrettyJsonValue | undefined; 13 | isError: boolean; 14 | }; 15 | -------------------------------------------------------------------------------- /src/views/workflow-queries/workflow-queries-status-icon/workflow-queries-status-icon.types.ts: -------------------------------------------------------------------------------- 1 | import { type WorkflowQueryStatus } from '../workflow-queries-tile/workflow-queries-tile.types'; 2 | 3 | export type Props = { 4 | status: WorkflowQueryStatus | undefined; 5 | }; 6 | -------------------------------------------------------------------------------- /src/views/workflow-queries/workflow-queries-tile-input/workflow-queries-tile-input.styles.ts: -------------------------------------------------------------------------------- 1 | import { type Theme } from 'baseui'; 2 | import { type TextareaOverrides } from 'baseui/textarea'; 3 | import { type StyleObject } from 'styletron-react'; 4 | 5 | export const overrides = { 6 | textarea: { 7 | Input: { 8 | style: ({ $theme }: { $theme: Theme }): StyleObject => ({ 9 | ...$theme.typography.MonoParagraphXSmall, 10 | }), 11 | }, 12 | } satisfies TextareaOverrides, 13 | }; 14 | -------------------------------------------------------------------------------- /src/views/workflow-queries/workflow-queries-tile-input/workflow-queries-tile-input.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Textarea } from 'baseui/textarea'; 4 | 5 | import { overrides } from './workflow-queries-tile-input.styles'; 6 | import { type Props } from './workflow-queries-tile-input.types'; 7 | 8 | export default function WorkflowQueriesTileInput(props: Props) { 9 | return ( 10 |