feat: criterias component
This commit is contained in:
parent
e79dfc0822
commit
38347bc88d
@ -34,37 +34,46 @@
|
|||||||
v-tab-item(key='rights', :transition='false', :reverse-transition='false')
|
v-tab-item(key='rights', :transition='false', :reverse-transition='false')
|
||||||
v-card
|
v-card
|
||||||
v-card-title.pb-0
|
v-card-title.pb-0
|
||||||
v-btn(color='primary')
|
v-subheader
|
||||||
v-icon(left) add
|
v-icon.mr-2 border_color
|
||||||
| Add Rule
|
.subheading Read and Write
|
||||||
v-spacer
|
v-spacer
|
||||||
v-btn(flat)
|
v-btn(flat, outline)
|
||||||
|
v-icon(left) arrow_drop_down
|
||||||
|
| Load Preset
|
||||||
|
v-btn(flat, outline)
|
||||||
v-icon(left) vertical_align_bottom
|
v-icon(left) vertical_align_bottom
|
||||||
| Import Rules
|
| Import Rules
|
||||||
v-list(dense, two-line)
|
.pa-3.pl-4
|
||||||
v-list-tile.grey.lighten-5.px-2
|
criterias
|
||||||
v-list-tile-avatar(color='red'): v-icon(color='white') remove_circle
|
v-divider.my-0
|
||||||
v-list-tile-content
|
v-card-title.pb-0
|
||||||
v-list-tile-title /javascript/*
|
v-subheader
|
||||||
v-list-tile-sub-title.caption #[strong WRITE]
|
v-icon.mr-2 pageview
|
||||||
v-list-tile-action
|
.subheading Read Only
|
||||||
v-btn(icon): v-icon(color='grey') delete
|
v-spacer
|
||||||
v-divider(inset).my-0
|
v-btn(flat, outline)
|
||||||
v-list-tile.grey.lighten-5.px-2
|
v-icon(left) arrow_drop_down
|
||||||
v-list-tile-avatar(color='green'): v-icon(color='white') check
|
| Load Preset
|
||||||
v-list-tile-content
|
v-btn(flat, outline)
|
||||||
v-list-tile-title /javascript/*
|
v-icon(left) vertical_align_bottom
|
||||||
v-list-tile-sub-title.caption #[strong WRITE]
|
| Import Rules
|
||||||
v-list-tile-action
|
.pa-3.pl-4
|
||||||
v-btn(icon): v-icon(color='grey') delete
|
criterias
|
||||||
v-divider(inset).my-0
|
v-divider.my-0
|
||||||
v-list-tile.grey.lighten-5.px-2
|
v-card-title.pb-0
|
||||||
v-list-tile-avatar(color='green'): v-icon(color='white') check
|
v-subheader Legend
|
||||||
v-list-tile-content
|
.px-4.pb-4
|
||||||
v-list-tile-title /javascript/*
|
.body-1.px-1.py-2 Any number of rules can be used at the same time. However, some rules requires more processing time than others. Rule types are color-coded as followed:
|
||||||
v-list-tile-sub-title.caption #[strong READ]
|
.caption
|
||||||
v-list-tile-action
|
v-icon(color='blue') stop
|
||||||
v-btn(icon): v-icon(color='grey') delete
|
span Fast rules. None or insignificant latency introduced to all page loads.
|
||||||
|
.caption
|
||||||
|
v-icon(color='orange') stop
|
||||||
|
span Medium rules. Some latency added to all page loads.
|
||||||
|
.caption
|
||||||
|
v-icon(color='red') stop
|
||||||
|
span Slow rules. May adds noticeable latency to all page loads. Avoid using in multiple rules.
|
||||||
|
|
||||||
v-tab-item(key='users', :transition='false', :reverse-transition='false')
|
v-tab-item(key='users', :transition='false', :reverse-transition='false')
|
||||||
v-card
|
v-card
|
||||||
@ -100,10 +109,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Criterias from '../common/criterias.vue'
|
||||||
|
|
||||||
import groupQuery from 'gql/admin-groups-query-single.gql'
|
import groupQuery from 'gql/admin-groups-query-single.gql'
|
||||||
import deleteGroupMutation from 'gql/admin-groups-mutation-delete.gql'
|
import deleteGroupMutation from 'gql/admin-groups-mutation-delete.gql'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
Criterias
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
group: {
|
group: {
|
||||||
|
141
client/components/common/criterias-item.vue
Normal file
141
client/components/common/criterias-item.vue
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.criterias-item
|
||||||
|
//- Type
|
||||||
|
v-select(solo, :items='filteredCriteriaTypes', v-model='item.type', placeholder='Rule Type', ref='typeSelect')
|
||||||
|
template(slot='item', slot-scope='data')
|
||||||
|
v-list-tile-avatar
|
||||||
|
v-avatar(:color='data.item.color', size='40', tile): v-icon(color='white') {{ data.item.icon }}
|
||||||
|
v-list-tile-content
|
||||||
|
v-list-tile-title(v-html='data.item.text')
|
||||||
|
v-list-tile-sub-title.caption(v-html='data.item.description')
|
||||||
|
|
||||||
|
//- Operator
|
||||||
|
v-select(solo, :items='filteredCriteriaOperators', v-model='item.operator', placeholder='Operator', :disabled='!item.type', :class='!item.type ? "blue-grey lighten-4" : ""')
|
||||||
|
template(slot='item', slot-scope='data')
|
||||||
|
v-list-tile-avatar
|
||||||
|
v-avatar.white--text(color='blue', size='30', tile) {{ data.item.icon }}
|
||||||
|
v-list-tile-content
|
||||||
|
v-list-tile-title(v-html='data.item.text')
|
||||||
|
|
||||||
|
//- Value
|
||||||
|
v-select(v-if='item.type === "country"', solo, :items='countries', v-model='item.value', placeholder='Countries...', multiple, item-text='name', item-value='code')
|
||||||
|
v-text-field(v-else-if='item.type === "path"', solo, v-model='item.value', label='Path (e.g. /section)')
|
||||||
|
v-text-field(v-else-if='item.type === "date"', solo, @click.native.stop='dateActivator = true', v-model='item.value', label='YYYY-MM-DD', readonly)
|
||||||
|
v-text-field.blue-grey.lighten-4(v-else, solo, disabled)
|
||||||
|
|
||||||
|
v-dialog(lazy, v-model='dateActivator', width='290px', ref='dateDialog')
|
||||||
|
v-date-picker(v-model='item.value', scrollable, color='primary')
|
||||||
|
v-btn(flat, color='primary' @click='$refs.dateDialog.save(date)', block) ok
|
||||||
|
|
||||||
|
v-btn(icon, @click='remove'): v-icon(color='blue-grey') clear
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
// import countriesQuery from 'gql/upsells-query-countries.gql'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['allowedCriteriaTypes'],
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
default() { return {} }
|
||||||
|
},
|
||||||
|
groupIndex: {
|
||||||
|
type: Number,
|
||||||
|
default() { return 0 }
|
||||||
|
},
|
||||||
|
itemIndex: {
|
||||||
|
type: Number,
|
||||||
|
default() { return 0 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
item: {
|
||||||
|
operator: '',
|
||||||
|
type: '',
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
dateActivator: false,
|
||||||
|
dateDialog: false,
|
||||||
|
countries: [],
|
||||||
|
criteriaTypes: [
|
||||||
|
{ text: 'Path', value: 'path', icon: 'space_bar', color: 'blue', description: 'Match the path of the document being viewed.' },
|
||||||
|
{ text: 'Date', value: 'date', icon: 'date_range', color: 'blue', description: 'Match the current calendar day.' },
|
||||||
|
{ text: 'Time', value: 'time', icon: 'access_time', color: 'blue', description: 'Match the current time of day.' },
|
||||||
|
{ text: 'User Country', value: 'country', icon: 'public', color: 'red', description: `Match the user's country.` },
|
||||||
|
{ text: 'User Group', value: 'group', icon: 'group', color: 'orange', description: 'Match the user group assignments.' }
|
||||||
|
],
|
||||||
|
criteriaOperators: {
|
||||||
|
country: [
|
||||||
|
{ text: 'In', value: 'in', icon: '[...]' },
|
||||||
|
{ text: 'Not In', value: 'notIn', icon: '[ x ]' }
|
||||||
|
],
|
||||||
|
path: [
|
||||||
|
{ text: 'Matches Exactly', value: 'eq', icon: '=' },
|
||||||
|
{ text: 'NOT Matches Exactly', value: 'ne', icon: '!=' },
|
||||||
|
{ text: 'Starts With', value: 'sw', icon: 'x...' },
|
||||||
|
{ text: 'NOT Starts With', value: 'nsw', icon: '!x...' },
|
||||||
|
{ text: 'Ends With', value: 'ew', icon: '...x' },
|
||||||
|
{ text: 'NOT Ends With', value: 'new', icon: '!...x' },
|
||||||
|
{ text: 'Matches Regex', value: 'regexp', icon: '^x$' }
|
||||||
|
],
|
||||||
|
date: [
|
||||||
|
{ text: 'On or After', value: 'gte', icon: '>=' },
|
||||||
|
{ text: 'On or Before', value: 'lte', icon: '<=' }
|
||||||
|
],
|
||||||
|
time: [
|
||||||
|
{ text: 'At or Later Than', value: 'gte', icon: '>=' },
|
||||||
|
{ text: 'At or Before', value: 'lte', icon: '<=' }
|
||||||
|
],
|
||||||
|
group: [
|
||||||
|
{ text: 'Is Part Of', value: 'in', icon: '[...]' },
|
||||||
|
{ text: 'Is Not Part Of', value: 'notIn', icon: '[ x ]' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredCriteriaOperators() {
|
||||||
|
return _.get(this.criteriaOperators, this.item.type, [])
|
||||||
|
},
|
||||||
|
filteredCriteriaTypes() {
|
||||||
|
console.info(this.allowedCriteriaTypes)
|
||||||
|
return _.filter(this.criteriaTypes, c => _.includes(this.allowedCriteriaTypes, c.value))
|
||||||
|
},
|
||||||
|
itemType() {
|
||||||
|
return this.item.type
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
itemType(newValue, oldValue) {
|
||||||
|
this.item.operator = _.head(this.criteriaOperators[newValue]).value
|
||||||
|
this.item.value = ''
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
handler(newValue, oldValue) {
|
||||||
|
this.$emit('update', this.groupIndex, this.itemIndex, this.item)
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (!this.item.type) {
|
||||||
|
this.$refs.typeSelect.showMenu()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
remove() {
|
||||||
|
this.$emit('remove', this.groupIndex, this.itemIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// apollo: {
|
||||||
|
// countries: {
|
||||||
|
// query: countriesQuery,
|
||||||
|
// update: (data) => data.location.countries
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
</script>
|
173
client/components/common/criterias.vue
Normal file
173
client/components/common/criterias.vue
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.criterias
|
||||||
|
transition-group(name='criterias-group', tag='div')
|
||||||
|
.criterias-group(v-for='(group, g) in groups', :key='g')
|
||||||
|
transition-group(name='criterias-item', tag='div')
|
||||||
|
criterias-item(v-for='(item, i) in group', :key='i', :item='item', :group-index='g', :item-index='i', @update='updateItem', @remove='removeItem')
|
||||||
|
.criterias-item-more
|
||||||
|
v-btn.ml-0(@click='addItem(group)', small, color='blue-grey lighten-2', dark, depressed)
|
||||||
|
v-icon(color='white', left) add
|
||||||
|
| Add condition
|
||||||
|
.criterias-group-more
|
||||||
|
v-btn(@click='addGroup', small, color='blue-grey lighten-1', dark, depressed)
|
||||||
|
v-icon(color='white', left) add
|
||||||
|
| Add condition group
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CriteriasItem from './criterias-item.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CriteriasItem
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
default() { return [] }
|
||||||
|
},
|
||||||
|
types: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return ['country', 'path', 'date', 'time', 'group']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
provide () {
|
||||||
|
return {
|
||||||
|
allowedCriteriaTypes: this.types
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dataGroups: this.value || []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
groups: {
|
||||||
|
get() { return this.dataGroups },
|
||||||
|
set(grp) {
|
||||||
|
this.dataGroups = grp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
dataGroups(newValue, oldValue) {
|
||||||
|
if (newValue !== oldValue) {
|
||||||
|
this.$emit('input', newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addGroup() {
|
||||||
|
this.dataGroups.push([{}])
|
||||||
|
},
|
||||||
|
addItem(group) {
|
||||||
|
group.push({})
|
||||||
|
},
|
||||||
|
updateItem(groupIndex, itemIndex, item) {
|
||||||
|
console.info(item)
|
||||||
|
this.$set(this.dataGroups[groupIndex], itemIndex, item)
|
||||||
|
},
|
||||||
|
removeItem(groupIndex, itemIndex) {
|
||||||
|
this.dataGroups[groupIndex].splice(itemIndex, 1)
|
||||||
|
if (this.dataGroups[groupIndex].length < 1) {
|
||||||
|
this.dataGroups.splice(groupIndex, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.criterias {
|
||||||
|
&-group {
|
||||||
|
background-color: mc('blue-grey', '100');
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&-enter-active, &-leave-active {
|
||||||
|
transition: all .5s ease;
|
||||||
|
}
|
||||||
|
&-enter, &-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& + .criterias-group {
|
||||||
|
margin-top: 1rem;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: 'OR';
|
||||||
|
position: absolute;
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 0 2rem;
|
||||||
|
top: -1.25rem;
|
||||||
|
left: 2rem;
|
||||||
|
background-color: mc('blue-grey', '100');
|
||||||
|
color: mc('blue-grey', '700');
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: .9rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-more {
|
||||||
|
margin: .5rem 0 0 .4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
display: flex;
|
||||||
|
background-color: mc('blue-grey', '200');
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: .5rem;
|
||||||
|
|
||||||
|
&-enter-active, &-leave-active {
|
||||||
|
transition: all .5s ease;
|
||||||
|
}
|
||||||
|
&-enter, &-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& + .criterias-item {
|
||||||
|
margin-top: .5rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: 'AND';
|
||||||
|
position: absolute;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: 600;
|
||||||
|
color: mc('blue-grey', '700');
|
||||||
|
font-size: .7rem;
|
||||||
|
background-color: mc('blue-grey', '100');
|
||||||
|
left: -2rem;
|
||||||
|
top: -1.3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
&:nth-child(1) {
|
||||||
|
flex: 0 1 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
flex: 0 1 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& + * {
|
||||||
|
margin-left: .5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-more {
|
||||||
|
margin-top: .15rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user