From d34bfc7d78be85b0796119b2be5294ef31485d12 Mon Sep 17 00:00:00 2001 From: Sviatoslav Bar Date: Sun, 15 Sep 2024 23:59:04 +0300 Subject: [PATCH] Feat/ lookups - object pages mixins [WTEL-4740] --- .../objectTableAccessControlMixin.js | 10 ++ .../objectTableMixin/tableComponentMixin.js | 112 ++++++++++++++ .../openedObjectAccessControlMixin.js | 11 ++ .../openedObjectMixin/nestedObjectMixin.js | 54 +++++++ .../openedObjectMixin/openedObjectMixin.js | 78 ++++++++++ .../openedObjectTabAccessControlMixin.js | 11 ++ .../openedTabComponentMixin.js | 44 ++++++ .../openedObjectTableTabMixin.js | 141 +++++++++++++++++ .../permissionsTabMixin.js | 146 ++++++++++++++++++ .../permissionsTabRolePopupMixin.js | 60 +++++++ src/app/mixins/objectPagesMixins/readme.md | 8 + 11 files changed, 675 insertions(+) create mode 100644 src/app/mixins/objectPagesMixins/objectTableMixin/_internals/objectTableAccessControlMixin.js create mode 100644 src/app/mixins/objectPagesMixins/objectTableMixin/tableComponentMixin.js create mode 100644 src/app/mixins/objectPagesMixins/openedObjectMixin/_internals/openedObjectAccessControlMixin.js create mode 100644 src/app/mixins/objectPagesMixins/openedObjectMixin/nestedObjectMixin.js create mode 100644 src/app/mixins/objectPagesMixins/openedObjectMixin/openedObjectMixin.js create mode 100644 src/app/mixins/objectPagesMixins/openedObjectTabMixin/_internals/openedObjectTabAccessControlMixin.js create mode 100644 src/app/mixins/objectPagesMixins/openedObjectTabMixin/openedTabComponentMixin.js create mode 100644 src/app/mixins/objectPagesMixins/openedObjectTableTabMixin/openedObjectTableTabMixin.js create mode 100644 src/app/mixins/objectPagesMixins/permissionsTabMixin/permissionsTabMixin.js create mode 100644 src/app/mixins/objectPagesMixins/permissionsTabMixin/permissionsTabRolePopupMixin.js create mode 100644 src/app/mixins/objectPagesMixins/readme.md diff --git a/src/app/mixins/objectPagesMixins/objectTableMixin/_internals/objectTableAccessControlMixin.js b/src/app/mixins/objectPagesMixins/objectTableMixin/_internals/objectTableAccessControlMixin.js new file mode 100644 index 00000000..b393b819 --- /dev/null +++ b/src/app/mixins/objectPagesMixins/objectTableMixin/_internals/objectTableAccessControlMixin.js @@ -0,0 +1,10 @@ +import accessControlMixin from '../../../baseMixins/accessControlMixin/accessControlMixin'; + +export default { + mixins: [accessControlMixin], + computed: { + hasTableActions() { + return this.hasEditAccess || this.hasDeleteAccess; + }, + }, +}; diff --git a/src/app/mixins/objectPagesMixins/objectTableMixin/tableComponentMixin.js b/src/app/mixins/objectPagesMixins/objectTableMixin/tableComponentMixin.js new file mode 100644 index 00000000..7cbb0243 --- /dev/null +++ b/src/app/mixins/objectPagesMixins/objectTableMixin/tableComponentMixin.js @@ -0,0 +1,112 @@ +import getNamespacedState from '@webitel/ui-sdk/src/store/helpers/getNamespacedState'; +import { mapActions, mapGetters, mapState } from 'vuex'; +import baseTableMixin from '../../baseMixins/baseTableMixin/baseTableMixin'; +import objectTableAccessControlMixin from './_internals/objectTableAccessControlMixin'; + +/** + * @fileOverview contains main tables (like the-contact-groups.vue) common logic + * @param {string} this.namespace - should be declared in data() + * and contain a string name for storeModule like 'ccenter/agents/skills' + * @param {string} this.routeName - should be declared in data() + * and contain a string name for edit and new entity route names + * like 'cc-agent' for create() and edit() method standardization + * @extends baseTableMixin, objectTableAccessControlMixin + */ +export default { + mixins: [baseTableMixin, objectTableAccessControlMixin], + computed: { + ...mapState({ + headersValue(state) { + return getNamespacedState(state, this.namespace).headers; + }, + dataList(state) { + console.warn(getNamespacedState(state, this.namespace)); + return getNamespacedState(state, this.namespace).dataList; + }, + page(state) { + return getNamespacedState(state, this.namespace).page; + }, + size(state) { + return getNamespacedState(state, this.namespace).size; + }, + search(state) { + return getNamespacedState(state, this.namespace).search; + }, + isNext(state) { + return getNamespacedState(state, this.namespace).isNextPage; + }, + }), + ...mapGetters('appearance', { + darkMode: 'DARK_MODE', + }), + headers() { + if (!this.headersValue) return []; + return this.headersValue.map((header) => { + let localizedText; + // set "false" if no locale prop + + if (header.locale) { + localizedText = !header.locale || typeof header.locale === 'string' + ? this.$t(header.locale) + : this.$t(...header.locale); + } + return { + ...header, + text: localizedText || header.text, + }; + }); + }, + selectedRows() { + return this.dataList.filter((item) => item._isSelected); + }, + // shows delete table action if some items are selected + anySelected() { + return !this.selectedRows?.length; + }, + }, + methods: { + ...mapActions({ + loadDataList(dispatch, payload) { + return dispatch(`${this.namespace}/LOAD_DATA_LIST`, payload); + }, + setSize(dispatch, payload) { + return dispatch(`${this.namespace}/SET_SIZE`, payload); + }, + setSearch(dispatch, payload) { + return dispatch(`${this.namespace}/SET_SEARCH`, payload); + }, + nextPage(dispatch, payload) { + return dispatch(`${this.namespace}/NEXT_PAGE`, payload); + }, + prevPage(dispatch, payload) { + return dispatch(`${this.namespace}/PREV_PAGE`, payload); + }, + dispatchSort(dispatch, payload) { + return dispatch(`${this.namespace}/SORT`, payload); + }, + dispatchDelete(dispatch, payload) { + return dispatch(`${this.namespace}/DELETE`, payload); + }, + patchItem(dispatch, payload) { + return dispatch(`${this.namespace}/PATCH_ITEM_PROPERTY`, payload); + }, + resetState(dispatch, payload) { + return dispatch(`${this.namespace}/RESET_ITEM_STATE`, payload); + }, + }), + create() { + this.resetState(); + this.$router.push({ name: `${this.routeName}-card`, params: { id: 'new' } }); + }, + edit(item) { + this.resetState(); + this.$router.push(this.editLink(item)); + }, + sort(...params) { + this.dispatchSort({ + header: params[0], + nextSortOrder: params[1], + }); + }, + }, +}; diff --git a/src/app/mixins/objectPagesMixins/openedObjectMixin/_internals/openedObjectAccessControlMixin.js b/src/app/mixins/objectPagesMixins/openedObjectMixin/_internals/openedObjectAccessControlMixin.js new file mode 100644 index 00000000..5f6c40f1 --- /dev/null +++ b/src/app/mixins/objectPagesMixins/openedObjectMixin/_internals/openedObjectAccessControlMixin.js @@ -0,0 +1,11 @@ +import accessControlMixin from '../../../baseMixins/accessControlMixin/accessControlMixin'; + +export default { + mixins: [accessControlMixin], + computed: { + hasSaveActionAccess() { + if (this.$route.params.id === 'new') return this.hasEditAccess; + return this.hasCreateAccess; + }, + }, +}; diff --git a/src/app/mixins/objectPagesMixins/openedObjectMixin/nestedObjectMixin.js b/src/app/mixins/objectPagesMixins/openedObjectMixin/nestedObjectMixin.js new file mode 100644 index 00000000..d285f76d --- /dev/null +++ b/src/app/mixins/objectPagesMixins/openedObjectMixin/nestedObjectMixin.js @@ -0,0 +1,54 @@ +import getNamespacedState from '@webitel/ui-sdk/src/store/helpers/getNamespacedState'; +import { mapActions, mapState } from 'vuex'; +import baseObjectMixin from '../../baseMixins/baseObjectMixin/baseObjectMixin'; + +/** + * @fileOverview contains nestedObject common logic + * (popup entity inside objectTab like opened-agent-skills-popup.vue) + * @param {string} this.namespace - should be declared in data() + * and contain a string name for storeModule like 'ccenter/agents/skills' + * @extends baseObjectMixin + */ +export default { + mixins: [baseObjectMixin], + + computed: { + ...mapState({ + id(state) { + return getNamespacedState(state, this.namespace).itemId; + }, + itemInstance(state) { + return getNamespacedState(state, this.namespace).itemInstance; + }, + }), + }, + + methods: { + ...mapActions({ + setItemProp(dispatch, payload) { + return dispatch(`${this.namespace}/SET_ITEM_PROPERTY`, payload); + }, + setId(dispatch, payload) { + return dispatch(`${this.namespace}/SET_ITEM_ID`, payload); + }, + }), + + async save() { + const invalid = this.checkValidations(); + if (!invalid) { + try { + if (this.id) { + await this.updateItem(); + } else { + await this.addItem(); + } + this.close(); + } catch {} + } + }, + + close() { + this.$emit('close'); + }, + }, +}; diff --git a/src/app/mixins/objectPagesMixins/openedObjectMixin/openedObjectMixin.js b/src/app/mixins/objectPagesMixins/openedObjectMixin/openedObjectMixin.js new file mode 100644 index 00000000..4c999328 --- /dev/null +++ b/src/app/mixins/objectPagesMixins/openedObjectMixin/openedObjectMixin.js @@ -0,0 +1,78 @@ +import getNamespacedState from '@webitel/ui-sdk/src/store/helpers/getNamespacedState'; +import { mapActions, mapState } from 'vuex'; +import Permissions from '../../../../modules/_shared/permissions-tab/components/permissions-tab.vue'; +import baseObjectMixin from '../../baseMixins/baseObjectMixin/baseObjectMixin'; +import headlineNavMixin from '../../baseMixins/headlineNavMixin/headlineNavMixin'; +import openedObjectAccessControlMixin from './_internals/openedObjectAccessControlMixin'; + +/** + * @fileOverview contains openedObject (wrapper with tabs, like opened-agent.vue) common logic + * @param {string} this.namespace - should be declared in data() + * and contain a string name for storeModule like 'ccenter/agents/skills' + * @extends baseObjectMixin + */ +export default { + mixins: [openedObjectAccessControlMixin, headlineNavMixin, baseObjectMixin], + components: { + Permissions, + }, + + created() { + this.loadPageData(); + }, + + computed: { + ...mapState({ + id(state) { + return getNamespacedState(state, this.namespace).itemId; + }, + itemInstance(state) { + return getNamespacedState(state, this.namespace).itemInstance; + }, + }), + permissionsTab() { + return { + text: this.$t('objects.permissions.permissions', 2), + value: 'permissions', + pathName: this.permissionsTabPathName, + }; + }, + currentTab() { + return this.tabs.find(({pathName}) => this.$route.name === pathName) || this.tabs[0]; + }, + }, + + methods: { + ...mapActions({ + setId(dispatch, payload) { + return dispatch(`${this.namespace}/SET_ITEM_ID`, payload); + }, + resetState(dispatch, payload) { + return dispatch(`${this.namespace}/RESET_ITEM_STATE`, payload); + }, + }), + + async loadPageData() { + await this.setId(this.$route.params.id); + return this.loadItem(); + }, + + setInitialTab() { + // eslint-disable-next-line prefer-destructuring + if (this.tabs) this.currentTab = this.tabs[0]; + }, + + close() { + + // Need to close the tab if it was open in a new tab + // https://webitel.atlassian.net/browse/WTEL-4575 + // TODO delete close method in all opened objects and add to them routeName property + this.resetState(); + if(window.history.length === 1) window.close(); + this.$router.push({name: this.routeName}); + }, + changeTab(tab) { + this.$router.push({ ...this.$route, name: tab.pathName }); + } + }, +}; diff --git a/src/app/mixins/objectPagesMixins/openedObjectTabMixin/_internals/openedObjectTabAccessControlMixin.js b/src/app/mixins/objectPagesMixins/openedObjectTabMixin/_internals/openedObjectTabAccessControlMixin.js new file mode 100644 index 00000000..f54e1052 --- /dev/null +++ b/src/app/mixins/objectPagesMixins/openedObjectTabMixin/_internals/openedObjectTabAccessControlMixin.js @@ -0,0 +1,11 @@ +import accessControlMixin from '../../../baseMixins/accessControlMixin/accessControlMixin'; + +export default { + mixins: [accessControlMixin], + computed: { + disableUserInput() { + if (this.$route.params.id === 'new') return !this.hasEditAccess; + return !this.hasCreateAccess; + }, + }, +}; diff --git a/src/app/mixins/objectPagesMixins/openedObjectTabMixin/openedTabComponentMixin.js b/src/app/mixins/objectPagesMixins/openedObjectTabMixin/openedTabComponentMixin.js new file mode 100644 index 00000000..16956f11 --- /dev/null +++ b/src/app/mixins/objectPagesMixins/openedObjectTabMixin/openedTabComponentMixin.js @@ -0,0 +1,44 @@ +import getNamespacedState from '@webitel/ui-sdk/src/store/helpers/getNamespacedState'; +import { mapActions, mapState } from 'vuex'; + +import openedObjectValidationMixin from '../../baseMixins/openedObjectValidationMixin/openedObjectValidationMixin'; +import openedObjectTabAccessControlMixin from './_internals/openedObjectTabAccessControlMixin'; + +/** + * @fileOverview contains openedObject tab + * (tab with subordinate entity, like opened-agent-general.vue) common logic + * @param {string} this.namespace - should be passed as prop from tabs wrapper + * @extends openedObjectValidationMixin, openedObjectTabAccessControlMixin + */ +export default { + mixins: [openedObjectValidationMixin, openedObjectTabAccessControlMixin], + props: { + namespace: { + type: String, + // required: true, FIXME: MAKE ME REQUIRED AFTER REFACTOR + }, + }, + computed: { + ...mapState({ + itemInstance(state) { + return getNamespacedState(state, this.namespace).itemInstance; + }, + }), + }, + methods: { + ...mapActions({ + setItemProp(dispatch, payload) { + return dispatch(`${this.namespace}/SET_ITEM_PROPERTY`, payload); + }, + addVariable(dispatch, payload) { + return dispatch(`${this.namespace}/ADD_VARIABLE_PAIR`, payload); + }, + deleteVariable(dispatch, payload) { + return dispatch(`${this.namespace}/DELETE_VARIABLE_PAIR`, payload); + }, + setVariableProp(dispatch, payload) { + return dispatch(`${this.namespace}/SET_VARIABLE_PROP`, payload); + }, + }), + }, +}; diff --git a/src/app/mixins/objectPagesMixins/openedObjectTableTabMixin/openedObjectTableTabMixin.js b/src/app/mixins/objectPagesMixins/openedObjectTableTabMixin/openedObjectTableTabMixin.js new file mode 100644 index 00000000..7a4ce718 --- /dev/null +++ b/src/app/mixins/objectPagesMixins/openedObjectTableTabMixin/openedObjectTableTabMixin.js @@ -0,0 +1,141 @@ +import getNamespacedState from '@webitel/ui-sdk/src/store/helpers/getNamespacedState'; +import { mapActions, mapGetters, mapState } from 'vuex'; +import ObjectListPopup from '../../../components/utils/object-list-popup/object-list-popup.vue'; +import OnePlusMany from '../../../components/utils/table-cell/one-plus-many-table-cell/one-plus-many-table-cell.vue'; +import baseTableMixin from '../../baseMixins/baseTableMixin/baseTableMixin'; +import openedTabComponentMixin from '../openedObjectTabMixin/openedTabComponentMixin'; + +/** + * @fileOverview contains openedObject tab with table + * (tab with subordinate entity, like opened-agent-teams.vue) common logic + * @param {string} this.subNamespace - should be declared in data() + * and contain a string name for sub-entity storeModule like 'teams' + * @extends openedTabComponentMixin, + * @extends baseTableMixin + */ +export default { + mixins: [openedTabComponentMixin, baseTableMixin], + components: { OnePlusMany, ObjectListPopup }, + inject: ['$eventBus'], + watch: { + parentId(value) { + this.setParentId(value); + }, + }, + + computed: { + ...mapState({ + parentId(state) { + return getNamespacedState(state, `${this.namespace}`).itemId; + }, + headersValue(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).headers; + }, + dataList(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).dataList; + }, + page(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).page; + }, + size(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).size; + }, + search(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).search; + }, + isNext(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).isNextPage; + }, + aggs(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).aggs; + }, + }), + ...mapGetters('appearance', { + darkMode: 'DARK_MODE', + }), + headers() { + if (!this.headersValue) return []; + return this.headersValue.map((header) => ({ + ...header, + text: + typeof header.locale === 'string' ? this.$t(header.locale) : this.$t(...header.locale), + })); + }, + }, + + methods: { + ...mapActions({ + addParentItem(dispatch, payload) { + return dispatch(`${this.namespace}/ADD_ITEM`, payload); + }, + }), + loadDataList(payload) { + if (!this.parentId) return; + this.loadDataListAction(payload); + }, + ...mapActions({ + setParentId(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SET_PARENT_ITEM_ID`, payload); + }, + setId(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SET_ITEM_ID`, payload); + }, + loadDataListAction(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/LOAD_DATA_LIST`, payload); + }, + setSize(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SET_SIZE`, payload); + }, + setSearch(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SET_SEARCH`, payload); + }, + nextPage(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/NEXT_PAGE`, payload); + }, + prevPage(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/PREV_PAGE`, payload); + }, + dispatchSort(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SORT`, payload); + }, + dispatchDelete(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/DELETE`, payload); + }, + patchItem(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/PATCH_ITEM_PROPERTY`, payload); + }, + resetItemState(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/RESET_ITEM_STATE`, payload); + }, + }), + + async create() { + const invalid = this.checkValidations(); + if (!invalid) { + try { + if (!this.parentId) { + await this.addParentItem(); + await this.$router.replace({ + ...this.$route, + params: { id: this.parentId }, + }); + } + this.addItem(); + } catch (err) { + throw err; + } + } else { + this.$eventBus.$emit('notification', { + type: 'error', + text: 'Check your validations!', + }); + } + }, + sort(...params) { + this.dispatchSort({ + header: params[0], + nextSortOrder: params[1], + }); + }, + }, +}; diff --git a/src/app/mixins/objectPagesMixins/permissionsTabMixin/permissionsTabMixin.js b/src/app/mixins/objectPagesMixins/permissionsTabMixin/permissionsTabMixin.js new file mode 100644 index 00000000..1a38be52 --- /dev/null +++ b/src/app/mixins/objectPagesMixins/permissionsTabMixin/permissionsTabMixin.js @@ -0,0 +1,146 @@ +import getNamespacedState from '@webitel/ui-sdk/src/store/helpers/getNamespacedState'; +import { mapActions, mapState } from 'vuex'; +import AccessMode from '../../../../modules/permissions/modules/objects/store/_internals/enums/AccessMode.enum'; +import tableComponentMixin from '../objectTableMixin/tableComponentMixin'; +import openedTabComponentMixin from '../openedObjectTabMixin/openedTabComponentMixin'; + +export default { + mixins: [openedTabComponentMixin, tableComponentMixin], + data: () => ({ + isRoleSelectPopup: false, + accessMode: AccessMode, + }), + destroyed() { + this.resetState(); + }, + computed: { + ...mapState({ + parentId(state) { + return getNamespacedState(state, `${this.namespace}`).itemId; + }, + headersValue(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).headers; + }, + dataListValue(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).dataList; + }, + page(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).page; + }, + size(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).size; + }, + search(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).search; + }, + isNext(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).isNextPage; + }, + permissionId() { + return this.$route.params.permissionId; + }, + }), + headers() { + if (!this.headersValue) return []; + return this.headersValue.map((header) => ({ + ...header, + text: + typeof header.locale === 'string' ? this.$t(header.locale) : this.$t(...header.locale), + })); + }, + dataList() { + return this.dataListValue.map((item) => { + const access = {}; + Object.keys(item.access).forEach((rule) => { + access[rule] = { + ...item.access[rule], + name: this.$t(`objects.permissions.object.accessMode.${item.access[rule].id}`), + }; + }); + return { + ...item, + access, + }; + }); + }, + accessOptions() { + return Object.values(AccessMode).map((mode) => ({ + id: mode, + name: this.$t(`objects.permissions.object.accessMode.${mode}`), + })); + }, + }, + + methods: { + ...mapActions({ + setParentId(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SET_PARENT_ITEM_ID`, payload); + }, + loadDataList(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/LOAD_DATA_LIST`, payload); + }, + setSize(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SET_SIZE`, payload); + }, + setSearch(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SET_SEARCH`, payload); + }, + nextPage(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/NEXT_PAGE`, payload); + }, + prevPage(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/PREV_PAGE`, payload); + }, + dispatchSort(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/SORT`, payload); + }, + changeCreateAccessMode(dispatch, payload) { + return dispatch( + `${this.namespace}/${this.subNamespace}/CHANGE_CREATE_ACCESS_MODE`, + payload, + ); + }, + changeReadAccessMode(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/CHANGE_READ_ACCESS_MODE`, payload); + }, + changeUpdateAccessMode(dispatch, payload) { + return dispatch( + `${this.namespace}/${this.subNamespace}/CHANGE_UPDATE_ACCESS_MODE`, + payload, + ); + }, + changeDeleteAccessMode(dispatch, payload) { + return dispatch( + `${this.namespace}/${this.subNamespace}/CHANGE_DELETE_ACCESS_MODE`, + payload, + ); + }, + resetState(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/RESET_ITEM_STATE`, payload); + }, + }), + addItem() { + return this.$router.push({ + ...this.$route, + params: { permissionId: 'new' }, + }); + }, + openRoleSelectPopup() { + this.isRoleSelectPopup = true; + }, + closeRoleSelectPopup() { + this.$router.go(-1); + this.isRoleSelectPopup = false; + }, + }, + watch: { + permissionId: { + handler(value) { + if (value === 'new') { + this.openRoleSelectPopup(); + } + }, + immediate: true, + }, + } +}; diff --git a/src/app/mixins/objectPagesMixins/permissionsTabMixin/permissionsTabRolePopupMixin.js b/src/app/mixins/objectPagesMixins/permissionsTabMixin/permissionsTabRolePopupMixin.js new file mode 100644 index 00000000..fed0427d --- /dev/null +++ b/src/app/mixins/objectPagesMixins/permissionsTabMixin/permissionsTabRolePopupMixin.js @@ -0,0 +1,60 @@ +import getNamespacedState from '@webitel/ui-sdk/src/store/helpers/getNamespacedState'; +import { mapActions, mapState } from 'vuex'; +import RolesAPI from '../../../../modules/permissions/modules/roles/api/roles'; + +export default { + props: { + namespace: { + type: String, + required: true, + }, + subNamespace: { + type: String, + required: true, + }, + }, + data: () => ({ + newGrantee: '', + }), + computed: { + ...mapState({ + dataList(state) { + return getNamespacedState(state, `${this.namespace}/${this.subNamespace}`).dataList; + }, + }), + }, + methods: { + ...mapActions({ + addRolePermissions(dispatch, payload) { + return dispatch(`${this.namespace}/${this.subNamespace}/ADD_ROLE_PERMISSIONS`, payload); + }, + }), + async save() { + try { + await this.addRolePermissions(this.newGrantee); + this.close(); + } catch (err) { + throw err; + } + }, + + // filter new roles + async getAvailableGrantees(params) { + const roles = await this.loadRoles(params); + roles.items = roles.items.filter( + (role) => !this.dataList.some((usedRoles) => role.id === usedRoles.grantee.id), + ); + return roles; + }, + async loadRoles(params) { + const fields = ['name', 'id', 'user']; + return RolesAPI.getExtendedRoles({ + ...params, + fields, + }); + }, + close() { + this.$emit('close'); + }, + }, +}; diff --git a/src/app/mixins/objectPagesMixins/readme.md b/src/app/mixins/objectPagesMixins/readme.md new file mode 100644 index 00000000..c2e58bce --- /dev/null +++ b/src/app/mixins/objectPagesMixins/readme.md @@ -0,0 +1,8 @@ +# objectPagesMixins +--- +Implement common logic of a default type of UI Component like: + +* Object **tables** (`the-users.vue`) +* Opened object card components wrapper: **openedObject** (`opened-user.vue`) +* Opened object tabs: **openedTabComponent** (`opened-user-tokens.vue`) +* etc.. \ No newline at end of file