Apply new table style to wizard logs view
Dieser Commit ist enthalten in:
Ursprung
a8e81150f1
Commit
7b57e7fcab
26 geänderte Dateien mit 599 neuen und 378 gelöschten Zeilen
|
@ -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}`;
|
||||
}
|
|
@ -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")();
|
||||
},
|
||||
},
|
||||
});
|
|
@ -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();
|
||||
},
|
||||
},
|
||||
});
|
|
@ -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;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
|
17
assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6
Normale Datei
17
assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6
Normale Datei
|
@ -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,
|
||||
});
|
||||
},
|
||||
});
|
|
@ -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);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
45
assets/javascripts/discourse/templates/admin-wizards-logs-show.hbs
Normale Datei
45
assets/javascripts/discourse/templates/admin-wizards-logs-show.hbs
Normale Datei
|
@ -0,0 +1,45 @@
|
|||
{{#if logs}}
|
||||
<div class="wizard-header large">
|
||||
<label>
|
||||
{{i18n "admin.wizard.log.title" name=wizard.name}}
|
||||
</label>
|
||||
|
||||
<div class="controls">
|
||||
{{d-button
|
||||
label="refresh"
|
||||
icon="sync"
|
||||
action="refresh"
|
||||
class="refresh"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard-table">
|
||||
{{#load-more selector=".wizard-table tr" action=(action "loadMore")}}
|
||||
{{#if noResults}}
|
||||
<p>{{i18n "search.no_results"}}</p>
|
||||
{{else}}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="date">{{i18n "admin.wizard.log.date"}}</th>
|
||||
<th>{{i18n "admin.wizard.log.action"}}</th>
|
||||
<th>{{i18n "admin.wizard.log.user"}}</th>
|
||||
<th>{{i18n "admin.wizard.log.message"}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each logs as |log|}}
|
||||
<tr>
|
||||
{{#each-in log as |field value|}}
|
||||
<td class="small">{{wizard-table-field field=field value=value}}</td>
|
||||
{{/each-in}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
|
||||
{{conditional-loading-spinner condition=refreshing}}
|
||||
{{/load-more}}
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,11 +1,11 @@
|
|||
<div class="admin-wizard-controls">
|
||||
<h3>{{i18n "admin.wizard.log.nav_label"}}</h3>
|
||||
|
||||
{{d-button
|
||||
label="refresh"
|
||||
icon="sync"
|
||||
action="refresh"
|
||||
class="refresh"}}
|
||||
<div class="admin-wizard-select admin-wizard-controls">
|
||||
{{combo-box
|
||||
value=wizardId
|
||||
content=wizardList
|
||||
onChange=(route-action "changeWizard")
|
||||
options=(hash
|
||||
none="admin.wizard.select"
|
||||
)}}
|
||||
</div>
|
||||
|
||||
{{wizard-message
|
||||
|
@ -14,27 +14,6 @@
|
|||
url=documentationUrl
|
||||
component="logs"}}
|
||||
|
||||
{{#load-more selector=".log-list tr" action=(action "loadMore") class="wizard-logs"}}
|
||||
{{#if noResults}}
|
||||
<p>{{i18n "search.no_results"}}</p>
|
||||
{{else}}
|
||||
<table class="table grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Message</th>
|
||||
<th class="date">Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each logs as |log|}}
|
||||
<tr>
|
||||
<td>{{log.message}}</td>
|
||||
<td class="date">{{bound-date log.date}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
|
||||
{{conditional-loading-spinner condition=refreshing}}
|
||||
{{/load-more}}
|
||||
<div class="admin-wizard-container">
|
||||
{{outlet}}
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<div class="controls">
|
||||
{{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 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<div class="wizard-submissions">
|
||||
{{#load-more selector=".wizard-submissions tr" action=(action "loadMore")}}
|
||||
<div class="wizard-table">
|
||||
{{#load-more selector=".wizard-table tr" action=(action "loadMore")}}
|
||||
{{#if noResults}}
|
||||
<p>
|
||||
{{i18n "search.no_results"}}
|
||||
</p>
|
||||
<p>{{i18n "search.no_results"}}</p>
|
||||
{{else}}
|
||||
<table>
|
||||
<thead>
|
||||
|
@ -49,9 +47,7 @@
|
|||
{{#each displaySubmissions as |submission|}}
|
||||
<tr>
|
||||
{{#each-in submission as |field value|}}
|
||||
<td>
|
||||
{{submission-field fieldName=field value=value}}
|
||||
</td>
|
||||
<td>{{wizard-table-field field=field value=value}}</td>
|
||||
{{/each-in}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
{{#if isText}}
|
||||
{{value.value}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isTextArea}}
|
||||
<div class="submission-long-text">
|
||||
<p class="submission-long-text-content {{textState}}">
|
||||
{{value.value}}
|
||||
</p>
|
||||
<a href {{action "expandText"}}>
|
||||
{{toggleText}}
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if isComposer}}
|
||||
<div class="submission-long-text">
|
||||
<p
|
||||
class="submission-composer-text submission-long-text-content {{
|
||||
textState
|
||||
}}"
|
||||
>
|
||||
{{value.value}}
|
||||
</p>
|
||||
<a href {{action "expandText"}}>
|
||||
{{toggleText}}
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if isComposerPreview}}
|
||||
{{d-icon "comment-alt"}}
|
||||
<span class="submission-composer-text">
|
||||
{{i18n "admin.wizard.submissions.composer_preview"}}: {{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isTextOnly}}
|
||||
{{value.value}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isDate}}
|
||||
<span class="submission-icon-item">
|
||||
{{d-icon "calendar"}}{{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isTime}}
|
||||
<span class="submission-icon-item">
|
||||
{{d-icon "clock"}}{{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isDateTime}}
|
||||
<span class="submission-icon-item" title={{value.value}}>
|
||||
{{d-icon "calendar"}}{{format-date value.value format="medium"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isNumber}}
|
||||
{{value.value}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isCheckbox}}
|
||||
{{#if checkboxValue}}
|
||||
<span class="submission-icon-item submission-checkbox-true">
|
||||
{{d-icon "check"}}{{value.value}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="submission-icon-item submission-checkbox-false">
|
||||
{{d-icon "times"}}{{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isUrl}}
|
||||
<span class="submission-icon-item submission-url">
|
||||
{{d-icon "link"}}
|
||||
<a target="_blank" rel="noopener noreferrer" href={{value.value}}>
|
||||
{{value.value}}
|
||||
</a>
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isUpload}}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="attachment"
|
||||
href={{file.url}}
|
||||
download
|
||||
>
|
||||
{{file.original_filename}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if isDropdown}}
|
||||
<span class="submission-icon-item">
|
||||
{{d-icon "check-square"}}
|
||||
{{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isTag}}
|
||||
{{#each value.value as |tag|}}
|
||||
{{discourse-tag tag}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isCategory}}
|
||||
<strong>
|
||||
{{i18n "admin.wizard.submissions.category_id"}}:
|
||||
</strong>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={{categoryUrl}}
|
||||
title={{value.value}}
|
||||
>
|
||||
{{value.value}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if isGroup}}
|
||||
<strong>
|
||||
{{i18n "admin.wizard.submissions.group_id"}}:
|
||||
</strong>
|
||||
{{value.value}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isUserSelector}}
|
||||
{{#each submittedUsers as |user|}}
|
||||
{{d-icon "user"}}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={{user.url}}
|
||||
title={{user.username}}
|
||||
>
|
||||
{{user.username}}
|
||||
</a>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isUser}}
|
||||
{{#link-to "user" value}}
|
||||
{{avatar value imageSize="tiny"}}
|
||||
{{/link-to}}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={{userProfileUrl}}
|
||||
title={{value.name}}
|
||||
>
|
||||
{{value.username}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if isSubmittedAt}}
|
||||
<span class="submission-date" title={{value.value}}>
|
||||
{{d-icon "clock"}}{{format-date value format="tiny"}}
|
||||
</span>
|
||||
{{/if}}
|
161
assets/javascripts/discourse/templates/components/wizard-table-field.hbs
Normale Datei
161
assets/javascripts/discourse/templates/components/wizard-table-field.hbs
Normale Datei
|
@ -0,0 +1,161 @@
|
|||
{{#if hasValue}}
|
||||
{{#if isText}}
|
||||
{{value.value}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isLongtext}}
|
||||
<div class="wizard-table-long-text">
|
||||
<p class="wizard-table-long-text-content {{textState}}">
|
||||
{{value.value}}
|
||||
</p>
|
||||
<a href {{action "expandText"}}>
|
||||
{{toggleText}}
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if isComposer}}
|
||||
<div class="wizard-table-long-text">
|
||||
<p class="wizard-table-composer-text wizard-table-long-text-content {{textState}}">
|
||||
{{value.value}}
|
||||
</p>
|
||||
<a href {{action "expandText"}}>
|
||||
{{toggleText}}
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if isComposerPreview}}
|
||||
{{d-icon "comment-alt"}}
|
||||
<span class="wizard-table-composer-text">
|
||||
{{i18n "admin.wizard.submissions.composer_preview"}}: {{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isTextOnly}}
|
||||
{{value.value}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isDate}}
|
||||
<span class="wizard-table-icon-item">
|
||||
{{d-icon "calendar"}}{{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isTime}}
|
||||
<span class="wizard-table-icon-item">
|
||||
{{d-icon "clock"}}{{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isDateTime}}
|
||||
<span class="wizard-table-icon-item" title={{value.value}}>
|
||||
{{d-icon "calendar"}}{{format-date value.value format="medium"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isNumber}}
|
||||
{{value.value}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isCheckbox}}
|
||||
{{#if checkboxValue}}
|
||||
<span class="wizard-table-icon-item checkbox-true">
|
||||
{{d-icon "check"}}{{value.value}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="wizard-table-icon-item checkbox-false">
|
||||
{{d-icon "times"}}{{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isUrl}}
|
||||
<span class="wizard-table-icon-item url">
|
||||
{{d-icon "link"}}
|
||||
<a target="_blank" rel="noopener noreferrer" href={{value.value}}>
|
||||
{{value.value}}
|
||||
</a>
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isUpload}}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="attachment"
|
||||
href={{file.url}}
|
||||
download
|
||||
>
|
||||
{{file.original_filename}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if isDropdown}}
|
||||
<span class="wizard-table-icon-item">
|
||||
{{d-icon "check-square"}}
|
||||
{{value.value}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if isTag}}
|
||||
{{#each value.value as |tag|}}
|
||||
{{discourse-tag tag}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isCategory}}
|
||||
<strong>
|
||||
{{i18n "admin.wizard.submissions.category_id"}}:
|
||||
</strong>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={{categoryUrl}}
|
||||
title={{value.value}}
|
||||
>
|
||||
{{value.value}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if isGroup}}
|
||||
<strong>
|
||||
{{i18n "admin.wizard.submissions.group_id"}}:
|
||||
</strong>
|
||||
{{value.value}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isUserSelector}}
|
||||
{{#each submittedUsers as |user|}}
|
||||
{{d-icon "user"}}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={{user.url}}
|
||||
title={{user.username}}
|
||||
>
|
||||
{{user.username}}
|
||||
</a>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isUser}}
|
||||
{{#link-to "user" value}}
|
||||
{{avatar value imageSize="tiny"}}
|
||||
{{/link-to}}
|
||||
{{/if}}
|
||||
|
||||
{{#if showUsername}}
|
||||
<a target="_blank" rel="noopener noreferrer" href={{userProfileUrl}} title={{username}}>
|
||||
{{username}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if isSubmittedAt}}
|
||||
<span class="date" title={{value.value}}>
|
||||
{{d-icon "clock"}}{{format-date value format="tiny"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
—
|
||||
{{/if}}
|
|
@ -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}}
|
||||
<div class="edit-directory-columns-container">
|
||||
{{#each model.fields as |field|}}
|
||||
{{#each model.columns as |column|}}
|
||||
<div class="edit-directory-column">
|
||||
<div class="left-content">
|
||||
<label class="column-name">
|
||||
{{input type="checkbox" checked=field.enabled}}
|
||||
{{directory-table-header-title field=field.label translated=true}}
|
||||
{{input type="checkbox" checked=column.enabled}}
|
||||
{{directory-table-header-title field=column.label translated=true}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"result": {
|
||||
"line": 91.96
|
||||
"line": 92.14
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Laden …
In neuem Issue referenzieren