Files
raven-client/ayanova/src/views/ay-data-list-view.vue
John Cardinal 223a9e4060 Removed clearable from most forms, it's too "busy" and fucks up the look of the form for not much benefit
maybe in future can look at only showing on mobile or something or when the field is active?
2020-11-11 20:03:53 +00:00

1570 lines
53 KiB
Vue

<template>
<v-row v-if="formState.ready">
<v-col>
<v-form ref="form">
<v-row>
<gz-error :errorBoxMessage="formState.errorBoxMessage"></gz-error>
<v-col cols="12">
<v-row>
<v-col cols="12" sm="6" lg="4" xl="3">
<v-text-field
v-model="obj.name"
:readonly="formState.readOnly"
:disabled="formState.readOnly"
:clearable="!formState.readOnly"
@click:clear="fieldValueChanged('name')"
:label="$ay.t('Name')"
:rules="[form().required(this, 'name')]"
:error-messages="form().serverErrors(this, 'name')"
ref="name"
@input="fieldValueChanged('name')"
data-cy="name"
></v-text-field>
</v-col>
<v-col cols="12" sm="6" lg="4" xl="3">
<v-checkbox
v-model="obj.public"
:readonly="formState.readOnly"
:label="$ay.t('AnyUser')"
ref="public"
@change="fieldValueChanged('public')"
></v-checkbox>
</v-col>
</v-row>
</v-col>
<template v-for="(item, index) in obj.editView">
<v-col :key="item.key" cols="12" sm="6" lg="4" xl="3" px-2>
<v-card :data-cy="'columncard:' + item.key">
<v-card-title>
{{ item.title }}
</v-card-title>
<v-card-text>
<!-- INCLUDE CONTROL -->
<v-switch
v-if="!item.rid"
v-model="item.include"
:label="$ay.t('Include')"
:ref="item.key"
:disabled="
item.sort != null || item.filter.items.length > 0
"
@change="includeChanged(item)"
></v-switch>
<div v-if="item.rid" class="v-label mb-8 mt-6">
{{ $ay.t("Include") }}
</div>
<!-- RE-ORDER CONTROL -->
<div class="d-flex justify-space-between">
<v-btn large icon @click="move('start', index)"
><v-icon large data-cy="movestart"
>$ayiStepBackward</v-icon
></v-btn
>
<v-btn large icon @click="move('left', index)"
><v-icon large>$ayiBackward</v-icon></v-btn
>
<v-btn large icon @click="move('right', index)"
><v-icon large>$ayiForward</v-icon></v-btn
>
<v-btn large icon @click="move('end', index)"
><v-icon large>$ayiStepForward</v-icon></v-btn
>
</div>
<!-- SORT CONTROL -->
<template v-if="item.isSortable">
<div @click="toggleSort(item)" class="pt-6">
<v-btn x-large v-if="item.sort == null" icon>
<v-icon x-large>$ayiSort</v-icon></v-btn
>
<v-btn
v-if="item.sort != null && item.sort == '-'"
icon
x-large
><v-icon color="primary" x-large
>$ayiSortAmountDown</v-icon
></v-btn
>
<v-btn
v-if="item.sort != null && item.sort == '+'"
icon
x-large
><v-icon color="primary" x-large
>$ayiSortAmountUp</v-icon
></v-btn
>
<label class="v-label theme--light"
>&nbsp;{{ $ay.t("Sort") }}</label
>
</div>
</template>
<!-- FILTER CONTROL -->
<template v-if="item.isFilterable">
<div class="pt-6">
<!-- ******** BUILDER FOR EACH TYPE Tag, decimal,currency, bool, integer, string, datetime ******** -->
<!-- DATETIME BUILDER -->
<div v-if="item.uiFieldDataType === 1">
<v-select
v-model="item.tempFilterToken"
:items="selectLists.dateFilterTokens"
item-text="name"
item-value="id"
:label="$ay.t('Filter')"
prepend-icon="$ayiFilter"
></v-select>
<div v-if="item.tempFilterToken == '*select*'">
<v-select
v-model="item.tempFilterOperator"
:items="selectLists.dateFilterOperators"
item-text="name"
item-value="id"
></v-select>
<gz-date-time-picker
v-if="
item.tempFilterOperator != '*NOVALUE*' &&
item.tempFilterOperator != '*HASVALUE*'
"
v-model="item.tempFilterValue"
></gz-date-time-picker>
</div>
<v-btn
large
block
v-if="item.tempFilterToken != null"
@click="addFilterCondition(item)"
><v-icon large>$ayiPlus</v-icon></v-btn
>
</div>
<!-- STRING(text-4, emailaddress-11, http-12) BUILDER -->
<div
v-if="
item.uiFieldDataType === 4 ||
item.uiFieldDataType === 11 ||
item.uiFieldDataType === 12
"
>
<v-select
v-model="item.tempFilterOperator"
:items="selectLists.stringFilterOperators"
item-text="name"
item-value="id"
:label="$ay.t('Filter')"
prepend-icon="$ayiFilter"
></v-select>
<v-text-field
v-if="
item.tempFilterOperator != null &&
item.tempFilterOperator != '*NOVALUE*' &&
item.tempFilterOperator != '*HASVALUE*'
"
v-model="item.tempFilterValue"
:clearable="!formState.readOnly"
></v-text-field>
<v-btn
large
block
v-if="item.tempFilterOperator != null"
@click="addFilterCondition(item)"
><v-icon large>$ayiPlus</v-icon></v-btn
>
</div>
<!-- INTEGER BUILDER -->
<!-- Also MemorySize type 14 are integers -->
<div
v-if="
item.uiFieldDataType === 5 ||
item.uiFieldDataType === 14
"
>
<v-select
v-model="item.tempFilterOperator"
:items="selectLists.integerFilterOperators"
item-text="name"
item-value="id"
:label="$ay.t('Filter')"
prepend-icon="$ayiFilter"
></v-select>
<v-text-field
v-if="
item.tempFilterOperator != null &&
item.tempFilterOperator != '*NOVALUE*' &&
item.tempFilterOperator != '*HASVALUE*'
"
v-model="item.tempFilterValue"
:clearable="!formState.readOnly"
type="number"
></v-text-field>
<v-btn
large
block
v-if="item.tempFilterOperator != null"
@click="addFilterCondition(item)"
><v-icon large>$ayiPlus</v-icon></v-btn
>
</div>
<!-- BOOL BUILDER -->
<div v-if="item.uiFieldDataType === 6">
<v-select
v-model="item.tempFilterOperator"
:items="selectLists.boolFilterOperators"
item-text="name"
item-value="id"
:label="$ay.t('Filter')"
prepend-icon="$ayiFilter"
></v-select>
<v-radio-group
v-model="item.tempFilterValue"
v-if="
item.tempFilterOperator != null &&
item.tempFilterOperator != '*NOVALUE*' &&
item.tempFilterOperator != '*HASVALUE*'
"
row
>
<v-radio
:label="$ay.t('False')"
:value="false"
></v-radio>
<v-radio
:label="$ay.t('True')"
:value="true"
></v-radio>
</v-radio-group>
<v-btn
large
block
v-if="item.tempFilterOperator != null"
@click="addFilterCondition(item)"
><v-icon large>$ayiPlus</v-icon></v-btn
>
</div>
<!-- DECIMAL BUILDER -->
<div v-if="item.uiFieldDataType === 7">
<v-select
v-model="item.tempFilterOperator"
:items="selectLists.decimalFilterOperators"
item-text="name"
item-value="id"
:label="$ay.t('Filter')"
prepend-icon="$ayiFilter"
></v-select>
<gz-decimal
v-if="
item.tempFilterOperator != null &&
item.tempFilterOperator != '*NOVALUE*' &&
item.tempFilterOperator != '*HASVALUE*'
"
v-model="item.tempFilterValue"
:clearable="!formState.readOnly"
></gz-decimal>
<v-btn
large
block
v-if="item.tempFilterOperator != null"
@click="addFilterCondition(item)"
><v-icon large>$ayiPlus</v-icon></v-btn
>
</div>
<!-- CURRENCY BUILDER -->
<div v-if="item.uiFieldDataType === 8">
<v-select
v-model="item.tempFilterOperator"
:items="selectLists.decimalFilterOperators"
item-text="name"
item-value="id"
:label="$ay.t('Filter')"
prepend-icon="$ayiFilter"
></v-select>
<gz-currency
v-if="
item.tempFilterOperator != null &&
item.tempFilterOperator != '*NOVALUE*' &&
item.tempFilterOperator != '*HASVALUE*'
"
v-model="item.tempFilterValue"
:clearable="!formState.readOnly"
></gz-currency>
<v-btn
large
block
v-if="item.tempFilterOperator != null"
@click="addFilterCondition(item)"
><v-icon large>$ayiPlus</v-icon></v-btn
>
</div>
<!-- TAG BUILDER -->
<div v-if="item.uiFieldDataType === 9">
<v-select
v-model="item.tempFilterOperator"
:items="selectLists.tagFilterOperators"
item-text="name"
item-value="id"
:label="$ay.t('Filter')"
prepend-icon="$ayiFilter"
></v-select>
<gz-tag-picker
v-if="item.tempFilterOperator != null"
v-model="item.tempFilterValue"
></gz-tag-picker>
<v-btn
large
block
v-if="item.tempFilterOperator != null"
@click="addFilterCondition(item)"
><v-icon large>$ayiPlus</v-icon></v-btn
>
</div>
<!-- ENUM BUILDER -->
<div v-if="item.uiFieldDataType === 10">
<v-select
v-model="item.tempFilterOperator"
:items="selectLists.enumFilterOperators"
item-text="name"
item-value="id"
:label="$ay.t('Filter')"
prepend-icon="$ayiFilter"
></v-select>
<v-select
v-if="
item.tempFilterOperator != null &&
item.tempFilterOperator != '*NOVALUE*' &&
item.tempFilterOperator != '*HASVALUE*'
"
v-model="item.tempFilterValue"
:items="enumSelectionList(item.enumType)"
item-text="name"
item-value="id"
></v-select>
<v-btn
large
block
v-if="item.tempFilterOperator != null"
@click="addFilterCondition(item)"
><v-icon large>$ayiPlus</v-icon></v-btn
>
</div>
</div>
<div class="pt-6">
<!-- FILTER LIST -->
<template v-if="item.filter.items.length > 0">
<v-list elevation="2">
<v-subheader v-if="item.filter.items.length > 1">
<!-- AND / OR FILTER CONDITIONS -->
<v-radio-group v-model="item.filter.any" row>
<v-radio
:label="$ay.t('GridFilterDialogAndRadioText')"
:value="false"
></v-radio>
<v-radio
:label="$ay.t('GridFilterDialogOrRadioText')"
:value="true"
></v-radio> </v-radio-group
></v-subheader>
<v-list-item
v-for="(filterItem, index) in item.filter.items"
:key="index"
>
<v-list-item-content>
<v-list-item-title v-text="filterItem.display">
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-btn
icon
@click="removeFilterCondition(item, index)"
>
<v-icon>$ayiTrashAlt</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
</template>
<!-- <v-divider></v-divider>
{{ item }} -->
</div>
</template>
</v-card-text>
</v-card>
</v-col>
</template>
</v-row>
</v-form>
</v-col>
</v-row>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Xeslint-disable */
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const FORM_KEY = "ay-data-list-view";
const API_BASE_URL = "data-list-view/";
let JUST_DELETED = false;
export default {
//unsaved changes are actually valid for this form so no need to warn
beforeRouteLeave(to, from, next) {
let vm = this;
if (this.formState.dirty && !JUST_DELETED) {
//Put in unsaved listview
let formSettings = window.$gz.form.getFormSettings(vm.formKey);
formSettings.saved.dataTable.unsavedListView = JSON.stringify(
generateListViewFromEdited(vm)
);
formSettings.saved.dataTable.listViewId = -1;
formSettings.temp.cachedListView = null;
formSettings.temp.page = 1;
window.$gz.form.setFormSettings(vm.formKey, formSettings);
next();
} else {
next();
}
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
},
async created() {
let vm = this;
try {
//set route values in data object so init form can handle
vm.dataListKey = this.$route.params.dataListKey;
vm.listViewId = this.$route.params.listViewId;
vm.formKey = this.$route.params.formKey;
await initForm(vm);
vm.formState.ready = true;
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");
vm.formState.loading = false;
} catch (err) {
vm.formState.ready = true;
window.$gz.errorHandler.handleFormError(err, vm);
}
},
data() {
return {
obj: {
editView: [],
name: "",
public: true,
concurrency: 0,
userId: 0
},
listViewId: undefined,
dataListKey: undefined,
formKey: undefined,
fieldDefinitions: [],
effectiveListView: undefined,
concurrency: undefined,
selectLists: {
dateFilterOperators: [],
dateFilterTokens: [],
stringFilterOperators: [],
integerFilterOperators: [],
boolFilterOperators: [],
decimalFilterOperators: [],
tagFilterOperators: [],
enumFilterOperators: []
},
formState: {
ready: false,
dirty: false,
valid: true,
readOnly: false,
loading: true,
errorBoxMessage: undefined,
appError: undefined,
serverError: {}
},
rights: window.$gz.role.getRights(window.$gz.type.DataListView)
};
},
//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");
}
//enable / disable duplicate button
let canDuplicate = !val.dirty && val.valid && !val.readOnly;
if (canDuplicate) {
window.$gz.eventBus.$emit(
"menu-enable-item",
FORM_KEY + ":duplicate"
);
} else {
window.$gz.eventBus.$emit(
"menu-disable-item",
FORM_KEY + ":duplicate"
);
}
},
deep: true
}
},
computed: {
canSave: function() {
return this.formState.valid && this.formState.dirty;
},
canDuplicate: function() {
return this.formState.valid && !this.formState.dirty;
}
},
methods: {
enumSelectionList: function(enumKey) {
return window.$gz.enums.getSelectionList(enumKey);
},
includeChanged: function(item) {
if (item.required && item.visible == false) {
item.required = false;
}
window.$gz.form.setFormState({
vm: this,
dirty: true
});
},
toggleSort: function(item) {
if (item.sort == null) {
item.sort = "+";
} else if (item.sort == "+") {
item.sort = "-";
} else {
item.sort = null;
}
//make sure sorted fields are INCLUDED
if (item.sort) {
item.include = true;
}
window.$gz.form.setFormState({
vm: this,
dirty: true
});
},
move: function(direction, index) {
let totalItems = this.obj.editView.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.obj.editView.splice(
newIndex,
0,
this.obj.editView.splice(index, 1)[0]
);
window.$gz.form.setFormState({
vm: this,
dirty: true
});
},
addFilterCondition(item) {
let filterItem = { op: null, value: null, display: null };
let filterItemSet = false;
//DATE relative token?
if (item.uiFieldDataType === 1) {
//some kind of relative date token?
if (item.tempFilterToken && item.tempFilterToken != "*select*") {
//special relative token
filterItem.op = "="; //equality
filterItem.token = true;
filterItem.value = item.tempFilterToken;
filterItemSet = true;
}
}
//BLANKS / NONBLANKS TOKENS?
if (false == filterItemSet && item.tempFilterOperator == "*NOVALUE*") {
filterItem.op = "=";
filterItem.value = "*NULL*";
filterItemSet = true;
}
if (false == filterItemSet && item.tempFilterOperator == "*HASVALUE*") {
filterItem.op = "!=";
filterItem.value = "*NULL*";
filterItemSet = true;
}
//JUST REGULAR FILTER ITEM
if (
false == filterItemSet &&
item.tempFilterOperator &&
item.tempFilterValue != null
) {
filterItem.op = item.tempFilterOperator;
filterItem.value = item.tempFilterValue;
//only add if there is both an op and a value
//above here for tokens that isn't a restriction but
//after passing through those conditions were at a point where there MUST be both
if (filterItem.op && filterItem.value != null) {
filterItemSet = true;
}
}
if (filterItemSet) {
//display
filterItem.display = getDisplayForFilter(
this,
item.uiFieldDataType,
filterItem.op,
filterItem.value,
item.enumType
);
//add only if not already in the collection (accidental double click)
//de-lodash
// if (!window.$gz. _.find(item.filter.items, filterItem)) {
//some fits better here as it only test for truthiness and returns immediately on true
//also the item is unique and display doesn't need to be compared for equality it's irrelevant
//so only the op and the value need to be checked
if (
!item.filter.items.some(
z => z.op == filterItem.op && z.value == filterItem.value
)
) {
item.filter.items.push(filterItem);
window.$gz.form.setFormState({
vm: this,
dirty: true
});
}
return;
}
},
removeFilterCondition(item, index) {
item.filter.items.splice(index, 1);
window.$gz.form.setFormState({
vm: this,
dirty: true
});
},
form() {
return window.$gz.form;
},
fieldValueChanged(ref) {
if (!this.formState.loading && !this.formState.readOnly) {
window.$gz.form.fieldValueChanged(this, ref);
}
},
async submit() {
if (this.canSave) {
let vm = this;
//check that "unsaved filter" is not the name
//if it is, set it empty and force user to set a name
if (vm.obj.name == vm.$ay.t("FilterUnsaved")) {
vm.obj.name = "";
return;
}
vm.formState.loading = true;
let url = API_BASE_URL;
let lvSave = {
id: 0,
userId: vm.obj.userId || 1,
name: vm.obj.name,
public: vm.obj.public,
listKey: vm.dataListKey,
listView: JSON.stringify(generateListViewFromEdited(vm))
};
//are we working off a pre-existing listview (save over)?
if (vm.listViewId > 0) {
lvSave.id = vm.listViewId;
lvSave.concurrency = vm.obj.concurrency;
url = url + vm.listViewId;
}
//clear any errors vm might be around from previous submit
window.$gz.form.deleteAllErrorBoxErrors(this);
try {
let res = await window.$gz.api.upsert(url, lvSave);
vm.formState.loading = false;
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//successfully updated regardless if POST or PUT so update the local cache
//Update the formSettings now that it's saved
let formSettings = window.$gz.form.getFormSettings(vm.formKey);
formSettings.temp.cachedListView = lvSave.listView;
formSettings.temp.page = 1;
formSettings.saved.dataTable.unsavedListView = null;
formSettings.saved.dataTable.listViewId =
res.data.id || vm.listViewId; //if res.data.id then a post, if null then a put and vm.listviewId has the id
window.$gz.form.setFormSettings(vm.formKey, formSettings);
//Logic for detecting if a post or put: if id then it was a post, if no id then it was a put
if (res.data.id) {
//Handle "post" of new record (CREATE)
//No longer dirty
window.$gz.form.setFormState({
vm: vm,
dirty: false
});
//change url to new record
vm.$router.replace(
window.$gz.api.replaceAfterLastSlash(
vm.$route.fullPath,
res.data.id
)
);
} else {
//Handle "put" of an existing record (UPDATE)
vm.obj.concurrency = res.data.concurrency;
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;
try {
if ((await window.$gz.dialog.confirmDelete()) !== true) {
return;
}
//do the delete
vm.formState.loading = true;
//No need to delete a non saved record, just abandon it...
if (vm.listViewId < 1) {
//this should not get offered for delete but to be safe and clear just in case:
JUST_DELETED = true;
// navigate backwards
vm.$router.go(-1);
} else {
let url = API_BASE_URL + vm.listViewId;
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 {
//workaround to prevent warning about leaving dirty record
//For some reason I couldn't just reset isdirty in formstate
JUST_DELETED = true;
//set it to the default list view so the caller doesn't try to load the non-existant deleted view it was just working with
let formSettings = window.$gz.form.getFormSettings(vm.formKey);
formSettings.temp.cachedListView = null;
formSettings.temp.page = 1;
formSettings.saved.dataTable.unsavedListView = null;
formSettings.saved.dataTable.listViewId = 0;
window.$gz.form.setFormSettings(vm.formKey, formSettings);
// navigate backwards
vm.$router.go(-1);
}
}
} catch (error) {
//Update the form status
window.$gz.form.setFormState({
vm: vm,
loading: false
});
window.$gz.errorHandler.handleFormError(error, vm);
}
},
async duplicate() {
let vm = this;
if (this.canDuplicate && vm.listViewId > 0) {
this.formState.loading = true;
let url = API_BASE_URL + "duplicate/" + vm.listViewId;
//clear any errors vm might be around from previous submit
window.$gz.form.deleteAllErrorBoxErrors(this);
try {
let res = await window.$gz.api.upsert(url);
vm.formState.loading = false;
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//switch to the new record in the formsettings
let formSettings = window.$gz.form.getFormSettings(vm.formKey);
formSettings.temp.cachedListView = null;
formSettings.temp.page = 1;
formSettings.saved.dataTable.unsavedListView = null;
formSettings.saved.dataTable.listViewId = res.data.id;
window.$gz.form.setFormSettings(vm.formKey, formSettings);
//Set some values that otherwise don't get updated because we're not really navigating fresh
vm.obj.name = res.data.name;
vm.obj.concurrency = res.data.concurrency;
vm.listViewId = res.data.id;
//Navigate to new record
//NOTE: this doesn't really update the form at all so need to set some th9ings
vm.$router.push(
vm.$route.fullPath.slice(0, -1) + res.data.id
// window.$gz.api.replaceAfterLastSlash(
// vm.$route.fullPath,
// res.data.id
// )
);
}
} catch (error) {
vm.formState.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;
case "duplicate":
m.vm.duplicate();
break;
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: false,
icon: "$ayiFilter",
title: "DataListView",
helpUrl: "form-ay-data-list-view",
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: "Delete",
icon: "$ayiTrashAlt",
surface: false,
key: FORM_KEY + ":delete",
vm: vm
});
}
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "Duplicate",
icon: "$ayiClone",
key: FORM_KEY + ":duplicate",
vm: vm
});
}
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
/////////////////////////////////
//
//
async function initForm(vm) {
await fetchTranslatedText(vm);
await populateSelectionLists(vm);
await populateFieldDefinitions(vm);
await fetchTranslatedFieldNames(vm);
await setEffectiveListView(vm);
await initDataObject(vm);
await fetchEnums(vm);
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
await window.$gz.translation.cacheTranslations([
"DataListView",
"GridFilterName",
"Include",
"AnyUser",
"Sort",
"Filter",
"GridFilterDialogAndRadioText",
"GridFilterDialogOrRadioText",
"GridRowFilterDropDownBlanksItem",
"GridRowFilterDropDownNonBlanksItem",
"GridRowFilterDropDownEquals",
"GridRowFilterDropDownGreaterThan",
"GridRowFilterDropDownGreaterThanOrEqualTo",
"GridRowFilterDropDownLessThan",
"GridRowFilterDropDownLessThanOrEqualTo",
"GridRowFilterDropDownNotEquals",
"GridRowFilterDropDownDoesNotContain",
"GridRowFilterDropDownContains",
"GridRowFilterDropDownStartsWith",
"GridRowFilterDropDownEndsWith",
"SelectItem",
"DateRangeYesterday",
"DateRangeToday",
"DateRangeTomorrow",
"DateRangeLastWeek",
"DateRangeThisWeek",
"DateRangeNextWeek",
"DateRangeLastMonth",
"DateRangeThisMonth",
"DateRangeNextMonth",
"DateRange14DayWindow",
"DateRangePast",
"DateRangeFuture",
"DateRangeLastYear",
"DateRangeThisYear",
"DateRangeInTheLastThreeMonths",
"DateRangeInTheLastSixMonths",
"DateRangePastYear",
"DateRangePast90Days",
"DateRangePast30Days",
"DateRangePast24Hours",
"DateRangeJanuary",
"DateRangeFebruary",
"DateRangeMarch",
"DateRangeApril",
"DateRangeMay",
"DateRangeJune",
"DateRangeJuly",
"DateRangeAugust",
"DateRangeSeptember",
"DateRangeOctober",
"DateRangeNovember",
"DateRangeDecember",
"DateRangePreviousYearThisMonth",
"DateRangePreviousYearLastMonth",
"DateRangePreviousYearNextMonth",
"True",
"False",
"Name"
]);
}
/////////////////////////////////
//
//
function populateSelectionLists(vm) {
vm.selectLists.dateFilterOperators.push(
...[
{ name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
{
name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
id: "*HASVALUE*"
},
{ name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
{ name: vm.$ay.t("GridRowFilterDropDownGreaterThan"), id: ">" },
{
name: vm.$ay.t("GridRowFilterDropDownGreaterThanOrEqualTo"),
id: ">="
},
{ name: vm.$ay.t("GridRowFilterDropDownLessThan"), id: "<" },
{ name: vm.$ay.t("GridRowFilterDropDownLessThanOrEqualTo"), id: "<=" },
{ name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
]
);
vm.selectLists.dateFilterTokens.push(
...[
{ name: "(" + vm.$ay.t("SelectItem") + ")", id: "*select*" }, //If select then use entry in date /time picker
{ name: vm.$ay.t("DateRangeYesterday"), id: "*yesterday*" },
{ name: vm.$ay.t("DateRangeToday"), id: "*today*" },
{ name: vm.$ay.t("DateRangeTomorrow"), id: "*tomorrow*" },
{ name: vm.$ay.t("DateRangeLastWeek"), id: "*lastweek*" },
{ name: vm.$ay.t("DateRangeThisWeek"), id: "*thisweek*" },
{ name: vm.$ay.t("DateRangeNextWeek"), id: "*nextweek*" },
{ name: vm.$ay.t("DateRangeLastMonth"), id: "*lastmonth*" },
{ name: vm.$ay.t("DateRangeThisMonth"), id: "*thismonth*" },
{ name: vm.$ay.t("DateRangeNextMonth"), id: "*nextmonth*" },
{ name: vm.$ay.t("DateRange14DayWindow"), id: "*14daywindow*" },
{ name: vm.$ay.t("DateRangePast"), id: "*past*" },
{ name: vm.$ay.t("DateRangeFuture"), id: "*future*" },
{ name: vm.$ay.t("DateRangeLastYear"), id: "*lastyear*" }, //prior year from jan to dec
{ name: vm.$ay.t("DateRangeThisYear"), id: "*thisyear*" },
{
name: vm.$ay.t("DateRangeInTheLastThreeMonths"),
id: "*last3months*"
},
{
name: vm.$ay.t("DateRangeInTheLastSixMonths"),
id: "*last6months*"
},
{ name: vm.$ay.t("DateRangePastYear"), id: "*pastyear*" }, //last 365 days
{ name: vm.$ay.t("DateRangePast90Days"), id: "*past90days*" },
{ name: vm.$ay.t("DateRangePast30Days"), id: "*past30days*" },
{ name: vm.$ay.t("DateRangePast24Hours"), id: "*past24hours*" },
{ name: vm.$ay.t("DateRangeJanuary"), id: "*january*" },
{ name: vm.$ay.t("DateRangeFebruary"), id: "*february*" },
{ name: vm.$ay.t("DateRangeMarch"), id: "*march*" },
{ name: vm.$ay.t("DateRangeApril"), id: "*april*" },
{ name: vm.$ay.t("DateRangeMay"), id: "*may*" },
{ name: vm.$ay.t("DateRangeJune"), id: "*june*" },
{ name: vm.$ay.t("DateRangeJuly"), id: "*july*" },
{ name: vm.$ay.t("DateRangeAugust"), id: "*august*" },
{ name: vm.$ay.t("DateRangeSeptember"), id: "*september*" },
{ name: vm.$ay.t("DateRangeOctober"), id: "*october*" },
{ name: vm.$ay.t("DateRangeNovember"), id: "*november*" },
{ name: vm.$ay.t("DateRangeDecember"), id: "*december*" },
{
name: vm.$ay.t("DateRangePreviousYearThisMonth"),
id: "*lastyearthismonth*"
},
{
name: vm.$ay.t("DateRangePreviousYearLastMonth"),
id: "*lastyearlastmonth*"
},
{
name: vm.$ay.t("DateRangePreviousYearNextMonth"),
id: "*lastyearnextmonth*"
}
]
);
vm.selectLists.stringFilterOperators.push(
...[
{ name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
{
name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
id: "*HASVALUE*"
},
{ name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
{ name: vm.$ay.t("GridRowFilterDropDownGreaterThan"), id: ">" },
{
name: vm.$ay.t("GridRowFilterDropDownGreaterThanOrEqualTo"),
id: ">="
},
{ name: vm.$ay.t("GridRowFilterDropDownLessThan"), id: "<" },
{ name: vm.$ay.t("GridRowFilterDropDownLessThanOrEqualTo"), id: "<=" },
{ name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" },
{ name: vm.$ay.t("GridRowFilterDropDownDoesNotContain"), id: "!-%-" },
{ name: vm.$ay.t("GridRowFilterDropDownContains"), id: "-%-" },
{ name: vm.$ay.t("GridRowFilterDropDownStartsWith"), id: "%-" },
{ name: vm.$ay.t("GridRowFilterDropDownEndsWith"), id: "-%" }
]
);
vm.selectLists.integerFilterOperators.push(
...[
{ name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
{
name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
id: "*HASVALUE*"
},
{ name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
{ name: vm.$ay.t("GridRowFilterDropDownGreaterThan"), id: ">" },
{
name: vm.$ay.t("GridRowFilterDropDownGreaterThanOrEqualTo"),
id: ">="
},
{ name: vm.$ay.t("GridRowFilterDropDownLessThan"), id: "<" },
{ name: vm.$ay.t("GridRowFilterDropDownLessThanOrEqualTo"), id: "<=" },
{ name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
]
);
vm.selectLists.boolFilterOperators.push(
...[
{ name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
{
name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
id: "*HASVALUE*"
},
{ name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
{ name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
]
);
vm.selectLists.decimalFilterOperators.push(
...[
{ name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
{
name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
id: "*HASVALUE*"
},
{ name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
{ name: vm.$ay.t("GridRowFilterDropDownGreaterThan"), id: ">" },
{
name: vm.$ay.t("GridRowFilterDropDownGreaterThanOrEqualTo"),
id: ">="
},
{ name: vm.$ay.t("GridRowFilterDropDownLessThan"), id: "<" },
{ name: vm.$ay.t("GridRowFilterDropDownLessThanOrEqualTo"), id: "<=" },
{ name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
]
);
//tags filter only by equals in initial release, see DataListSqlFilterCriteriaBuilder.cs line 523 for deets
vm.selectLists.tagFilterOperators.push({
name: vm.$ay.t("GridRowFilterDropDownEquals"),
id: "="
});
vm.selectLists.enumFilterOperators.push(
...[
{ name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
{
name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
id: "*HASVALUE*"
},
{ name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
{ name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
]
);
}
////////////////////
//
async function populateFieldDefinitions(vm) {
//http://localhost:7575/api/v8/data-list/listfields?DataListKey=TestWidgetDataList
let res = await window.$gz.api.get(
"data-list/listfields?DataListKey=" + vm.dataListKey
);
if (res.error) {
throw new Error(res.error);
} else {
vm.fieldDefinitions = res.data;
}
}
//////////////////////////////////////////////////////////
//
// Ensures column names are present in translation table
//
async function fetchTranslatedFieldNames(vm) {
let columnKeys = [];
for (let i = 1; i < vm.fieldDefinitions.length; i++) {
let cm = vm.fieldDefinitions[i];
columnKeys.push(cm.tKey);
}
await window.$gz.translation.cacheTranslations(columnKeys);
}
/////////////////////////////////
//
//
async function setEffectiveListView(vm) {
/*
effectiveListView
- Second get the ListView that is currently in use so can setup the page view
- If listviewid is zero then that's starting with the default list view so need to fetch it and then init the form
- If listviewid is -1 then that's starting with an unsaved listview so get that from the saved form store
- If listviewid is greater than 0 then it's a saved listview and there sb a cached version of it but ideally maybe fetch it from
*/
if (vm.listViewId == null) {
throw new Error(
"ay-data-list::setEffectiveListView - listViewId is not set"
);
}
let formSettings = window.$gz.form.getFormSettings(vm.formKey);
if (vm.listViewId == -1) {
if (formSettings.saved.dataTable.unsavedListView != null) {
vm.effectiveListView = JSON.parse(
formSettings.saved.dataTable.unsavedListView
);
vm.obj.name = vm.$ay.t("FilterUnsaved");
return Promise.resolve();
}
} else if (vm.listViewId == 0) {
//get default list view
//http://localhost:7575/api/v8/DataListView/default/TestWidgetDataList
let res = await window.$gz.api.get(
"data-list-view/default/" + vm.dataListKey
);
if (res.error) {
throw new Error(res.error);
} else {
vm.effectiveListView = JSON.parse(res.data);
vm.obj.name = vm.$ay.t("FilterUnsaved");
}
} else {
//listview has an id value
let res = await window.$gz.api.get("data-list-view/" + vm.listViewId);
if (res.error) {
throw new Error(res.error);
} else {
vm.effectiveListView = JSON.parse(res.data.listView);
vm.obj.public = res.data.public;
vm.obj.name = res.data.name;
vm.obj.concurrency = res.data.concurrency;
vm.obj.userId = res.data.userId;
}
}
}
////////////////////
//
function initDataObject(vm) {
if (vm.effectiveListView == null) {
throw new Error(
"ay-data-list::initDataObject - effectiveListView is not set"
);
}
if (vm.fieldDefinitions == null) {
throw new Error(
"ay-data-list::initDataObject - fieldDefinitions are not set"
);
}
let ret = [];
//Pass 1, iterate the listview first
for (let i = 0; i < vm.effectiveListView.length; i++) {
let lvItem = vm.effectiveListView[i];
//de-lodash
//let fld = window.$gz. _.find(vm.fieldDefinitions, ["fieldKey", lvItem.fld]);
let fld = vm.fieldDefinitions.find(z => z.fieldKey == lvItem.fld);
let o = {
key: fld.fieldKey,
title: vm.$ay.t(fld.tKey),
include: true,
isFilterable: fld.isFilterable,
isSortable: fld.isSortable,
enumType: fld.enumType,
uiFieldDataType: fld.uiFieldDataType,
isCustomField: fld.isCustomField,
sort: lvItem.sort || null,
filter: lvItem.filter || { any: false, items: [] },
tempFilterOperator: null,
tempFilterToken: null,
tempFilterValue: null
};
if (fld.isRowId) {
o.rid = true;
}
//If it's a tag and it's not been set yet it needs to have an empty array to stat with for the picker
if (o.uiFieldDataType == 9 && o.tempFilterValue == null) {
o.tempFilterValue = [];
}
//Add display text for filter item (same as in addFilterCondition)
for (let j = 0; j < o.filter.items.length; j++) {
let fi = o.filter.items[j];
fi.display = getDisplayForFilter(
vm,
o.uiFieldDataType,
fi.op,
fi.value,
o.enumType
);
}
ret.push(o);
}
//Pass 2, remaining fields not already dealt with
for (let i = 0; i < vm.fieldDefinitions.length; i++) {
let fld = vm.fieldDefinitions[i];
//is this field already in ret array?
//de-lodash
// if (null == window.$gz. _.find(ret, ["key", fld.fieldKey])) {
if (null == ret.find(z => z.key == fld.fieldKey)) {
//nope, so add it
let o = {
key: fld.fieldKey,
title: vm.$ay.t(fld.tKey),
include: false,
isFilterable: fld.isFilterable,
isSortable: fld.isSortable,
enumType: fld.enumType,
uiFieldDataType: fld.uiFieldDataType,
isCustomField: fld.isCustomField,
sort: null,
filter: { any: false, items: [] },
tempFilterOperator: null,
tempFilterToken: null,
tempFilterValue: null
};
if (fld.isRowId) {
o.rid = true;
o.include = true;
}
//If it's a tag and it's not been set yet it needs to have an empty array to stat with for the picker
if (o.uiFieldDataType == 9 && o.tempFilterValue == null) {
o.tempFilterValue = [];
}
ret.push(o);
}
}
vm.obj.editView = ret;
// if (window.$gz.dev) {
// if (vm.obj.editView.length != vm.fieldDefinitions.length) {
// throw new Error(
// "ay-data-list-view::initDataObject - working array length not equal to total field definition length"
// );
// }
// }
return Promise.resolve();
//eoc
}
//////////////////////////////////////////////////////////
//
// Ensures translated enum lists are available pre-cached
//
function fetchEnums(vm) {
//build an array of all enums then execute method
let enumKeys = [];
for (let i = 0; i < vm.fieldDefinitions.length; i++) {
let fld = vm.fieldDefinitions[i];
if (fld.uiFieldDataType == 10) {
enumKeys.push(fld.enumType);
}
}
if (enumKeys.length > 0) {
return window.$gz.enums.fetchEnumList(enumKeys);
}
return Promise.resolve();
}
//////////////////////////////////////////////////////////
//
// Convert working object to actual listView
//
function updateEditedListView(vm) {
//turn the obj.editView settings into an actual listview
//compare it with the effectiveListView to see if there are any changes between the two
//set the form to dirty if there are changes and can save
//this.formState.dirty = true;
//this way user can build their way back to the same view and then no need to save if no changes
//build an array of all enums then execute method
}
//////////////////////////////////////////////////////////
//
// Convert filter properties to translated / displayable
// used when making new filter and loading existing
//
function getDisplayForFilter(
vm,
uiFieldDataType,
filterOperator,
filterValue,
enumType
) {
//BLANKS FILTER
if (filterOperator == "=" && filterValue == "*NULL*") {
//de-lodash
// return window.$gz. _.find(vm.selectLists.stringFilterOperators, {
// id: "*NOVALUE*"
// }).name;
return vm.selectLists.stringFilterOperators.find(z => z.id == "*NOVALUE*")
.name;
}
// NONBLANKS FILTER
if (filterOperator == "!=" && filterValue == "*NULL*") {
//de-lodash
// return window.$gz. _.find(vm.selectLists.stringFilterOperators, {
// id: "*HASVALUE*"
// }).name;
return vm.selectLists.stringFilterOperators.find(z => z.id == "*HASVALUE*")
.name;
}
//DATE RELATIVE TOKEN FILTER
if (uiFieldDataType === 1 && filterValue[0] == "*") {
//de-lodash
// let valueDisplay = window.$gz. _.find(vm.selectLists.dateFilterTokens, {
// id: filterValue
// }).name;
let valueDisplay = vm.selectLists.dateFilterTokens.find(
z => z.id == filterValue
).name;
return filterOperator + " " + valueDisplay;
}
//VALUE FILTER
//Nothing more to do if there isn't both a value AND an operator at this point
if (filterOperator == null || filterValue == null) {
// if (window.$gz.dev) {
// throw new Error(
// "ay-data-list-view::getDisplayForFilter Value filter missing one ore more of Operator, Value"
// );
// }
return "";
}
let valueDisplay = "selected value";
switch (uiFieldDataType) {
case 1: //date translate
valueDisplay = window.$gz.locale.utcDateToShortDateAndTimeLocalized(
filterValue
);
break;
case 8: //currency translate
valueDisplay = window.$gz.locale.currencyLocalized(filterValue);
break;
case 7: //decimal translate
valueDisplay = window.$gz.locale.decimalLocalized(filterValue);
break;
case 6: //BOOL translate
let tKey = filterValue ? "True" : "False";
valueDisplay = vm.$ay.t(tKey);
break;
case 10: //ENUM translate
valueDisplay = window.$gz.enums.get(enumType, filterValue);
break;
default:
valueDisplay = filterValue;
break;
}
//Operator
//de-lodash
// let opDisplay = window.$gz. _.find(vm.selectLists.stringFilterOperators, {
// id: filterOperator
// }).name;
let opDisplay = vm.selectLists.stringFilterOperators.find(
z => z.id == filterOperator
).name;
return opDisplay + ' "' + valueDisplay + '"';
//eoc
}
//////////////////////////////////////////////////////////
//
// Convert editedList view to real list view and return
//
function generateListViewFromEdited(vm) {
//obj: { editView: [], name: "", public: true },
if (vm.obj.editView == null || vm.obj.editView.length == 0) {
return;
}
let ret = [];
for (let i = 0; i < vm.obj.editView.length; i++) {
let ev = vm.obj.editView[i];
if (!ev.include) {
continue;
}
let o = {
fld: ev.key
};
if (ev.sort != null) {
o.sort = ev.sort;
}
if (ev.filter && ev.filter.items && ev.filter.items.length > 0) {
let f = {
items: []
};
if (ev.filter.any) {
f.any = true;
}
for (let j = 0; j < ev.filter.items.length; j++) {
let evfi = ev.filter.items[j];
let thisFilterItem = {
op: evfi.op,
value: evfi.value
};
if (evfi.token) {
thisFilterItem.token = true;
}
f.items.push(thisFilterItem);
}
o.filter = f;
}
ret.push(o);
}
return ret;
//eoc
}
/////////////END OF FORM//////////////////
</script>