Skip to content

Commit

Permalink
Feat/ CRM - lookups [WTEL-4740]
Browse files Browse the repository at this point in the history
  • Loading branch information
SviatoslavBar committed Sep 13, 2024
1 parent 4dbb207 commit 0b70705
Show file tree
Hide file tree
Showing 91 changed files with 5,297 additions and 275 deletions.
274 changes: 136 additions & 138 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"@vueuse/core": "^10.10.0",
"@webitel/ui-sdk": "^24.8.11",
"@webitel/ui-sdk": "^24.10.7",
"axios": "^1.7.2",
"deep-equal": "^2.2.1",
"dompurify": "^3.1.2",
Expand All @@ -26,7 +26,7 @@
"vue-i18n": "^9.13.1",
"vue-router": "^4.3.2",
"vuex": "^4.1.0",
"webitel-sdk": "^24.4.16"
"webitel-sdk": "^24.8.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "5.0.4",
Expand Down
84 changes: 84 additions & 0 deletions src/app/api/PermissionsAPIService/APIPermissionsGetter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { getDefaultGetListResponse, getDefaultGetParams } from '@webitel/ui-sdk/src/api/defaults/index.js';
import applyTransform, {
camelToSnake,
generateUrl,
merge,
mergeEach,
notify,
sanitize,
snakeToCamel,
starToSearch,
} from '@webitel/ui-sdk/src/api/transformers/index.js';
import instance from '../instance';

export default class APIPermissionsGetter {
nestedUrl = 'acl';

constructor(url) {
this.baseUrl = url;

this.listGetter = async ({ parentId, ...params }) => {
const fieldsToSend = ['page', 'size', 'q', 'sort', 'fields', 'id'];

const defaultObject = {
user: false,
};

const url = applyTransform(params, [
merge(getDefaultGetParams()),
starToSearch('search'),
(params) => ({
...params,
q: params.search,
}),
sanitize(fieldsToSend),
camelToSnake(),
generateUrl(`${this.baseUrl}/${parentId}/${this.nestedUrl}`),
]);
try {
const response = await instance.get(url);
const { items, next } = applyTransform(response.data, [
snakeToCamel(),
merge(getDefaultGetListResponse()),
]);
return {
items: applyTransform(items, [
mergeEach(defaultObject),
APIPermissionsGetter.handlePermissionsList,
]),
next,
};
} catch (err) {
throw applyTransform(err, [notify]);
}
};
}

static handlePermissionsList(items) {
return items.map((item) => ({
...item,
access: {
x: {
id: (item.granted.match(/x/g) || []).length + 1,
rule: 'x'.repeat((item.granted.match(/x/g) || []).length),
},
r: {
id: (item.granted.match(/r/g) || []).length + 1,
rule: 'r'.repeat((item.granted.match(/r/g) || []).length),
},
w: {
id: (item.granted.match(/w/g) || []).length + 1,
rule: 'w'.repeat((item.granted.match(/w/g) || []).length),
},
d: {
id: (item.granted.match(/d/g) || []).length + 1,
rule: 'd'.repeat((item.granted.match(/d/g) || []).length),
},
},
}));
}

async getList(params) {
return this.listGetter(params);
}
}
27 changes: 27 additions & 0 deletions src/app/api/PermissionsAPIService/APIPermissionsPatcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import applyTransform, {
camelToSnake,
notify,
snakeToCamel,
} from '@webitel/ui-sdk/src/api/transformers/index.js';
import instance from '../instance';

export default class APIPermissionsPatcher {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.patcher = async ({ changes, id }) => {
const afterUrl = 'acl';
const body = applyTransform(changes, [camelToSnake()]);
const url = `${baseUrl}/${id}/${afterUrl}`;
try {
const response = await instance.patch(url, body);
return applyTransform(response.data, [snakeToCamel()]);
} catch (err) {
throw applyTransform(err, [notify]);
}
};
}

async patchItem({ id, changes }) {
return this.patcher({ id, changes });
}
}
41 changes: 41 additions & 0 deletions src/app/components/actions/delete-all-action.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<template>
<div class="delete-all-action">
<wt-tooltip>
<template #activator>
<wt-icon-btn
class="icon-action"
icon="bucket"
v-bind="$attrs"
@click="$emit('click')"
/>
</template>
{{ actionPanelDeleteTooltip }}
</wt-tooltip>
</div>
</template>

<script>
export default {
name: 'DeleteAllAction',
props: {
selectedCount: {
type: Number,
},
},
computed: {
actionPanelDeleteTooltip() {
return this.selectedCount
? this.$t('iconHints.deleteSelected', {
count: this.selectedCount,
})
: this.$t('iconHints.deleteAll');
},
},
};
</script>

<style lang="scss" scoped>
.delete-all-action {
line-height: 0;
}
</style>
5 changes: 5 additions & 0 deletions src/app/components/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import DeleteAllAction from './delete-all-action.vue';

const actions = [DeleteAllAction];

export default actions;
61 changes: 61 additions & 0 deletions src/app/components/utils/object-list-popup/object-list-popup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<template>
<wt-popup
v-bind="$attrs"
size="sm"
min-width="480"
@close="close"
>
<template #title>
{{ title }}
</template>
<template #main>
<section>
<wt-table
:data="dataList"
:grid-actions="false"
:headers="tableHeaders"
:selectable="false"
/>
</section>
</template>
</wt-popup>
</template>

<script>
export default {
name: 'ObjectListPopup',
props: {
title: {
type: String,
default: '',
},
dataList: {
type: Array,
default: () => [],
},
headers: {
type: Array,
description: 'Or default "name" header',
},
},
computed: {
tableHeaders() {
const defaultHeaders = [
{
value: 'name',
text: this.$t('reusable.name'),
},
];
return this.headers || defaultHeaders;
},
},
methods: {
close() {
this.$emit('close');
},
},
};
</script>

<style lang="scss" scoped>
</style>
154 changes: 154 additions & 0 deletions src/app/components/utils/selection-popup/selection-popup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<template>
<wt-popup
v-bind="$attrs"
:min-width="minWidth"
size="sm"
class="selection-popup"
overflow
@close="close"
>
<template #title>
{{ title }}
</template>
<template #main>
<ul class="popup-options">
<li
v-for="(option, key) of options"
:key="key"
:class="{'active': option.value === selected.value }"
class="popup-options__item-wrap"
@click="selectOption(option)"
>
<slot
name="option"
:option="option"
>
<wt-icon
v-if="option.icon"
:icon="option.icon"
size="sm"
/>
<h4 class="popup-options__item-header">
{{ option.title }}
</h4>
<wt-tooltip
popper-class="selection-popup__tooltip-popper"
>
<template #activator>
<wt-icon-btn
v-if="option.description"
color="info"
icon="rounded-info"
/>
</template>
{{ option.description }}
</wt-tooltip>
</slot>
</li>
</ul>
<!--Slot for displaying specific template styling-->
<slot name="after-section" />
</template>

<template #actions>
<wt-button
:disabled="!selected"
@click="add"
>
{{ $t('objects.create') }}
</wt-button>
<wt-button
color="secondary"
@click="close"
>
{{ $t('objects.close') }}
</wt-button>
</template>
</wt-popup>
</template>

<script>
export default {
name: 'SelectionPopup',
model: {
prop: 'selected',
event: 'change',
},
props: {
title: {
type: String,
},
selected: {
type: Object,
description: "Should have following schema: { value: '', title: '', description: ''}",
},
options: {
type: Array,
default: () => [],
},
minWidth: {
type: [String, Number],
default: 480,
},
},
methods: {
add() {
this.$emit('select', this.selected);
},
close() {
this.$emit('close');
},
selectOption(option) {
this.$emit('change', option);
},
isSelected(option) {
return option === this.selected;
},
},
};
</script>

<style lang="scss" scoped>
.selection-popup {
.popup-options {
margin-top: 20px;
padding-right: 10px;
.popup-options__item-wrap {
position: relative;
display: flex;
align-items: center;
margin-bottom: 10px;
padding: 7px 10px;
cursor: pointer;
transition: var(--transition);
border: 1px solid var(--form-border-color);
border-radius: var(--border-radius);
.wt-icon {
margin-right: var(--spacing-xs);
}
&:last-child {
margin-bottom: 0;
}
&:hover, &.active {
border-color: var(--primary-color);
}
.wt-tooltip {
margin-left: auto;
}
}
.popup-options__item-header {
@extend %typo-subtitle-2;
}
}
}
.selection-popup__tooltip-popper {
max-width: 480px;
}
</style>
Loading

0 comments on commit 0b70705

Please sign in to comment.