diff --git a/quasar.conf.js b/quasar.conf.js index 1511b82..f0400c0 100644 --- a/quasar.conf.js +++ b/quasar.conf.js @@ -7,7 +7,7 @@ module.exports = function (context) { boot: [ 'browse', 'components', - 'dev', + 'development', 'i18n', 'message', 'service', diff --git a/src/app/Prototype/Components/Buttons/PrototypeButtonDropdown.js b/src/app/Prototype/Components/Buttons/PrototypeButtonDropdown.js new file mode 100644 index 0000000..28d7206 --- /dev/null +++ b/src/app/Prototype/Components/Buttons/PrototypeButtonDropdown.js @@ -0,0 +1,35 @@ +/** + * @typedef {PrototypeButtonDropdown} + */ +export default { + /** + */ + methods: { + /** + * @param {Function} h + * @param {Object} data + * @returns {*} + */ + renderButtonDropdown (h, data) { + // TODO: implement dropdown items + /* + + + + {{ action.label }} + + + + */ + data.attrs.split = true + + return h('q-btn-dropdown', data) + } + } +} diff --git a/src/app/Prototype/Components/Buttons/PrototypeButtonParse.js b/src/app/Prototype/Components/Buttons/PrototypeButtonParse.js new file mode 100644 index 0000000..d2c47d5 --- /dev/null +++ b/src/app/Prototype/Components/Buttons/PrototypeButtonParse.js @@ -0,0 +1,50 @@ +/** + * @typedef {PrototypeButtonParse} + */ +export default { + /** + */ + methods: { + /** + * @param {Object} button + * @returns {Object} + */ + parseAttrs (button) { + return { ...button.attrs, ...this.override } + }, + /** + * @param {Object} button + * @returns {Object} + */ + parseListeners (button) { + if (typeof button.listeners !== 'object') { + return button.listeners + } + let context = {} + if (this.context) { + context = this.$util.clone(this.context) + } + const reduce = (listeners, key) => { + listeners[key] = ($event) => button.listeners[key]($event, { context }) + return listeners + } + return Object.keys(button.listeners).reduce(reduce, {}) + }, + /** + * @param {Object} button + */ + parseButton (button) { + let action = button + if (button.configure && typeof button.configure === 'function') { + const clone = this.$util.clone(button) + const parameters = { context: this.context, position: this.position, scope: this.scope } + action = button.configure.call(this, clone, parameters) + } + return { + ...action, + attrs: this.parseAttrs(action), + listeners: this.parseListeners(action) + } + } + } +} diff --git a/src/app/Prototype/Components/Buttons/PrototypeButtonSingle.js b/src/app/Prototype/Components/Buttons/PrototypeButtonSingle.js new file mode 100644 index 0000000..904286a --- /dev/null +++ b/src/app/Prototype/Components/Buttons/PrototypeButtonSingle.js @@ -0,0 +1,17 @@ +/** + * @typedef {PrototypeButtonSingle} + */ +export default { + /** + */ + methods: { + /** + * @param {Function} h + * @param {Object} data + * @returns {*} + */ + renderButtonSingle (h, data) { + return h('q-btn', data) + } + } +} diff --git a/src/app/Prototype/Components/Form/PrototypeComponents.js b/src/app/Prototype/Components/Form/PrototypeComponents.js index d8312cf..08a27b0 100644 --- a/src/app/Prototype/Components/Form/PrototypeComponents.js +++ b/src/app/Prototype/Components/Form/PrototypeComponents.js @@ -1,10 +1,18 @@ -import PrototypeError from 'src/app/Prototype/Components/Form/PrototypeError' +import PrototypeError from './PrototypeError' +import PrototypeFieldComponent from './PrototypeFieldComponent' +import PrototypeFieldLabel from './PrototypeFieldLabel' +import PrototypeFieldError from './PrototypeFieldError' /** * @typedef {PrototypeFormComponents} */ export default { name: 'PrototypeFormComponents', + /** + */ + mixins: [ + PrototypeFieldLabel, PrototypeFieldComponent, PrototypeFieldError + ], /** */ components: { @@ -16,25 +24,8 @@ export default { fields: { type: Object, default: () => ({}) - }, - value: { - type: Object, - default: () => ({}) - }, - errors: { - type: Object, - default: () => ({}) - }, - validations: { - type: Object, - default: () => ({}) } }, - /** - */ - data: () => ({ - record: {} - }), /** */ methods: { @@ -45,7 +36,7 @@ export default { renderField (h, field) { const key = field.$key - const error = this.hasError(key) + const error = this.fieldHasError(key) const style = { display: field.$layout.formHidden ? 'none' : '' } @@ -63,39 +54,6 @@ export default { return h('div', data, children) }, - /** - * @param {Function} h - * @param {Object} field - * @returns {*} - */ - renderFieldLabel (h, field) { - return h('label', { domProps: { innerHTML: this.labelContent(field) } }) - }, - /** - * @param {Function} h - * @param {Object} field - * @returns {*} - */ - renderFieldComponent (h, field) { - const key = field.$key - - return h(field.is, { - ref: this.componentRef(field), - domProps: { tabIndex: this.componentTabIndex(), value: this.record[key] }, - props: { value: this.record[key] }, - attrs: { ...field.attrs }, - on: { ...field.listeners, input: ($event) => this.componentInput($event, field) } - }) - }, - /** - * @param {Function} h - * @param {string} key - * @param {boolean} error - * @returns {*} - */ - renderFieldError (h, key, error) { - return h('prototype-error', { attrs: { show: error, message: this.errorContent(key) } }) - }, /** * @param {string|number} width * @param {string|number} height @@ -109,45 +67,10 @@ export default { } return classNames }, - /** - * @param {Object} field - * @returns {string} - */ - labelContent (field) { - // Se o field não possuir label, ele não exibe (*) - return (!field.label) ? '' : `${field.label} ${field.$required ? '*' : ''}` - }, - /** - * @param {Object} field - */ - componentRef (field) { - return `form:component-${field.$layout.formOrder}` - }, - /** - * @returns {number} - */ - componentTabIndex () { - if (!this.counter) { - this.counter = 0 - } - this.counter++ - return this.counter - }, - /** - * @param {Object} $event - * @param {Object} component - */ - componentInput ($event, component) { - this.record[component.$key] = component.parseInput($event) - this.$emit('input', component.$key, component.parseInput($event)) - if (component.listeners.input) { - component.listeners.input($event) - } - }, /** * @param {string} key */ - hasError (key) { + fieldHasError (key) { if (this.errors[key]) { return true } @@ -156,52 +79,8 @@ export default { return false } return record[key].$error - }, - /** - * @param {string} key - * @returns {string} - */ - errorContent (key) { - const errorMessages = [] - const forEach = (validation) => { - if (!validations[validation]) { - let translation = `domains.${this.domain}.validations.${validation}`.replace(/\//g, '.') - if (!this.$te(translation)) { - translation = `validation.${validation}` - } - errorMessages.push(this.$t(translation, validations.$params[validation])) - } - } - - const validations = this.$util.prop(this.validations, `record.${key}`) - if (validations) { - Object.keys(validations.$params).forEach(forEach) - } - if (this.errors[key]) { - errorMessages.push(this.errors[key]) - } - return errorMessages.join(' / ') - } - }, - /** - */ - watch: { - /** - * @param value - */ - value: { - deep: true, - handler (value) { - this.record = this.$util.clone(value) - } } }, - /** - */ - created () { - this.counter = 1 - this.record = this.$util.clone(this.value) - }, /** * @param {Function} h * @returns {*} @@ -210,6 +89,7 @@ export default { // console.log('~> render', this.$options.name, JSON.stringify(this.record)) const data = { class: 'form form-grid' } const children = Object.values(this.fields).map((field) => this.renderField(h, field)) + return h('div', data, children) } } diff --git a/src/app/Prototype/Components/Form/PrototypeFieldComponent.js b/src/app/Prototype/Components/Form/PrototypeFieldComponent.js new file mode 100644 index 0000000..3bd93f3 --- /dev/null +++ b/src/app/Prototype/Components/Form/PrototypeFieldComponent.js @@ -0,0 +1,88 @@ +/** + * @typedef {PrototypeFieldComponent} + */ +export default { + /** + */ + props: { + value: { + type: Object, + default: () => ({}) + }, + validations: { + type: Object, + default: () => ({}) + } + }, + /** + */ + data: () => ({ + record: {} + }), + /** + */ + methods: { + /** + * @param {Object} field + */ + componentRef (field) { + return `form:component-${field.$layout.formOrder}` + }, + /** + * @returns {number} + */ + componentTabIndex () { + if (!this.counter) { + this.counter = 0 + } + this.counter++ + return this.counter + }, + /** + * @param {Object} $event + * @param {Object} component + */ + componentInput ($event, component) { + this.record[component.$key] = component.parseInput($event) + this.$emit('input', component.$key, component.parseInput($event)) + if (component.listeners.input) { + component.listeners.input($event) + } + }, + /** + * @param {Function} h + * @param {Object} field + * @returns {*} + */ + renderFieldComponent (h, field) { + const key = field.$key + + return h(field.is, { + ref: this.componentRef(field), + domProps: { tabIndex: this.componentTabIndex(), value: this.record[key] }, + props: { value: this.record[key] }, + attrs: { ...field.attrs }, + on: { ...field.listeners, input: ($event) => this.componentInput($event, field) } + }) + } + }, + /** + */ + watch: { + /** + * @param value + */ + value: { + deep: true, + handler (value) { + this.record = this.$util.clone(value) + } + } + }, + /** + */ + created () { + this.counter = 1 + this.record = this.$util.clone(this.value) + } +} diff --git a/src/app/Prototype/Components/Form/PrototypeFieldError.js b/src/app/Prototype/Components/Form/PrototypeFieldError.js new file mode 100644 index 0000000..745c9f3 --- /dev/null +++ b/src/app/Prototype/Components/Form/PrototypeFieldError.js @@ -0,0 +1,51 @@ +/** + * @typedef {PrototypeFieldError} + */ +export default { + /** + */ + props: { + errors: { + type: Object, + default: () => ({}) + } + }, + /** + */ + methods: { + /** + * @param {string} key + * @returns {string} + */ + errorContent (key) { + const errorMessages = [] + const forEach = (validation) => { + if (!validations[validation]) { + let translation = `domains.${this.domain}.validations.${validation}`.replace(/\//g, '.') + if (!this.$te(translation)) { + translation = `validation.${validation}` + } + errorMessages.push(this.$t(translation, validations.$params[validation])) + } + } + + const validations = this.$util.prop(this.validations, `record.${key}`) + if (validations) { + Object.keys(validations.$params).forEach(forEach) + } + if (this.errors[key]) { + errorMessages.push(this.errors[key]) + } + return errorMessages.join(' / ') + }, + /** + * @param {Function} h + * @param {string} key + * @param {boolean} error + * @returns {*} + */ + renderFieldError (h, key, error) { + return h('prototype-error', { attrs: { show: error, message: this.errorContent(key) } }) + } + } +} diff --git a/src/app/Prototype/Components/Form/PrototypeFieldLabel.js b/src/app/Prototype/Components/Form/PrototypeFieldLabel.js new file mode 100644 index 0000000..71fe31c --- /dev/null +++ b/src/app/Prototype/Components/Form/PrototypeFieldLabel.js @@ -0,0 +1,25 @@ +/** + * @typedef {PrototypeFieldLabel} + */ +export default { + /** + */ + methods: { + /** + * @param {Function} h + * @param {Object} field + * @returns {*} + */ + renderFieldLabel (h, field) { + return h('label', { domProps: { innerHTML: this.labelContent(field) } }) + }, + /** + * @param {Object} field + * @returns {string} + */ + labelContent (field) { + // Se o field não possuir label, ele não exibe (*) + return (!field.label) ? '' : `${field.label} ${field.$required ? '*' : ''}` + } + } +} diff --git a/src/app/Prototype/Components/PrototypeButtons.js b/src/app/Prototype/Components/PrototypeButtons.js index b1cec97..68bf170 100644 --- a/src/app/Prototype/Components/PrototypeButtons.js +++ b/src/app/Prototype/Components/PrototypeButtons.js @@ -1,5 +1,17 @@ +import PrototypeButtonParse from './Buttons/PrototypeButtonParse' +import PrototypeButtonDropdown from './Buttons/PrototypeButtonDropdown' +import PrototypeButtonSingle from './Buttons/PrototypeButtonSingle' + +/** + * @typedef {PrototypeButtons} + */ export default { name: 'PrototypeButtons', + /** + */ + mixins: [ + PrototypeButtonParse, PrototypeButtonDropdown, PrototypeButtonSingle + ], /** */ props: { @@ -60,85 +72,11 @@ export default { } return this.renderButtonSingle(h, data) }, - /** - * @param {Function} h - * @param {Object} data - * @returns {*} - */ - renderButtonDropdown (h, data) { - // TODO: implement dropdown items - /* - - - - {{ action.label }} - - - - */ - data.attrs.split = true - return h('q-btn-dropdown', data) - }, - /** - * @param {Function} h - * @param {Object} data - * @returns {*} - */ - renderButtonSingle (h, data) { - return h('q-btn', data) - }, /** * @param {string} key */ buttonRef (key) { return `form:button-${key}` - }, - /** - * @param {Object} button - * @returns {Object} - */ - parseAttrs (button) { - return { ...button.attrs, ...this.override } - }, - /** - * @param {Object} button - * @returns {Object} - */ - parseListeners (button) { - if (typeof button.listeners !== 'object') { - return button.listeners - } - let context = {} - if (this.context) { - context = this.$util.clone(this.context) - } - const reduce = (listeners, key) => { - listeners[key] = ($event) => button.listeners[key]($event, { context }) - return listeners - } - return Object.keys(button.listeners).reduce(reduce, {}) - }, - /** - * @param {Object} button - */ - parseButton (button) { - let action = button - if (button.configure && typeof button.configure === 'function') { - const clone = this.$util.clone(button) - const parameters = { context: this.context, position: this.position, scope: this.scope } - action = button.configure.call(this, clone, parameters) - } - return { - ...action, - attrs: this.parseAttrs(action), - listeners: this.parseListeners(action) - } } }, /** @@ -149,6 +87,7 @@ export default { class: 'app-form-buttons' } const children = Object.values(this.actions).map((button) => this.renderButton(h, button)) + return h('div', data, children) } } diff --git a/src/app/Prototype/Components/PrototypeForm.js b/src/app/Prototype/Components/PrototypeForm.js index 6ceb509..5c6ccc5 100644 --- a/src/app/Prototype/Components/PrototypeForm.js +++ b/src/app/Prototype/Components/PrototypeForm.js @@ -27,12 +27,13 @@ export default { /** * @param {Function} h */ - renderFormWrapper (h) { + renderForm (h) { const data = { class: 'app-form-wrapper' } const children = [ this.renderFormBody(h), this.renderPrototypeButtons(h, 'form-footer', { record: this.record }) ] + return h('div', data, children) }, /** @@ -46,7 +47,6 @@ export default { const children = [ this.renderFormBodyComponents(h, this.getComponents()) ] - if (this.hasGroups) { Object.keys(this.groups).forEach((key) => { const data = { @@ -129,7 +129,7 @@ export default { } } const children = [ - this.renderFormWrapper(h), + this.renderForm(h), this.renderFormDebuggers(h) ] diff --git a/src/app/Prototype/Components/PrototypeTable.js b/src/app/Prototype/Components/PrototypeTable.js index 99d96b2..8d3463c 100644 --- a/src/app/Prototype/Components/PrototypeTable.js +++ b/src/app/Prototype/Components/PrototypeTable.js @@ -1,6 +1,8 @@ import Dynamic from '../Contracts/Dynamic' import Table from '../Contracts/Table' -import PrototypeButtons from 'src/app/Prototype/Components/PrototypeButtons' +import PrototypeSlots from 'src/app/Prototype/Components/Table/PrototypeSlots' + +import PrototypeButtons from './PrototypeButtons' /** * @typedef {PrototypeTable} @@ -15,14 +17,16 @@ export default { /** */ mixins: [ - Dynamic, Table + Dynamic, Table, PrototypeSlots ], + /** + */ methods: { /** * @param {Function} h * @returns {*} */ - renderTableWrapper (h) { + renderTable (h) { const attrs = { ...this.bind, data: this.data, @@ -41,141 +45,10 @@ export default { 'update:selected': (selected) => { this.selected = selected } } - const scopedSlots = { - 'top': (props) => { - return this.renderTableTop(h, props) - }, - 'body-cell-id': (props) => { - return this.renderTableCellButtons(h, props) - }, - 'pagination': (props) => { - return this.renderTablePagination(h, props) - } - } + const scopedSlots = this.renderTableSlots(h) return h('q-table', { class: 'PrototypeTable', props, attrs, on, scopedSlots }) }, - /** - * @param {Function} h - * @param {Object} props - * @returns {*} - */ - renderTableTop (h, props) { - return [ - this.renderTableColumnsSelector(h), - h('q-space'), - this.renderPrototypeButtonsCompact(h, 'table-top', { records: this.selected }), - h('q-space'), - this.renderTableSearch(h) - ] - }, - /** - * @param {Function} h - * @returns {*} - */ - renderTableColumnsSelector (h) { - const attrs = { - 'display-value': this.$q.lang.table.columns, - 'multiple': true, - 'borderless': true, - 'dense': true, - 'options-dense': true, - 'emit-value': true, - 'map-options': true, - 'options': this.columns, - 'option-value': 'name' - } - const props = { - value: this.visibleColumns - } - const style = { - 'min-width': '150px' - } - const on = { - input: (visibleColumns) => { this.visibleColumns = visibleColumns } - } - - return h('q-select', { attrs, props, on, style }) - }, - /** - * @param {Function} h - * @returns {*} - */ - renderTableSearch (h) { - const attrs = { - dense: true, - debounce: 300, - placeholder: this.$t('prototype.table.search') - } - const props = { - value: this.filter - } - const on = { - input: (filter) => { - this.filter = filter - this.search() - } - } - const scopedSlots = { - append: () => h('q-icon', { attrs: { name: 'search' } }) - } - - return h('q-input', { attrs, props, on, scopedSlots }) - }, - /** - * @param {Function} h - * @param {Object} props - * @returns {*} - */ - renderTableCellButtons (h, props) { - const data = { - style: { position: 'relative' } - } - const children = [ - props.row[this.primaryKey], - this.renderPrototypeButtonsCompact(h, 'table-cell', { record: props.row }) - ] - - return h('q-td', data, children) - }, - /** - * @param {Function} h - * @param {Object} props - * @returns {*} - */ - renderTablePagination (h, props) { - const texts = [ - props.pagination.rowsPerPage * (props.pagination.page - 1) + 1, '-' - ] - let fragment = props.pagination.rowsPerPage * (props.pagination.page) - if (props.isLastPage) { - fragment = props.pagination.rowsNumber - } - texts.push(fragment) - texts.push('/') - texts.push(props.pagination.rowsNumber) - - const button = { - round: true, dense: true, flat: true, textColor: 'grey-8' - } - - const previous = { - attrs: { ...button, disable: props.isFirstPage, icon: 'chevron_left' }, - on: { click: this.previousPage } - } - - const next = { - attrs: { ...button, disable: props.isLastPage, icon: 'chevron_right' }, - on: { click: this.nextPage } - } - - return [ - h('span', { class: 'q-table__bottom-item' }, texts.join(' ')), - h('q-btn', previous), - h('span', { class: 'text-center' }, `${props.pagination.page} / ${props.pagination.pagesNumber}`), - h('q-btn', next) - ] - }, /** * @param {Function} h */ @@ -199,7 +72,7 @@ export default { attrs: { padding: true } } const children = [ - this.renderTableWrapper(h), + this.renderTable(h), this.renderTableDebuggers(h) ] diff --git a/src/app/Prototype/Components/Table/PrototypeSlotTop.js b/src/app/Prototype/Components/Table/PrototypeSlotTop.js new file mode 100644 index 0000000..39d8078 --- /dev/null +++ b/src/app/Prototype/Components/Table/PrototypeSlotTop.js @@ -0,0 +1,54 @@ +/** + * @param {Function} h + * @returns {*} + */ +export const renderTableColumnsSelector = function (h) { + const attrs = { + 'display-value': this.$q.lang.table.columns, + 'multiple': true, + 'borderless': true, + 'dense': true, + 'options-dense': true, + 'emit-value': true, + 'map-options': true, + 'options': this.columns, + 'option-value': 'name' + } + const props = { + value: this.visibleColumns + } + const style = { + 'min-width': '150px' + } + const on = { + input: (visibleColumns) => { this.visibleColumns = visibleColumns } + } + + return h('q-select', { attrs, props, on, style }) +} + +/** + * @param {Function} h + * @returns {*} + */ +export const renderTableSearch = function (h) { + const attrs = { + dense: true, + debounce: 300, + placeholder: this.$t('prototype.table.search') + } + const props = { + value: this.filter + } + const on = { + input: (filter) => { + this.filter = filter + this.search() + } + } + const scopedSlots = { + append: () => h('q-icon', { attrs: { name: 'search' } }) + } + + return h('q-input', { attrs, props, on, scopedSlots }) +} diff --git a/src/app/Prototype/Components/Table/PrototypeSlots.js b/src/app/Prototype/Components/Table/PrototypeSlots.js new file mode 100644 index 0000000..c42767b --- /dev/null +++ b/src/app/Prototype/Components/Table/PrototypeSlots.js @@ -0,0 +1,106 @@ +import { renderTableColumnsSelector, renderTableSearch } from './PrototypeSlotTop' + +/** + * @typedef {PrototypeTop} + */ +export default { + /** + */ + methods: { + /** + * @param h + * @returns {*} + */ + renderTableSlots (h) { + return { + 'top': (props) => { + return this.renderTableTop(h, props) + }, + 'body-cell-id': (props) => { + return this.renderTableCellButtons(h, props) + }, + 'pagination': (props) => { + return this.renderTablePagination(h, props) + } + } + }, + /** + * @param {Function} h + * @param {Object} props + * @returns {*} + */ + renderTableTop (h, props) { + return [ + this.renderTableColumnsSelector(h), + h('q-space'), + this.renderPrototypeButtonsCompact(h, 'table-top', { records: this.selected }), + h('q-space'), + this.renderTableSearch(h) + ] + }, + /** + * @param {Function} h + * @returns {*} + */ + renderTableColumnsSelector: renderTableColumnsSelector, + /** + * @param {Function} h + * @returns {*} + */ + renderTableSearch: renderTableSearch, + /** + * @param {Function} h + * @param {Object} props + * @returns {*} + */ + renderTableCellButtons (h, props) { + const data = { + style: { position: 'relative' } + } + const children = [ + props.row[this.primaryKey], + this.renderPrototypeButtonsCompact(h, 'table-cell', { record: props.row }) + ] + + return h('q-td', data, children) + }, + /** + * @param {Function} h + * @param {Object} props + * @returns {*} + */ + renderTablePagination (h, props) { + const texts = [ + props.pagination.rowsPerPage * (props.pagination.page - 1) + 1, '-' + ] + let fragment = props.pagination.rowsPerPage * (props.pagination.page) + if (props.isLastPage) { + fragment = props.pagination.rowsNumber + } + texts.push(fragment) + texts.push('/') + texts.push(props.pagination.rowsNumber) + + const button = { + round: true, dense: true, flat: true, textColor: 'grey-8' + } + + const previous = { + attrs: { ...button, disable: props.isFirstPage, icon: 'chevron_left' }, + on: { click: this.previousPage } + } + + const next = { + attrs: { ...button, disable: props.isLastPage, icon: 'chevron_right' }, + on: { click: this.nextPage } + } + + return [ + h('span', { class: 'q-table__bottom-item' }, texts.join(' ')), + h('q-btn', previous), + h('span', { class: 'text-center' }, `${props.pagination.page} / ${props.pagination.pagesNumber}`), + h('q-btn', next) + ] + } + } +} diff --git a/src/app/Prototype/Prototype.js b/src/app/Prototype/Prototype.js index a3b4fa0..08fb2c3 100644 --- a/src/app/Prototype/Prototype.js +++ b/src/app/Prototype/Prototype.js @@ -40,6 +40,15 @@ export default class Prototype extends Skeleton { .finally(callback) } + /** + * @param {String|Array} key + * @param {string} [fallback] + * @returns {String|Object} + */ + $lang (key, fallback = '') { + return lang(key, fallback) + } + /** * @override */ @@ -83,6 +92,12 @@ export default class Prototype extends Skeleton { this.$browse(`${this.path}/add`, true) } + /** + */ + back () { + this.$browse(-1) + } + /** * @param {Object} record * @param {Array} records @@ -197,15 +212,21 @@ export default class Prototype extends Skeleton { this.action('add') .actionScopes(['index']) .actionPositions(['table-top']) - .actionLabel(lang('prototype.action.add.label')) + .actionLabel(this.$lang('prototype.action.add.label')) .actionIcon('add') .actionColor('primary') + this.action('back') + .actionScopes(['index', 'create', 'read', 'update']) + .actionPositions(['form-footer']) + .actionLabel(this.$lang('prototype.action.back.label')) + .actionIcon('reply') + this.action('cancel') .actionFloatRight() .actionScopes(['index', 'create', 'read', 'update']) .actionPositions(['form-footer']) - .actionLabel(lang('prototype.action.cancel.label')) + .actionLabel(this.$lang('prototype.action.cancel.label')) .actionIcon('close') this.action('refresh') @@ -219,7 +240,7 @@ export default class Prototype extends Skeleton { .actionScopes(['create', 'update']) .actionPositions(['form-footer']) .actionFloatRight() - .actionLabel(lang('prototype.action.save.label')) + .actionLabel(this.$lang('prototype.action.save.label')) .actionIcon('save') .actionColor('primary') .actionOn('click', function () { @@ -237,20 +258,20 @@ export default class Prototype extends Skeleton { this.action('view') .actionScopes(['index']) .actionPositions(['table-top', 'table-cell']) - .actionLabel(lang('prototype.action.view.label')) + .actionLabel(this.$lang('prototype.action.view.label')) .actionIcon('visibility') this.action('edit') .actionScopes(['index']) .actionPositions(['table-top', 'table-cell']) - .actionLabel(lang('prototype.action.edit.label')) + .actionLabel(this.$lang('prototype.action.edit.label')) .actionColor('primary') .actionIcon('edit') this.action('destroy') .actionScopes(['index']) .actionPositions(['table-top', 'table-cell']) - .actionLabel(lang('prototype.action.destroy.label')) + .actionLabel(this.$lang('prototype.action.destroy.label')) .actionColor('negative') .actionIcon('delete') } diff --git a/src/app/Prototype/Prototype/Action.js b/src/app/Prototype/Prototype/Action.js index d70f0f9..515d70b 100644 --- a/src/app/Prototype/Prototype/Action.js +++ b/src/app/Prototype/Prototype/Action.js @@ -48,6 +48,16 @@ export default { */ actionOrder (order) { const id = this.__currentAction + Object.keys(this.__actions).forEach((key) => { + if (key === this.__currentAction) { + return + } + const action = this.__actions[key] + if (action.order < order) { + return + } + action.order = action.order + 1 + }) if (this.__actions[id]) { this.__actions[id].order = order } diff --git a/src/boot/dev.js b/src/boot/development.js similarity index 53% rename from src/boot/dev.js rename to src/boot/development.js index 4f63093..092c00b 100755 --- a/src/boot/dev.js +++ b/src/boot/development.js @@ -10,4 +10,12 @@ export default ({ Vue }) => { return process.env.app.APP_DEV } }) + + /** + */ + Object.defineProperty(Vue.prototype, '$log', { + get () { + return process.env.NODE_ENV !== 'production' ? console.log : () => undefined + } + }) } diff --git a/src/domains/Auth/Service/AuthService.js b/src/domains/Auth/Service/AuthService.js index 6c532e2..5600a3c 100644 --- a/src/domains/Auth/Service/AuthService.js +++ b/src/domains/Auth/Service/AuthService.js @@ -40,6 +40,12 @@ export default class AuthService extends API { sublabel: 'Just a simple test ; )', icon: 'code', path: '/dashboard/test' + }, + { + label: 'Test With Hooks', + sublabel: 'Demo to show declare hooks', + icon: 'code', + path: '/dashboard/test-with-hooks' } ] }) diff --git a/src/domains/Example/Test/Prototype/TestWithHooks.js b/src/domains/Example/Test/Prototype/TestWithHooks.js new file mode 100644 index 0000000..5e7979a --- /dev/null +++ b/src/domains/Example/Test/Prototype/TestWithHooks.js @@ -0,0 +1,68 @@ +import Test from './Test' +import { path } from 'src/domains/Example/Test/Routes' + +/** + * @type {TestWithHooks} + */ +export default class TestWithHooks extends Test { + /** + * @type {string} + */ + static path = '/dashboard/test-with-hooks' + + /** + * @type {string} + */ + static domain = 'example.test' + + /** + * TestWithHooks constructor. + */ + construct () { + // construct the parent + super.construct() + + // configure some actions + this.configureActions() + + // configure some hooks + this.configureHooks() + } + + /** + */ + configureActions () { + this.action('cancel') + .actionColor('red') + .actionTextColor('white') + + this.action('go-to-test') + .actionScopes(['index', 'create', 'read', 'update']) + .actionPositions(['form-footer']) + .actionIcon('send') + .actionColor('yellow') + .actionOrder(2) + .actionLabel(this.$lang(`domains.${TestWithHooks.domain}.actions.goToTest`)) + .actionOn('click', function ({ $event, context }) { + this.$log('~> $event', $event) + this.$log('~> context', context) + this.$browse(path) + }) + } + + /** + */ + configureHooks () { + /** + */ + this.hook('fetch:record', function () { + this.$message.toast(this.$lang(`domains.${this.domain}.messages.record`)) + }) + + /** + */ + this.hook('fetch:records', function () { + this.$message.toast(this.$lang(`domains.${this.domain}.messages.records`)) + }) + } +} diff --git a/src/domains/Example/Test/Routes/components.js b/src/domains/Example/Test/Routes/components.js new file mode 100644 index 0000000..11cd637 --- /dev/null +++ b/src/domains/Example/Test/Routes/components.js @@ -0,0 +1,19 @@ +/** + * @returns {Promise} + */ +export const testTable = () => import('src/view/Dashboard/Example/Test/TestTable') + +/** + * @returns {Promise} + */ +export const testForm = () => import('src/view/Dashboard/Example/Test/TestForm') + +/** + * @returns {Promise} + */ +export const testWithHooksTable = () => import('src/view/Dashboard/Example/TestWithHooks/TestWithHooksTable') + +/** + * @returns {Promise} + */ +export const testWithHooksForm = () => import('src/view/Dashboard/Example/TestWithHooks/TestWithHooksForm') diff --git a/src/domains/Example/Test/Routes/index.js b/src/domains/Example/Test/Routes/index.js index 5c8f66f..00a69ee 100644 --- a/src/domains/Example/Test/Routes/index.js +++ b/src/domains/Example/Test/Routes/index.js @@ -1,24 +1,19 @@ import { crud } from 'src/app/Router' +import { testForm, testTable, testWithHooksForm, testWithHooksTable } from './components' /** * @type {string} */ export const path = '/dashboard/test' -/** - * @returns {Promise} - */ -export const table = () => import('src/view/Dashboard/Example/Test/TestTable') - -/** - * @returns {Promise} - */ -export const form = () => import('src/view/Dashboard/Example/Test/TestForm') - /** * @param {AppRouter} router * @returns {Array} */ export default (router) => { - return crud(path, table, form) + return [ + ...crud(path, testTable, testForm), + ...crud('/dashboard/test-with-hooks', testWithHooksTable, testWithHooksForm), + ...crud('/dashboard/test-custom-components', testWithHooksTable, testWithHooksForm) + ] } diff --git a/src/domains/Example/Test/en-us.js b/src/domains/Example/Test/en-us.js index ee59a38..fdccdf7 100644 --- a/src/domains/Example/Test/en-us.js +++ b/src/domains/Example/Test/en-us.js @@ -12,5 +12,12 @@ export default { name: 'Name', age: 'Age', description: 'Description' + }, + actions: { + goToTest: 'Go to Test' + }, + messages: { + record: 'We fetch the record with service', + records: 'We fetch the records with service' } } diff --git a/src/i18n/en-us/prototype/index.js b/src/i18n/en-us/prototype/index.js index fd97a9d..32b588d 100644 --- a/src/i18n/en-us/prototype/index.js +++ b/src/i18n/en-us/prototype/index.js @@ -43,6 +43,9 @@ export default { }, cancel: { label: 'Cancel' + }, + back: { + label: 'Back' } } } diff --git a/src/view/Dashboard/Example/TestWithHooks/TestWithHooksForm.vue b/src/view/Dashboard/Example/TestWithHooks/TestWithHooksForm.vue new file mode 100644 index 0000000..2e6f0b2 --- /dev/null +++ b/src/view/Dashboard/Example/TestWithHooks/TestWithHooksForm.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/view/Dashboard/Example/TestWithHooks/TestWithHooksTable.vue b/src/view/Dashboard/Example/TestWithHooks/TestWithHooksTable.vue new file mode 100644 index 0000000..c0d49a2 --- /dev/null +++ b/src/view/Dashboard/Example/TestWithHooks/TestWithHooksTable.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/view/Dashboard/Index.vue b/src/view/Dashboard/Index.vue index 2a490a1..351bf4e 100644 --- a/src/view/Dashboard/Index.vue +++ b/src/view/Dashboard/Index.vue @@ -73,4 +73,5 @@ export default { > img width 100% + max-width 960px