Skip to content

Commit

Permalink
Showing 14 changed files with 33,837 additions and 33,253 deletions.
11 changes: 11 additions & 0 deletions api/projects/schedules.go
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions api/router.go
Original file line number Diff line number Diff line change
@@ -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")

5 changes: 5 additions & 0 deletions db/Schedule.go
Original file line number Diff line number Diff line change
@@ -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"`
}
1 change: 1 addition & 0 deletions db/Store.go
Original file line number Diff line number Diff line change
@@ -197,6 +197,7 @@ type Store interface {
DeleteTemplate(projectID int, templateID int) error

GetSchedules() ([]Schedule, error)
GetProjectSchedules(projectID int) ([]ScheduleWithTpl, error)
GetTemplateSchedules(projectID int, templateID int) ([]Schedule, error)
CreateSchedule(schedule Schedule) (Schedule, error)
UpdateSchedule(schedule Schedule) error
14 changes: 11 additions & 3 deletions db/bolt/schedule.go
Original file line number Diff line number Diff line change
@@ -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,15 +26,23 @@ 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{}, func(referringObj interface{}) bool {
s := referringObj.(db.ScheduleWithTpl)
return s.RepositoryID == nil
}, &schedules)
return
}

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
}
9 changes: 9 additions & 0 deletions db/sql/schedule.go
Original file line number Diff line number Diff line change
@@ -72,6 +72,15 @@ func (d *SqlDb) GetSchedules() (schedules []db.Schedule, err error) {
return
}

func (d *SqlDb) GetProjectSchedules(projectID int) (schedules []db.ScheduleWithTpl, err error) {
_, err = d.selectAll(&schedules,
"SELECT ps.*, pt.name as tpl_name FROM project__schedule ps "+
"JOIN project__template pt ON pt.id = ps.template_id "+
"WHERE ps.repository_id IS NULL AND ps.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=?",
66,289 changes: 33,161 additions & 33,128 deletions web/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
"ansi-to-html": "^0.7.2",
"axios": "^0.28.0",
"core-js": "^3.23.2",
"cron-parser": "^4.9.0",
"moment": "^2.29.4",
"vue": "^2.6.14",
"vue-codemirror": "^4.0.6",
16 changes: 15 additions & 1 deletion web/src/App.vue
Original file line number Diff line number Diff line change
@@ -216,6 +216,20 @@
</v-list-item-content>
</v-list-item>

<v-list-item
v-if="project.type === ''"
key="schedule"
:to="`/project/${projectId}/schedule`"
>
<v-list-item-icon>
<v-icon>mdi-clock-outline</v-icon>
</v-list-item-icon>

<v-list-item-content>
<v-list-item-title>{{ $t('Schedule') }}</v-list-item-title>
</v-list-item-content>
</v-list-item>

<v-list-item
v-if="project.type === ''"
key="inventory"
@@ -547,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;
}
432 changes: 432 additions & 0 deletions web/src/components/ScheduleForm.vue

Large diffs are not rendered by default.

86 changes: 0 additions & 86 deletions web/src/components/SubscriptionForm.vue

This file was deleted.

78 changes: 44 additions & 34 deletions web/src/components/TemplateForm.vue
Original file line number Diff line number Diff line change
@@ -238,34 +238,16 @@
dense
></v-select>

<v-row>
<v-col cols="5" class="pr-1">
<v-text-field
style="font-size: 14px"
v-model="cronFormat"
:label="$t('cron')"
:disabled="formSaving"
placeholder="* * * * *"
v-if="schedules == null || schedules.length <= 1"
outlined
dense
hide-details
></v-text-field>
</v-col>
<v-checkbox
class="mt-0"
:label="$t('iWantToRunATaskByTheCronOnlyForForNewCommitsOfSome')"
v-model="cronRepositoryIdVisible"
/>

<v-row v-if="cronRepositoryIdVisible" class="mb-2">
<v-col cols="7">
<a
v-if="!cronRepositoryIdVisible && cronRepositoryId == null"
@click="cronRepositoryIdVisible = true"
class="text-caption d-block"
style="line-height: 1.1;"
>
{{ $t('iWantToRunATaskByTheCronOnlyForForNewCommitsOfSome') }}
</a>

<v-select
style="font-size: 14px"
v-if="cronRepositoryIdVisible || cronRepositoryId != null"
v-model="cronRepositoryId"
:label="$t('repository2')"
:placeholder="$t('cronChecksNewCommitBeforeRun')"
@@ -278,16 +260,24 @@
dense
hide-details
></v-select>
</v-col>

<v-col cols="5">
<v-select
v-model="cronFormat"
:label="$t('Interval')"
:placeholder="$t('New commit check interval')"
item-value="cron"
item-text="title"
:items="cronFormats"
:disabled="formSaving"
outlined
dense
hide-details
/>
</v-col>
</v-row>

<small class="mt-1 mb-4 d-block">
{{ $t('readThe') }}
<a target="_blank" href="https://pkg.go.dev/github.com/robfig/cron/v3#hdr-CRON_Expression_Format">{{ $t('docs') }}</a>
{{ $t('toLearnMoreAboutCron') }}
</small>

<v-checkbox
class="mt-0"
:label="$t('suppressSuccessAlerts')"
@@ -356,6 +346,22 @@ export default {
data() {
return {
cronFormats: [{
cron: '* * * * *',
title: '1 minute',
}, {
cron: '*/5 * * * *',
title: '5 minutes',
}, {
cron: '*/10 * * * *',
title: '10 minutes',
}, {
cron: '@hourly',
title: '1 hour',
}, {
cron: '@daily',
title: '24 hours',
}],
itemTypeIndex: 0,
TEMPLATE_TYPE_ICONS,
TEMPLATE_TYPE_TITLES,
@@ -517,9 +523,13 @@ export default {
responseType: 'json',
})).data;
if (this.schedules.length === 1) {
this.cronFormat = this.schedules[0].cron_format;
this.cronRepositoryId = this.schedules[0].repository_id;
if (this.schedules.length > 0) {
const schedule = this.schedules.find((s) => s.repository_id != null);
if (schedule != null) {
this.cronFormat = schedule.cron_format;
this.cronRepositoryId = schedule.repository_id;
this.cronRepositoryIdVisible = this.cronRepositoryId != null;
}
}
this.itemTypeIndex = Object.keys(TEMPLATE_TYPE_ICONS).indexOf(this.item.type);
@@ -566,7 +576,7 @@ export default {
}
} else if (this.schedules.length > 1) {
// do nothing
} else if (this.cronFormat == null || this.cronFormat === '') {
} else if (this.cronFormat == null || this.cronFormat === '' || !this.cronRepositoryIdVisible) {
// drop schedule
await axios({
method: 'delete',
6 changes: 5 additions & 1 deletion web/src/router/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import Schedule from '../views/project/Schedule.vue';
import History from '../views/project/History.vue';
import Activity from '../views/project/Activity.vue';
import Settings from '../views/project/Settings.vue';
@@ -14,7 +15,6 @@ import Users from '../views/Users.vue';
import Auth from '../views/Auth.vue';
import New from '../views/project/New.vue';
import Integrations from '../views/project/Integrations.vue';

import IntegrationExtractor from '../views/project/IntegrationExtractor.vue';

Vue.use(VueRouter);
@@ -36,6 +36,10 @@ const routes = [
path: '/project/:projectId/activity',
component: Activity,
},
{
path: '/project/:projectId/schedule',
component: Schedule,
},
{
path: '/project/:projectId/settings',
component: Settings,
141 changes: 141 additions & 0 deletions web/src/views/project/Schedule.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<div v-if="items != null">
<EditDialog
v-model="editDialog"
:save-button-text="$t('save')"
:title="$t('Edit Schedule')"
:max-width="500"
@save="loadItems"
>
<template v-slot:form="{ onSave, onError, needSave, needReset }">
<ScheduleForm
:project-id="projectId"
:item-id="itemId"
@save="onSave"
@error="onError"
:need-save="needSave"
:need-reset="needReset"
/>
</template>
</EditDialog>

<ObjectRefsDialog
object-title="schedule"
:object-refs="itemRefs"
:project-id="projectId"
v-model="itemRefsDialog"
/>

<YesNoDialog
:title="$t('Delete Schedule')"
:text="$t('askDeleteEnv')"
v-model="deleteItemDialog"
@yes="deleteItem(itemId)"
/>

<v-toolbar flat >
<v-app-bar-nav-icon @click="showDrawer()"></v-app-bar-nav-icon>
<v-toolbar-title>{{ $t('Schedule') }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn
color="primary"
@click="editItem('new')"
v-if="can(USER_PERMISSIONS.manageProjectResources)"
>{{ $t('New Schedule') }}
</v-btn>
</v-toolbar>

<v-data-table
:headers="headers"
:items="items"
hide-default-footer
class="mt-4"
:items-per-page="Number.MAX_VALUE"
>
<template v-slot:item.tpl_name="{ item }">
<div class="d-flex">
<router-link :to="
'/project/' + item.project_id +
'/templates/' + item.template_id"
>{{ item.tpl_name }}
</router-link>
</div>
</template>

<template v-slot:item.actions="{ item }">
<div style="white-space: nowrap">
<v-btn
icon
class="mr-1"
@click="askDeleteItem(item.id)"
>
<v-icon>mdi-delete</v-icon>
</v-btn>

<v-btn
icon
class="mr-1"
@click="editItem(item.id)"
>
<v-icon>mdi-pencil</v-icon>
</v-btn>
</div>
</template>

<template v-slot:expanded-item="{ headers, item }">
<td
:colspan="headers.length"
v-if="openedItems.some((template) => template.id === item.id)"
>
<TaskList
style="border: 1px solid lightgray; border-radius: 6px; margin: 10px 0;"
:template="item"
:limit="5"
:hide-footer="true"
/>
</td>
</template>
</v-data-table>
</div>

</template>
<script>
import ItemListPageBase from '@/components/ItemListPageBase';
import ScheduleForm from '@/components/ScheduleForm.vue';
import TaskList from '@/components/TaskList.vue';
export default {
components: { TaskList, ScheduleForm },
mixins: [ItemListPageBase],
data() {
return {
openedItems: [],
};
},
methods: {
getHeaders() {
return [{
text: this.$i18n.t('Cron'),
value: 'cron_format',
}, {
text: this.$i18n.t('Template'),
value: 'tpl_name',
width: '100%',
}, {
text: this.$i18n.t('actions'),
value: 'actions',
sortable: false,
}];
},
getItemsUrl() {
return `/api/project/${this.projectId}/schedules`;
},
getSingleItemUrl() {
return `/api/project/${this.projectId}/schedules/${this.itemId}`;
},
getEventName() {
return 'i-schedule';
},
},
};
</script>

0 comments on commit 6b945e8

Please sign in to comment.