diff --git a/dashboard/src/theme.scss b/dashboard/src/theme.scss
index a70c952dd..1cfee1c9b 100644
--- a/dashboard/src/theme.scss
+++ b/dashboard/src/theme.scss
@@ -687,7 +687,7 @@ multiselect {
}
.checklist-item-acknowledged {
- border-left: 2px solid transparent;
+ border-left: 2px solid $brand-success;
background-color: transparent;
}
diff --git a/dashboard/src/views/app.html b/dashboard/src/views/app.html
index 089013743..2c17c1f9d 100644
--- a/dashboard/src/views/app.html
+++ b/dashboard/src/views/app.html
@@ -768,11 +768,22 @@
+
+
-
- {{ item.message }}
-
+
+
+ {{ item.message }}
+
+
+
+
+
+
+ {{ item.message }}
+
+
diff --git a/dashboard/src/views/app.js b/dashboard/src/views/app.js
index 32b5a787e..d4c1259f3 100644
--- a/dashboard/src/views/app.js
+++ b/dashboard/src/views/app.js
@@ -137,6 +137,9 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
};
$scope.info = {
+ checklist: [],
+ showDoneChecklist: false,
+
notes: {
busy: false,
editing: false,
@@ -171,15 +174,18 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
},
show: function () {
- $scope.info.notes.busy = false;
+ $scope.info.checklist = $scope.app.checklist;
$scope.info.notes.content = $scope.app.notes;
$scope.info.notes.editing = false;
-
- $scope.info.checklist = $scope.app.checklist;
+ $scope.info.notes.busy = false;
},
- checklistAck: function () {
+ checklistAck(item) {
+ item.acknowledged = !item.acknowledged;
+ Client.configureApp($scope.app.id, 'checklist', { checklist: $scope.info.checklist }, function (error) {
+ if (error) return console.error('Failed to save checklist.', error);
+ });
}
};
diff --git a/src/apps.js b/src/apps.js
index c730ea24e..7c7935b17 100644
--- a/src/apps.js
+++ b/src/apps.js
@@ -32,6 +32,7 @@ exports = module.exports = {
setIcon,
setTags,
setNotes,
+ setChecklist,
setMemoryLimit,
setCpuQuota,
setMounts,
@@ -1543,6 +1544,15 @@ async function setNotes(app, notes, auditSource) {
await eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: app.id, app, notes });
}
+async function setChecklist(app, checklist, auditSource) {
+ assert.strictEqual(typeof app, 'object');
+ assert.strictEqual(typeof checklist, 'object');
+ assert.strictEqual(typeof auditSource, 'object');
+
+ await update(app.id, { checklist });
+ await eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: app.id, app, checklist });
+}
+
async function setIcon(app, icon, auditSource) {
assert.strictEqual(typeof app, 'object');
assert(icon === null || typeof icon === 'string');
diff --git a/src/routes/apps.js b/src/routes/apps.js
index bf760a160..729e17303 100644
--- a/src/routes/apps.js
+++ b/src/routes/apps.js
@@ -24,6 +24,7 @@ exports = module.exports = {
setLabel,
setTags,
setNotes,
+ setChecklist,
setIcon,
setTurn,
setRedis,
@@ -270,6 +271,18 @@ async function setNotes(req, res, next) {
next(new HttpSuccess(200, {}));
}
+async function setChecklist(req, res, next) {
+ assert.strictEqual(typeof req.body, 'object');
+ assert.strictEqual(typeof req.app, 'object');
+
+ if (typeof req.body.checklist !== 'object') return next(new HttpError(400, 'checklist must be an object'));
+
+ const [error] = await safe(apps.setChecklist(req.app, req.body.checklist, AuditSource.fromRequest(req)));
+ if (error) return next(BoxError.toHttpError(error));
+
+ next(new HttpSuccess(200, {}));
+}
+
async function setIcon(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
diff --git a/src/server.js b/src/server.js
index 3bc7fa4e2..89f734e19 100644
--- a/src/server.js
+++ b/src/server.js
@@ -244,6 +244,7 @@ async function initializeExpressSync() {
router.post('/api/v1/apps/:id/configure/tags', json, token, routes.apps.load, authorizeOperator, routes.apps.setTags);
router.post('/api/v1/apps/:id/configure/icon', json, token, routes.apps.load, authorizeOperator, routes.apps.setIcon);
router.post('/api/v1/apps/:id/configure/notes', json, token, routes.apps.load, authorizeOperator, routes.apps.setNotes);
+ router.post('/api/v1/apps/:id/configure/checklist', json, token, routes.apps.load, authorizeOperator, routes.apps.setChecklist);
router.post('/api/v1/apps/:id/configure/memory_limit', json, token, routes.apps.load, authorizeOperator, routes.apps.setMemoryLimit);
router.post('/api/v1/apps/:id/configure/cpu_quota', json, token, routes.apps.load, authorizeOperator, routes.apps.setCpuQuota);
router.post('/api/v1/apps/:id/configure/automatic_backup', json, token, routes.apps.load, authorizeOperator, routes.apps.setAutomaticBackup);