From 92ac21132b6d7299efffa65797f0641ff933c1ac Mon Sep 17 00:00:00 2001 From: fiftin Date: Sat, 22 Jun 2024 22:09:10 +0500 Subject: [PATCH 1/7] feat(web): add schedule page --- web/src/App.vue | 14 ++++ web/src/router/index.js | 6 +- web/src/views/project/Schedule.vue | 109 +++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 web/src/views/project/Schedule.vue diff --git a/web/src/App.vue b/web/src/App.vue index 467c3067..67f0b742 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -216,6 +216,20 @@ + + + mdi-clock-outline + + + + {{ $t('Schedule') }} + + + +
+ + + + + + + + + + + {{ $t('environment2') }} + + {{ $t('newEnvironment') }} + + + + + + +
+ + + From 33a9b0d7305f5d000d7ea7fcda5c6834a8b7d548 Mon Sep 17 00:00:00 2001 From: fiftin Date: Sat, 22 Jun 2024 22:32:53 +0500 Subject: [PATCH 2/7] feat(be): add project schedules function --- db/Store.go | 1 + db/sql/schedule.go | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/db/Store.go b/db/Store.go index e794136d..2bd5f7bc 100644 --- a/db/Store.go +++ b/db/Store.go @@ -197,6 +197,7 @@ type Store interface { DeleteTemplate(projectID int, templateID int) error GetSchedules() ([]Schedule, error) + GetProjectSchedules(projectID int) ([]Schedule, error) GetTemplateSchedules(projectID int, templateID int) ([]Schedule, error) CreateSchedule(schedule Schedule) (Schedule, error) UpdateSchedule(schedule Schedule) error diff --git a/db/sql/schedule.go b/db/sql/schedule.go index 4f1abe35..fbddde26 100644 --- a/db/sql/schedule.go +++ b/db/sql/schedule.go @@ -72,6 +72,13 @@ func (d *SqlDb) GetSchedules() (schedules []db.Schedule, err error) { return } +func (d *SqlDb) GetProjectSchedules(projectID int) (schedules []db.Schedule, err error) { + _, err = d.selectAll(&schedules, + "select * from project__schedule where project_id=?", + projectID) + return +} + func (d *SqlDb) GetTemplateSchedules(projectID int, templateID int) (schedules []db.Schedule, err error) { _, err = d.selectAll(&schedules, "select * from project__schedule where project_id=? and template_id=?", From 477c0dfe7d0af88ce57a412374e207c5a14d1c0f Mon Sep 17 00:00:00 2001 From: fiftin Date: Sun, 23 Jun 2024 22:24:22 +0500 Subject: [PATCH 3/7] fix(web): schedule form --- api/projects/schedules.go | 11 ++++ api/router.go | 1 + db/Schedule.go | 5 ++ db/Store.go | 2 +- db/bolt/schedule.go | 11 ++-- db/sql/schedule.go | 6 ++- web/src/App.vue | 2 +- web/src/components/ScheduleForm.vue | 80 +++++++++++++++++++++++++++++ web/src/views/project/Schedule.vue | 33 ++++++------ 9 files changed, 129 insertions(+), 22 deletions(-) create mode 100644 web/src/components/ScheduleForm.vue diff --git a/api/projects/schedules.go b/api/projects/schedules.go index 7ecf68c7..6cbde754 100644 --- a/api/projects/schedules.go +++ b/api/projects/schedules.go @@ -42,6 +42,17 @@ func GetSchedule(w http.ResponseWriter, r *http.Request) { helpers.WriteJSON(w, http.StatusOK, schedule) } +func GetProjectSchedules(w http.ResponseWriter, r *http.Request) { + project := context.Get(r, "project").(db.Project) + + tplSchedules, err := helpers.Store(r).GetProjectSchedules(project.ID) + if err != nil { + helpers.WriteError(w, err) + return + } + + helpers.WriteJSON(w, http.StatusOK, tplSchedules) +} func GetTemplateSchedules(w http.ResponseWriter, r *http.Request) { project := context.Get(r, "project").(db.Project) templateID, err := helpers.GetIntParam("template_id", w, r) diff --git a/api/router.go b/api/router.go index 79b3b70d..9d58af70 100644 --- a/api/router.go +++ b/api/router.go @@ -178,6 +178,7 @@ func Route() *mux.Router { projectUserAPI.Path("/templates").HandlerFunc(projects.GetTemplates).Methods("GET", "HEAD") projectUserAPI.Path("/templates").HandlerFunc(projects.AddTemplate).Methods("POST") + projectUserAPI.Path("/schedules").HandlerFunc(projects.GetProjectSchedules).Methods("GET", "HEAD") projectUserAPI.Path("/schedules").HandlerFunc(projects.AddSchedule).Methods("POST") projectUserAPI.Path("/schedules/validate").HandlerFunc(projects.ValidateScheduleCronFormat).Methods("POST") diff --git a/db/Schedule.go b/db/Schedule.go index 9f53e34a..30194a7b 100644 --- a/db/Schedule.go +++ b/db/Schedule.go @@ -8,3 +8,8 @@ type Schedule struct { RepositoryID *int `db:"repository_id" json:"repository_id"` LastCommitHash *string `db:"last_commit_hash" json:"-"` } + +type ScheduleWithTpl struct { + Schedule + TemplateName string `db:"tpl_name" json:"tpl_name"` +} diff --git a/db/Store.go b/db/Store.go index 2bd5f7bc..77e8df82 100644 --- a/db/Store.go +++ b/db/Store.go @@ -197,7 +197,7 @@ type Store interface { DeleteTemplate(projectID int, templateID int) error GetSchedules() ([]Schedule, error) - GetProjectSchedules(projectID int) ([]Schedule, error) + GetProjectSchedules(projectID int) ([]ScheduleWithTpl, error) GetTemplateSchedules(projectID int, templateID int) ([]Schedule, error) CreateSchedule(schedule Schedule) (Schedule, error) UpdateSchedule(schedule Schedule) error diff --git a/db/bolt/schedule.go b/db/bolt/schedule.go index ba928e9f..a9083091 100644 --- a/db/bolt/schedule.go +++ b/db/bolt/schedule.go @@ -16,7 +16,7 @@ func (d *BoltDb) GetSchedules() (schedules []db.Schedule, err error) { for _, proj := range allProjects { var projSchedules []db.Schedule - projSchedules, err = d.GetProjectSchedules(proj.ID) + projSchedules, err = d.getProjectSchedules(proj.ID) if err != nil { return } @@ -26,7 +26,12 @@ func (d *BoltDb) GetSchedules() (schedules []db.Schedule, err error) { return } -func (d *BoltDb) GetProjectSchedules(projectID int) (schedules []db.Schedule, err error) { +func (d *BoltDb) getProjectSchedules(projectID int) (schedules []db.Schedule, err error) { + err = d.getObjects(projectID, db.ScheduleProps, db.RetrieveQueryParams{}, nil, &schedules) + return +} + +func (d *BoltDb) GetProjectSchedules(projectID int) (schedules []db.ScheduleWithTpl, err error) { err = d.getObjects(projectID, db.ScheduleProps, db.RetrieveQueryParams{}, nil, &schedules) return } @@ -34,7 +39,7 @@ func (d *BoltDb) GetProjectSchedules(projectID int) (schedules []db.Schedule, er func (d *BoltDb) GetTemplateSchedules(projectID int, templateID int) (schedules []db.Schedule, err error) { schedules = make([]db.Schedule, 0) - projSchedules, err := d.GetProjectSchedules(projectID) + projSchedules, err := d.getProjectSchedules(projectID) if err != nil { return } diff --git a/db/sql/schedule.go b/db/sql/schedule.go index fbddde26..d4702269 100644 --- a/db/sql/schedule.go +++ b/db/sql/schedule.go @@ -72,9 +72,11 @@ func (d *SqlDb) GetSchedules() (schedules []db.Schedule, err error) { return } -func (d *SqlDb) GetProjectSchedules(projectID int) (schedules []db.Schedule, err error) { +func (d *SqlDb) GetProjectSchedules(projectID int) (schedules []db.ScheduleWithTpl, err error) { _, err = d.selectAll(&schedules, - "select * from project__schedule where project_id=?", + "SELECT ps.*, pt.name as tpl_name FROM project__schedule ps "+ + "JOIN project__template pt ON pt.id = ps.template_id "+ + "WHERE ps.project_id=?", projectID) return } diff --git a/web/src/App.vue b/web/src/App.vue index 67f0b742..2c3bc8da 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -561,7 +561,7 @@ .v-data-table-header { } -.theme--light.v-data-table > .v-data-table__wrapper > table > thead > tr:last-child > th { +.v-data-table > .v-data-table__wrapper > table > thead > tr:last-child > th { text-transform: uppercase; white-space: nowrap; } diff --git a/web/src/components/ScheduleForm.vue b/web/src/components/ScheduleForm.vue new file mode 100644 index 00000000..c90562e6 --- /dev/null +++ b/web/src/components/ScheduleForm.vue @@ -0,0 +1,80 @@ + + + diff --git a/web/src/views/project/Schedule.vue b/web/src/views/project/Schedule.vue index db78a585..0862cea9 100644 --- a/web/src/views/project/Schedule.vue +++ b/web/src/views/project/Schedule.vue @@ -3,12 +3,12 @@ From 8418f085837ccf289ad3543d2f6a4f796d60a69f Mon Sep 17 00:00:00 2001 From: fiftin Date: Mon, 24 Jun 2024 17:32:06 +0500 Subject: [PATCH 6/7] feat(schedule): display next run time --- web/src/components/ScheduleForm.vue | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/web/src/components/ScheduleForm.vue b/web/src/components/ScheduleForm.vue index da05f5c8..02a12a59 100644 --- a/web/src/components/ScheduleForm.vue +++ b/web/src/components/ScheduleForm.vue @@ -39,10 +39,13 @@ :rules="[v => !!v || $t('Cron required')]" required :disabled="formSaving" - class="mb-4" @input="refreshCheckboxes()" > +
+ Next run {{ nextRunTime | formatDate }}. +
+
Date: Mon, 24 Jun 2024 18:16:21 +0500 Subject: [PATCH 7/7] fix(schedule): nect run time for new schedule --- web/src/components/ScheduleForm.vue | 45 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/web/src/components/ScheduleForm.vue b/web/src/components/ScheduleForm.vue index 02a12a59..e0b78756 100644 --- a/web/src/components/ScheduleForm.vue +++ b/web/src/components/ScheduleForm.vue @@ -43,7 +43,7 @@ >
- Next run {{ nextRunTime | formatDate }}. + Next run {{ nextRunTime() | formatDate }}.
@@ -286,12 +286,6 @@ export default { }; }, - computed: { - nextRunTime() { - return parser.parseExpression(this.item.cron_format).next(); - }, - }, - async created() { this.templates = (await axios({ method: 'get', @@ -302,51 +296,56 @@ export default { methods: { + nextRunTime() { + return parser.parseExpression(this.item.cron_format).next(); + }, + refreshCheckboxes() { const fields = JSON.parse( JSON.stringify(parser.parseExpression(this.item.cron_format).fields), ); - if (this.isMinutely(this.item.cron_format)) { + if (this.isHourly(this.item.cron_format)) { this.minutes = fields.minute; + this.timing = 'hourly'; } else { this.minutes = []; } - if (this.isHourly(this.item.cron_format)) { + if (this.isDaily(this.item.cron_format)) { this.hours = fields.hour; - this.timing = 'hourly'; + this.timing = 'daily'; } else { this.hours = []; } - if (this.isDaily(this.item.cron_format)) { - this.timing = 'daily'; - this.days = fields.dayOfMonth; - } else { - this.days = []; - } - if (this.isWeekly(this.item.cron_format)) { - this.timing = 'weekly'; this.weekdays = fields.dayOfWeek; + this.timing = 'weekly'; } else { + this.months = []; this.weekdays = []; } - if (this.timing !== 'weekly' && this.isMinutely(this.item.cron_format)) { + if (this.isMonthly(this.item.cron_format)) { + this.days = fields.dayOfMonth; this.timing = 'monthly'; } else { this.months = []; + this.weekdays = []; } if (this.isYearly(this.item.cron_format)) { - this.timing = 'yearly'; this.months = fields.month; + this.timing = 'yearly'; } }, afterLoadData() { + if (this.isNew) { + this.item.cron_format = '* * * * *'; + } + this.refreshCheckboxes(); }, @@ -358,15 +357,15 @@ export default { return /^\S+\s\S+\s\S+\s[^*]\S*\s\S+$/.test(s); }, - isDaily(s) { + isMonthly(s) { return /^\S+\s\S+\s[^*]\S*\s\S+\s\S+$/.test(s); }, - isHourly(s) { + isDaily(s) { return /^\S+\s[^*]\S*\s\S+\s\S+\s\S+$/.test(s); }, - isMinutely(s) { + isHourly(s) { return /^[^*]\S*\s\S+\s\S+\s\S+\s\S+$/.test(s); },