This commit is contained in:
2021-03-22 15:17:07 +00:00
parent d6ab38912e
commit 14bc5f6788
4 changed files with 492 additions and 15 deletions

View File

@@ -65,24 +65,10 @@ todo: v8 migrate additions
****************
******************
Tags
*****************
(italic is mine original message, your original response in []. The **** is my reply to yours)
How do I "see" ALL possible tags so I as an end-user can pick an existing tag OR so I can see the format of how tags are entered in my company (i.e. my company might use a prefix PC for a Part Cateogry or a DZ for a dispatch zone, or enter dispatch zone names by main street instead of east/north etc - and a supervisor won't want to have to manually sit with each staff and tell them what to do, thinking it should be intuitive...)
[not a feature currently. What are your thoughts on what is should look like and where it would go?]
Where can I as an end-user see ALL tags? what if I wanted/needed to remove/edit the same tag everywhere can't I do so from a list of available used tags - i.e. tag "blue" no longer used, want it removed from everything?
[not a feature currently. What are your thoughts on what is should look like and where it would go?]
****When I click to enter a tag (but have not yet typed anything), I'd expect/like to see a list of ALL existing tags drop down that I can then scroll down and select(doesn't do this as of right now March 15 2021 alpha-104). Whereas if I instead start typing a letter, then I would expect to see a dropdown list of tags that start with that letter (does this already!)
**************************
PO
*************************
(italic is mine original message, your original response in []. The **** is my reply to yours)
Is this as expected? Statuses don't automatically change at ANY point .... I take it that the status is FULLY up to the user. And the default appears to be Open - On Order UNLESS the end-user themselves actually changes it.
[Yes, completely up to user how they choose to use it. It's so different in how it works I struggled to find a system that woudl work automatically and not get in the way. The status before was tied to how it worked but it doesn't work that way anymore and technically users could just hide it if they don't use it. If you have any suggestions on something different I can look into it, just couldn't think of a clean automatic system at the time]
***OK no further suggestions at this time
(italic is mine original message, your original response in []. The **** is my reply to yours)
ISSUE **PO numbers duplicating:
@@ -1021,4 +1007,7 @@ build 105
Tag extension or any extension refresh main data table it was run from after operation (so can see results) automatically
** looked into and realized could cause issues forcing a refresh when the user doesn't want it necessarily if they are picking and choosing records to work with in extension more than once
REMOVE THE extra decimal place - make it so max of two decimal places so if have a 6.25% tax would enter in 6.25; if 16.75% would enter in 16.75 I know of no known tax rate that has more than 2 decimal places
** Many places globally have 3 decimal place tax rates, even in the US https://taxfoundation.org/2020-sales-taxes/
** Many places globally have 3 decimal place tax rates, even in the US https://taxfoundation.org/2020-sales-taxes/
When I click to enter a tag (but have not yet typed anything), I'd expect/like to see a list of ALL existing tags drop down that I can then scroll down and select(doesn't do this as of right now March 15 2021 alpha-104)
** Oh, ok, I thought you meant an area where tags could be viewed. That's not practical, there could be 10,000 tags, it's open ended, we can't send the whole list every drop down of every tag. What's the use-case for this?
like if a person isn't sure what tags to use or...??

View File

@@ -570,6 +570,12 @@ export default new Router({
/* webpackChunkName: "adm" */ "./views/adm-global-select-templates.vue"
)
},
{
path: "/adm-global-seeds",
name: "adm-global-seeds",
component: () =>
import(/* webpackChunkName: "adm" */ "./views/adm-global-seeds.vue")
},
{
path: "/adm-global-logo",
name: "adm-global-logo",

View File

@@ -0,0 +1,477 @@
<template>
<v-row v-if="formState.ready">
<v-col>
<v-form ref="form">
<!-- Prevent implicit submission of the form on enter key, this is not necessary on a form with a text area which is why I never noticed it with the other forms -->
<button
type="submit"
disabled
style="display: none"
aria-hidden="true"
></button>
<v-row>
<gz-error :error-box-message="formState.errorBoxMessage"></gz-error>
<v-col cols="12">
<v-select
v-model="templateId"
:items="selectLists.pickListTemplates"
item-text="name"
item-value="id"
:label="$ay.t('PickListTemplates')"
@input="templateSelected"
data-cy="selectTemplate"
:disabled="formState.dirty"
>
</v-select>
</v-col>
SEEDS HERE
</v-row>
</v-form>
</v-col>
</v-row>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Xeslint-disable */
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//NOTE: This is a simple form with no need for business rules or validation so stripped out any extraneous code related to all that
//
const FORM_KEY = "adm-global-seeds";
const API_BASE_URL = "global-biz-setting/seeds/";
export default {
async beforeRouteLeave(to, from, next) {
if (!this.formState.dirty) {
next();
return;
}
if ((await window.$gz.dialog.confirmLeaveUnsaved()) === true) {
next();
} else {
next(false);
}
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
},
async created() {
let vm = this;
try {
await initForm(vm);
vm.formState.ready = true;
vm.readOnly = !vm.rights.change;
window.$gz.eventBus.$on("menu-click", clickHandler);
//NOTE: this would normally be in getDataFromAPI but this form doesn't really need that function so doing it here
//modify the menu as necessary
generateMenu(vm);
//init disable save button so it can be enabled only on edit to show dirty form
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":delete");
vm.formState.loading = false;
} catch (err) {
vm.formState.ready = true;
window.$gz.errorHandler.handleFormError(err, vm);
}
},
data() {
return {
obj: {
id: null,
concurrency: null,
template: null
},
selectLists: {
pickListTemplates: []
},
availableFields: [],
workingArray: [],
fieldKeys: [],
templateId: 0,
lastFetchedTemplateId: 0,
formState: {
ready: false,
dirty: false,
valid: true,
readOnly: false,
loading: true,
errorBoxMessage: null,
appError: null,
serverError: {}
},
rights: window.$gz.role.getRights(window.$gz.type.FormCustom)
};
}, //WATCHERS
watch: {
formState: {
handler: function(val) {
//,oldval is available here too if necessary
if (this.formState.loading) {
return;
}
//enable / disable save button
let canSave = val.dirty && val.valid && !val.readOnly;
if (canSave) {
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":save");
} else {
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
}
},
deep: true
},
templateId(val) {
if (val) {
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":delete");
} else {
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":delete");
}
}
},
methods: {
includeChanged: function(item) {
window.$gz.form.setFormState({
vm: this,
dirty: true
});
},
move: function(direction, index) {
let totalItems = this.workingArray.length;
let newIndex = 0;
//calculate new index
switch (direction) {
case "start":
newIndex = 0;
break;
case "left":
newIndex = index - 1;
if (newIndex < 0) {
newIndex = 0;
}
break;
case "right":
newIndex = index + 1;
if (newIndex > totalItems - 1) {
newIndex = totalItems - 1;
}
break;
case "end":
newIndex = totalItems - 1;
break;
}
this.workingArray.splice(
newIndex,
0,
this.workingArray.splice(index, 1)[0]
);
window.$gz.form.setFormState({
vm: this,
dirty: true
});
},
templateSelected: function() {
let vm = this;
if (vm.lastFetchedTemplateId == vm.templateId) {
return; //no change
}
vm.workingArray = [];
if (!vm.templateId || vm.templateId == 0) {
vm.lastFetchedTemplateId = 0;
return;
} else {
vm.getDataFromApi();
}
},
async getDataFromApi() {
let vm = this;
vm.formState.loading = true;
if (!vm.templateId || vm.templateId == 0) {
return;
}
vm.lastFetchedTemplateId = vm.templateId;
window.$gz.form.deleteAllErrorBoxErrors(vm);
try {
//get available fields
let res = await window.$gz.api.get(
API_BASE_URL + "listfields/" + vm.templateId
);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
vm.availableFields = res.data;
vm.fieldKeys = [];
for (let i = 0; i < res.data.length; i++) {
vm.fieldKeys.push(res.data[i].tKey);
}
await window.$gz.translation.cacheTranslations(vm.fieldKeys);
}
//weirdly, this wasn't working properly until I put it in a function, it was just executing immediately before translations were resolved from fetch above
//get current edited template
res = await window.$gz.api.get(API_BASE_URL + vm.templateId);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
vm.obj = res.data;
synthesizeWorkingArray(vm);
//Update the form status
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true,
loading: false
});
}
} catch (error) {
//Update the form status
window.$gz.form.setFormState({
vm: vm,
loading: false
});
window.$gz.errorHandler.handleFormError(error, vm);
}
},
async submit() {
let vm = this;
let url = API_BASE_URL;
//clear any errors vm might be around from previous submit
window.$gz.form.deleteAllErrorBoxErrors(vm);
//Create template data object here....
//Note that server expects to see a string array of json template, not actual json
let newObj = {
id: vm.templateId,
template: "[]"
};
//temporary array to hold template for later stringification
let temp = [];
for (let i = 0; i < vm.workingArray.length; i++) {
let ti = vm.workingArray[i];
if (ti.include == true) {
temp.push({
fld: ti.key
});
}
}
try {
//now set the template as a json string
newObj.template = JSON.stringify(temp);
let res = await window.$gz.api.upsert(url, newObj);
vm.formState.loading = false;
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//It's a 204 no data response so no error means it's ok
//form is now clean
window.$gz.form.setFormState({
vm: vm,
dirty: false
});
}
} catch (error) {
vm.formState.loading = false;
window.$gz.errorHandler.handleFormError(error, vm);
}
},
async remove() {
let vm = this;
if (
(await window.$gz.dialog.confirmGeneric(
"ResetToDefault",
"warning"
)) !== true
) {
return;
}
try {
//do the delete
vm.formState.loading = true;
//No need to delete a new record, just abandon it...
if (vm.templateId && vm.templateId != 0) {
let url = API_BASE_URL + vm.templateId;
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.remove(url);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//trigger reload of form
this.getDataFromApi();
}
}
} catch (error) {
//Update the form status
window.$gz.form.setFormState({
vm: vm,
loading: false
});
window.$gz.errorHandler.handleFormError(error, vm);
}
}
}
};
/////////////////////////////
//
//
function clickHandler(menuItem) {
if (!menuItem) {
return;
}
let m = window.$gz.menu.parseMenuItem(menuItem);
if (m.owner == FORM_KEY && !m.disabled) {
switch (m.key) {
case "save":
m.vm.submit();
break;
case "delete":
m.vm.remove();
break;
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: false,
readOnly: vm.formState.readOnly,
icon: null,
title: "PickListTemplates",
helpUrl: "adm-global-select-templates",
formData: {
ayaType: window.$gz.type.FormCustom,
formCustomTemplateKey: undefined
},
menuItems: []
};
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "Save",
icon: "$ayiSave",
surface: true,
key: FORM_KEY + ":save",
vm: vm
});
if (vm.rights.delete) {
menuOptions.menuItems.push({
title: "ResetToDefault",
icon: "$ayiUndo",
surface: false,
key: FORM_KEY + ":delete",
vm: vm
});
}
}
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
/////////////////////////////////
//
//
async function initForm(vm) {
await fetchTranslatedText(vm);
await populateSelectionLists(vm);
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
await window.$gz.translation.cacheTranslations(["Include", "ResetToDefault"]);
}
//////////////////////
//
//
async function populateSelectionLists(vm) {
let res = await window.$gz.api.get(API_BASE_URL + "List");
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
res.data.sort(window.$gz.util.sortByKey("name"));
vm.selectLists.pickListTemplates = res.data;
window.$gz.form.addNoSelectionItem(vm.selectLists.pickListTemplates);
}
}
////////////////////
//
function synthesizeWorkingArray(vm) {
vm.workingArray = [];
if (vm.obj.template == null) {
return;
}
let template = JSON.parse(vm.obj.template);
//first, insert the templated fields into the working array so they are in current selected order
for (let i = 0; i < template.length; i++) {
let templateItem = template[i];
//de-lodash
// let afItem = window.$gz. _.find(vm.availableFields, [
// "fieldKey",
// templateItem.fld
// ]);
let afItem = vm.availableFields.find(z => z.fieldKey == templateItem.fld);
if (afItem != null) {
//Push into working array
vm.workingArray.push({
key: afItem.fieldKey,
required: afItem.isRowId == true,
include: true,
title: vm.$ay.t(afItem.tKey)
});
}
}
//Now iterate all the available fields and insert the ones that were not in the current template
for (let i = 0; i < vm.availableFields.length; i++) {
let afItem = vm.availableFields[i];
//skip the active column
if (afItem.isActiveColumn == true) {
continue;
}
//is this field already in the template and was added above?
//de-lodash
// if (window.$gz ._.find(template, ["fld", afItem.fieldKey]) != null) {
// continue;
// }
if (template.find(z => z.fld == afItem.fieldKey) != null) {
continue;
}
//Push into working array
vm.workingArray.push({
key: afItem.fieldKey,
required: afItem.isRowId == true,
include: false,
title: vm.$ay.t(afItem.tKey)
});
}
}
</script>

View File

@@ -86,6 +86,11 @@
$ay.t("PickListTemplates")
}}</v-list-item-title>
</v-list-item>
<v-list-item link to="adm-global-seeds" data-cy="seeds">
<v-list-item-title>{{
$ay.t("GlobalNextSeeds")
}}</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-col>