From 4e80e73019164588f0426e4ea1afaa1c6fe1e107 Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Fri, 1 Mar 2024 10:09:12 -0800 Subject: [PATCH 1/4] Add preset workflow library stub; add search & filtering Signed-off-by: Tyler Ohlsen --- common/interfaces.ts | 14 ++-- .../workflows/new_workflow/new_workflow.tsx | 76 ++++++++++++++----- .../pages/workflows/new_workflow/presets.tsx | 59 ++++++++++++++ .../pages/workflows/new_workflow/use_case.tsx | 1 + .../workflows/workflow_list/workflow_list.tsx | 2 +- 5 files changed, 128 insertions(+), 24 deletions(-) create mode 100644 public/pages/workflows/new_workflow/presets.tsx diff --git a/common/interfaces.ts b/common/interfaces.ts index a493d650..a927f0e8 100644 --- a/common/interfaces.ts +++ b/common/interfaces.ts @@ -69,16 +69,20 @@ export type UseCaseTemplate = { }; export type Workflow = { - id: string; + // won't exist until created in backend + id?: string; name: string; useCase: string; + template: UseCaseTemplate; description?: string; // ReactFlow state may not exist if a workflow is created via API/backend-only. workspaceFlowState?: WorkspaceFlowState; - template: UseCaseTemplate; - lastUpdated: number; - lastLaunched: number; - state: WORKFLOW_STATE; + // won't exist until created in backend + lastUpdated?: number; + // won't exist until launched/provisioned in backend + lastLaunched?: number; + // won't exist until launched/provisioned in backend + state?: WORKFLOW_STATE; }; export enum USE_CASE { diff --git a/public/pages/workflows/new_workflow/new_workflow.tsx b/public/pages/workflows/new_workflow/new_workflow.tsx index ce87c443..d5644210 100644 --- a/public/pages/workflows/new_workflow/new_workflow.tsx +++ b/public/pages/workflows/new_workflow/new_workflow.tsx @@ -3,10 +3,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React from 'react'; -import { EuiFlexItem, EuiFlexGrid } from '@elastic/eui'; +import React, { useState, useEffect } from 'react'; +import { debounce } from 'lodash'; +import { + EuiFlexItem, + EuiFlexGrid, + EuiFlexGroup, + EuiFieldSearch, +} from '@elastic/eui'; import { UseCase } from './use_case'; +import { getPresetWorkflows } from './presets'; +import { Workflow } from '../../../../common'; interface NewWorkflowProps {} @@ -18,26 +26,58 @@ interface NewWorkflowProps {} * workflow for users to start with. */ export function NewWorkflow(props: NewWorkflowProps) { + // preset workflow state + const presetWorkflows = getPresetWorkflows(); + const [filteredWorkflows, setFilteredWorkflows] = useState( + getPresetWorkflows() + ); + + // search bar state + const [searchQuery, setSearchQuery] = useState(''); + const debounceSearchQuery = debounce((query: string) => { + setSearchQuery(query); + }, 200); + + // When search query updated, re-filter preset list + useEffect(() => { + setFilteredWorkflows(fetchFilteredWorkflows(presetWorkflows, searchQuery)); + }, [searchQuery]); + return ( - - - + + debounceSearchQuery(e.target.value)} /> - + + {filteredWorkflows.map((workflow: Workflow) => { + return ( + + + + ); + })} + - - - - + ); } + +// Collect the final preset workflow list after applying all filters +function fetchFilteredWorkflows( + allWorkflows: Workflow[], + searchQuery: string +): Workflow[] { + return searchQuery.length === 0 + ? allWorkflows + : allWorkflows.filter((workflow) => + workflow.name.toLowerCase().includes(searchQuery.toLowerCase()) + ); +} diff --git a/public/pages/workflows/new_workflow/presets.tsx b/public/pages/workflows/new_workflow/presets.tsx new file mode 100644 index 00000000..2950a005 --- /dev/null +++ b/public/pages/workflows/new_workflow/presets.tsx @@ -0,0 +1,59 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Workflow, WorkspaceFlowState } from '../../../../common'; + +// TODO: fetch from the backend when the workflow library is complete. +/** + * Used to fetch the library of preset workflows to provide to users. + */ +export function getPresetWorkflows(): Workflow[] { + return [ + { + name: 'Semantic Search', + description: + 'This semantic search workflow includes the essential ingestion and search pipelines that covers the most common search use cases.', + useCase: 'SEMANTIC_SEARCH', + template: {}, + workspaceFlowState: { + nodes: [], + edges: [], + } as WorkspaceFlowState, + }, + { + name: 'Semantic Search with Reranking', + description: + 'This semantic search workflow variation includes an ML processor to rerank fetched results.', + useCase: 'SEMANTIC_SEARCH_WITH_RERANK', + template: {}, + workspaceFlowState: { + nodes: [], + edges: [], + } as WorkspaceFlowState, + }, + { + name: 'Start From Scratch', + description: + 'Build your workflow from scratch according to your specific use cases. Start by adding components for your ingest or query needs.', + useCase: '', + template: {}, + workspaceFlowState: { + nodes: [], + edges: [], + } as WorkspaceFlowState, + }, + { + name: 'Visual Search', + description: + 'Build an application that will return results based on images.', + useCase: 'SEMANTIC_SEARCH', + template: {}, + workspaceFlowState: { + nodes: [], + edges: [], + } as WorkspaceFlowState, + }, + ] as Workflow[]; +} diff --git a/public/pages/workflows/new_workflow/use_case.tsx b/public/pages/workflows/new_workflow/use_case.tsx index c7094c9a..baacb201 100644 --- a/public/pages/workflows/new_workflow/use_case.tsx +++ b/public/pages/workflows/new_workflow/use_case.tsx @@ -28,6 +28,7 @@ export function UseCase(props: UseCaseProps) { } titleSize="s" paddingSize="l" + layout="horizontal" > diff --git a/public/pages/workflows/workflow_list/workflow_list.tsx b/public/pages/workflows/workflow_list/workflow_list.tsx index 3e5b4484..f122a2e0 100644 --- a/public/pages/workflows/workflow_list/workflow_list.tsx +++ b/public/pages/workflows/workflow_list/workflow_list.tsx @@ -109,7 +109,7 @@ export function WorkflowList(props: WorkflowListProps) { debounceSearchQuery(e.target.value)} /> From 1793726de3cb28a42347e6c1b35915ad88cc8d04 Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Fri, 1 Mar 2024 11:27:28 -0800 Subject: [PATCH 2/4] Add navigation; handle new workflow state on details page Signed-off-by: Tyler Ohlsen --- common/constants.ts | 5 ++++ .../workflow_detail/components/header.tsx | 3 +- .../pages/workflow_detail/workflow_detail.tsx | 28 +++++++++++++++---- .../workflows/new_workflow/new_workflow.tsx | 27 ++++++++++++++++-- .../pages/workflows/new_workflow/use_case.tsx | 8 ++++-- public/store/reducers/workflows_reducer.ts | 24 ++++++++++++++++ 6 files changed, 83 insertions(+), 12 deletions(-) diff --git a/common/constants.ts b/common/constants.ts index 0903f38c..fa890192 100644 --- a/common/constants.ts +++ b/common/constants.ts @@ -29,3 +29,8 @@ export const SEARCH_WORKFLOWS_NODE_API_PATH = `${BASE_WORKFLOW_NODE_API_PATH}/se export const GET_WORKFLOW_STATE_NODE_API_PATH = `${BASE_WORKFLOW_NODE_API_PATH}/state`; export const CREATE_WORKFLOW_NODE_API_PATH = `${BASE_WORKFLOW_NODE_API_PATH}/create`; export const DELETE_WORKFLOW_NODE_API_PATH = `${BASE_WORKFLOW_NODE_API_PATH}/delete`; + +/** + * MISCELLANEOUS + */ +export const NEW_WORKFLOW_ID_URL = 'new'; diff --git a/public/pages/workflow_detail/components/header.tsx b/public/pages/workflow_detail/components/header.tsx index 987baeb5..3c165ee9 100644 --- a/public/pages/workflow_detail/components/header.tsx +++ b/public/pages/workflow_detail/components/header.tsx @@ -12,6 +12,7 @@ import { rfContext, AppState, removeDirty } from '../../../store'; interface WorkflowDetailHeaderProps { tabs: any[]; + formattedWorkflowName: string; workflow?: Workflow; } @@ -22,7 +23,7 @@ export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) { return ( {}}> Prototype diff --git a/public/pages/workflow_detail/workflow_detail.tsx b/public/pages/workflow_detail/workflow_detail.tsx index e57bcc83..f7988d77 100644 --- a/public/pages/workflow_detail/workflow_detail.tsx +++ b/public/pages/workflow_detail/workflow_detail.tsx @@ -5,7 +5,7 @@ import React, { useEffect, useState } from 'react'; import { RouteComponentProps, useLocation } from 'react-router-dom'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { ReactFlowProvider } from 'reactflow'; import queryString from 'query-string'; import { EuiPage, EuiPageBody } from '@elastic/eui'; @@ -16,6 +16,7 @@ import { AppState } from '../../store'; import { ResizableWorkspace } from './workspace'; import { Launches } from './launches'; import { Prototype } from './prototype'; +import { NEW_WORKFLOW_ID_URL } from '../../../common'; export interface WorkflowDetailRouterProps { workflowId: string; @@ -45,13 +46,26 @@ function replaceActiveTab(activeTab: string, props: WorkflowDetailProps) { * The workflow details page. This is where users will configure, create, and * test their created workflows. Additionally, can be used to load existing workflows * to view details and/or make changes to them. + * New, unsaved workflows are cached in the redux store and displayed here. */ + +// TODO: if exiting the page, or if saving, clear the cached workflow. Can use redux clearCachedWorkflow() export function WorkflowDetail(props: WorkflowDetailProps) { - const { workflows } = useSelector((state: AppState) => state.workflows); + const { workflows, cachedWorkflow } = useSelector( + (state: AppState) => state.workflows + ); - const workflow = workflows[props.match?.params?.workflowId]; - const workflowName = workflow ? workflow.name : ''; + const isNewWorkflow = props.match?.params?.workflowId === NEW_WORKFLOW_ID_URL; + const workflow = isNewWorkflow + ? cachedWorkflow + : workflows[props.match?.params?.workflowId]; + const workflowName = workflow + ? workflow.name + : isNewWorkflow && !cachedWorkflow + ? 'new_workflow' + : ''; + // tab state const tabFromUrl = queryString.parse(useLocation().search)[ ACTIVE_TAB_PARAM ] as WORKFLOW_DETAILS_TAB; @@ -112,7 +126,11 @@ export function WorkflowDetail(props: WorkflowDetailProps) { - + {selectedTabId === WORKFLOW_DETAILS_TAB.EDITOR && ( )} diff --git a/public/pages/workflows/new_workflow/new_workflow.tsx b/public/pages/workflows/new_workflow/new_workflow.tsx index d5644210..32215dd8 100644 --- a/public/pages/workflows/new_workflow/new_workflow.tsx +++ b/public/pages/workflows/new_workflow/new_workflow.tsx @@ -11,10 +11,11 @@ import { EuiFlexGroup, EuiFieldSearch, } from '@elastic/eui'; - +import { useDispatch } from 'react-redux'; import { UseCase } from './use_case'; import { getPresetWorkflows } from './presets'; import { Workflow } from '../../../../common'; +import { cacheWorkflow } from '../../../store'; interface NewWorkflowProps {} @@ -26,6 +27,7 @@ interface NewWorkflowProps {} * workflow for users to start with. */ export function NewWorkflow(props: NewWorkflowProps) { + const dispatch = useDispatch(); // preset workflow state const presetWorkflows = getPresetWorkflows(); const [filteredWorkflows, setFilteredWorkflows] = useState( @@ -54,12 +56,20 @@ export function NewWorkflow(props: NewWorkflowProps) { - {filteredWorkflows.map((workflow: Workflow) => { + {filteredWorkflows.map((workflow: Workflow, index) => { return ( - + + dispatch( + cacheWorkflow({ + ...workflow, + name: toSnakeCase(workflow.name), + }) + ) + } /> ); @@ -81,3 +91,14 @@ function fetchFilteredWorkflows( workflow.name.toLowerCase().includes(searchQuery.toLowerCase()) ); } + +// Utility fn to convert to snakecase. Used when caching the workflow +// to make a valid name and cause less friction if users decide +// to save it later on. +function toSnakeCase(text: string): string { + return text + .replace(/\W+/g, ' ') + .split(/ |\B(?=[A-Z])/) + .map((word) => word.toLowerCase()) + .join('_'); +} diff --git a/public/pages/workflows/new_workflow/use_case.tsx b/public/pages/workflows/new_workflow/use_case.tsx index baacb201..111c4f7c 100644 --- a/public/pages/workflows/new_workflow/use_case.tsx +++ b/public/pages/workflows/new_workflow/use_case.tsx @@ -13,9 +13,12 @@ import { EuiHorizontalRule, EuiButton, } from '@elastic/eui'; +import { NEW_WORKFLOW_ID_URL, PLUGIN_ID } from '../../../../common'; + interface UseCaseProps { title: string; description: string; + onClick: () => {}; } export function UseCase(props: UseCaseProps) { @@ -40,9 +43,8 @@ export function UseCase(props: UseCaseProps) { { - // TODO: possibly link to the workflow details with a pre-configured flow - }} + onClick={props.onClick} + href={`${PLUGIN_ID}#/workflows/${NEW_WORKFLOW_ID_URL}`} > Go diff --git a/public/store/reducers/workflows_reducer.ts b/public/store/reducers/workflows_reducer.ts index 93f22e89..d06eac97 100644 --- a/public/store/reducers/workflows_reducer.ts +++ b/public/store/reducers/workflows_reducer.ts @@ -78,6 +78,7 @@ const initialState = { loading: false, errorMessage: '', workflows: {} as WorkflowDict, + cachedWorkflow: undefined as Workflow | undefined, }; const WORKFLOWS_ACTION_PREFIX = 'workflows'; @@ -86,6 +87,8 @@ const SEARCH_WORKFLOWS_ACTION = `${WORKFLOWS_ACTION_PREFIX}/searchWorkflows`; const GET_WORKFLOW_STATE_ACTION = `${WORKFLOWS_ACTION_PREFIX}/getWorkflowState`; const CREATE_WORKFLOW_ACTION = `${WORKFLOWS_ACTION_PREFIX}/createWorkflow`; const DELETE_WORKFLOW_ACTION = `${WORKFLOWS_ACTION_PREFIX}/deleteWorkflow`; +const CACHE_WORKFLOW_ACTION = `${WORKFLOWS_ACTION_PREFIX}/cacheWorkflow`; +const CLEAR_CACHED_WORKFLOW_ACTION = `${WORKFLOWS_ACTION_PREFIX}/clearCachedWorkflow`; export const getWorkflow = createAsyncThunk( GET_WORKFLOW_ACTION, @@ -167,6 +170,20 @@ export const deleteWorkflow = createAsyncThunk( } ); +export const cacheWorkflow = createAsyncThunk( + CACHE_WORKFLOW_ACTION, + async (workflow: Workflow) => { + return workflow; + } +); + +// A no-op function to trigger a reducer case. +// Will clear any stored workflow in the cachedWorkflow state +export const clearCachedWorkflow = createAsyncThunk( + CLEAR_CACHED_WORKFLOW_ACTION, + async () => {} +); + const workflowsSlice = createSlice({ name: 'workflows', initialState, @@ -238,6 +255,13 @@ const workflowsSlice = createSlice({ state.loading = false; state.errorMessage = ''; }) + .addCase(cacheWorkflow.fulfilled, (state, action) => { + const workflow = action.payload; + state.cachedWorkflow = workflow; + }) + .addCase(clearCachedWorkflow.fulfilled, (state, action) => { + state.cachedWorkflow = undefined; + }) // Rejected states: set state consistently across all actions .addCase(getWorkflow.rejected, (state, action) => { state.errorMessage = action.payload as string; From 673cc8ec3c4425b95e7023281831abc51539225e Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Fri, 1 Mar 2024 12:33:42 -0800 Subject: [PATCH 3/4] Add editor warning; add workflow fetching on cold reload Signed-off-by: Tyler Ohlsen --- common/constants.ts | 2 + .../workflow_detail/components/header.tsx | 20 +++++++--- .../pages/workflow_detail/workflow_detail.tsx | 37 ++++++++++++++----- .../workflows/new_workflow/new_workflow.tsx | 20 +++++++--- .../pages/workflows/new_workflow/presets.tsx | 8 +++- 5 files changed, 65 insertions(+), 22 deletions(-) diff --git a/common/constants.ts b/common/constants.ts index fa890192..77d1cf52 100644 --- a/common/constants.ts +++ b/common/constants.ts @@ -34,3 +34,5 @@ export const DELETE_WORKFLOW_NODE_API_PATH = `${BASE_WORKFLOW_NODE_API_PATH}/del * MISCELLANEOUS */ export const NEW_WORKFLOW_ID_URL = 'new'; +export const START_FROM_SCRATCH_WORKFLOW_NAME = 'Start From Scratch'; +export const DEFAULT_NEW_WORKFLOW_NAME = 'new_workflow'; diff --git a/public/pages/workflow_detail/components/header.tsx b/public/pages/workflow_detail/components/header.tsx index 3c165ee9..2b99e57e 100644 --- a/public/pages/workflow_detail/components/header.tsx +++ b/public/pages/workflow_detail/components/header.tsx @@ -5,14 +5,14 @@ import React, { useContext } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { EuiPageHeader, EuiButton } from '@elastic/eui'; -import { Workflow } from '../../../../common'; +import { EuiPageHeader, EuiButton, EuiLoadingSpinner } from '@elastic/eui'; +import { DEFAULT_NEW_WORKFLOW_NAME, Workflow } from '../../../../common'; import { saveWorkflow } from '../utils'; import { rfContext, AppState, removeDirty } from '../../../store'; interface WorkflowDetailHeaderProps { tabs: any[]; - formattedWorkflowName: string; + isNewWorkflow: boolean; workflow?: Workflow; } @@ -23,14 +23,24 @@ export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) { return ( + ) + } rightSideItems={[ + // TODO: add launch logic {}}> - Prototype + Launch , { // @ts-ignore saveWorkflow(props.workflow, reactFlowInstance); diff --git a/public/pages/workflow_detail/workflow_detail.tsx b/public/pages/workflow_detail/workflow_detail.tsx index f7988d77..53f23372 100644 --- a/public/pages/workflow_detail/workflow_detail.tsx +++ b/public/pages/workflow_detail/workflow_detail.tsx @@ -12,11 +12,14 @@ import { EuiPage, EuiPageBody } from '@elastic/eui'; import { BREADCRUMBS } from '../../utils'; import { getCore } from '../../services'; import { WorkflowDetailHeader } from './components'; -import { AppState } from '../../store'; +import { AppState, searchWorkflows } from '../../store'; import { ResizableWorkspace } from './workspace'; import { Launches } from './launches'; import { Prototype } from './prototype'; -import { NEW_WORKFLOW_ID_URL } from '../../../common'; +import { + DEFAULT_NEW_WORKFLOW_NAME, + NEW_WORKFLOW_ID_URL, +} from '../../../common'; export interface WorkflowDetailRouterProps { workflowId: string; @@ -49,20 +52,21 @@ function replaceActiveTab(activeTab: string, props: WorkflowDetailProps) { * New, unsaved workflows are cached in the redux store and displayed here. */ -// TODO: if exiting the page, or if saving, clear the cached workflow. Can use redux clearCachedWorkflow() export function WorkflowDetail(props: WorkflowDetailProps) { + const dispatch = useDispatch(); const { workflows, cachedWorkflow } = useSelector( (state: AppState) => state.workflows ); + const { isDirty } = useSelector((state: AppState) => state.workspace); - const isNewWorkflow = props.match?.params?.workflowId === NEW_WORKFLOW_ID_URL; - const workflow = isNewWorkflow - ? cachedWorkflow - : workflows[props.match?.params?.workflowId]; + // selected workflow state + const workflowId = props.match?.params?.workflowId; + const isNewWorkflow = workflowId === NEW_WORKFLOW_ID_URL; + const workflow = isNewWorkflow ? cachedWorkflow : workflows[workflowId]; const workflowName = workflow ? workflow.name - : isNewWorkflow && !cachedWorkflow - ? 'new_workflow' + : isNewWorkflow && !workflow + ? DEFAULT_NEW_WORKFLOW_NAME : ''; // tab state @@ -92,6 +96,19 @@ export function WorkflowDetail(props: WorkflowDetailProps) { ]); }); + // On initial load: + // - fetch workflow, if there is an existing workflow ID + // - add a window listener to warn users if they exit/refresh + // without saving latest changes + useEffect(() => { + if (!isNewWorkflow) { + // TODO: can optimize to only fetch a single workflow + dispatch(searchWorkflows({ query: { match_all: {} } })); + } + window.onbeforeunload = (e) => + isDirty || isNewWorkflow ? true : undefined; + }, []); + const tabs = [ { id: WORKFLOW_DETAILS_TAB.EDITOR, @@ -128,7 +145,7 @@ export function WorkflowDetail(props: WorkflowDetailProps) { {selectedTabId === WORKFLOW_DETAILS_TAB.EDITOR && ( diff --git a/public/pages/workflows/new_workflow/new_workflow.tsx b/public/pages/workflows/new_workflow/new_workflow.tsx index 32215dd8..c255fd50 100644 --- a/public/pages/workflows/new_workflow/new_workflow.tsx +++ b/public/pages/workflows/new_workflow/new_workflow.tsx @@ -14,7 +14,11 @@ import { import { useDispatch } from 'react-redux'; import { UseCase } from './use_case'; import { getPresetWorkflows } from './presets'; -import { Workflow } from '../../../../common'; +import { + DEFAULT_NEW_WORKFLOW_NAME, + START_FROM_SCRATCH_WORKFLOW_NAME, + Workflow, +} from '../../../../common'; import { cacheWorkflow } from '../../../store'; interface NewWorkflowProps {} @@ -66,7 +70,7 @@ export function NewWorkflow(props: NewWorkflowProps) { dispatch( cacheWorkflow({ ...workflow, - name: toSnakeCase(workflow.name), + name: processWorkflowName(workflow.name), }) ) } @@ -92,9 +96,15 @@ function fetchFilteredWorkflows( ); } -// Utility fn to convert to snakecase. Used when caching the workflow -// to make a valid name and cause less friction if users decide -// to save it later on. +// Utility fn to process workflow names from their presentable/readable titles +// on the UI, to a valid name format. +// This leads to less friction if users decide to save the name later on. +function processWorkflowName(workflowName: string): string { + return workflowName === START_FROM_SCRATCH_WORKFLOW_NAME + ? DEFAULT_NEW_WORKFLOW_NAME + : toSnakeCase(workflowName); +} + function toSnakeCase(text: string): string { return text .replace(/\W+/g, ' ') diff --git a/public/pages/workflows/new_workflow/presets.tsx b/public/pages/workflows/new_workflow/presets.tsx index 2950a005..0cf7d382 100644 --- a/public/pages/workflows/new_workflow/presets.tsx +++ b/public/pages/workflows/new_workflow/presets.tsx @@ -3,7 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Workflow, WorkspaceFlowState } from '../../../../common'; +import { + START_FROM_SCRATCH_WORKFLOW_NAME, + Workflow, + WorkspaceFlowState, +} from '../../../../common'; // TODO: fetch from the backend when the workflow library is complete. /** @@ -34,7 +38,7 @@ export function getPresetWorkflows(): Workflow[] { } as WorkspaceFlowState, }, { - name: 'Start From Scratch', + name: START_FROM_SCRATCH_WORKFLOW_NAME, description: 'Build your workflow from scratch according to your specific use cases. Start by adding components for your ingest or query needs.', useCase: '', From c6373765051440612f09e26edc299ba2eab9665a Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Mon, 4 Mar 2024 10:44:53 -0800 Subject: [PATCH 4/4] Skip CI if rapid is labeled Signed-off-by: Tyler Ohlsen --- .github/workflows/build-and-test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 676df60f..dc4b8230 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -16,6 +16,7 @@ jobs: product: opensearch-dashboards build-and-test-linux: + if: ${{ github.event.label.name != 'rapid' }} needs: Get-CI-Image-Tag name: Build & test strategy: @@ -49,7 +50,8 @@ jobs: # TODO: once github actions supports windows and macos docker containers, we can # merge these in to the above step's matrix, including adding windows support - build-and-test-windows-macos: + build-and-test-macos: + if: ${{ github.event.label.name != 'rapid' }} name: Build & test strategy: matrix: