///////////////////////////////// // Menu utils and handlers // export default { /////////////////////////////////////////// // TECH SUPPORT / CONTACT FORUM URL // contactSupportUrl() { const dbId = encodeURIComponent( window.$gz.store.state.globalSettings.serverDbId ); const company = encodeURIComponent( window.$gz.store.state.globalSettings.company ); return `https://contact.ayanova.com/contact?dbid=${dbId}&company=${company}`; }, /////////////////////////////// // CHANGE HANDLER // // Deal with a menu change request // called from App.vue handleMenuChange(vm, ctx) { const UTILITY_TYPES = [ window.$gz.type.NoType, window.$gz.type.Global, window.$gz.type.NoType, window.$gz.type.ServerState, window.$gz.type.License, window.$gz.type.LogFile, window.$gz.type.ServerJob, window.$gz.type.TrialSeeder, window.$gz.type.ServerMetrics, window.$gz.type.UserOptions, window.$gz.type.FormCustom, window.$gz.type.DataListSavedFilter, window.$gz.type.GlobalOps, window.$gz.type.BizMetrics, window.$gz.type.Backup, window.$gz.type.Notification, window.$gz.type.NotifySubscription ]; vm.appBar.isMain = ctx.isMain; vm.appBar.icon = ctx.icon; vm.appBar.title = ""; //this prevents fou[translated]c vm.appBar.readOnly = ctx.readOnly; if (ctx.readOnly === true) { vm.appBar.color = "readonlybanner"; } else { vm.appBar.color = ctx.isMain ? "primary" : "secondary"; } //ctx.title if set is a Translation key //ctx.formData.recordName is the object name or serial number or whatever identifies it uniquely let recordName = ""; if ( ctx && ctx.formData && ctx.formData.recordName && ctx.formData.recordName != "null" //some forms (part) present "null" as the record name due to attempts to format a name so if that's the case just turn it into null here to bypass ) { recordName = ctx.formData.recordName; } const hasRecordName = !window.$gz.util.stringIsNullOrEmpty(recordName); if (ctx.title) { //it has a title translation key const translatedTitle = vm.$ay.t(ctx.title); if (hasRecordName) { //recordname takes all precedence in AppBar in order to conserve space (narrow view etc) //also it just looks cleaner, the icon is already there to indicate where the user is at vm.appBar.title = recordName; document.title = `${recordName} - ${translatedTitle} AyaNova `; } else { vm.appBar.title = translatedTitle; document.title = `${translatedTitle} ${recordName}`; } } else { if (hasRecordName) { //not title but has record name vm.appBar.title = recordName; document.title = `${recordName} AyaNova`; } else { document.title = "AyaNova"; } } //Parse the formdata if present //FORMDATA is OPTIONAL and only required for forms that need to allow //viewing object history, attachments, custom fields, etc that kind of thing //usually CORE objects with an id, NOT utility type forms let formAyaType = 0; let formRecordId = 0; if (ctx.formData) { if (ctx.formData.ayaType != null) { formAyaType = ctx.formData.ayaType; } if (ctx.formData.recordId != null) { formRecordId = ctx.formData.recordId; } } //flag for if it's wikiable, reviewable, attachable, searchable, historical const isCoreBizObject = formAyaType != 0 && formRecordId != 0; //set the help url if presented or default to the User section intro vm.appBar.helpUrl = ctx.helpUrl ? ctx.helpUrl : "user-intro"; vm.appBar.menuItems = []; //CONTEXT TOP PORTION //populate the context portion of the menu so handle accordingly if (ctx.menuItems) { vm.appBar.menuItems = ctx.menuItems; } //STANDARD BIZ OBJECT OPTIONS //NOTE: This applies equally to all core business object types that are basically real world and have an id and a type (all are wikiable, attachable and reviewable) //Not utility type objects like datalist etc //there will be few exceptions so they will be coded in later if needed but assume anything with an id and a type if (isCoreBizObject && !ctx.hideCoreBizStandardOptions) { //"Review" was follow up type of schedule marker //basically it's now a "Reminder" type of object but it's own thing with separate collection vm.appBar.menuItems.push({ title: "Review", icon: "$ayiCalendarCheck", key: "app:review", data: { ayaType: formAyaType, recordId: formRecordId, recordName: recordName } }); //AFAIK right now any item with an id and a type can have a history //anything not would be the exception rather than the rule vm.appBar.menuItems.push({ title: "History", icon: "$ayiHistory", key: "app:history", data: { ayaType: formAyaType, recordId: formRecordId } }); } //CUSTOMIZE //set custom fields and link to translation text editor if ( isCoreBizObject && ctx.formData && ctx.formData.formCustomTemplateKey != undefined && window.$gz.role.hasRole([ window.$gz.role.AUTHORIZATION_ROLES.BizAdmin, window.$gz.role.AUTHORIZATION_ROLES.BizAdminRestricted ]) ) { //NOTE: BizAdmin can edit, BizAdminRestricted can read only //add customize menu item //customize vm.appBar.menuItems.push({ title: "Customize", icon: "$ayiCustomize", data: ctx.formData.formCustomTemplateKey, key: "app:customize" }); } //GLOBAL BOTTOM PORTION //SEARCH //all forms except the search form if (!ctx.hideSearch && !UTILITY_TYPES.includes(formAyaType)) { //For all forms but not on the search form itself; if this is necessary for others then make a nosearch or something flag controlled by incoming ctx but if not then this should suffice vm.appBar.menuItems.push({ title: "Search", icon: "$ayiSearch", key: "app:search", data: formAyaType }); } //HELP vm.appBar.menuItems.push({ title: "MenuHelp", icon: "$ayiQuestionCircle", key: "app:help", data: vm.appBar.helpUrl }); //ABOUT if (!isCoreBizObject && ctx.helpUrl != "ay-about") { vm.appBar.menuItems.push({ title: "HelpAboutAyaNova", icon: "$ayiInfoCircle", key: "app:nav:abt", data: "ay-about" }); } }, //Unused to date of beta 0.9 // /////////////////////////////// // // CHANGE HANDLER // // // // Deal with a menu item update request // // called from App.vue // handleReplaceMenuItem(vm, newItem) { // if (!vm.appBar.menuItems || !newItem) { // return; // } // //Find the key that is in the collection and replace it // for (let i = 0; i < vm.appBar.menuItems.length; i++) { // if (vm.appBar.menuItems[i].key == newItem.key) { // //NOTE: since we are adding a new object, it has no reactivity in it so we need to use the Vue.Set to set it which // //automatically adds the setters and getters that trigger reactivity // //If it was set directly on the array it wouldn't update the UI // vm.$set(vm.appBar.menuItems, i, newItem); // return; // } // } // }, ////////////////////////////////////////////// // LAST REPORT CHANGE HANDLER // update / add last report menu item // handleUpsertLastReport(vm, newItem) { if (!vm.appBar.menuItems || !newItem) { return; } /* window.$gz.eventBus.$emit("menu-upsert-last-report", { title: reportSelected.name, notrans: true, icon: "$ayiFileAlt", key: formKey + ":report:" + reportSelected.id, vm: vm }); */ let key = null; //Find the last report key and update it if present for (let i = 0; i < vm.appBar.menuItems.length; i++) { key = vm.appBar.menuItems[i].key; if (key && key.includes(":report:")) { vm.appBar.menuItems[i].key = newItem.key; vm.appBar.menuItems[i].title = newItem.title; return; } } //No prior last report so slot it in under the report one for (let i = 0; i < vm.appBar.menuItems.length; i++) { key = vm.appBar.menuItems[i].key; if (key && key.endsWith(":report")) { vm.appBar.menuItems.splice(i + 1, 0, newItem); } } }, /////////////////////////////// // ENABLE / DISABLE HANDLER // // Deal with a menu item enable / disable // called from App.vue handleDisableMenuItem(vm, key, disabled) { if (!vm.appBar.menuItems || !key) { return; } //Find the menu item and set it to disabled and recolor it to disabled color and return for (let i = 0; i < vm.appBar.menuItems.length; i++) { const menuItem = vm.appBar.menuItems[i]; if (menuItem.key == key) { vm.$set(vm.appBar.menuItems[i], "disabled", disabled); //menuItem.disabled = disabled; vm.$set(vm.appBar.menuItems[i], "color", disabled ? "disabled" : ""); return; } } }, /////////////////////////////// // CHANGE ICON HANDLER // Change icon dymanically // (note, can pass null for new icon to clear it) // handleChangeMenuItemIcon(vm, key, newIcon) { if (!vm.appBar.menuItems || !key) { return; } //Find the menu item and change it's icon for (let i = 0; i < vm.appBar.menuItems.length; i++) { const menuItem = vm.appBar.menuItems[i]; if (menuItem.key == key) { vm.$set(vm.appBar.menuItems[i], "icon", newIcon); return; } } }, /////////////////////////////// // APP (GLOBAL) CLICK HANDLER // // Deal with a menu change request // called from App.vue handleAppClick(vm, menuItem) { //Key will start with the string "app:" if it's a global application command that should be handled here, //otherwise it's a local command for a local form only //If there is any extended information required for the command it will be in the data property of the menu item //split a key into component parts, part one is the responsible party, part two is the command, part three only exists to make it unique if necessary //each part is separated by a colon //Handle different items const item = this.parseMenuItem(menuItem); if (!item.disabled && item.owner == "app") { switch (item.key) { case "help": if (item.data.includes("~customer~")) { window.open( window.$gz.api.helpUrlCustomer() + item.data.replace("~customer~", ""), "_blank" ); } else { window.open(window.$gz.api.helpUrl() + item.data, "_blank"); } break; case "search": vm.$router.push({ name: "home-search", params: { ayatype: item.data } }); break; case "review": //go to list // path: "/home-reviews/:aType?/:objectId?", vm.$router.push({ name: "home-reviews", params: { aType: window.$gz.util.stringToIntOrNull(item.data.ayaType), objectId: window.$gz.util.stringToIntOrNull(item.data.recordId), name: item.data.recordName } }); break; case "history": vm.$router.push({ name: "ay-history", params: { ayatype: item.data.ayaType, recordid: item.data.recordId } }); break; case "customize": vm.$router.push({ name: "ay-customize", params: { formCustomTemplateKey: item.data } }); break; case "nav": vm.$router.push({ name: item.data }); break; default: window.$gz.eventBus.$emit( "notify-warning", "gzmenu:handleAppClick - unrecognized command [" + menuItem.key + "]" ); } } }, /////////////////////////////// // PARSE MENU ITEM CLICK // // parse out the parts of a // menu item from a click event // parseMenuItem(menuItem) { //format is "AREA:KEY:UNIQUEID" //and data is in data portion const keyparts = menuItem.key.split(":"); const ret = { owner: keyparts[0], key: keyparts[1], data: menuItem.data, disabled: menuItem.disabled, vm: menuItem.vm ? menuItem.vm : null }; if (keyparts.length > 2) { ret.id = keyparts[2]; } return ret; }, /////////////////////////////////// // WIRE UP MENU EVENTS // // called once from app.vue only // wireUpEventHandlers(vm) { const that = this; window.$gz.eventBus.$on("menu-change", function handleMenuChange(ctx) { that.handleMenuChange(vm, ctx); }); window.$gz.eventBus.$on( "menu-upsert-last-report", function handleUpsertLastReport(newItem) { that.handleUpsertLastReport(vm, newItem); } ); window.$gz.eventBus.$on("menu-disable-item", function handleDisableMenuItem( key ) { that.handleDisableMenuItem(vm, key, true); }); window.$gz.eventBus.$on("menu-enable-item", function handleDisableMenuItem( key ) { that.handleDisableMenuItem(vm, key, false); }); window.$gz.eventBus.$on( "menu-change-item-icon", function handleChangeMenuItemIcon(key, newIcon) { that.handleChangeMenuItemIcon(vm, key, newIcon); } ); window.$gz.eventBus.$on("menu-click", function handleMenuClick(menuitem) { that.handleAppClick(vm, menuitem); }); } //new functions above here };