summaryrefslogtreecommitdiff
path: root/source/features/github-actions-indicators.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'source/features/github-actions-indicators.tsx')
-rw-r--r--source/features/github-actions-indicators.tsx72
1 files changed, 58 insertions, 14 deletions
diff --git a/source/features/github-actions-indicators.tsx b/source/features/github-actions-indicators.tsx
index 93467b03..a73b9df6 100644
--- a/source/features/github-actions-indicators.tsx
+++ b/source/features/github-actions-indicators.tsx
@@ -1,7 +1,7 @@
import cache from 'webext-storage-cache';
import React from 'dom-chef';
import select from 'select-dom';
-import {PlayIcon} from '@primer/octicons-react';
+import {StopIcon, PlayIcon} from '@primer/octicons-react';
import {parseCron} from '@cheap-glitch/mi-cron';
import * as pageDetect from 'github-url-detection';
@@ -10,6 +10,11 @@ import * as api from '../github-helpers/api';
import {cacheByRepo} from '../github-helpers';
import observe from '../helpers/selector-observer';
+type Workflow = {
+ name: string;
+ isEnabled: boolean;
+};
+
type WorkflowDetails = {
schedule?: string;
manuallyDispatchable: boolean;
@@ -25,7 +30,21 @@ function addTooltip(element: HTMLElement, tooltip: string): void {
}
}
-const getWorkflowsDetails = cache.function('workflows', async (): Promise<Record<string, WorkflowDetails> | false> => {
+// There is no way to get a workflow list in the v4 API #6543
+const getWorkflows = async (): Promise<Workflow[]> => {
+ const response = await api.v3('actions/workflows');
+
+ const workflows = response.workflows as any[];
+
+ // The response is not reliable: Some workflow's path is '' and deleted workflow's state is 'active'
+ return workflows
+ .map<Workflow>(workflow => ({
+ name: workflow.path.split('/').pop()!,
+ isEnabled: workflow.state === 'active',
+ }));
+};
+
+const getFilesInWorkflowPath = async (): Promise<Record<string, string>> => {
const {repository: {workflowFiles}} = await api.v4(`
repository() {
workflowFiles: object(expression: "HEAD:.github/workflows") {
@@ -43,16 +62,33 @@ const getWorkflowsDetails = cache.function('workflows', async (): Promise<Record
}
`);
- const workflows = workflowFiles?.entries ?? [];
- if (workflows.length === 0) {
- return false;
+ const workflows: any[] = workflowFiles?.entries ?? [];
+
+ const result: Record<string, string> = {};
+ for (const workflow of workflows) {
+ result[workflow.name] = workflow.object.text;
}
- const details: Record<string, WorkflowDetails> = {};
+ return result;
+};
+
+const getWorkflowsDetails = cache.function('workflows-details', async (): Promise<Record<string, Workflow & WorkflowDetails>> => {
+ const [workflows, workflowFiles] = await Promise.all([getWorkflows(), getFilesInWorkflowPath()]);
+
+ const details: Record<string, Workflow & WorkflowDetails> = {};
+
for (const workflow of workflows) {
- const workflowYaml: string = workflow.object.text;
+ const workflowYaml = workflowFiles[workflow.name];
+
+ if (workflowYaml === undefined) {
+ // Cannot find workflow yaml; workflow removed.
+ continue;
+ }
+
const cron = /schedule[:\s-]+cron[:\s'"]+([^'"\n]+)/m.exec(workflowYaml);
+
details[workflow.name] = {
+ ...workflow,
schedule: cron?.[1],
manuallyDispatchable: workflowYaml.includes('workflow_dispatch:'),
};
@@ -66,24 +102,29 @@ const getWorkflowsDetails = cache.function('workflows', async (): Promise<Record
});
async function addIndicators(workflowListItem: HTMLAnchorElement): Promise<void> {
- // Memoized above
- const workflows = await getWorkflowsDetails();
- if (!workflows) {
- return; // Impossibru, for types only
- }
-
+ // There might be a disabled indicator already
if (select.exists('.octicon-stop', workflowListItem)) {
return;
}
+ // Called in `init`, memoized
+ const workflows = await getWorkflowsDetails();
const workflowName = workflowListItem.href.split('/').pop()!;
const workflow = workflows[workflowName];
if (!workflow) {
return;
}
+ const svgTrailer = <div className="ActionListItem-visual--trailing m-auto d-flex gap-2"/>;
+ workflowListItem.append(svgTrailer);
+
+ if (!workflow.isEnabled) {
+ svgTrailer.append(<StopIcon className="m-auto"/>);
+ addTooltip(workflowListItem, 'This workflow is not enabled');
+ }
+
if (workflow.manuallyDispatchable) {
- workflowListItem.append(<PlayIcon className="ActionListItem-visual--trailing m-auto"/>);
+ svgTrailer.append(<PlayIcon className="m-auto"/>);
addTooltip(workflowListItem, 'This workflow can be triggered manually');
}
@@ -136,4 +177,7 @@ https://github.com/fregante/browser-extension-template/actions
Manual + scheduled:
https://github.com/fregante/eslint-formatters/actions
+Manually disabled:
+https://github.com/134130/134130/actions
+
*/