Merge pull request #142 from paviliondev/ui_conventions
UX: Update Submissions Admin UI
Dieser Commit ist enthalten in:
Commit
3383aec37f
18 geänderte Dateien mit 609 neuen und 36 gelöschten Zeilen
112
assets/javascripts/discourse/components/submission-field.js.es6
Normale Datei
112
assets/javascripts/discourse/components/submission-field.js.es6
Normale Datei
|
@ -0,0 +1,112 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
isText: equal("value.type", "text"),
|
||||
isComposer: equal("value.type", "composer"),
|
||||
isDate: equal("value.type", "date"),
|
||||
isTime: equal("value.type", "time"),
|
||||
isDateTime: equal("value.type", "date_time"),
|
||||
isNumber: equal("value.type", "number"),
|
||||
isCheckbox: equal("value.type", "checkbox"),
|
||||
isUrl: equal("value.type", "url"),
|
||||
isUpload: equal("value.type", "upload"),
|
||||
isDropdown: equal("value.type", "dropdown"),
|
||||
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"),
|
||||
isComposerPreview: equal("value.type", "composer_preview"),
|
||||
textState: "text-collapsed",
|
||||
toggleText: I18n.t("admin.wizard.submissions.expand_text"),
|
||||
|
||||
@discourseComputed("value")
|
||||
checkboxValue(value) {
|
||||
const isCheckbox = this.get("isCheckbox");
|
||||
if (isCheckbox) {
|
||||
if (value.value.includes("true")) {
|
||||
return true;
|
||||
} else if (value.value.includes("false")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
expandText() {
|
||||
const state = this.get("textState");
|
||||
|
||||
if (state === "text-collapsed") {
|
||||
this.set("textState", "text-expanded");
|
||||
this.set("toggleText", I18n.t("admin.wizard.submissions.collapse_text"));
|
||||
} else if (state === "text-expanded") {
|
||||
this.set("textState", "text-collapsed");
|
||||
this.set("toggleText", I18n.t("admin.wizard.submissions.expand_text"));
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("value")
|
||||
file(value) {
|
||||
const isUpload = this.get("isUpload");
|
||||
if (isUpload) {
|
||||
return value.value;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("value")
|
||||
submittedUsers(value) {
|
||||
const isUserSelector = this.get("isUserSelector");
|
||||
const users = [];
|
||||
|
||||
if (isUserSelector) {
|
||||
const userData = value.value;
|
||||
const usernames = [];
|
||||
|
||||
if (userData.indexOf(",")) {
|
||||
usernames.push(...userData.split(","));
|
||||
|
||||
usernames.forEach((u) => {
|
||||
const user = {
|
||||
username: u,
|
||||
url: `/u/${u}`,
|
||||
};
|
||||
users.push(user);
|
||||
});
|
||||
}
|
||||
}
|
||||
return users;
|
||||
},
|
||||
|
||||
@discourseComputed("value")
|
||||
userProfileUrl(value) {
|
||||
const isUser = this.get("isUser");
|
||||
|
||||
if (isUser) {
|
||||
return `/u/${value.username}`;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("value")
|
||||
categoryUrl(value) {
|
||||
const isCategory = this.get("isCategory");
|
||||
|
||||
if (isCategory) {
|
||||
return `/c/${value.value}`;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("value")
|
||||
groupUrl(value) {
|
||||
const isGroup = this.get("isGroup");
|
||||
|
||||
if (isGroup) {
|
||||
return `/g/${value.value}`;
|
||||
}
|
||||
},
|
||||
});
|
|
@ -9,6 +9,8 @@ export default Controller.extend({
|
|||
page: 0,
|
||||
canLoadMore: true,
|
||||
logs: [],
|
||||
documentationUrl: "https://thepavilion.io/t/2818",
|
||||
messageKey: "viewing",
|
||||
|
||||
loadLogs() {
|
||||
if (!this.canLoadMore) {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import Controller from "@ember/controller";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
actions: {
|
||||
save() {
|
||||
this.send("closeModal");
|
||||
},
|
||||
resetToDefault() {
|
||||
this.get("model.fields").forEach((field) => {
|
||||
field.set("enabled", true);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,6 +1,8 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import CustomWizard from "../models/custom-wizard";
|
||||
|
||||
export default Controller.extend({
|
||||
|
@ -25,6 +27,24 @@ export default Controller.extend({
|
|||
});
|
||||
},
|
||||
|
||||
@discourseComputed("submissions", "fields.@each.enabled")
|
||||
displaySubmissions(submissions, fields) {
|
||||
let result = [];
|
||||
|
||||
submissions.forEach((submission) => {
|
||||
let sub = {};
|
||||
|
||||
Object.keys(submission).forEach((fieldId) => {
|
||||
if (fields.some((f) => f.id === fieldId && f.enabled)) {
|
||||
sub[fieldId] = submission[fieldId];
|
||||
}
|
||||
});
|
||||
result.push(sub);
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
if (!this.loadingMore && this.submissions.length < this.total) {
|
||||
|
@ -32,5 +52,14 @@ export default Controller.extend({
|
|||
this.loadMoreSubmissions();
|
||||
}
|
||||
},
|
||||
|
||||
showEditColumnsModal() {
|
||||
return showModal("admin-wizards-submissions-columns", {
|
||||
model: {
|
||||
fields: this.get("fields"),
|
||||
submissions: this.get("submissions"),
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||
|
||||
export default Controller.extend({
|
||||
documentationUrl: "https://thepavilion.io/t/2818",
|
||||
|
||||
@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";
|
||||
}
|
||||
|
||||
return key;
|
||||
},
|
||||
});
|
|
@ -1,10 +1,10 @@
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
import EmberObject from "@ember/object";
|
||||
import { buildProperties, mapped, present } from "../lib/wizard-json";
|
||||
import { listProperties, snakeCase } from "../lib/wizard";
|
||||
import wizardSchema from "../lib/wizard-schema";
|
||||
import { Promise } from "rsvp";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { Promise } from "rsvp";
|
||||
import { listProperties, snakeCase } from "../lib/wizard";
|
||||
import { buildProperties, mapped, present } from "../lib/wizard-json";
|
||||
import wizardSchema from "../lib/wizard-schema";
|
||||
|
||||
const CustomWizard = EmberObject.extend({
|
||||
save(opts) {
|
||||
|
@ -224,31 +224,32 @@ CustomWizard.reopenClass({
|
|||
})
|
||||
.then((result) => {
|
||||
if (result.wizard) {
|
||||
let fields = ["username"];
|
||||
let fields = [{ id: "username", label: "User" }];
|
||||
let submissions = [];
|
||||
let wizard = result.wizard;
|
||||
let total = result.total;
|
||||
|
||||
result.submissions.forEach((s) => {
|
||||
let submission = {
|
||||
username: s.username,
|
||||
username: s.user,
|
||||
};
|
||||
|
||||
Object.keys(s.fields).forEach((f) => {
|
||||
if (fields.indexOf(f) < 0) {
|
||||
fields.push(f);
|
||||
}
|
||||
|
||||
if (fields.includes(f)) {
|
||||
submission[f] = s.fields[f];
|
||||
Object.keys(s.fields).forEach((fieldId) => {
|
||||
if (!fields.some((field) => field.id === fieldId)) {
|
||||
fields.push({ id: fieldId, label: s.fields[fieldId].label });
|
||||
}
|
||||
submission[fieldId] = s.fields[fieldId];
|
||||
});
|
||||
|
||||
submission["submitted_at"] = s.submitted_at;
|
||||
submissions.push(submission);
|
||||
});
|
||||
|
||||
fields.push("submitted_at");
|
||||
let submittedAt = {
|
||||
id: "submitted_at",
|
||||
label: "Submitted At",
|
||||
};
|
||||
|
||||
fields.push(submittedAt);
|
||||
|
||||
return {
|
||||
wizard,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import CustomWizard from "../models/custom-wizard";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { A } from "@ember/array";
|
||||
import EmberObject from "@ember/object";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import CustomWizard from "../models/custom-wizard";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model(params) {
|
||||
|
@ -8,9 +9,14 @@ export default DiscourseRoute.extend({
|
|||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
const fields = model.fields.map((f) => {
|
||||
const fieldsObject = EmberObject.create(f);
|
||||
fieldsObject.enabled = true;
|
||||
return fieldsObject;
|
||||
});
|
||||
controller.setProperties({
|
||||
wizard: model.wizard,
|
||||
fields: model.fields,
|
||||
fields: A(fields),
|
||||
submissions: A(model.submissions),
|
||||
total: model.total,
|
||||
});
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
class="refresh"}}
|
||||
</div>
|
||||
|
||||
{{wizard-message
|
||||
key=messageKey
|
||||
opts=messageOpts
|
||||
url=documentationUrl
|
||||
component="logs"}}
|
||||
|
||||
{{#load-more selector=".log-list tr" action=(action "loadMore") class="wizard-logs"}}
|
||||
{{#if noResults}}
|
||||
<p>{{i18n "search.no_results"}}</p>
|
||||
|
|
|
@ -1,8 +1,24 @@
|
|||
{{#if submissions}}
|
||||
<div class="wizard-header large">
|
||||
<label>{{i18n "admin.wizard.submissions.title" name=wizard.name}}</label>
|
||||
<label>
|
||||
{{i18n "admin.wizard.submissions.title" name=wizard.name}}
|
||||
</label>
|
||||
|
||||
<a class="btn btn-default download-link" href={{downloadUrl}} target="_blank" rel="noopener noreferrer">
|
||||
<div class="controls">
|
||||
{{d-button
|
||||
icon="sliders-h"
|
||||
label="admin.wizard.submissions.edit_columns"
|
||||
action=(action "showEditColumnsModal")
|
||||
class="btn-default open-edit-columns-btn download-link"
|
||||
}}
|
||||
</div>
|
||||
|
||||
<a
|
||||
class="btn btn-default download-link"
|
||||
href={{downloadUrl}}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{d-icon "download"}}
|
||||
<span class="d-button-label">
|
||||
{{i18n "admin.wizard.submissions.download"}}
|
||||
|
@ -13,21 +29,29 @@
|
|||
<div class="wizard-submissions">
|
||||
{{#load-more selector=".wizard-submissions tr" action=(action "loadMore")}}
|
||||
{{#if noResults}}
|
||||
<p>{{i18n "search.no_results"}}</p>
|
||||
<p>
|
||||
{{i18n "search.no_results"}}
|
||||
</p>
|
||||
{{else}}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
{{#each fields as |f|}}
|
||||
<th>{{f}}</th>
|
||||
{{#each fields as |field|}}
|
||||
{{#if field.enabled}}
|
||||
<th>
|
||||
{{field.label}}
|
||||
</th>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each submissions as |s|}}
|
||||
{{#each displaySubmissions as |submission|}}
|
||||
<tr>
|
||||
{{#each-in s as |k v|}}
|
||||
<td>{{v}}</td>
|
||||
{{#each-in submission as |field value|}}
|
||||
<td>
|
||||
{{submission-field fieldName=field value=value}}
|
||||
</td>
|
||||
{{/each-in}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="admin-wizard-select">
|
||||
<div class="admin-wizard-select admin-wizard-controls">
|
||||
{{combo-box
|
||||
value=wizardId
|
||||
content=wizardList
|
||||
|
@ -8,6 +8,12 @@
|
|||
)}}
|
||||
</div>
|
||||
|
||||
{{wizard-message
|
||||
key=messageKey
|
||||
opts=messageOpts
|
||||
url=documentationUrl
|
||||
component="submissions"}}
|
||||
|
||||
<div class="admin-wizard-container">
|
||||
{{outlet}}
|
||||
</div>
|
||||
|
|
163
assets/javascripts/discourse/templates/components/submission-field.hbs
Normale Datei
163
assets/javascripts/discourse/templates/components/submission-field.hbs
Normale Datei
|
@ -0,0 +1,163 @@
|
|||
{{#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}}
|
|
@ -0,0 +1,32 @@
|
|||
{{#d-modal-body title="directory.edit_columns.title"}}
|
||||
{{#if loading}}
|
||||
{{loading-spinner size="large"}}
|
||||
{{else}}
|
||||
<div class="edit-directory-columns-container">
|
||||
{{#each model.fields as |field|}}
|
||||
<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}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer">
|
||||
{{d-button
|
||||
class="btn-primary"
|
||||
label="directory.edit_columns.save"
|
||||
action=(action "save")
|
||||
}}
|
||||
|
||||
{{d-button
|
||||
class="btn-secondary reset-to-default"
|
||||
label="directory.edit_columns.reset_to_default"
|
||||
action=(action "resetToDefault")
|
||||
}}
|
||||
</div>
|
|
@ -72,6 +72,51 @@
|
|||
table td {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
table thead th {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.submission-icon-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
svg {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.submission-checkbox-true {
|
||||
text-transform: capitalize;
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.submission-checkbox-false {
|
||||
text-transform: capitalize;
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.submission-long-text {
|
||||
&-content {
|
||||
white-space: nowrap;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 250px;
|
||||
margin-bottom: 0;
|
||||
|
||||
&.text-expanded {
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: var(--font-down-1);
|
||||
}
|
||||
}
|
||||
|
||||
.submission-composer-text {
|
||||
font-family: monospace;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-wizards-logs {
|
||||
|
@ -204,6 +249,11 @@
|
|||
&.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin-left: auto;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-wizard-buttons {
|
||||
|
|
|
@ -94,6 +94,14 @@ en:
|
|||
destroying: Destroying wizards...
|
||||
import_complete: Import complete
|
||||
destroy_complete: Destruction complete
|
||||
submissions:
|
||||
select: "Select a wizard to see its submissions"
|
||||
viewing: "You're viewing the submissions of the %{wizardName}. Click 'Download' on the right to download them."
|
||||
documentation: "Check out the submissions documentation"
|
||||
logs:
|
||||
viewing: "View recent logs for wizards on the forum"
|
||||
documentation: "Check out the logs documentation"
|
||||
|
||||
|
||||
editor:
|
||||
show: "Show"
|
||||
|
@ -362,6 +370,12 @@ 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"
|
||||
|
||||
api:
|
||||
label: "API"
|
||||
|
|
|
@ -32,7 +32,8 @@ class CustomWizard::Wizard
|
|||
:actions,
|
||||
:action_ids,
|
||||
:user,
|
||||
:submissions
|
||||
:submissions,
|
||||
:template
|
||||
|
||||
attr_reader :all_step_ids
|
||||
|
||||
|
@ -79,6 +80,7 @@ class CustomWizard::Wizard
|
|||
|
||||
@actions = attrs['actions'] || []
|
||||
@action_ids = @actions.map { |a| a['id'] }
|
||||
@template = attrs
|
||||
end
|
||||
|
||||
def cast_bool(val)
|
||||
|
|
|
@ -33,6 +33,13 @@ if respond_to?(:register_svg_icon)
|
|||
register_svg_icon "chevron-right"
|
||||
register_svg_icon "chevron-left"
|
||||
register_svg_icon "save"
|
||||
register_svg_icon "sliders-h"
|
||||
register_svg_icon "calendar"
|
||||
register_svg_icon "check"
|
||||
register_svg_icon "times"
|
||||
register_svg_icon "clock"
|
||||
register_svg_icon "link"
|
||||
register_svg_icon "comment-alt"
|
||||
register_svg_icon "far-life-ring"
|
||||
register_svg_icon "arrow-right"
|
||||
end
|
||||
|
|
|
@ -1,13 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::SubmissionSerializer < ApplicationSerializer
|
||||
attributes :id,
|
||||
:username,
|
||||
:fields,
|
||||
:submitted_at
|
||||
|
||||
def username
|
||||
object.user.present? ?
|
||||
object.user.username :
|
||||
I18n.t('admin.wizard.submission.no_user', user_id: object.user_id)
|
||||
has_one :user, serializer: ::BasicUserSerializer, embed: :objects
|
||||
|
||||
def include_user?
|
||||
object.user.present?
|
||||
end
|
||||
|
||||
def fields
|
||||
@fields ||= begin
|
||||
result = {}
|
||||
|
||||
object.wizard.template['steps'].each do |step|
|
||||
step['fields'].each do |field|
|
||||
if value = object.fields[field['id']]
|
||||
result[field['id']] = {
|
||||
value: value,
|
||||
type: field['type'],
|
||||
label: field['label']
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
51
spec/serializers/custom_wizard/submission_serializer_spec.rb
Normale Datei
51
spec/serializers/custom_wizard/submission_serializer_spec.rb
Normale Datei
|
@ -0,0 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../plugin_helper'
|
||||
|
||||
describe CustomWizard::SubmissionSerializer do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
|
||||
let(:template_json) {
|
||||
JSON.parse(File.open(
|
||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||
).read)
|
||||
}
|
||||
|
||||
before do
|
||||
CustomWizard::Template.save(template_json, skip_jobs: true)
|
||||
wizard = CustomWizard::Wizard.create(template_json["id"], user)
|
||||
CustomWizard::Submission.new(wizard,
|
||||
step_1_field_1: "I am user submission",
|
||||
submitted_at: Time.now.iso8601
|
||||
).save
|
||||
@list = CustomWizard::Submission.list(wizard, page: 0)
|
||||
end
|
||||
|
||||
it 'should return submission attributes' do
|
||||
json_array = ActiveModel::ArraySerializer.new(
|
||||
@list.submissions,
|
||||
each_serializer: described_class
|
||||
).as_json
|
||||
|
||||
expect(json_array.length).to eq(1)
|
||||
expect(json_array[0][:id].present?).to eq(true)
|
||||
expect(json_array[0][:user].present?).to eq(true)
|
||||
expect(json_array[0][:submitted_at].present?).to eq(true)
|
||||
end
|
||||
|
||||
it "should return field values, types and labels" do
|
||||
json_array = ActiveModel::ArraySerializer.new(
|
||||
@list.submissions,
|
||||
each_serializer: described_class
|
||||
).as_json
|
||||
|
||||
expect(json_array.length).to eq(1)
|
||||
expect(json_array[0][:fields].as_json).to eq({
|
||||
"step_1_field_1": {
|
||||
"value": "I am user submission",
|
||||
"type": "text",
|
||||
"label": "Text"
|
||||
}
|
||||
}.as_json)
|
||||
end
|
||||
end
|
Laden …
In neuem Issue referenzieren