diff --git a/server/api/agent.go b/server/api/agent.go
index c798b0f48..c1d3baa52 100644
--- a/server/api/agent.go
+++ b/server/api/agent.go
@@ -73,6 +73,7 @@ func PatchAgent(c *gin.Context) {
return
}
agent.Name = in.Name
+ agent.NoSchedule = in.NoSchedule
err = _store.AgentUpdate(agent)
if err != nil {
@@ -95,8 +96,9 @@ func PostAgent(c *gin.Context) {
user := session.User(c)
agent := &model.Agent{
- Name: in.Name,
- OwnerID: user.ID,
+ Name: in.Name,
+ NoSchedule: in.NoSchedule,
+ OwnerID: user.ID,
Token: base32.StdEncoding.EncodeToString(
securecookie.GenerateRandomKey(32),
),
diff --git a/server/grpc/rpc.go b/server/grpc/rpc.go
index 2405a0c3b..e14c8ced7 100644
--- a/server/grpc/rpc.go
+++ b/server/grpc/rpc.go
@@ -70,6 +70,13 @@ func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Pipeline, er
return nil, err
}
for {
+ agent, err := s.getAgentFromContext(c)
+ if err != nil {
+ return nil, err
+ } else if agent.NoSchedule {
+ return nil, nil
+ }
+
task, err := s.queue.Poll(c, fn)
if err != nil {
return nil, err
@@ -82,6 +89,7 @@ func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Pipeline, er
err = json.Unmarshal(task.Data, pipeline)
return pipeline, err
}
+
if err := s.Done(c, task.ID, rpc.State{}); err != nil {
log.Error().Err(err).Msgf("mark task '%s' done failed", task.ID)
}
diff --git a/server/model/agent.go b/server/model/agent.go
index 594b309b3..9ee3a1ad0 100644
--- a/server/model/agent.go
+++ b/server/model/agent.go
@@ -26,6 +26,7 @@ type Agent struct {
Backend string `json:"backend" xorm:"VARCHAR(100)"`
Capacity int32 `json:"capacity"`
Version string `json:"version"`
+ NoSchedule bool `json:"no_schedule"`
}
// TableName return database table name for xorm
diff --git a/web/components.d.ts b/web/components.d.ts
index 8a8bd2f2f..375836573 100644
--- a/web/components.d.ts
+++ b/web/components.d.ts
@@ -21,10 +21,8 @@ declare module '@vue/runtime-core' {
FluidContainer: typeof import('./src/components/layout/FluidContainer.vue')['default']
GeneralTab: typeof import('./src/components/repo/settings/GeneralTab.vue')['default']
Header: typeof import('./src/components/layout/scaffold/Header.vue')['default']
- IBiCheckCircle: typeof import('~icons/bi/check-circle')['default']
IBiCheckCircleFill: typeof import('~icons/bi/check-circle-fill')['default']
IBiCircle: typeof import('~icons/bi/circle')['default']
- IBiPauseCircleFill: typeof import('~icons/bi/pause-circle-fill')['default']
IBiPlayCircleFill: typeof import('~icons/bi/play-circle-fill')['default']
IBiSlashCircleFill: typeof import('~icons/bi/slash-circle-fill')['default']
IBiStopCircleFill: typeof import('~icons/bi/stop-circle-fill')['default']
@@ -33,13 +31,9 @@ declare module '@vue/runtime-core' {
ICarbonCloseOutline: typeof import('~icons/carbon/close-outline')['default']
ICarbonInProgress: typeof import('~icons/carbon/in-progress')['default']
IClarityDeployLine: typeof import('~icons/clarity/deploy-line')['default']
- IClarityNoAccessSolid: typeof import('~icons/clarity/no-access-solid')['default']
IClaritySettingsSolid: typeof import('~icons/clarity/settings-solid')['default']
- IClaritySuccessStandardSolid: typeof import('~icons/clarity/success-standard-solid')['default']
- IClarityTimesCircleSolid: typeof import('~icons/clarity/times-circle-solid')['default']
Icon: typeof import('./src/components/atomic/Icon.vue')['default']
IconButton: typeof import('./src/components/atomic/IconButton.vue')['default']
- IEntypoDotsTwoVertical: typeof import('~icons/entypo/dots-two-vertical')['default']
IGgTrash: typeof import('~icons/gg/trash')['default']
IIcBaselineDarkMode: typeof import('~icons/ic/baseline-dark-mode')['default']
IIcBaselineDownloadForOffline: typeof import('~icons/ic/baseline-download-for-offline')['default']
@@ -67,24 +61,14 @@ declare module '@vue/runtime-core' {
IMdiSync: typeof import('~icons/mdi/sync')['default']
IMdiTagOutline: typeof import('~icons/mdi/tag-outline')['default']
InputField: typeof import('./src/components/form/InputField.vue')['default']
- IOcticonSkip24: typeof import('~icons/octicon/skip24')['default']
- IPhCheckCircle: typeof import('~icons/ph/check-circle')['default']
IPhGitlabLogoSimpleFill: typeof import('~icons/ph/gitlab-logo-simple-fill')['default']
- IPhHand: typeof import('~icons/ph/hand')['default']
- IPhHourglass: typeof import('~icons/ph/hourglass')['default']
- IPhProhibit: typeof import('~icons/ph/prohibit')['default']
- IPhWarning: typeof import('~icons/ph/warning')['default']
- IPhXCircle: typeof import('~icons/ph/x-circle')['default']
ISimpleIconsGitea: typeof import('~icons/simple-icons/gitea')['default']
ITeenyiconsGitSolid: typeof import('~icons/teenyicons/git-solid')['default']
- IUiwCircleCheck: typeof import('~icons/uiw/circle-check')['default']
- IUiwCircleClose: typeof import('~icons/uiw/circle-close')['default']
- IUiwStop: typeof import('~icons/uiw/stop')['default']
+ ITeenyiconsRefreshOutline: typeof import('~icons/teenyicons/refresh-outline')['default']
IVaadinQuestionCircleO: typeof import('~icons/vaadin/question-circle-o')['default']
ListItem: typeof import('./src/components/atomic/ListItem.vue')['default']
ManualPipelinePopup: typeof import('./src/components/layout/popups/ManualPipelinePopup.vue')['default']
Navbar: typeof import('./src/components/layout/header/Navbar.vue')['default']
- NavbarIcon: typeof import('./src/components/layout/header/NavbarIcon.vue')['default']
NumberField: typeof import('./src/components/form/NumberField.vue')['default']
OrgSecretsTab: typeof import('./src/components/org/settings/OrgSecretsTab.vue')['default']
Panel: typeof import('./src/components/layout/Panel.vue')['default']
diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json
index 529a43df2..974537171 100644
--- a/web/src/assets/locales/en.json
+++ b/web/src/assets/locales/en.json
@@ -336,6 +336,10 @@
"name": "Name",
"placeholder": "Name of the agent"
},
+ "no_schedule": {
+ "name": "Disable agent",
+ "placeholder": "Stop agent from taking new tasks"
+ },
"token": "Token",
"platform": "Platform",
"backend": "Backend",
diff --git a/web/src/components/admin/settings/AdminAgentsTab.vue b/web/src/components/admin/settings/AdminAgentsTab.vue
index ab9348769..a3f5ff364 100644
--- a/web/src/components/admin/settings/AdminAgentsTab.vue
+++ b/web/src/components/admin/settings/AdminAgentsTab.vue
@@ -43,6 +43,14 @@
/>
+
+
+
+
@@ -97,6 +105,7 @@ import { useI18n } from 'vue-i18n';
import Button from '~/components/atomic/Button.vue';
import ListItem from '~/components/atomic/ListItem.vue';
+import Checkbox from '~/components/form/Checkbox.vue';
import InputField from '~/components/form/InputField.vue';
import TextField from '~/components/form/TextField.vue';
import Panel from '~/components/layout/Panel.vue';
diff --git a/web/src/lib/api/types/agent.ts b/web/src/lib/api/types/agent.ts
index 5932accee..a5ed07cf8 100644
--- a/web/src/lib/api/types/agent.ts
+++ b/web/src/lib/api/types/agent.ts
@@ -9,4 +9,5 @@ export type Agent = {
backend: string;
capacity: number;
version: string;
+ no_schedule: boolean;
};