cfbd3dca00
At present, the user that are not in the administrator group have no access to edit scripts and styles in page editor panel. This commit add configuration in group rule manage webpage so that users' permission on writing styles and writing scripts can be modified.
337 lines
12 KiB
Vue
337 lines
12 KiB
Vue
<template lang="pug">
|
|
v-card(flat)
|
|
v-card-text(v-if='group.id === 1')
|
|
v-alert.radius-7.mb-0(
|
|
:class='$vuetify.theme.dark ? "grey darken-4" : "orange lighten-5"'
|
|
color='orange darken-2'
|
|
outlined
|
|
icon='mdi-lock-outline'
|
|
) This group has access to everything.
|
|
template(v-else)
|
|
v-card-title(:class='$vuetify.theme.dark ? `grey darken-3-d5` : ``')
|
|
v-alert.radius-7.caption(
|
|
:class='$vuetify.theme.dark ? `grey darken-3-d3` : `grey lighten-4`'
|
|
color='grey'
|
|
outlined
|
|
icon='mdi-information'
|
|
) You must enable global content permissions (under Permissions tab) for page rules to have any effect.
|
|
v-spacer
|
|
v-btn.mx-2(depressed, color='primary', @click='addRule')
|
|
v-icon(left) mdi-plus
|
|
| Add Rule
|
|
v-menu(
|
|
right
|
|
offset-y
|
|
nudge-left='115'
|
|
)
|
|
template(v-slot:activator='{ on }')
|
|
v-btn.is-icon(v-on='on', outlined, color='primary')
|
|
v-icon mdi-dots-horizontal
|
|
v-list(dense)
|
|
v-list-item(@click='comingSoon')
|
|
v-list-item-avatar
|
|
v-icon mdi-application-import
|
|
v-list-item-title Load Preset
|
|
v-divider
|
|
v-list-item(@click='comingSoon')
|
|
v-list-item-avatar
|
|
v-icon mdi-application-export
|
|
v-list-item-title Save As Preset
|
|
v-divider
|
|
v-list-item(@click='comingSoon')
|
|
v-list-item-avatar
|
|
v-icon mdi-cloud-upload
|
|
v-list-item-title Import Rules
|
|
v-divider
|
|
v-list-item(@click='comingSoon')
|
|
v-list-item-avatar
|
|
v-icon mdi-cloud-download
|
|
v-list-item-title Export Rules
|
|
v-card-text(:class='$vuetify.theme.dark ? `grey darken-4-l5` : `white`')
|
|
.rules
|
|
.caption(v-if='group.pageRules.length === 0')
|
|
em(:class='$vuetify.theme.dark ? `grey--text` : `blue-grey--text`') This group has no page rules yet.
|
|
.rule(v-for='rule of group.pageRules', :key='rule.id')
|
|
v-btn.ma-0.radius-4.rule-deny-btn(
|
|
solo
|
|
:color='rule.deny ? "red" : "green"'
|
|
dark
|
|
@click='rule.deny = !rule.deny'
|
|
height='48'
|
|
)
|
|
v-icon(v-if='rule.deny') mdi-cancel
|
|
v-icon(v-else) mdi-check-circle
|
|
//- Roles
|
|
v-select.ml-1(
|
|
solo
|
|
:items='roles'
|
|
v-model='rule.roles'
|
|
placeholder='Select Role(s)...'
|
|
hide-details
|
|
multiple
|
|
chips
|
|
deletable-chips
|
|
small-chips
|
|
height='48px'
|
|
style='flex: 0 1 440px;'
|
|
:menu-props='{ "maxHeight": 500 }'
|
|
clearable
|
|
dense
|
|
)
|
|
template(slot='selection', slot-scope='{ item, index }')
|
|
v-chip.white--text.ml-0(v-if='index <= 1', small, label, :color='rule.deny ? `red` : `green`').caption {{ item.value }}
|
|
v-chip.white--text.ml-0(v-if='index === 2', small, label, :color='rule.deny ? `red lighten-2` : `green lighten-2`').caption + {{ rule.roles.length - 2 }} more
|
|
template(slot='item', slot-scope='props')
|
|
v-list-item-action(style='min-width: 30px;')
|
|
v-checkbox(
|
|
v-model='props.attrs.inputValue'
|
|
hide-details
|
|
color='primary'
|
|
)
|
|
v-icon.mr-2(:color='rule.deny ? `red` : `green`') {{props.item.icon}}
|
|
v-list-item-content
|
|
v-list-item-title.body-2 {{props.item.text}}
|
|
v-chip.mr-2.grey--text(label, small, :color='$vuetify.theme.dark ? `grey darken-4` : `grey lighten-4`').caption {{props.item.value}}
|
|
|
|
//- Match
|
|
v-select.ml-1.mr-1(
|
|
solo
|
|
:items='matches'
|
|
v-model='rule.match'
|
|
placeholder='Match...'
|
|
hide-details
|
|
height='48px'
|
|
style='flex: 0 1 250px;'
|
|
dense
|
|
)
|
|
template(slot='selection', slot-scope='{ item, index }')
|
|
.body-2 {{item.text}}
|
|
template(slot='item', slot-scope='data')
|
|
v-list-item-avatar
|
|
v-avatar.white--text.radius-4(color='blue', size='30', tile) {{ data.item.icon }}
|
|
v-list-item-content
|
|
v-list-item-title(v-html='data.item.text')
|
|
//- Locales
|
|
v-select.mr-1(
|
|
:background-color='$vuetify.theme.dark ? `grey darken-3-d5` : `blue-grey lighten-5`'
|
|
solo
|
|
:items='locales'
|
|
v-model='rule.locales'
|
|
placeholder='Any Locale'
|
|
item-value='code'
|
|
item-text='name'
|
|
multiple
|
|
hide-details
|
|
height='48px'
|
|
dense
|
|
:menu-props='{ "minWidth": 250 }'
|
|
style='flex: 0 1 150px;'
|
|
)
|
|
template(slot='selection', slot-scope='{ item, index }')
|
|
v-chip.white--text.ml-0(v-if='rule.locales.length === 1', small, label, :color='rule.deny ? `red` : `green`').caption {{ item.code.toUpperCase() }}
|
|
v-chip.white--text.ml-0(v-else-if='index === 0', small, label, :color='rule.deny ? `red` : `green`').caption {{ rule.locales.length }} locales
|
|
v-list-item(slot='prepend-item', @click='rule.locales = []')
|
|
v-list-item-action(style='min-width: 30px;')
|
|
v-checkbox(
|
|
:input-value='rule.locales.length === 0'
|
|
hide-details
|
|
color='primary'
|
|
readonly
|
|
)
|
|
v-icon.mr-2(:color='rule.deny ? `red` : `green`') mdi-earth
|
|
v-list-item-content
|
|
v-list-item-title.body-2 Any Locale
|
|
v-divider(slot='prepend-item')
|
|
template(slot='item', slot-scope='props')
|
|
v-list-item-action(style='min-width: 30px;')
|
|
v-checkbox(
|
|
v-model='props.attrs.inputValue'
|
|
hide-details
|
|
color='primary'
|
|
)
|
|
v-icon.mr-2(:color='rule.deny ? `red` : `green`') mdi-web
|
|
v-list-item-content
|
|
v-list-item-title.body-2 {{props.item.name}}
|
|
v-chip.mr-2.grey--text(label, small, :color='$vuetify.theme.dark ? `grey darken-4` : `grey lighten-4`').caption {{props.item.code.toUpperCase()}}
|
|
|
|
//- Path
|
|
v-text-field(
|
|
solo
|
|
v-model='rule.path'
|
|
label='Path'
|
|
:prefix='(rule.match !== `END` && rule.match !== `TAG`) ? `/` : null'
|
|
:placeholder='rule.match === `REGEX` ? `Regular Expression` : rule.match === `TAG` ? `Tag` : `Path`'
|
|
:suffix='rule.match === `REGEX` ? `/` : null'
|
|
hide-details
|
|
:color='$vuetify.theme.dark ? `grey` : `blue-grey`'
|
|
)
|
|
|
|
v-btn.ml-2(icon, @click='removeRule(rule.id)', small)
|
|
v-icon(:color='$vuetify.theme.dark ? `grey` : `blue-grey`') mdi-close
|
|
|
|
v-divider.mt-3
|
|
.overline.py-3 Rules Order
|
|
.body-2.pl-3 Rules are applied in order of path specificity. A more precise path will always override a less defined path.
|
|
.body-2.pl-5 For example, #[span.teal--text /geography/countries] will override #[span.teal--text /geography].
|
|
.body-2.pl-3.pt-2 When 2 rules have the same specificity, the priority is given from lowest to highest as follows:
|
|
.body-2.pl-3.pt-1
|
|
ul
|
|
li
|
|
strong Path Starts With...
|
|
em.caption.pl-1 (lowest)
|
|
li
|
|
strong Path Ends With...
|
|
li
|
|
strong Path Matches Regex...
|
|
li
|
|
strong Tag Matches...
|
|
li
|
|
strong Path Is Exactly...
|
|
em.caption.pl-1 (highest)
|
|
.body-2.pl-3.pt-2 When 2 rules have the same path specificity AND the same match type, #[strong.red--text DENY] will always override an #[strong.green--text ALLOW] rule.
|
|
v-divider.mt-3
|
|
.overline.py-3 Regular Expressions
|
|
span Expressions that are deemed unsafe or could result in exponential time processing will be rejected upon saving.
|
|
|
|
</template>
|
|
|
|
<script>
|
|
import _ from 'lodash'
|
|
import { customAlphabet } from 'nanoid/non-secure'
|
|
|
|
/* global siteLangs */
|
|
|
|
const nanoid = customAlphabet('1234567890abcdef', 10)
|
|
|
|
export default {
|
|
props: {
|
|
value: {
|
|
type: Object,
|
|
default: () => ({})
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
roles: [
|
|
{ text: 'Read Pages', value: 'read:pages', icon: 'mdi-file-eye-outline' },
|
|
{ text: 'Create Pages', value: 'write:pages', icon: 'mdi-file-plus-outline' },
|
|
{ text: 'Edit + Move Pages', value: 'manage:pages', icon: 'mdi-file-document-edit-outline' },
|
|
{ text: 'Delete Pages', value: 'delete:pages', icon: 'mdi-file-remove-outline' },
|
|
{ text: 'View Pages Source', value: 'read:source', icon: 'mdi-code-tags' },
|
|
{ text: 'View Pages History', value: 'read:history', icon: 'mdi-history' },
|
|
{ text: 'Read / Use Assets', value: 'read:assets', icon: 'mdi-image-search-outline' },
|
|
{ text: 'Upload Assets', value: 'write:assets', icon: 'mdi-image-plus' },
|
|
{ text: 'Edit + Delete Assets', value: 'manage:assets', icon: 'mdi-image-size-select-large' },
|
|
{ text: 'Edit Scripts', value: 'write:scripts', icon: 'mdi-language-javascript' },
|
|
{ text: 'Edit Styles', value: 'write:styles', icon: 'mdi-language-css3' },
|
|
{ text: 'Read Comments', value: 'read:comments', icon: 'mdi-comment-search-outline' },
|
|
{ text: 'Create Comments', value: 'write:comments', icon: 'mdi-comment-plus-outline' },
|
|
{ text: 'Edit + Delete Comments', value: 'manage:comments', icon: 'mdi-comment-remove-outline' }
|
|
],
|
|
matches: [
|
|
{ text: 'Path Starts With...', value: 'START', icon: '/...' },
|
|
{ text: 'Path is Exactly...', value: 'EXACT', icon: '=' },
|
|
{ text: 'Path Ends With...', value: 'END', icon: '.../' },
|
|
{ text: 'Path Matches Regex...', value: 'REGEX', icon: '$.*' },
|
|
{ text: 'Tag Matches...', value: 'TAG', icon: 'T' }
|
|
]
|
|
}
|
|
},
|
|
computed: {
|
|
group: {
|
|
get() { return this.value },
|
|
set(val) { this.$set('input', val) }
|
|
},
|
|
locales() { return siteLangs }
|
|
},
|
|
methods: {
|
|
addRule(group) {
|
|
this.group.pageRules.push({
|
|
id: nanoid(),
|
|
path: '',
|
|
roles: [],
|
|
match: 'START',
|
|
deny: false,
|
|
locales: []
|
|
})
|
|
},
|
|
removeRule(ruleId) {
|
|
this.group.pageRules.splice(_.findIndex(this.group.pageRules, ['id', ruleId]), 1)
|
|
},
|
|
comingSoon() {
|
|
this.$store.commit('showNotification', {
|
|
style: 'indigo',
|
|
message: `Coming soon...`,
|
|
icon: 'directions_boat'
|
|
})
|
|
},
|
|
dude (stuff) {
|
|
console.info(stuff)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.rules {
|
|
background-color: mc('blue-grey', '50');
|
|
border-radius: 4px;
|
|
padding: 1rem;
|
|
position: relative;
|
|
|
|
@at-root .v-application.theme--dark & {
|
|
background-color: mc('grey', '800');
|
|
}
|
|
}
|
|
|
|
.rule {
|
|
display: flex;
|
|
background-color: mc('blue-grey', '100');
|
|
border-radius: 4px;
|
|
padding: .5rem;
|
|
align-items: center;
|
|
|
|
&-enter-active, &-leave-active {
|
|
transition: all .5s ease;
|
|
}
|
|
&-enter, &-leave-to {
|
|
opacity: 0;
|
|
}
|
|
|
|
@at-root .v-application.theme--dark & {
|
|
background-color: mc('grey', '700');
|
|
}
|
|
|
|
& + .rule {
|
|
margin-top: .5rem;
|
|
position: relative;
|
|
|
|
&::before {
|
|
content: '+';
|
|
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: 1.25rem;
|
|
background-color: mc('blue-grey', '50');
|
|
left: -2rem;
|
|
top: -1.3rem;
|
|
|
|
@at-root .v-application.theme--dark & {
|
|
background-color: mc('grey', '800');
|
|
color: mc('grey', '600');
|
|
}
|
|
}
|
|
}
|
|
|
|
.input-group + * {
|
|
margin-left: .5rem;
|
|
}
|
|
}
|
|
</style>
|