From 7b57e7fcab64fc037ec7b293dfaabc579034f105 Mon Sep 17 00:00:00 2001 From: angusmcleod Date: Thu, 9 Sep 2021 14:07:12 +0800 Subject: [PATCH] Apply new table style to wizard logs view --- ...field.js.es6 => wizard-table-field.js.es6} | 51 ++++-- ...ns.js.es6 => admin-wizards-columns.js.es6} | 5 +- .../admin-wizards-logs-show.js.es6 | 52 ++++++ .../controllers/admin-wizards-logs.js.es6 | 68 +++----- .../admin-wizards-submissions-show.js.es6 | 10 +- .../custom-wizard-admin-route-map.js.es6 | 14 +- .../models/custom-wizard-logs.js.es6 | 46 ++++- .../routes/admin-wizards-logs-show.js.es6 | 17 ++ .../routes/admin-wizards-logs.js.es6 | 18 +- .../templates/admin-wizards-logs-show.hbs | 45 +++++ .../templates/admin-wizards-logs.hbs | 43 ++--- .../admin-wizards-submissions-show.hbs | 14 +- .../templates/components/submission-field.hbs | 163 ------------------ .../components/wizard-table-field.hbs | 161 +++++++++++++++++ ...-columns.hbs => admin-wizards-columns.hbs} | 8 +- assets/stylesheets/common/wizard-admin.scss | 37 ++-- config/locales/client.en.yml | 14 +- config/routes.rb | 1 + controllers/custom_wizard/admin/logs.rb | 41 ++++- coverage/.last_run.json | 2 +- ...06135416_split_custom_wizard_log_fields.rb | 80 +++++---- lib/custom_wizard/log.rb | 31 ++-- serializers/custom_wizard/log_serializer.rb | 8 +- spec/components/custom_wizard/log_spec.rb | 12 +- .../admin/logs_controller_spec.rb | 31 +++- .../custom_wizard/log_serializer_spec.rb | 5 +- 26 files changed, 599 insertions(+), 378 deletions(-) rename assets/javascripts/discourse/components/{submission-field.js.es6 => wizard-table-field.js.es6} (69%) rename assets/javascripts/discourse/controllers/{admin-wizards-submissions-columns.js.es6 => admin-wizards-columns.js.es6} (73%) create mode 100644 assets/javascripts/discourse/controllers/admin-wizards-logs-show.js.es6 create mode 100644 assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6 create mode 100644 assets/javascripts/discourse/templates/admin-wizards-logs-show.hbs delete mode 100644 assets/javascripts/discourse/templates/components/submission-field.hbs create mode 100644 assets/javascripts/discourse/templates/components/wizard-table-field.hbs rename assets/javascripts/discourse/templates/modal/{admin-wizards-submissions-columns.hbs => admin-wizards-columns.hbs} (72%) diff --git a/assets/javascripts/discourse/components/submission-field.js.es6 b/assets/javascripts/discourse/components/wizard-table-field.js.es6 similarity index 69% rename from assets/javascripts/discourse/components/submission-field.js.es6 rename to assets/javascripts/discourse/components/wizard-table-field.js.es6 index 5ebc0ccd..ce6b1584 100644 --- a/assets/javascripts/discourse/components/submission-field.js.es6 +++ b/assets/javascripts/discourse/components/wizard-table-field.js.es6 @@ -1,10 +1,11 @@ import Component from "@ember/component"; import { action } from "@ember/object"; -import { equal } from "@ember/object/computed"; +import { equal, notEmpty } from "@ember/object/computed"; import discourseComputed from "discourse-common/utils/decorators"; import I18n from "I18n"; export default Component.extend({ + classNameBindings: ["value.type"], isText: equal("value.type", "text"), isComposer: equal("value.type", "composer"), isDate: equal("value.type", "date"), @@ -18,13 +19,29 @@ export default Component.extend({ isTag: equal("value.type", "tag"), isCategory: equal("value.type", "category"), isGroup: equal("value.type", "group"), - isUser: equal("fieldName", "username"), isUserSelector: equal("value.type", "user_selector"), - isSubmittedAt: equal("fieldName", "submitted_at"), - isTextArea: equal("value.type", "textarea"), + isSubmittedAt: equal("field", "submitted_at"), isComposerPreview: equal("value.type", "composer_preview"), textState: "text-collapsed", - toggleText: I18n.t("admin.wizard.submissions.expand_text"), + toggleText: I18n.t("admin.wizard.expand_text"), + + @discourseComputed("value", "isUser") + hasValue(value, isUser) { + if (isUser) { + return value; + } + return value && value.value; + }, + + @discourseComputed("field", "value.type") + isUser(field, type) { + return field === "username" || field === "user" || type === "user"; + }, + + @discourseComputed("value.type") + isLongtext(type) { + return type === "textarea" || type === "long_text"; + }, @discourseComputed("value") checkboxValue(value) { @@ -44,10 +61,10 @@ export default Component.extend({ if (state === "text-collapsed") { this.set("textState", "text-expanded"); - this.set("toggleText", I18n.t("admin.wizard.submissions.collapse_text")); + this.set("toggleText", I18n.t("admin.wizard.collapse_text")); } else if (state === "text-expanded") { this.set("textState", "text-collapsed"); - this.set("toggleText", I18n.t("admin.wizard.submissions.expand_text")); + this.set("toggleText", I18n.t("admin.wizard.expand_text")); } }, @@ -83,19 +100,24 @@ export default Component.extend({ return users; }, - @discourseComputed("value") - userProfileUrl(value) { - const isUser = this.get("isUser"); + @discourseComputed("isUser", "field", "value") + username(isUser, field, value) { + if (isUser) {return value.username;} + if (field === "username") {return value.value;} + return null; + }, - if (isUser) { - return `/u/${value.username}`; - } + showUsername: notEmpty("username"), + + @discourseComputed("username") + userProfileUrl(username) { + if (username) {return `/u/${username}`;} + return "/"; }, @discourseComputed("value") categoryUrl(value) { const isCategory = this.get("isCategory"); - if (isCategory) { return `/c/${value.value}`; } @@ -104,7 +126,6 @@ export default Component.extend({ @discourseComputed("value") groupUrl(value) { const isGroup = this.get("isGroup"); - if (isGroup) { return `/g/${value.value}`; } diff --git a/assets/javascripts/discourse/controllers/admin-wizards-submissions-columns.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-columns.js.es6 similarity index 73% rename from assets/javascripts/discourse/controllers/admin-wizards-submissions-columns.js.es6 rename to assets/javascripts/discourse/controllers/admin-wizards-columns.js.es6 index 4af487ee..4754c577 100644 --- a/assets/javascripts/discourse/controllers/admin-wizards-submissions-columns.js.es6 +++ b/assets/javascripts/discourse/controllers/admin-wizards-columns.js.es6 @@ -6,10 +6,9 @@ export default Controller.extend(ModalFunctionality, { save() { this.send("closeModal"); }, + resetToDefault() { - this.get("model.fields").forEach((field) => { - field.set("enabled", true); - }); + this.get("model.reset")(); }, }, }); diff --git a/assets/javascripts/discourse/controllers/admin-wizards-logs-show.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-logs-show.js.es6 new file mode 100644 index 00000000..7e3fdff1 --- /dev/null +++ b/assets/javascripts/discourse/controllers/admin-wizards-logs-show.js.es6 @@ -0,0 +1,52 @@ +import discourseComputed from "discourse-common/utils/decorators"; +import { notEmpty } from "@ember/object/computed"; +import CustomWizardLogs from "../models/custom-wizard-logs"; +import Controller from "@ember/controller"; + +export default Controller.extend({ + refreshing: false, + hasLogs: notEmpty("logs"), + page: 0, + canLoadMore: true, + logs: [], + messageKey: "viewing", + + loadLogs() { + if (!this.canLoadMore) { + return; + } + const page = this.get("page"); + const wizardId = this.get("wizard.id"); + + this.set("refreshing", true); + + CustomWizardLogs.list(wizardId, page) + .then((result) => { + this.set("logs", this.logs.concat(result.logs)); + }) + .finally(() => this.set("refreshing", false)); + }, + + @discourseComputed("hasLogs", "refreshing") + noResults(hasLogs, refreshing) { + return !hasLogs && !refreshing; + }, + + actions: { + loadMore() { + if (!this.loadingMore && this.logs.length < this.total) { + this.set("page", (this.page += 1)); + this.loadLogs(); + } + }, + + refresh() { + this.setProperties({ + canLoadMore: true, + page: 0, + logs: [], + }); + this.loadLogs(); + }, + }, +}); diff --git a/assets/javascripts/discourse/controllers/admin-wizards-logs.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-logs.js.es6 index f45013d7..7388a8d6 100644 --- a/assets/javascripts/discourse/controllers/admin-wizards-logs.js.es6 +++ b/assets/javascripts/discourse/controllers/admin-wizards-logs.js.es6 @@ -1,52 +1,34 @@ -import discourseComputed from "discourse-common/utils/decorators"; -import { notEmpty } from "@ember/object/computed"; -import CustomWizardLogs from "../models/custom-wizard-logs"; import Controller from "@ember/controller"; +import { default as discourseComputed } from "discourse-common/utils/decorators"; export default Controller.extend({ - refreshing: false, - hasLogs: notEmpty("logs"), - page: 0, - canLoadMore: true, - logs: [], documentationUrl: "https://thepavilion.io/t/2818", - messageKey: "viewing", - loadLogs() { - if (!this.canLoadMore) { - return; + @discourseComputed("wizardId") + wizardName(wizardId) { + let currentWizard = this.wizardList.find( + (wizard) => wizard.id === wizardId + ); + if (currentWizard) { + return currentWizard.name; + } + }, + + @discourseComputed("wizardName") + messageOpts(wizardName) { + return { + wizardName, + }; + }, + + @discourseComputed("wizardId") + messageKey(wizardId) { + let key = "select"; + + if (wizardId) { + key = "viewing"; } - this.set("refreshing", true); - - CustomWizardLogs.list() - .then((result) => { - if (!result || result.length === 0) { - this.set("canLoadMore", false); - } - this.set("logs", this.logs.concat(result)); - }) - .finally(() => this.set("refreshing", false)); - }, - - @discourseComputed("hasLogs", "refreshing") - noResults(hasLogs, refreshing) { - return !hasLogs && !refreshing; - }, - - actions: { - loadMore() { - this.set("page", (this.page += 1)); - this.loadLogs(); - }, - - refresh() { - this.setProperties({ - canLoadMore: true, - page: 0, - logs: [], - }); - this.loadLogs(); - }, + return key; }, }); diff --git a/assets/javascripts/discourse/controllers/admin-wizards-submissions-show.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-submissions-show.js.es6 index 7ba0050f..10621cd3 100644 --- a/assets/javascripts/discourse/controllers/admin-wizards-submissions-show.js.es6 +++ b/assets/javascripts/discourse/controllers/admin-wizards-submissions-show.js.es6 @@ -54,10 +54,14 @@ export default Controller.extend({ }, showEditColumnsModal() { - return showModal("admin-wizards-submissions-columns", { + return showModal("admin-wizards-columns", { model: { - fields: this.get("fields"), - submissions: this.get("submissions"), + columns: this.get("fields"), + reset: () => { + this.get("fields").forEach((field) => { + field.set("enabled", true); + }); + }, }, }); }, diff --git a/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 b/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 index 5468e863..1ca6d41b 100644 --- a/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 +++ b/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 @@ -43,10 +43,16 @@ export default { } ); - this.route("adminWizardsLogs", { - path: "/logs", - resetNamespace: true, - }); + this.route( + "adminWizardsLogs", + { path: "/logs", resetNamespace: true }, + function () { + this.route("adminWizardsLogsShow", { + path: "/:wizardId/", + resetNamespace: true, + }); + } + ); this.route("adminWizardsManager", { path: "/manager", diff --git a/assets/javascripts/discourse/models/custom-wizard-logs.js.es6 b/assets/javascripts/discourse/models/custom-wizard-logs.js.es6 index e2de8a07..1bd19dfe 100644 --- a/assets/javascripts/discourse/models/custom-wizard-logs.js.es6 +++ b/assets/javascripts/discourse/models/custom-wizard-logs.js.es6 @@ -3,14 +3,48 @@ import { popupAjaxError } from "discourse/lib/ajax-error"; import EmberObject from "@ember/object"; const CustomWizardLogs = EmberObject.extend(); +const logItemTypes = { + date: "date_time", + action: "text", + message: "long_text", + user: "user", + username: "text", +}; + +function logItem(item, attr) { + return { + value: item[attr], + type: logItemTypes[attr], + }; +} CustomWizardLogs.reopenClass({ - list(page = 0) { - return ajax("/admin/wizards/logs", { - data: { - page, - }, - }).catch(popupAjaxError); + list(wizardId, page = 0) { + let data = { + page, + }; + + return ajax(`/admin/wizards/logs/${wizardId}`, { data }) + .catch(popupAjaxError) + .then((result) => { + if (result.logs) { + result.logs = result.logs.map((item) => { + let map = {}; + + if (item.date) {map.date = logItem(item, "date");} + if (item.action) {map.action = logItem(item, "action");} + if (item.user) { + map.user = item.user; + } else { + map.user = logItem(item, "username"); + } + if (item.message) {map.message = logItem(item, "message");} + + return map; + }); + } + return result; + }); }, }); diff --git a/assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6 new file mode 100644 index 00000000..474360ec --- /dev/null +++ b/assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6 @@ -0,0 +1,17 @@ +import CustomWizardLogs from "../models/custom-wizard-logs"; +import DiscourseRoute from "discourse/routes/discourse"; +import { A } from "@ember/array"; + +export default DiscourseRoute.extend({ + model(params) { + return CustomWizardLogs.list(params.wizardId); + }, + + setupController(controller, model) { + controller.setProperties({ + wizard: model.wizard, + logs: A(model.logs), + total: model.total, + }); + }, +}); diff --git a/assets/javascripts/discourse/routes/admin-wizards-logs.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-logs.js.es6 index 56b91350..a1575050 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-logs.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-logs.js.es6 @@ -1,12 +1,24 @@ -import CustomWizardLogs from "../models/custom-wizard-logs"; import DiscourseRoute from "discourse/routes/discourse"; +import { ajax } from "discourse/lib/ajax"; export default DiscourseRoute.extend({ model() { - return CustomWizardLogs.list(); + return ajax(`/admin/wizards/wizard`); }, setupController(controller, model) { - controller.set("logs", model); + const showParams = this.paramsFor("adminWizardsLogsShow"); + + controller.setProperties({ + wizardId: showParams.wizardId, + wizardList: model.wizard_list, + }); + }, + + actions: { + changeWizard(wizardId) { + this.controllerFor("adminWizardsLogs").set("wizardId", wizardId); + this.transitionTo("adminWizardsLogsShow", wizardId); + }, }, }); diff --git a/assets/javascripts/discourse/templates/admin-wizards-logs-show.hbs b/assets/javascripts/discourse/templates/admin-wizards-logs-show.hbs new file mode 100644 index 00000000..898198d1 --- /dev/null +++ b/assets/javascripts/discourse/templates/admin-wizards-logs-show.hbs @@ -0,0 +1,45 @@ +{{#if logs}} +
+ + +
+ {{d-button + label="refresh" + icon="sync" + action="refresh" + class="refresh"}} +
+
+ +
+ {{#load-more selector=".wizard-table tr" action=(action "loadMore")}} + {{#if noResults}} +

{{i18n "search.no_results"}}

+ {{else}} + + + + + + + + + + + {{#each logs as |log|}} + + {{#each-in log as |field value|}} + + {{/each-in}} + + {{/each}} + +
{{i18n "admin.wizard.log.date"}}{{i18n "admin.wizard.log.action"}}{{i18n "admin.wizard.log.user"}}{{i18n "admin.wizard.log.message"}}
{{wizard-table-field field=field value=value}}
+ {{/if}} + + {{conditional-loading-spinner condition=refreshing}} + {{/load-more}} +
+{{/if}} diff --git a/assets/javascripts/discourse/templates/admin-wizards-logs.hbs b/assets/javascripts/discourse/templates/admin-wizards-logs.hbs index ea0afb7c..45738a9f 100644 --- a/assets/javascripts/discourse/templates/admin-wizards-logs.hbs +++ b/assets/javascripts/discourse/templates/admin-wizards-logs.hbs @@ -1,11 +1,11 @@ -
-

{{i18n "admin.wizard.log.nav_label"}}

- - {{d-button - label="refresh" - icon="sync" - action="refresh" - class="refresh"}} +
+ {{combo-box + value=wizardId + content=wizardList + onChange=(route-action "changeWizard") + options=(hash + none="admin.wizard.select" + )}}
{{wizard-message @@ -14,27 +14,6 @@ url=documentationUrl component="logs"}} -{{#load-more selector=".log-list tr" action=(action "loadMore") class="wizard-logs"}} - {{#if noResults}} -

{{i18n "search.no_results"}}

- {{else}} - - - - - - - - - {{#each logs as |log|}} - - - - - {{/each}} - -
MessageDate
{{log.message}}{{bound-date log.date}}
- {{/if}} - - {{conditional-loading-spinner condition=refreshing}} -{{/load-more}} +
+ {{outlet}} +
diff --git a/assets/javascripts/discourse/templates/admin-wizards-submissions-show.hbs b/assets/javascripts/discourse/templates/admin-wizards-submissions-show.hbs index df97513b..72ec7c38 100644 --- a/assets/javascripts/discourse/templates/admin-wizards-submissions-show.hbs +++ b/assets/javascripts/discourse/templates/admin-wizards-submissions-show.hbs @@ -7,7 +7,7 @@
{{d-button icon="sliders-h" - label="admin.wizard.submissions.edit_columns" + label="admin.wizard.edit_columns" action=(action "showEditColumnsModal") class="btn-default open-edit-columns-btn download-link" }} @@ -26,12 +26,10 @@
-
- {{#load-more selector=".wizard-submissions tr" action=(action "loadMore")}} +
+ {{#load-more selector=".wizard-table tr" action=(action "loadMore")}} {{#if noResults}} -

- {{i18n "search.no_results"}} -

+

{{i18n "search.no_results"}}

{{else}} @@ -49,9 +47,7 @@ {{#each displaySubmissions as |submission|}} {{#each-in submission as |field value|}} - + {{/each-in}} {{/each}} diff --git a/assets/javascripts/discourse/templates/components/submission-field.hbs b/assets/javascripts/discourse/templates/components/submission-field.hbs deleted file mode 100644 index c635ff47..00000000 --- a/assets/javascripts/discourse/templates/components/submission-field.hbs +++ /dev/null @@ -1,163 +0,0 @@ -{{#if isText}} - {{value.value}} -{{/if}} - -{{#if isTextArea}} -
-

- {{value.value}} -

- - {{toggleText}} - -
-{{/if}} - -{{#if isComposer}} -
-

- {{value.value}} -

- - {{toggleText}} - -
-{{/if}} - -{{#if isComposerPreview}} - {{d-icon "comment-alt"}} - - {{i18n "admin.wizard.submissions.composer_preview"}}: {{value.value}} - -{{/if}} - -{{#if isTextOnly}} - {{value.value}} -{{/if}} - -{{#if isDate}} - - {{d-icon "calendar"}}{{value.value}} - -{{/if}} - -{{#if isTime}} - - {{d-icon "clock"}}{{value.value}} - -{{/if}} - -{{#if isDateTime}} - - {{d-icon "calendar"}}{{format-date value.value format="medium"}} - -{{/if}} - -{{#if isNumber}} - {{value.value}} -{{/if}} - -{{#if isCheckbox}} - {{#if checkboxValue}} - - {{d-icon "check"}}{{value.value}} - - {{else}} - - {{d-icon "times"}}{{value.value}} - - {{/if}} -{{/if}} - -{{#if isUrl}} - - {{d-icon "link"}} - - {{value.value}} - - -{{/if}} - -{{#if isUpload}} - - {{file.original_filename}} - -{{/if}} - -{{#if isDropdown}} - - {{d-icon "check-square"}} - {{value.value}} - -{{/if}} - -{{#if isTag}} - {{#each value.value as |tag|}} - {{discourse-tag tag}} - {{/each}} -{{/if}} - -{{#if isCategory}} - - {{i18n "admin.wizard.submissions.category_id"}}: - - - {{value.value}} - -{{/if}} - -{{#if isGroup}} - - {{i18n "admin.wizard.submissions.group_id"}}: - - {{value.value}} -{{/if}} - -{{#if isUserSelector}} - {{#each submittedUsers as |user|}} - {{d-icon "user"}} - - {{user.username}} - - {{/each}} -{{/if}} - -{{#if isUser}} - {{#link-to "user" value}} - {{avatar value imageSize="tiny"}} - {{/link-to}} - - {{value.username}} - -{{/if}} - -{{#if isSubmittedAt}} - - {{d-icon "clock"}}{{format-date value format="tiny"}} - -{{/if}} diff --git a/assets/javascripts/discourse/templates/components/wizard-table-field.hbs b/assets/javascripts/discourse/templates/components/wizard-table-field.hbs new file mode 100644 index 00000000..bd7da5c4 --- /dev/null +++ b/assets/javascripts/discourse/templates/components/wizard-table-field.hbs @@ -0,0 +1,161 @@ +{{#if hasValue}} + {{#if isText}} + {{value.value}} + {{/if}} + + {{#if isLongtext}} +
+

+ {{value.value}} +

+ + {{toggleText}} + +
+ {{/if}} + + {{#if isComposer}} +
+

+ {{value.value}} +

+ + {{toggleText}} + +
+ {{/if}} + + {{#if isComposerPreview}} + {{d-icon "comment-alt"}} + + {{i18n "admin.wizard.submissions.composer_preview"}}: {{value.value}} + + {{/if}} + + {{#if isTextOnly}} + {{value.value}} + {{/if}} + + {{#if isDate}} + + {{d-icon "calendar"}}{{value.value}} + + {{/if}} + + {{#if isTime}} + + {{d-icon "clock"}}{{value.value}} + + {{/if}} + + {{#if isDateTime}} + + {{d-icon "calendar"}}{{format-date value.value format="medium"}} + + {{/if}} + + {{#if isNumber}} + {{value.value}} + {{/if}} + + {{#if isCheckbox}} + {{#if checkboxValue}} + + {{d-icon "check"}}{{value.value}} + + {{else}} + + {{d-icon "times"}}{{value.value}} + + {{/if}} + {{/if}} + + {{#if isUrl}} + + {{d-icon "link"}} + + {{value.value}} + + + {{/if}} + + {{#if isUpload}} + + {{file.original_filename}} + + {{/if}} + + {{#if isDropdown}} + + {{d-icon "check-square"}} + {{value.value}} + + {{/if}} + + {{#if isTag}} + {{#each value.value as |tag|}} + {{discourse-tag tag}} + {{/each}} + {{/if}} + + {{#if isCategory}} + + {{i18n "admin.wizard.submissions.category_id"}}: + + + {{value.value}} + + {{/if}} + + {{#if isGroup}} + + {{i18n "admin.wizard.submissions.group_id"}}: + + {{value.value}} + {{/if}} + + {{#if isUserSelector}} + {{#each submittedUsers as |user|}} + {{d-icon "user"}} + + {{user.username}} + + {{/each}} + {{/if}} + + {{#if isUser}} + {{#link-to "user" value}} + {{avatar value imageSize="tiny"}} + {{/link-to}} + {{/if}} + + {{#if showUsername}} + + {{username}} + + {{/if}} + + {{#if isSubmittedAt}} + + {{d-icon "clock"}}{{format-date value format="tiny"}} + + {{/if}} +{{else}} + — +{{/if}} diff --git a/assets/javascripts/discourse/templates/modal/admin-wizards-submissions-columns.hbs b/assets/javascripts/discourse/templates/modal/admin-wizards-columns.hbs similarity index 72% rename from assets/javascripts/discourse/templates/modal/admin-wizards-submissions-columns.hbs rename to assets/javascripts/discourse/templates/modal/admin-wizards-columns.hbs index a167a954..eb5218b1 100644 --- a/assets/javascripts/discourse/templates/modal/admin-wizards-submissions-columns.hbs +++ b/assets/javascripts/discourse/templates/modal/admin-wizards-columns.hbs @@ -1,14 +1,14 @@ -{{#d-modal-body title="directory.edit_columns.title"}} +{{#d-modal-body title="admin.wizard.edit_columns"}} {{#if loading}} {{loading-spinner size="large"}} {{else}}
- {{#each model.fields as |field|}} + {{#each model.columns as |column|}}
diff --git a/assets/stylesheets/common/wizard-admin.scss b/assets/stylesheets/common/wizard-admin.scss index 7027950a..7c6cd95d 100644 --- a/assets/stylesheets/common/wizard-admin.scss +++ b/assets/stylesheets/common/wizard-admin.scss @@ -66,10 +66,10 @@ } } -.wizard-submissions { +.wizard-table { overflow: scroll; - table td { + table td:not(.small) { min-width: 150px; } @@ -77,25 +77,26 @@ text-transform: capitalize; } - .submission-icon-item { + .wizard-table-icon-item { display: flex; align-items: center; + svg { margin-right: 5px; } } - .submission-checkbox-true { + .wizard-table-checkbox-true { text-transform: capitalize; color: var(--success); } - .submission-checkbox-false { + .wizard-table-checkbox-false { text-transform: capitalize; color: var(--danger); } - .submission-long-text { + .wizard-table-long-text { &-content { white-space: nowrap; word-wrap: break-word; @@ -114,25 +115,11 @@ } } - .submission-composer-text { + .wizard-table-composer-text { font-family: monospace; } } -.admin-wizards-logs { - .admin-wizard-controls { - h3 { - margin: 0 7px; - } - } - - .wizard-logs { - .date { - width: 100px; - } - } -} - .wizard-settings-parent { padding: 20px; border: 1px solid var(--primary-low); @@ -215,6 +202,10 @@ margin-bottom: 0; } + button { + font-size: 1rem; + } + .download-link { font-size: 1rem; line-height: 20px; @@ -230,10 +221,6 @@ font-size: 1rem; background-color: var(--primary-low); } - - button { - font-size: 1rem; - } } } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index ae2594d2..cb30cf76 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -58,6 +58,9 @@ en: select_type: "Select a type" condition: "Condition" index: "Index" + edit_columns: "Edit Columns" + expand_text: "Read More" + collapse_text: "Show Less" pro_support_button: title: "Request Pro Support" @@ -108,6 +111,7 @@ en: viewing: "You're viewing the submissions of the %{wizardName}" documentation: "Check out the submissions documentation" logs: + select: "Select a wizard to see its logs" viewing: "View recent logs for wizards on the forum" documentation: "Check out the logs documentation" @@ -378,9 +382,6 @@ en: nav_label: "Submissions" title: "{{name}} Submissions" download: "Download" - edit_columns: "Edit Columns" - expand_text: "Read More" - collapse_text: "Show Less" group_id: "Group ID" category_id: "Category ID" composer_preview: "Composer Preview" @@ -437,9 +438,14 @@ en: log: label: "Logs" - + log: nav_label: "Logs" + title: "{{name}} Logs" + date: Date + action: Action + user: User + message: Message manager: nav_label: Manager diff --git a/config/routes.rb b/config/routes.rb index abe36479..3a37a137 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,6 +38,7 @@ Discourse::Application.routes.append do get 'admin/wizards/api/:name/authorize' => 'admin_api#authorize' get 'admin/wizards/logs' => 'admin_logs#index' + get 'admin/wizards/logs/:wizard_id' => 'admin_logs#show' get 'admin/wizards/manager' => 'admin_manager#index' get 'admin/wizards/manager/export' => 'admin_manager#export' diff --git a/controllers/custom_wizard/admin/logs.rb b/controllers/custom_wizard/admin/logs.rb index 976814f8..7ca37bb2 100644 --- a/controllers/custom_wizard/admin/logs.rb +++ b/controllers/custom_wizard/admin/logs.rb @@ -1,9 +1,44 @@ # frozen_string_literal: true class CustomWizard::AdminLogsController < CustomWizard::AdminController + before_action :find_wizard, except: [:index] + def index - render_serialized( - CustomWizard::Log.list(params[:page].to_i, params[:limit].to_i), - CustomWizard::LogSerializer + render json: ActiveModel::ArraySerializer.new( + CustomWizard::Wizard.list(current_user), + each_serializer: CustomWizard::BasicWizardSerializer ) end + + def show + render_json_dump( + wizard: CustomWizard::BasicWizardSerializer.new(@wizard, root: false), + logs: ActiveModel::ArraySerializer.new( + log_list.logs, + each_serializer: CustomWizard::LogSerializer + ), + total: log_list.total + ) + end + + protected + + def log_list + @log_list ||= begin + list = CustomWizard::Log.list(params[:page].to_i, params[:limit].to_i, params[:wizard_id]) + + if list.logs.any? && (usernames = list.logs.map(&:username)).present? + user_map = User.where(username: usernames) + .reduce({}) do |result, user| + result[user.username] = user + result + end + + list.logs.each do |log_item| + log_item.user = user_map[log_item.username] + end + end + + list + end + end end diff --git a/coverage/.last_run.json b/coverage/.last_run.json index cff5740b..23e2ecb9 100644 --- a/coverage/.last_run.json +++ b/coverage/.last_run.json @@ -1,5 +1,5 @@ { "result": { - "line": 91.96 + "line": 92.14 } } diff --git a/db/migrate/20210806135416_split_custom_wizard_log_fields.rb b/db/migrate/20210806135416_split_custom_wizard_log_fields.rb index 984a7a23..8107bc07 100644 --- a/db/migrate/20210806135416_split_custom_wizard_log_fields.rb +++ b/db/migrate/20210806135416_split_custom_wizard_log_fields.rb @@ -1,51 +1,56 @@ # frozen_string_literal: true class SplitCustomWizardLogFields < ActiveRecord::Migration[6.1] + KEY_MAP = { + wizard: "wizard_id", + action: "action", + user: "username", + date: "date", + message: "message" + } + def change reversible do |dir| dir.up do # separate wizard/action/user into their own keys - wizard_logs = PluginStoreRow.where(" - plugin_name = 'custom_wizard_log' - ") + wizard_logs = PluginStoreRow.where("plugin_name = 'custom_wizard_log'") - if wizard_logs.exists? - wizard_logs.each do |row| - begin - log_json = JSON.parse(row.value) - rescue TypeError, JSON::ParserError - next - end + if wizard_logs.exists? + wizard_logs.each do |row| + begin + log_json = JSON.parse(row.value) + rescue TypeError, JSON::ParserError + next + end - if log_json.key?('message') && log_json['message'].is_a?(String) + if log_json.key?('message') && log_json['message'].is_a?(String) - attr_strs = [] + attr_strs = [] - # assumes no whitespace in the values - attr_strs << log_json['message'].slice!(/(wizard: \S*; )/, 1) - attr_strs << log_json['message'].slice!(/(action: \S*; )/, 1) - attr_strs << log_json['message'].slice!(/(user: \S*; )/, 1) + # assumes no whitespace in the values + attr_strs << log_json['message'].slice!(/(wizard: \S*; )/, 1) + attr_strs << log_json['message'].slice!(/(action: \S*; )/, 1) + attr_strs << log_json['message'].slice!(/(user: \S*; )/, 1) - attr_strs.each do |attr_str| - if attr_str.is_a? String - attr_str.gsub!(/[;]/ , "") - key, value = attr_str.split(': ') - value.strip! if value - log_json[key] = value ? value : '' - end + attr_strs.each do |attr_str| + if attr_str.is_a? String + attr_str.gsub!(/[;]/ , "") + key, value = attr_str.split(': ') + value.strip! if value + key = KEY_MAP[key.to_sym] ? KEY_MAP[key.to_sym] : key + log_json[key] = value ? value : '' end - - row.value = log_json.to_json - row.save - end + + row.value = log_json.to_json + row.save end end + end end + dir.down do - wizard_logs = PluginStoreRow.where(" - plugin_name = 'custom_wizard_log' - ") + wizard_logs = PluginStoreRow.where("plugin_name = 'custom_wizard_log'") if wizard_logs.exists? wizard_logs.each do |row| @@ -56,19 +61,26 @@ class SplitCustomWizardLogFields < ActiveRecord::Migration[6.1] end # concatenate wizard/action/user to start of message - prefixes = log_json.extract!('wizard', 'action', 'user') + prefixes = log_json.extract!('wizard_id', 'action', 'username') + message_prefix = "" - message_prefix = prefixes.map { |k, v| "#{k}: #{v}" }.join('; ') + if prefixes.present? + message_prefix = prefixes.map do |k, v| + key = KEY_MAP.key(k) ? KEY_MAP.key(k) : k + "#{key.to_s}: #{v};" + end.join(' ') + end if log_json.key?('message') - log_json['message'] = "#{message_prefix}; #{log_json['message']}" + message = log_json['message'] + message = "#{message_prefix} #{message}" if message_prefix.present? + log_json['message'] = message else log_json['message'] = message_prefix end row.value = log_json.to_json row.save - end end end diff --git a/lib/custom_wizard/log.rb b/lib/custom_wizard/log.rb index c50a5712..cb5b78c7 100644 --- a/lib/custom_wizard/log.rb +++ b/lib/custom_wizard/log.rb @@ -2,46 +2,51 @@ class CustomWizard::Log include ActiveModel::Serialization - attr_accessor :date, :wizard, :action, :user, :message + attr_reader :date, :wizard_id, :action, :username, :message + attr_accessor :user PAGE_LIMIT = 100 def initialize(attrs) @date = attrs['date'] - @wizard = attrs['wizard'] @action = attrs['action'] - @user = attrs['user'] @message = attrs['message'] + @wizard_id = attrs['wizard_id'] + @username = attrs['username'] end - def self.create(wizard, action, user, message) + def self.create(wizard_id, action, username, message) log_id = SecureRandom.hex(12) PluginStore.set('custom_wizard_log', log_id.to_s, { date: Time.now, - wizard: wizard, + wizard_id: wizard_id, action: action, - user: user, + username: username, message: message } ) end - def self.list_query - PluginStoreRow.where(" - plugin_name = 'custom_wizard_log' AND - (value::json->'date') IS NOT NULL - ").order("value::json->>'date' DESC") + def self.list_query(wizard_id = nil) + query = PluginStoreRow.where("plugin_name = 'custom_wizard_log' AND (value::json->'date') IS NOT NULL") + query = query.where("(value::json->>'wizard_id') = ?", wizard_id) if wizard_id + query.order("value::json->>'date' DESC") end - def self.list(page = 0, limit = nil) + def self.list(page = 0, limit = nil, wizard_id = nil) limit = limit.to_i > 0 ? limit.to_i : PAGE_LIMIT page = page.to_i + logs = self.list_query(wizard_id) - self.list_query.limit(limit) + result = OpenStruct.new(logs: [], total: nil) + result.total = logs.size + result.logs = logs.limit(limit) .offset(page * limit) .map { |r| self.new(JSON.parse(r.value)) } + + result end end diff --git a/serializers/custom_wizard/log_serializer.rb b/serializers/custom_wizard/log_serializer.rb index c4683ba8..56c5fd8f 100644 --- a/serializers/custom_wizard/log_serializer.rb +++ b/serializers/custom_wizard/log_serializer.rb @@ -1,4 +1,10 @@ # frozen_string_literal: true + class CustomWizard::LogSerializer < ApplicationSerializer - attributes :date, :wizard, :action, :user, :message + attributes :date, + :action, + :username, + :message + + has_one :user, serializer: ::BasicUserSerializer, embed: :objects end diff --git a/spec/components/custom_wizard/log_spec.rb b/spec/components/custom_wizard/log_spec.rb index 62f2e6df..0b4832c0 100644 --- a/spec/components/custom_wizard/log_spec.rb +++ b/spec/components/custom_wizard/log_spec.rb @@ -10,19 +10,25 @@ describe CustomWizard::Log do it "creates logs" do expect( - CustomWizard::Log.list.length + CustomWizard::Log.list.logs.length ).to eq(3) end it "lists logs by time created" do expect( - CustomWizard::Log.list.first.message + CustomWizard::Log.list.logs.first.message ).to eq("Third log message") end it "paginates logs" do expect( - CustomWizard::Log.list(0, 2).length + CustomWizard::Log.list(0, 2).logs.length ).to eq(2) end + + it "lists logs by wizard" do + expect( + CustomWizard::Log.list(0, 2, 'third-test-wizard').logs.length + ).to eq(1) + end end diff --git a/spec/requests/custom_wizard/admin/logs_controller_spec.rb b/spec/requests/custom_wizard/admin/logs_controller_spec.rb index 5aaf9578..1559fa6f 100644 --- a/spec/requests/custom_wizard/admin/logs_controller_spec.rb +++ b/spec/requests/custom_wizard/admin/logs_controller_spec.rb @@ -3,21 +3,40 @@ require_relative '../../../plugin_helper' describe CustomWizard::AdminLogsController do fab!(:admin_user) { Fabricate(:user, admin: true) } + let(:template) { get_wizard_fixture("wizard") } before do - CustomWizard::Log.create('first-test-wizard', 'perform_first_action', 'first_test_user', 'First log message') - CustomWizard::Log.create('second-test-wizard', 'perform_second_action', 'second_test_user', 'Second log message') - CustomWizard::Log.create('third-test-wizard', 'perform_third_action', 'third_test_user', 'Third log message') + ["first", "second", "third"].each_with_index do |key, index| + temp = template.dup + temp["id"] = "#{key}_test_wizard" + CustomWizard::Template.save(temp, skip_jobs: true) + CustomWizard::Log.create("#{key}_test_wizard", "perform_#{key}_action", "#{key}_test_user", "#{key} log message") + end sign_in(admin_user) end - it "returns a list of logs" do + it "returns a list of wizards" do get "/admin/wizards/logs.json" expect(response.parsed_body.length).to eq(3) end + it "returns a list of logs for a wizard" do + get "/admin/wizards/logs/first_test_wizard.json" + expect(response.parsed_body['logs'].length).to eq(1) + end + it "paginates" do - get "/admin/wizards/logs.json", params: { page: 1, limit: 2 } - expect(response.parsed_body.length).to eq(1) + get "/admin/wizards/logs/first_test_wizard.json", params: { page: 1 } + expect(response.parsed_body['logs'].length).to eq(0) + end + + it "returns total logs for a wizard" do + get "/admin/wizards/logs/first_test_wizard.json" + expect(response.parsed_body['total']).to eq(1) + end + + it "returns basic wizard" do + get "/admin/wizards/logs/first_test_wizard.json" + expect(response.parsed_body['wizard']['id']).to eq("first_test_wizard") end end diff --git a/spec/serializers/custom_wizard/log_serializer_spec.rb b/spec/serializers/custom_wizard/log_serializer_spec.rb index b452b9c5..d520fefa 100644 --- a/spec/serializers/custom_wizard/log_serializer_spec.rb +++ b/spec/serializers/custom_wizard/log_serializer_spec.rb @@ -10,13 +10,12 @@ describe CustomWizard::LogSerializer do CustomWizard::Log.create('second-test-wizard', 'perform_second_action', 'second_test_user', 'Second log message') json_array = ActiveModel::ArraySerializer.new( - CustomWizard::Log.list(0), + CustomWizard::Log.list(0).logs, each_serializer: CustomWizard::LogSerializer ).as_json expect(json_array.length).to eq(2) - expect(json_array[0][:wizard]).to eq("second-test-wizard") expect(json_array[0][:action]).to eq("perform_second_action") - expect(json_array[0][:user]).to eq("second_test_user") + expect(json_array[0][:username]).to eq('second_test_user') expect(json_array[0][:message]).to eq("Second log message") end end
- {{submission-field fieldName=field value=value}} - {{wizard-table-field field=field value=value}}