From fcd6948539b6e3a047d1fcf8a30ca0a2be692792 Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Tue, 7 Jan 2025 23:01:23 +0700 Subject: [PATCH 01/28] feat(runs_list): add button delete workflow run --- templates/repo/actions/runs_list.tmpl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index fa1adb3e3b..0ccda8b094 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -35,9 +35,32 @@
{{svg "octicon-calendar" 16}}{{DateUtils.TimeSince .Updated}}
{{svg "octicon-stopwatch" 16}}{{.Duration}}
+ {{ if and (ne .Status 6) (ne .Status 5) }} +
+ +
+ {{ end }}
{{end}} + + {{template "base/paginate" .}} From 862237cd05488e22147cacd4a3dda8ad89c73b9b Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Tue, 7 Jan 2025 23:33:48 +0700 Subject: [PATCH 02/28] fix: lint --- templates/repo/actions/runs_list.tmpl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index 0ccda8b094..29417c2c68 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -35,18 +35,19 @@
{{svg "octicon-calendar" 16}}{{DateUtils.TimeSince .Updated}}
{{svg "octicon-stopwatch" 16}}{{.Duration}}
- {{ if and (ne .Status 6) (ne .Status 5) }} + {{if and (ne .Status 6) (ne .Status 5)}}
- {{ end }} + {{end}}
From 5358fc50547679f1cd36de23771cc06f317bcbb0 Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Wed, 8 Jan 2025 01:14:49 +0700 Subject: [PATCH 03/28] feat(action_model): add query DeleteRunByID --- models/actions/run.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/models/actions/run.go b/models/actions/run.go index a224a910ab..e19cb7ee95 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -435,3 +435,10 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error { } type ActionRunIndex db.ResourceIndex + +// DeleteRunByID delete action_run. +func DeleteRunByID(ctx context.Context, id int64) error { + var run ActionRun + _, err := db.GetEngine(ctx).Where("id=?", id).Delete(&run) + return err +} From c8dbc29c9a3574f59b8d7b87bc97ab183d7573b5 Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Wed, 8 Jan 2025 01:16:00 +0700 Subject: [PATCH 04/28] feat(web): add path DELETE /username/reponame/actions/runs/{id} --- routers/web/repo/actions/actions.go | 29 +++++++++++++++++++++++++++++ routers/web/web.go | 2 ++ 2 files changed, 31 insertions(+) diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index 539c4b6ed0..97c3075165 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -6,8 +6,10 @@ package actions import ( "bytes" stdCtx "context" + "fmt" "net/http" "slices" + "strconv" "strings" actions_model "code.gitea.io/gitea/models/actions" @@ -424,3 +426,30 @@ func decodeNode(node yaml.Node, out any) bool { } return true } + +func DeleteRun(ctx *context.Context) { + actionRunIDStr := ctx.PathParam("id") + if len(actionRunIDStr) < 1 { + ctx.ServerError("missing action_run.id for delete action run", nil) + return + } + actionRunID, err := strconv.ParseInt(actionRunIDStr, 10, 64) + if err != nil { + ctx.ServerError("failed to casting action_run.id string to int64", err) + return + } + + actionRun, err := actions_model.GetRunByID(ctx, actionRunID) + if err != nil { + ctx.ServerError("failed to get action_run", err) + return + } + err = actions_model.DeleteRunByID(ctx, actionRun.ID) + if err != nil { + ctx.ServerError("failed to delete action_run", err) + return + } + ctx.JSON(http.StatusOK, map[string]any{ + "redirect": fmt.Sprintf("%s/actions", ctx.Repo.RepoLink), + }) +} diff --git a/routers/web/web.go b/routers/web/web.go index 32d65865ac..8335d14e7f 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1434,6 +1434,8 @@ func registerRoutes(m *web.Router) { m.Group("/workflows/{workflow_name}", func() { m.Get("/badge.svg", actions.GetWorkflowBadge) }) + + m.Delete("/runs/{id}", reqRepoActionsReader, actions.DeleteRun) }, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoActionsReader, actions.MustEnableActions) // end "/{username}/{reponame}/actions" From 3938aeadd55f009c5b04cf7c4c32903751ee7bd1 Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Wed, 8 Jan 2025 01:16:45 +0700 Subject: [PATCH 05/28] feat(initGlobalDeleteButton): add option http method delete when data-method is delete --- web_src/js/features/common-button.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web_src/js/features/common-button.ts b/web_src/js/features/common-button.ts index acce992b90..2de2eb8616 100644 --- a/web_src/js/features/common-button.ts +++ b/web_src/js/features/common-button.ts @@ -1,4 +1,4 @@ -import {POST} from '../modules/fetch.ts'; +import {DELETE, POST} from '../modules/fetch.ts'; import {addDelegatedEventListener, hideElem, queryElems, showElem, toggleElem} from '../utils/dom.ts'; import {fomanticQuery} from '../modules/fomantic/base.ts'; import {camelize} from 'vue'; @@ -62,7 +62,10 @@ export function initGlobalDeleteButton(): void { } } - const response = await POST(btn.getAttribute('data-url'), {data: postData}); + const method = btn.getAttribute('data-method')?.toUpperCase() || 'POST'; + const response = method === 'DELETE' + ? await DELETE(btn.getAttribute('data-url')) + : await POST(btn.getAttribute('data-url'), {data: postData}); if (response.ok) { const data = await response.json(); window.location.href = data.redirect; From 6c58a023626cfcf7004ff9277927fdc9c20b68e2 Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Wed, 8 Jan 2025 01:41:45 +0700 Subject: [PATCH 06/28] fix: lint --- templates/repo/actions/runs_list.tmpl | 30 ++++++++++----------------- web_src/js/features/common-button.ts | 6 +++--- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index 29417c2c68..26010403df 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -37,17 +37,9 @@
{{svg "octicon-stopwatch" 16}}{{.Duration}}
{{if and (ne .Status 6) (ne .Status 5)}}
- -
- {{end}} + + + {{end}} @@ -55,13 +47,13 @@ {{template "base/paginate" .}} diff --git a/web_src/js/features/common-button.ts b/web_src/js/features/common-button.ts index 2de2eb8616..3df071d617 100644 --- a/web_src/js/features/common-button.ts +++ b/web_src/js/features/common-button.ts @@ -63,9 +63,9 @@ export function initGlobalDeleteButton(): void { } const method = btn.getAttribute('data-method')?.toUpperCase() || 'POST'; - const response = method === 'DELETE' - ? await DELETE(btn.getAttribute('data-url')) - : await POST(btn.getAttribute('data-url'), {data: postData}); + const response = method === 'DELETE' ? + await DELETE(btn.getAttribute('data-url')) : + await POST(btn.getAttribute('data-url'), {data: postData}); if (response.ok) { const data = await response.json(); window.location.href = data.redirect; From 8170c47b07fcc2cf15917c32567892780f8f831f Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Wed, 8 Jan 2025 02:15:50 +0700 Subject: [PATCH 07/28] feat(DeleteRunByID): add delete action_run_job --- models/actions/run.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/models/actions/run.go b/models/actions/run.go index e19cb7ee95..54faa029d8 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -436,9 +436,22 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error { type ActionRunIndex db.ResourceIndex -// DeleteRunByID delete action_run. +// DeleteRunByID delete action_run and action_run_job. func DeleteRunByID(ctx context.Context, id int64) error { - var run ActionRun - _, err := db.GetEngine(ctx).Where("id=?", id).Delete(&run) - return err + ctx, committer, err := db.TxContext(ctx) + if err != nil { + return err + } + defer committer.Close() + _, err = db.GetEngine(ctx).Where("id=?", id).Delete(ActionRun{}) + if err != nil { + return err + } + + _, err = db.GetEngine(ctx).Where("run_id=?", id).Delete(ActionRunJob{}) + if err != nil { + return err + } + + return committer.Commit() } From c4bdf78bda53e23c0125df0191c5692a2ed3ec84 Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Wed, 8 Jan 2025 10:19:19 +0700 Subject: [PATCH 08/28] refactor: change middleware to reqRepoActionsWriter --- routers/web/web.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/web.go b/routers/web/web.go index 8335d14e7f..2bc49efc55 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1435,7 +1435,7 @@ func registerRoutes(m *web.Router) { m.Get("/badge.svg", actions.GetWorkflowBadge) }) - m.Delete("/runs/{id}", reqRepoActionsReader, actions.DeleteRun) + m.Delete("/runs/{id}", reqRepoActionsWriter, actions.DeleteRun) }, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoActionsReader, actions.MustEnableActions) // end "/{username}/{reponame}/actions" From 1e752123e93392866604320c68895546cfd9bca2 Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Wed, 8 Jan 2025 15:25:09 +0700 Subject: [PATCH 09/28] feat(websrc): add repo action for handling delete --- web_src/js/features/repo-action-list.ts | 97 +++++++++++++++++++++++++ web_src/js/index.ts | 2 + 2 files changed, 99 insertions(+) create mode 100644 web_src/js/features/repo-action-list.ts diff --git a/web_src/js/features/repo-action-list.ts b/web_src/js/features/repo-action-list.ts new file mode 100644 index 0000000000..cd9a8b1ccb --- /dev/null +++ b/web_src/js/features/repo-action-list.ts @@ -0,0 +1,97 @@ +import {queryElems, toggleElem} from '../utils/dom.ts'; +import {confirmModal} from './comp/ConfirmModal.ts'; +import {showErrorToast} from '../modules/toast.ts'; +import {POST} from '../modules/fetch.ts'; + +function initRepoActionListCheckboxes() { + const actionListSelectAll = document.querySelector('.action-checkbox-all'); + if (!actionListSelectAll) return; // logged out state + const issueCheckboxes = document.querySelectorAll('.action-checkbox:not([disabled])'); + const actionDelete = document.querySelector('#action-delete'); + const syncIssueSelectionState = () => { + const enabledCheckboxes = Array.from(issueCheckboxes).filter((el) => !el.disabled); + const checkedCheckboxes = enabledCheckboxes.filter((el) => el.checked); + const anyChecked = Boolean(checkedCheckboxes.length); + const allChecked = anyChecked && checkedCheckboxes.length === enabledCheckboxes.length; + + if (allChecked) { + actionListSelectAll.checked = true; + actionListSelectAll.indeterminate = false; + } else if (anyChecked) { + actionListSelectAll.checked = false; + actionListSelectAll.indeterminate = true; + } else { + actionListSelectAll.checked = false; + actionListSelectAll.indeterminate = false; + } + if (actionDelete) { + toggleElem('#action-delete', anyChecked); + } + }; + + for (const el of issueCheckboxes) { + el.addEventListener('change', syncIssueSelectionState); + } + + actionListSelectAll.addEventListener('change', () => { + for (const el of issueCheckboxes) { + if (!el.disabled) { + el.checked = actionListSelectAll.checked; + } + } + syncIssueSelectionState(); + }); + + queryElems(document, '.action-action', (el) => el.addEventListener('click', + async (e: MouseEvent) => { + e.preventDefault(); + + const action = el.getAttribute('data-action'); + const url = el.getAttribute('data-url'); + const actionIDList: number[] = []; + const radix = 10; + for (const el of document.querySelectorAll('.action-checkbox:checked:not([disabled])')) { + const id = el.getAttribute('data-action-id'); + if (id) { + actionIDList.push(parseInt(id, radix)); + } + } + if (actionIDList.length < 1) return; + + // for delete + if (action === 'delete') { + const confirmText = el.getAttribute('data-action-delete-confirm'); + if (!await confirmModal({content: confirmText, confirmButtonColor: 'red'})) { + return; + } + } + + try { + await deleteActions(url, actionIDList); + window.location.reload(); + } catch (err) { + showErrorToast(err.responseJSON?.error ?? err.message); + } + }, + )); +} + +async function deleteActions(url: string, actionIds: number[]) { + try { + const response = await POST(url, { + data: { + actionIds, + }, + }); + if (!response.ok) { + throw new Error('failed to delete actions'); + } + } catch (error) { + console.error(error); + } +} +export function initRepoActionList() { + if (document.querySelector('.page-content.repository.actions')) { + initRepoActionListCheckboxes(); + } +} diff --git a/web_src/js/index.ts b/web_src/js/index.ts index 022be033da..6ed0c375dc 100644 --- a/web_src/js/index.ts +++ b/web_src/js/index.ts @@ -86,6 +86,7 @@ import { initGlobalEnterQuickSubmit, initGlobalFormDirtyLeaveConfirm, } from './features/common-form.ts'; +import {initRepoActionList} from './features/repo-action-list.ts'; initGiteaFomantic(); initDirAuto(); @@ -214,5 +215,6 @@ onDomReady(() => { initColorPickers, initOAuth2SettingsDisableCheckbox, + initRepoActionList, ]); }); From aa8a3d0789c74285185f026e11cbb420aea9f1b5 Mon Sep 17 00:00:00 2001 From: zsbahtiar Date: Wed, 8 Jan 2025 15:35:15 +0700 Subject: [PATCH 10/28] feat(action.list): add checkbox all and button delete --- templates/repo/actions/list.tmpl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/templates/repo/actions/list.tmpl b/templates/repo/actions/list.tmpl index 7d782c0ade..c781d4ee01 100644 --- a/templates/repo/actions/list.tmpl +++ b/templates/repo/actions/list.tmpl @@ -25,7 +25,19 @@
-