8016-userRole #1677
|
@ -654,7 +654,7 @@ const rowCtrlClickFunction = computed(() => {
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
:disable-infinite-scroll="isTableMode"
|
:disable-infinite-scroll="isTableMode"
|
||||||
:before-save-fn="removeTextValue"
|
:before-save-fn="removeTextValue"
|
||||||
@save-changes="reload"
|
@save-changes="reload && emit('saveChanges')"
|
||||||
:has-sub-toolbar="$props.hasSubToolbar ?? isEditable"
|
:has-sub-toolbar="$props.hasSubToolbar ?? isEditable"
|
||||||
:auto-load="hasParams || $attrs['auto-load']"
|
:auto-load="hasParams || $attrs['auto-load']"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeMount, computed, markRaw } from 'vue';
|
import { onBeforeMount, computed, markRaw, watch } from 'vue';
|
||||||
import { useRoute, useRouter, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router';
|
import { useRoute, useRouter, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router';
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import useCardSize from 'src/composables/useCardSize';
|
import useCardSize from 'src/composables/useCardSize';
|
||||||
import VnSubToolbar from '../ui/VnSubToolbar.vue';
|
import VnSubToolbar from '../ui/VnSubToolbar.vue';
|
||||||
|
|
||||||
const emit = defineEmits(['onFetch']);
|
const emit = defineEmits(['onFetch', 'onChange']);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: { type: Number, required: false, default: null },
|
id: { type: Number, required: false, default: null },
|
||||||
|
@ -68,6 +68,12 @@ function hasRouteParam(params, valueToCheck = ':addressId') {
|
||||||
return Object.values(params).includes(valueToCheck);
|
return Object.values(params).includes(valueToCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => arrayData?.store?.data,
|
||||||
|
(data) => {
|
||||||
|
emit('onChange', data);
|
||||||
|
},
|
||||||
|
);
|
||||||
function formatUrl(id) {
|
function formatUrl(id) {
|
||||||
const newId = id || entityId.value;
|
const newId = id || entityId.value;
|
||||||
const regex = /\/(\d+)/;
|
const regex = /\/(\d+)/;
|
||||||
|
|
|
@ -29,6 +29,12 @@ const entity = ref();
|
||||||
emit('onFetch', data);
|
emit('onFetch', data);
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
|
@on-change="
|
||||||
|
(data) => {
|
||||||
|
entity = data;
|
||||||
|
emit('onFetch', data);
|
||||||
|
}
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<VnDescriptor v-model="entity" v-bind="$attrs">
|
<VnDescriptor v-model="entity" v-bind="$attrs">
|
||||||
<template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
|
<template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
|
||||||
|
|
|
@ -9,6 +9,7 @@ import filter from './Card/AccountFilter.js';
|
||||||
import VnSection from 'src/components/common/VnSection.vue';
|
import VnSection from 'src/components/common/VnSection.vue';
|
||||||
import FetchData from 'src/components/FetchData.vue';
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
import VnInputPassword from 'src/components/common/VnInputPassword.vue';
|
import VnInputPassword from 'src/components/common/VnInputPassword.vue';
|
||||||
|
import RoleJoin from './Role/RoleJoin';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
|
@ -58,7 +59,7 @@ const columns = computed(() => [
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
},
|
},
|
||||||
format: ({ role }, dashIfEmpty) => dashIfEmpty(role?.name),
|
format: ({ role }, dashIfEmpty) => dashIfEmpty(RoleJoin(role)),
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -149,12 +150,12 @@ const columns = computed(() => [
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
>
|
>
|
||||||
<template #more-create-dialog="{ data }">
|
<template #more-create-dialog="{ data }">
|
||||||
<VnInputPassword
|
<VnInputPassword
|
||||||
:label="t('Password')"
|
:label="t('Password')"
|
||||||
v-model="data.password"
|
v-model="data.password"
|
||||||
:required="true"
|
:required="true"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</VnTable>
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
|
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
|
import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
|
||||||
import VnImg from 'src/components/ui/VnImg.vue';
|
import VnImg from 'src/components/ui/VnImg.vue';
|
||||||
import filter from './AccountFilter.js';
|
|
||||||
import useHasAccount from 'src/composables/useHasAccount.js';
|
import useHasAccount from 'src/composables/useHasAccount.js';
|
||||||
|
import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
|
||||||
|
import AccountCard from './AccountCard.vue';
|
||||||
|
import RoleJoin from '../Role/RoleJoin';
|
||||||
|
|
||||||
const $props = defineProps({ id: { type: Number, default: null } });
|
const $props = defineProps({ id: { type: Number, default: null } });
|
||||||
|
|
||||||
|
@ -20,13 +21,7 @@ onMounted(async () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<EntityDescriptor
|
<CardDescriptor v-bind="$attrs" :id="entityId" :card="AccountCard" module="Account">
|
||||||
ref="descriptor"
|
|
||||||
:url="`VnUsers/preview`"
|
|
||||||
:filter="{ ...filter, where: { id: entityId } }"
|
|
||||||
data-key="Account"
|
|
||||||
title="nickname"
|
|
||||||
>
|
|
||||||
<template #menu>
|
<template #menu>
|
||||||
<AccountDescriptorMenu :entity-id="entityId" />
|
<AccountDescriptorMenu :entity-id="entityId" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -50,7 +45,7 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<VnLv :label="$t('account.card.nickname')" :value="entity.name" />
|
<VnLv :label="$t('account.card.nickname')" :value="entity.name" />
|
||||||
<VnLv :label="$t('account.card.role')" :value="entity.role?.name" />
|
<VnLv :label="$t('account.card.role')" :value="RoleJoin(entity.role)" />
|
||||||
</template>
|
</template>
|
||||||
<template #actions="{ entity }">
|
<template #actions="{ entity }">
|
||||||
<QCardActions class="q-gutter-x-md">
|
<QCardActions class="q-gutter-x-md">
|
||||||
|
@ -78,7 +73,7 @@ onMounted(async () => {
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</QCardActions>
|
</QCardActions>
|
||||||
</template>
|
</template>
|
||||||
</EntityDescriptor>
|
</CardDescriptor>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.q-item__label {
|
.q-item__label {
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
export default {
|
export default {
|
||||||
include: { relation: 'role', scope: { fields: ['id', 'name'] } },
|
include: {
|
||||||
|
relation: 'role',
|
||||||
|
scope: {
|
||||||
|
include: [{ relation: 'role', scope: { fields: ['id', 'name'] } }],
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,49 +1,120 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const arrayData = useArrayData('Account');
|
||||||
|
|
||||||
|
const vnTableRef = ref({});
|
||||||
const rolesOptions = ref([]);
|
const rolesOptions = ref([]);
|
||||||
const formModelRef = ref();
|
const roleRoleRef = ref();
|
||||||
watch(
|
const suggestions = ref([]);
|
||||||
() => route.params.id,
|
const myRoleRoles = ref([]);
|
||||||
() => formModelRef.value.reset()
|
const selectedRows = ref([]);
|
||||||
);
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
name: 'roleFk',
|
||||||
|
label: t('account.card.role'),
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
options: rolesOptions,
|
||||||
|
inputDebounce: 0,
|
||||||
|
},
|
||||||
|
format: (row) => rolesOptions.value?.find((role) => role.id === row.roleFk)?.name,
|
||||||
|
create: true,
|
||||||
|
columnCreate: {
|
||||||
|
event: {
|
||||||
|
'update:modelValue': (role) => suggestionNewRole(role),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
columnFilter: false,
|
||||||
|
cardVisible: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hasGrant',
|
||||||
|
label: t('account.card.privileges.delegate'),
|
||||||
|
component: 'checkbox',
|
||||||
|
create: true,
|
||||||
|
columnFilter: false,
|
||||||
|
cardVisible: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const suggestionColumns = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'center',
|
||||||
|
name: 'role',
|
||||||
|
field: 'role',
|
||||||
|
label: t('Suggestion for role change'),
|
||||||
|
format: (row) => rolesOptions.value?.find((role) => role.id === row)?.name,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
async function suggestionNewRole(role) {
|
||||||
|
const newRoleRole = await roleRoleRef.value.fetch({ where: { inheritsFrom: role } });
|
||||||
|
|
||||||
|
suggestions.value = newRoleRole.filter((value) =>
|
||||||
|
myRoleRoles.value.includes(value.role),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMyRoleRole(roles) {
|
||||||
|
const myRoleRole = await roleRoleRef.value.fetch({
|
||||||
|
where: { inheritsFrom: { inq: roles.map((role) => role.roleFk) } },
|
||||||
|
});
|
||||||
|
|
||||||
|
myRoleRoles.value = myRoleRole.map((role) => role.role);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData url="VnRoles" auto-load @on-fetch="(data) => (rolesOptions = data)" />
|
<FetchData url="VnRoles" @on-fetch="(data) => (rolesOptions = data)" auto-load />
|
||||||
<FormModel
|
<FetchData ref="roleRoleRef" url="RoleRoles" />
|
||||||
ref="formModelRef"
|
<VnTable
|
||||||
model="AccountPrivileges"
|
ref="vnTableRef"
|
||||||
url="VnUsers/preview"
|
data-key="AccountPrivileges"
|
||||||
:filter="{ where: { id: route.params.id } }"
|
:url="`VnUsers/${route.params.id}/role`"
|
||||||
:url-create="`VnUsers/${route.params.id}/privileges`"
|
save-url="userRoles/crud"
|
||||||
:id="route.params.id"
|
v-model:selected="selectedRows"
|
||||||
|
:table="{
|
||||||
|
'row-key': 'id',
|
||||||
|
selection: 'multiple',
|
||||||
|
}"
|
||||||
|
:create="{
|
||||||
|
urlCreate: 'userRoles/crud',
|
||||||
|
title: t('Add Privileges'),
|
||||||
|
onDataSaved: () => {
|
||||||
|
$refs.vnTableRef.reload();
|
||||||
|
},
|
||||||
|
showSaveAndContinueBtn: true,
|
||||||
|
formInitialData: { hasGrant: false },
|
||||||
|
mapper: (data) => {
|
||||||
|
return { creates: [{ ...data, userFk: route.params.id }] };
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
:columns
|
||||||
|
:right-search="false"
|
||||||
|
:is-editable="true"
|
||||||
|
@on-fetch="(data) => getMyRoleRole(data)"
|
||||||
|
@save-changes="() => arrayData.fetch({})"
|
||||||
auto-load
|
auto-load
|
||||||
>
|
>
|
||||||
<template #form="{ data }">
|
<template #more-create-dialog="{ data }">
|
||||||
<div class="q-gutter-y-sm">
|
<QTable
|
||||||
<QCheckbox
|
v-if="data.roleFk && suggestions.length > 0"
|
||||||
v-model="data.hasGrant"
|
:rows="suggestions"
|
||||||
:label="t('account.card.privileges.delegate')"
|
:columns="suggestionColumns"
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
|
||||||
:label="t('account.card.role')"
|
|
||||||
v-model="data.roleFk"
|
|
||||||
:options="rolesOptions"
|
|
||||||
option-value="id"
|
|
||||||
option-label="name"
|
|
||||||
hide-selected
|
|
||||||
:required="true"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Suggestion for role change: Sugerencia de cambio de rol
|
||||||
|
Add Privileges: Añadir privilegios
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import filter from './AccountFilter.js';
|
import filter from './AccountFilter.js';
|
||||||
import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
|
import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
|
||||||
import VnTitle from 'src/components/common/VnTitle.vue';
|
import VnTitle from 'src/components/common/VnTitle.vue';
|
||||||
|
import RoleJoin from '../Role/RoleJoin';
|
||||||
|
|
||||||
const $props = defineProps({ id: { type: Number, default: 0 } });
|
const $props = defineProps({ id: { type: Number, default: 0 } });
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ const entityId = computed(() => $props.id || route.params.id);
|
||||||
/>
|
/>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<VnLv :label="$t('account.card.nickname')" :value="entity.name" />
|
<VnLv :label="$t('account.card.nickname')" :value="entity.name" />
|
||||||
<VnLv :label="$t('account.card.role')" :value="entity.role?.name" />
|
<VnLv :label="$t('account.card.role')" :value="RoleJoin(entity.role)" />
|
||||||
</QCard>
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
</CardSummary>
|
</CardSummary>
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function (roles) {
|
||||||
|
return roles.map((r) => r.role.name).join(', ');
|
||||||
|
}
|
Loading…
Reference in New Issue