From cba1786c9c6869c40fa590a2bd8146b065cb81a7 Mon Sep 17 00:00:00 2001 From: Nishchay Rajput Date: Sat, 23 May 2026 16:55:19 +0530 Subject: [PATCH] added tag retention tasks list subcommand Signed-off-by: Nishchay Rajput --- cmd/harbor/root/tag/retention/cmd.go | 8 +- cmd/harbor/root/tag/retention/tasks.go | 23 ++++ cmd/harbor/root/tag/retention/tasks/cmd.go | 30 +++++ cmd/harbor/root/tag/retention/tasks/list.go | 95 +++++++++++++++ .../harbor-tag-retention-tasks-list.md | 39 ++++++ doc/cli-docs/harbor-tag-retention-tasks.md | 33 +++++ doc/cli-docs/harbor-tag-retention.md | 8 +- .../man1/harbor-tag-retention-tasks-list.1 | 47 +++++++ .../man1/harbor-tag-retention-tasks.1 | 35 ++++++ doc/man-docs/man1/harbor-tag-retention.1 | 9 +- pkg/api/retention_execution_handler.go | 49 ++++++++ pkg/prompt/prompt.go | 23 ++++ pkg/views/retention/executions/view.go | 109 +++++++++++++++++ pkg/views/retention/tasks/view.go | 115 ++++++++++++++++++ 14 files changed, 613 insertions(+), 10 deletions(-) create mode 100644 cmd/harbor/root/tag/retention/tasks.go create mode 100644 cmd/harbor/root/tag/retention/tasks/cmd.go create mode 100644 cmd/harbor/root/tag/retention/tasks/list.go create mode 100644 doc/cli-docs/harbor-tag-retention-tasks-list.md create mode 100644 doc/cli-docs/harbor-tag-retention-tasks.md create mode 100644 doc/man-docs/man1/harbor-tag-retention-tasks-list.1 create mode 100644 doc/man-docs/man1/harbor-tag-retention-tasks.1 create mode 100644 pkg/api/retention_execution_handler.go create mode 100644 pkg/views/retention/executions/view.go create mode 100644 pkg/views/retention/tasks/view.go diff --git a/cmd/harbor/root/tag/retention/cmd.go b/cmd/harbor/root/tag/retention/cmd.go index 9fd7449b0..c72304462 100644 --- a/cmd/harbor/root/tag/retention/cmd.go +++ b/cmd/harbor/root/tag/retention/cmd.go @@ -28,15 +28,17 @@ within a project. Tag retention rules help in managing and controlling the lifec of tags by defining rules for automatic cleanup and retention. A user can only create up to 15 tag retention rules per project.`, - Example: ` harbor tag retention create # Create a new tag retention rule - harbor tag retention list # List all tag retention rules in the project - harbor tag retention delete # Delete a specific tag retention rules`, + Example: ` harbor tag retention create # Create a new tag retention rule + harbor tag retention list # List all tag retention rules in the project + harbor tag retention delete # Delete a specific tag retention rules + harbor tag retention tasks list # List retention execution tasks`, } cmd.AddCommand( CreateRetentionCommand(), ListRetentionRulesCommand(), DeleteRetentionRuleCommand(), + TasksCommand(), ) return cmd } diff --git a/cmd/harbor/root/tag/retention/tasks.go b/cmd/harbor/root/tag/retention/tasks.go new file mode 100644 index 000000000..f6f7ffa8b --- /dev/null +++ b/cmd/harbor/root/tag/retention/tasks.go @@ -0,0 +1,23 @@ +// Copyright Project Harbor 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. +package retention + +import ( + tasksub "github.com/goharbor/harbor-cli/cmd/harbor/root/tag/retention/tasks" + "github.com/spf13/cobra" +) + +func TasksCommand() *cobra.Command { + return tasksub.TasksCommand() +} diff --git a/cmd/harbor/root/tag/retention/tasks/cmd.go b/cmd/harbor/root/tag/retention/tasks/cmd.go new file mode 100644 index 000000000..34f9be70b --- /dev/null +++ b/cmd/harbor/root/tag/retention/tasks/cmd.go @@ -0,0 +1,30 @@ +// Copyright Project Harbor 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. +package retention + +import "github.com/spf13/cobra" + +func TasksCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tasks", + Short: "Manage retention execution tasks", + Long: "List retention execution tasks", + } + + cmd.AddCommand( + ListCommand(), + ) + + return cmd +} diff --git a/cmd/harbor/root/tag/retention/tasks/list.go b/cmd/harbor/root/tag/retention/tasks/list.go new file mode 100644 index 000000000..8cb784a0f --- /dev/null +++ b/cmd/harbor/root/tag/retention/tasks/list.go @@ -0,0 +1,95 @@ +// Copyright Project Harbor 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. +package retention + +import ( + "fmt" + "strconv" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + taskview "github.com/goharbor/harbor-cli/pkg/views/retention/tasks" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func ListCommand() *cobra.Command { + var projectName string + var projectID int + var executionID int64 + + cmd := &cobra.Command{ + Use: "list [PROJECT_NAME]", + Short: "List retention tasks for an execution", + Long: "List repository-level retention tasks for a specific retention execution", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) > 0 { + projectName = args[0] + } + + if projectID != -1 && projectName != "" { + return fmt.Errorf("cannot specify both --project-id and --project-name flags") + } + + if projectID == -1 && projectName == "" { + name, err := prompt.GetProjectNameFromUser() + if err != nil { + return err + } + projectName = name + } + + projectIDStr := projectName + isName := true + if projectID != -1 { + projectIDStr = strconv.Itoa(projectID) + isName = false + } + + retentionID, err := api.GetRetentionId(projectIDStr, isName) + if err != nil { + return fmt.Errorf("failed to resolve retention policy: %w", err) + } + + if executionID == -1 { + executionID = prompt.GetRetentionExecutionIDFromUser(retentionID) + } + if executionID == 0 { + fmt.Println("No retention executions found") + return nil + } + + resp, err := api.ListRetentionTasks(retentionID, executionID) + if err != nil { + return fmt.Errorf("failed to list retention tasks: %w", err) + } + + if viper.GetString("output-format") != "" { + utils.PrintPayloadInJSONFormat(resp.Payload) + return nil + } + + taskview.ListRetentionTasks(resp.Payload) + return nil + }, + } + + cmd.Flags().StringVarP(&projectName, "project-name", "p", "", "Project name") + cmd.Flags().IntVarP(&projectID, "project-id", "i", -1, "Project ID") + cmd.Flags().Int64VarP(&executionID, "execution-id", "e", -1, "Retention execution ID") + + return cmd +} diff --git a/doc/cli-docs/harbor-tag-retention-tasks-list.md b/doc/cli-docs/harbor-tag-retention-tasks-list.md new file mode 100644 index 000000000..884e40dd8 --- /dev/null +++ b/doc/cli-docs/harbor-tag-retention-tasks-list.md @@ -0,0 +1,39 @@ +--- +title: harbor tag retention tasks list +weight: 50 +--- +## harbor tag retention tasks list + +### Description + +##### List retention tasks for an execution + +### Synopsis + +List repository-level retention tasks for a specific retention execution + +```sh +harbor tag retention tasks list [PROJECT_NAME] [flags] +``` + +### Options + +```sh + -e, --execution-id int Retention execution ID (default -1) + -h, --help help for list + -i, --project-id int Project ID (default -1) + -p, --project-name string Project name +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor tag retention tasks](harbor-tag-retention-tasks.md) - Manage retention execution tasks + diff --git a/doc/cli-docs/harbor-tag-retention-tasks.md b/doc/cli-docs/harbor-tag-retention-tasks.md new file mode 100644 index 000000000..9fc332b83 --- /dev/null +++ b/doc/cli-docs/harbor-tag-retention-tasks.md @@ -0,0 +1,33 @@ +--- +title: harbor tag retention tasks +weight: 70 +--- +## harbor tag retention tasks + +### Description + +##### Manage retention execution tasks + +### Synopsis + +List retention execution tasks + +### Options + +```sh + -h, --help help for tasks +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor tag retention](harbor-tag-retention.md) - Manage tag retention rules in the project +* [harbor tag retention tasks list](harbor-tag-retention-tasks-list.md) - List retention tasks for an execution + diff --git a/doc/cli-docs/harbor-tag-retention.md b/doc/cli-docs/harbor-tag-retention.md index ca2158ed9..928579685 100644 --- a/doc/cli-docs/harbor-tag-retention.md +++ b/doc/cli-docs/harbor-tag-retention.md @@ -21,9 +21,10 @@ A user can only create up to 15 tag retention rules per project. ### Examples ```sh - harbor tag retention create # Create a new tag retention rule - harbor tag retention list # List all tag retention rules in the project - harbor tag retention delete # Delete a specific tag retention rules + harbor tag retention create # Create a new tag retention rule + harbor tag retention list # List all tag retention rules in the project + harbor tag retention delete # Delete a specific tag retention rules + harbor tag retention tasks list # List retention execution tasks ``` ### Options @@ -46,4 +47,5 @@ A user can only create up to 15 tag retention rules per project. * [harbor tag retention create](harbor-tag-retention-create.md) - Create a tag retention rule in a project * [harbor tag retention delete](harbor-tag-retention-delete.md) - Delete a tag retention rule for a project * [harbor tag retention list](harbor-tag-retention-list.md) - List tag retention rules of a project +* [harbor tag retention tasks](harbor-tag-retention-tasks.md) - Manage retention execution tasks diff --git a/doc/man-docs/man1/harbor-tag-retention-tasks-list.1 b/doc/man-docs/man1/harbor-tag-retention-tasks-list.1 new file mode 100644 index 000000000..83e06902c --- /dev/null +++ b/doc/man-docs/man1/harbor-tag-retention-tasks-list.1 @@ -0,0 +1,47 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-tag-retention-tasks-list - List retention tasks for an execution + + +.SH SYNOPSIS +\fBharbor tag retention tasks list [PROJECT_NAME] [flags]\fP + + +.SH DESCRIPTION +List repository-level retention tasks for a specific retention execution + + +.SH OPTIONS +\fB-e\fP, \fB--execution-id\fP=-1 + Retention execution ID + +.PP +\fB-h\fP, \fB--help\fP[=false] + help for list + +.PP +\fB-i\fP, \fB--project-id\fP=-1 + Project ID + +.PP +\fB-p\fP, \fB--project-name\fP="" + Project name + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-tag-retention-tasks(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-tag-retention-tasks.1 b/doc/man-docs/man1/harbor-tag-retention-tasks.1 new file mode 100644 index 000000000..94028df60 --- /dev/null +++ b/doc/man-docs/man1/harbor-tag-retention-tasks.1 @@ -0,0 +1,35 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-tag-retention-tasks - Manage retention execution tasks + + +.SH SYNOPSIS +\fBharbor tag retention tasks [flags]\fP + + +.SH DESCRIPTION +List retention execution tasks + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for tasks + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-tag-retention(1)\fP, \fBharbor-tag-retention-tasks-list(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-tag-retention.1 b/doc/man-docs/man1/harbor-tag-retention.1 index 47b2e60a9..9d20b9ddf 100644 --- a/doc/man-docs/man1/harbor-tag-retention.1 +++ b/doc/man-docs/man1/harbor-tag-retention.1 @@ -41,11 +41,12 @@ A user can only create up to 15 tag retention rules per project. .SH EXAMPLE .EX - harbor tag retention create # Create a new tag retention rule - harbor tag retention list # List all tag retention rules in the project - harbor tag retention delete # Delete a specific tag retention rules + harbor tag retention create # Create a new tag retention rule + harbor tag retention list # List all tag retention rules in the project + harbor tag retention delete # Delete a specific tag retention rules + harbor tag retention tasks list # List retention execution tasks .EE .SH SEE ALSO -\fBharbor-tag(1)\fP, \fBharbor-tag-retention-create(1)\fP, \fBharbor-tag-retention-delete(1)\fP, \fBharbor-tag-retention-list(1)\fP \ No newline at end of file +\fBharbor-tag(1)\fP, \fBharbor-tag-retention-create(1)\fP, \fBharbor-tag-retention-delete(1)\fP, \fBharbor-tag-retention-list(1)\fP, \fBharbor-tag-retention-tasks(1)\fP \ No newline at end of file diff --git a/pkg/api/retention_execution_handler.go b/pkg/api/retention_execution_handler.go new file mode 100644 index 000000000..c880c4a77 --- /dev/null +++ b/pkg/api/retention_execution_handler.go @@ -0,0 +1,49 @@ +// Copyright Project Harbor 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. +package api + +import ( + "strconv" + + "github.com/goharbor/go-client/pkg/sdk/v2.0/client/retention" + "github.com/goharbor/harbor-cli/pkg/utils" +) + +func ListRetentionExecutions(retentionID string) (*retention.ListRetentionExecutionsOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + policyID, err := strconv.ParseInt(retentionID, 10, 64) + if err != nil { + return nil, err + } + + return client.Retention.ListRetentionExecutions(ctx, &retention.ListRetentionExecutionsParams{ID: policyID}) +} + +func ListRetentionTasks(retentionID string, executionID int64) (*retention.ListRetentionTasksOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + policyID, err := strconv.ParseInt(retentionID, 10, 64) + if err != nil { + return nil, err + } + + return client.Retention.ListRetentionTasks(ctx, &retention.ListRetentionTasksParams{ID: policyID, Eid: executionID}) +} diff --git a/pkg/prompt/prompt.go b/pkg/prompt/prompt.go index f21932e5f..d25ca8e77 100644 --- a/pkg/prompt/prompt.go +++ b/pkg/prompt/prompt.go @@ -38,6 +38,7 @@ import ( rtasks "github.com/goharbor/harbor-cli/pkg/views/replication/task/select" repoView "github.com/goharbor/harbor-cli/pkg/views/repository/select" + rexecView "github.com/goharbor/harbor-cli/pkg/views/retention/executions" retview "github.com/goharbor/harbor-cli/pkg/views/retention/select" robotView "github.com/goharbor/harbor-cli/pkg/views/robot/select" sview "github.com/goharbor/harbor-cli/pkg/views/scanner/select" @@ -467,3 +468,25 @@ func GetRetentionTagRule(retentionID string) int64 { }() return <-retentionIndex } + +func GetRetentionExecutionIDFromUser(retentionID string) int64 { + executionID := make(chan int64) + length := make(chan int) + + go func() { + response, err := api.ListRetentionExecutions(retentionID) + if err != nil || response == nil { + length <- 0 + return + } + + length <- len(response.Payload) + rexecView.RetentionExecutionList(response.Payload, executionID) + }() + + if <-length == 0 { + return 0 + } + + return <-executionID +} diff --git a/pkg/views/retention/executions/view.go b/pkg/views/retention/executions/view.go new file mode 100644 index 000000000..ab7f63516 --- /dev/null +++ b/pkg/views/retention/executions/view.go @@ -0,0 +1,109 @@ +// Copyright Project Harbor 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. +package executions + +import ( + "fmt" + "os" + + "github.com/charmbracelet/bubbles/list" + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/views/base/selection" + "github.com/goharbor/harbor-cli/pkg/views/base/tablelist" + "golang.org/x/term" +) + +func truncateString(s string, maxLen int) string { + if len(s) > maxLen { + return s[:maxLen-3] + "..." + } + return s +} + +func getTerminalWidth() int { + width, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + return 160 + } + return width +} + +func getAdjustedColumns() []table.Column { + totalWidth := getTerminalWidth() + columnWidths := []int{totalWidth / 12, totalWidth / 12, totalWidth / 12, totalWidth / 10, totalWidth / 8, totalWidth / 8, totalWidth / 8} + return []table.Column{ + {Title: "ID", Width: columnWidths[0]}, + {Title: "Policy", Width: columnWidths[1]}, + {Title: "Dry Run", Width: columnWidths[2]}, + {Title: "Trigger", Width: columnWidths[3]}, + {Title: "Status", Width: columnWidths[4]}, + {Title: "Start Time", Width: columnWidths[5]}, + {Title: "End Time", Width: columnWidths[6]}, + } +} + +func ListRetentionExecutions(executions []*models.RetentionExecution) { + var rows []table.Row + columns := getAdjustedColumns() + + for _, execution := range executions { + rows = append(rows, table.Row{ + truncateString(fmt.Sprintf("%d", execution.ID), columns[0].Width), + truncateString(fmt.Sprintf("%d", execution.PolicyID), columns[1].Width), + truncateString(fmt.Sprintf("%v", execution.DryRun), columns[2].Width), + truncateString(execution.Trigger, columns[3].Width), + truncateString(execution.Status, columns[4].Width), + truncateString(execution.StartTime, columns[5].Width), + truncateString(execution.EndTime, columns[6].Width), + }) + } + + m := tablelist.NewModel(columns, rows, len(rows)) + if _, err := tea.NewProgram(m).Run(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } +} + +func RetentionExecutionList(executions []*models.RetentionExecution, choice chan<- int64) { + itemsList := make([]list.Item, len(executions)) + items := map[string]int64{} + + for i, execution := range executions { + display := fmt.Sprintf("ID: %d | Policy: %d | Status: %s | Trigger: %s | Dry Run: %v | Start: %s | End: %s", + execution.ID, + execution.PolicyID, + execution.Status, + execution.Trigger, + execution.DryRun, + execution.StartTime, + execution.EndTime, + ) + items[display] = execution.ID + itemsList[i] = selection.Item(display) + } + + m := selection.NewModel(itemsList, "a Retention Execution") + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + if err != nil { + fmt.Println("Error running selection UI:", err) + os.Exit(1) + } + + if model, ok := p.(selection.Model); ok { + choice <- items[model.Choice] + } +} diff --git a/pkg/views/retention/tasks/view.go b/pkg/views/retention/tasks/view.go new file mode 100644 index 000000000..8bc761a40 --- /dev/null +++ b/pkg/views/retention/tasks/view.go @@ -0,0 +1,115 @@ +// Copyright Project Harbor 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. +package tasks + +import ( + "fmt" + "os" + + "github.com/charmbracelet/bubbles/list" + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/views/base/selection" + "github.com/goharbor/harbor-cli/pkg/views/base/tablelist" + "golang.org/x/term" +) + +func truncateString(s string, maxLen int) string { + if len(s) > maxLen { + return s[:maxLen-3] + "..." + } + return s +} + +func getTerminalWidth() int { + width, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + return 180 + } + return width +} + +func getAdjustedColumns() []table.Column { + totalWidth := getTerminalWidth() + columnWidths := []int{totalWidth / 15, totalWidth / 10, totalWidth / 7, totalWidth / 10, totalWidth / 10, totalWidth / 10, totalWidth / 10, totalWidth / 10, totalWidth / 10, totalWidth / 10} + return []table.Column{ + {Title: "ID", Width: columnWidths[0]}, + {Title: "Exec ID", Width: columnWidths[1]}, + {Title: "Repository", Width: columnWidths[2]}, + {Title: "Status", Width: columnWidths[3]}, + {Title: "Retained", Width: columnWidths[4]}, + {Title: "Total", Width: columnWidths[5]}, + {Title: "Code", Width: columnWidths[6]}, + {Title: "Revision", Width: columnWidths[7]}, + {Title: "Start Time", Width: columnWidths[8]}, + {Title: "End Time", Width: columnWidths[9]}, + } +} + +func ListRetentionTasks(tasks []*models.RetentionExecutionTask) { + var rows []table.Row + columns := getAdjustedColumns() + + for _, task := range tasks { + rows = append(rows, table.Row{ + truncateString(fmt.Sprintf("%d", task.ID), columns[0].Width), + truncateString(fmt.Sprintf("%d", task.ExecutionID), columns[1].Width), + truncateString(task.Repository, columns[2].Width), + truncateString(task.Status, columns[3].Width), + truncateString(fmt.Sprintf("%d", task.Retained), columns[4].Width), + truncateString(fmt.Sprintf("%d", task.Total), columns[5].Width), + truncateString(fmt.Sprintf("%d", task.StatusCode), columns[6].Width), + truncateString(fmt.Sprintf("%d", task.StatusRevision), columns[7].Width), + truncateString(task.StartTime, columns[8].Width), + truncateString(task.EndTime, columns[9].Width), + }) + } + + m := tablelist.NewModel(columns, rows, len(rows)) + if _, err := tea.NewProgram(m).Run(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } +} + +func RetentionTaskList(tasks []*models.RetentionExecutionTask, choice chan<- int64) { + itemsList := make([]list.Item, len(tasks)) + items := map[string]int64{} + + for i, task := range tasks { + display := fmt.Sprintf("ID: %d | Exec: %d | Repo: %s | Status: %s | Retained: %d | Total: %d | Code: %d", + task.ID, + task.ExecutionID, + task.Repository, + task.Status, + task.Retained, + task.Total, + task.StatusCode, + ) + items[display] = task.ID + itemsList[i] = selection.Item(display) + } + + m := selection.NewModel(itemsList, "a Retention Task") + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + if err != nil { + fmt.Println("Error running selection UI:", err) + os.Exit(1) + } + + if model, ok := p.(selection.Model); ok { + choice <- items[model.Choice] + } +}