diff --git a/base/200-clusterrole-tenant.yaml b/base/200-clusterrole-tenant.yaml
index 66d338130..98d2609b9 100644
--- a/base/200-clusterrole-tenant.yaml
+++ b/base/200-clusterrole-tenant.yaml
@@ -1,4 +1,4 @@
-# Copyright 2019-2023 The Tekton Authors
+# Copyright 2019-2024 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -44,6 +44,7 @@ rules:
- apiGroups:
- tekton.dev
resources:
+ - stepactions
- tasks
- taskruns
- pipelines
diff --git a/overlays/patches/read-write/clusterrole-tenant-patch.yaml b/overlays/patches/read-write/clusterrole-tenant-patch.yaml
index 9cc35435c..5707dbef3 100644
--- a/overlays/patches/read-write/clusterrole-tenant-patch.yaml
+++ b/overlays/patches/read-write/clusterrole-tenant-patch.yaml
@@ -1,4 +1,4 @@
-# Copyright 2020-2023 The Tekton Authors
+# Copyright 2020-2024 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
apiGroups:
- tekton.dev
resources:
+ - stepactions
- tasks
- taskruns
- pipelines
diff --git a/packages/e2e/cypress/fixtures/kinds.json b/packages/e2e/cypress/fixtures/kinds.json
index d4207a1aa..4c002ec70 100644
--- a/packages/e2e/cypress/fixtures/kinds.json
+++ b/packages/e2e/cypress/fixtures/kinds.json
@@ -5,6 +5,7 @@
{ "label": "ClusterTasks", "path": "/clustertasks" },
{ "label": "TaskRuns", "path": "/taskruns" },
{ "label": "CustomRuns", "path": "/customruns" },
+ { "label": "StepActions", "path": "/stepactions" },
{ "label": "EventListeners", "path": "/eventlisteners" },
{ "label": "Triggers", "path": "/triggers" },
{ "label": "TriggerBindings", "path": "/triggerbindings" },
diff --git a/packages/utils/src/utils/router.js b/packages/utils/src/utils/router.js
index cafde225c..416827b3f 100644
--- a/packages/utils/src/utils/router.js
+++ b/packages/utils/src/utils/router.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2023 The Tekton Authors
+Copyright 2019-2024 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -146,6 +146,14 @@ export const paths = {
settings() {
return '/settings';
},
+ stepActions: {
+ all() {
+ return '/stepactions';
+ },
+ byNamespace() {
+ return byNamespace({ path: '/stepactions' });
+ }
+ },
taskRuns: {
all() {
return '/taskruns';
diff --git a/src/api/index.js b/src/api/index.js
index 3275c8303..fc52bc2b1 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -43,6 +43,7 @@ export * from './interceptors';
export * from './pipelineRuns';
export * from './pipelines';
export * from './serviceAccounts';
+export * from './stepActions';
export * from './taskRuns';
export * from './tasks';
export * from './triggerBindings';
diff --git a/src/api/stepActions.js b/src/api/stepActions.js
new file mode 100644
index 000000000..22f831a92
--- /dev/null
+++ b/src/api/stepActions.js
@@ -0,0 +1,72 @@
+/*
+Copyright 2024 The Tekton Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { deleteRequest, get } from './comms';
+import {
+ getQueryParams,
+ getTektonAPI,
+ useCollection,
+ useResource
+} from './utils';
+
+function getStepActionsAPI({ filters, isWebSocket, name, namespace }) {
+ return getTektonAPI(
+ 'stepactions',
+ { isWebSocket, namespace, version: 'v1alpha1' },
+ getQueryParams({ filters, name })
+ );
+}
+
+export function getStepActions({ filters = [], namespace } = {}) {
+ const uri = getStepActionsAPI({ filters, namespace });
+ return get(uri);
+}
+
+export function getStepAction({ name, namespace }) {
+ const uri = getTektonAPI('stepactions', {
+ name,
+ namespace,
+ version: 'v1alpha1'
+ });
+ return get(uri);
+}
+
+export function deleteStepAction({ name, namespace }) {
+ const uri = getTektonAPI('stepactions', {
+ name,
+ namespace,
+ version: 'v1alpha1'
+ });
+ return deleteRequest(uri);
+}
+
+export function useStepActions(params) {
+ const webSocketURL = getStepActionsAPI({ ...params, isWebSocket: true });
+ return useCollection({
+ api: getStepActions,
+ kind: 'StepAction',
+ params,
+ webSocketURL
+ });
+}
+
+export function useStepAction(params, queryConfig) {
+ const webSocketURL = getStepActionsAPI({ ...params, isWebSocket: true });
+ return useResource({
+ api: getStepAction,
+ kind: 'StepAction',
+ params,
+ queryConfig,
+ webSocketURL
+ });
+}
diff --git a/src/api/stepActions.test.js b/src/api/stepActions.test.js
new file mode 100644
index 000000000..6942a0f46
--- /dev/null
+++ b/src/api/stepActions.test.js
@@ -0,0 +1,87 @@
+/*
+Copyright 2024 The Tekton Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { http, HttpResponse } from 'msw';
+
+import * as API from './stepActions';
+import * as utils from './utils';
+import { server } from '../../config_frontend/msw';
+
+it('getStepActions', () => {
+ const data = {
+ items: 'stepactions'
+ };
+ server.use(http.get(/\/stepactions\//, () => HttpResponse.json(data)));
+ return API.getStepActions().then(stepActions => {
+ expect(stepActions).toEqual(data);
+ });
+});
+
+it('getStepAction', () => {
+ const name = 'foo';
+ const data = { fake: 'stepAction' };
+ server.use(http.get(new RegExp(`/${name}$`), () => HttpResponse.json(data)));
+ return API.getStepAction({ name }).then(stepAction => {
+ expect(stepAction).toEqual(data);
+ });
+});
+
+it('deleteStepAction', () => {
+ const name = 'foo';
+ const data = { fake: 'stepAction' };
+ server.use(
+ http.delete(new RegExp(`/${name}$`), () => HttpResponse.json(data))
+ );
+ return API.deleteStepAction({ name }).then(stepAction => {
+ expect(stepAction).toEqual(data);
+ });
+});
+
+it('useStepActions', () => {
+ const query = { fake: 'query' };
+ const params = { fake: 'params' };
+ vi.spyOn(utils, 'useCollection').mockImplementation(() => query);
+ expect(API.useStepActions(params)).toEqual(query);
+ expect(utils.useCollection).toHaveBeenCalledWith(
+ expect.objectContaining({
+ api: API.getStepActions,
+ kind: 'StepAction',
+ params
+ })
+ );
+});
+
+it('useStepAction', () => {
+ const query = { fake: 'query' };
+ const params = { fake: 'params' };
+ vi.spyOn(utils, 'useResource').mockImplementation(() => query);
+ expect(API.useStepAction(params)).toEqual(query);
+ expect(utils.useResource).toHaveBeenCalledWith(
+ expect.objectContaining({
+ api: API.getStepAction,
+ kind: 'StepAction',
+ params
+ })
+ );
+
+ const queryConfig = { fake: 'queryConfig' };
+ API.useStepAction(params, queryConfig);
+ expect(utils.useResource).toHaveBeenCalledWith(
+ expect.objectContaining({
+ api: API.getStepAction,
+ kind: 'StepAction',
+ params,
+ queryConfig
+ })
+ );
+});
diff --git a/src/containers/App/App.jsx b/src/containers/App/App.jsx
index e7681e33b..c54cf5d3c 100644
--- a/src/containers/App/App.jsx
+++ b/src/containers/App/App.jsx
@@ -65,6 +65,7 @@ import {
ResourceList,
Settings,
SideNav,
+ StepActions,
TaskRun,
TaskRuns,
Tasks,
@@ -293,6 +294,16 @@ export function App({ lang }) {
+
+
+
+
+
+
+
+
+
+
diff --git a/src/containers/CustomResourceDefinition/CustomResourceDefinition.jsx b/src/containers/CustomResourceDefinition/CustomResourceDefinition.jsx
index 42f251e93..5fb939282 100644
--- a/src/containers/CustomResourceDefinition/CustomResourceDefinition.jsx
+++ b/src/containers/CustomResourceDefinition/CustomResourceDefinition.jsx
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2023 The Tekton Authors
+Copyright 2019-2024 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -28,6 +28,7 @@ import {
useCustomResource,
useInterceptor,
usePipeline,
+ useStepAction,
useTask
} from '../../api';
@@ -41,6 +42,8 @@ function useResource({ group, name, namespace, type, version }) {
return useInterceptor({ name, namespace });
case 'pipelines':
return usePipeline({ name, namespace });
+ case 'stepactions':
+ return useStepAction({ name, namespace });
case 'tasks':
return useTask({ name, namespace });
default:
diff --git a/src/containers/SideNav/SideNav.jsx b/src/containers/SideNav/SideNav.jsx
index 8d267588c..83bb41d30 100644
--- a/src/containers/SideNav/SideNav.jsx
+++ b/src/containers/SideNav/SideNav.jsx
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2023 The Tekton Authors
+Copyright 2019-2024 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -124,6 +124,11 @@ function SideNav({ expanded, showKubernetesResources = false }) {
>
CustomRuns
+
+ StepActions
+
{isTriggersInstalled && (
({
+ id: stepAction.metadata.uid,
+ name: (
+
+ {stepAction.metadata.name}
+
+ ),
+ namespace: stepAction.metadata.namespace,
+ createdTime: (
+
+ ),
+ actions: !isReadOnly ? (
+