mirror of
https://github.com/nocodb/nocodb.git
synced 2026-05-01 07:56:46 +00:00
refactor(gui): linting
Signed-off-by: Pranav C <61551451+pranavxc@users.noreply.github.com>
This commit is contained in:
@@ -1,286 +1,323 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
<v-card style="">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['acl-gql','reload']"
|
||||
@click="aclInit"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['acl-gql','reload']"
|
||||
outlined
|
||||
tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
@click="aclInit"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small v-ge="['acl-gql','open-folder']"
|
||||
color="primary"
|
||||
@click="openFolder">
|
||||
<x-btn
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
color="primary"
|
||||
@click="openFolder"
|
||||
>
|
||||
Open Folder
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save ACL"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="save"
|
||||
:disabled="disableSaveButton"
|
||||
v-ge="['acl-gql','save']">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['acl-gql','save']"
|
||||
outlined
|
||||
tooltip="Save ACL"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search ${nodes.tn} resolvers`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search ${nodes.tn} resolvers`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<v-simple-table v-if="data1" dense>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center" rowspan="2">
|
||||
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-1 flex-shrink-1" dense
|
||||
v-model="allToggle"></v-checkbox>
|
||||
</template>
|
||||
<span>{{allToggle ? 'Disable' : 'Enable'}} all {{nodes.tn}} resolvers for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{nodes.tn}} Resolvers</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
<th v-for="role in roles"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{role}}</span>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<th v-for="role in roles"
|
||||
<tr>
|
||||
<th colspan="2" class="text-center" rowspan="2">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="allToggle"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-1 flex-shrink-1"
|
||||
dense
|
||||
v-on="on"
|
||||
/>
|
||||
</template>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} resolvers for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{ nodes.tn }} Resolvers</span>
|
||||
</div>
|
||||
</th>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
class="pa-1"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-0" dense v-model="columnToggle[role]"
|
||||
@change="toggleColumn(role,columnToggle[role])"></v-checkbox>
|
||||
</template>
|
||||
<span>
|
||||
<span>{{columnToggle[role] ? 'Disable' : 'Enable'}} all resolvers for {{role}}</span></span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="columnToggle[role]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleColumn(role,columnToggle[role])"
|
||||
/>
|
||||
</template>
|
||||
<span>
|
||||
<span>{{ columnToggle[role] ? 'Disable' : 'Enable' }} all resolvers for {{ role }}</span></span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(resolver,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1">
|
||||
<td width="20" class="pl-6 pr-3">
|
||||
<tr v-for="(resolver,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1">
|
||||
<td width="20" class="pl-6 pr-3">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="rowToggle[path]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0 ml-3"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-0 ml-3" v-model="rowToggle[path]"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
dense></v-checkbox>
|
||||
</template>
|
||||
|
||||
<span>{{rowToggle[path] ? 'Disable' : 'Enable'}} this resolver for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{path}}</span>
|
||||
</template>
|
||||
<span>{{path}}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(role,i) in roles">
|
||||
<td style="border-left: 1px solid grey" class="pa-1" :key="`${path}_${role}`">
|
||||
<div class="d-flex justify-center">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" class="mt-0" dense
|
||||
v-model="data1[path][role]"
|
||||
@change="toggleCell(path,role,data1[path][role])"
|
||||
></v-checkbox>
|
||||
</div>
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this resolver for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
</tr>
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(role,i) in roles">
|
||||
<td :key="`${path}_${role}`" style="border-left: 1px solid grey" class="pa-1">
|
||||
<div class="d-flex justify-center">
|
||||
<v-checkbox
|
||||
v-model="data1[path][role]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0"
|
||||
dense
|
||||
@change="toggleCell(path,role,data1[path][role])"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
export default {
|
||||
name: 'AclGql',
|
||||
|
||||
export default {
|
||||
name: "acl-gql",
|
||||
props: ['nodes'],
|
||||
data () {
|
||||
return {
|
||||
disableSaveButton: true,
|
||||
search: '',
|
||||
policyPath: '',
|
||||
columnToggle: {},
|
||||
rowToggle: {},
|
||||
roles: [
|
||||
'creator',
|
||||
'editor',
|
||||
'guest'
|
||||
],
|
||||
data1: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openFolder () {
|
||||
// shell.openItem(path.dirname(this.policyPath))
|
||||
},
|
||||
toggleColumn (role, checked) {
|
||||
for (const [resolver, roles] of Object.entries(this.data1)) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleRow (resolver, checked) {
|
||||
for (const role in this.data1[resolver]) {
|
||||
this.$set(this.data1[resolver], role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleAll (checked) {
|
||||
this.disableSaveButton = false
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = checked
|
||||
}
|
||||
for (const role of this.roles) {
|
||||
this.columnToggle[role] = checked
|
||||
}
|
||||
|
||||
props: ["nodes"],
|
||||
methods: {
|
||||
openFolder() {
|
||||
shell.openItem(path.dirname(this.policyPath));
|
||||
},
|
||||
toggleColumn(role, checked) {
|
||||
for (let [resolver, roles] of Object.entries(this.data1)) {
|
||||
for (const roles of Object.values(this.data1)) {
|
||||
for (const role of this.roles) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleRow(resolver, checked) {
|
||||
for (let role in this.data1[resolver]) {
|
||||
this.$set(this.data1[resolver], role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.disableSaveButton = false;
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = checked;
|
||||
}
|
||||
for (let role of this.roles) {
|
||||
this.columnToggle[role] = checked;
|
||||
}
|
||||
|
||||
for (let roles of Object.values(this.data1)) {
|
||||
for (let role of this.roles) {
|
||||
this.$set(roles, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell(resolver, role, checked) {
|
||||
this.disableSaveButton = false;
|
||||
this.$set(this.columnToggle, role, Object.values(this.data1).some(roles => roles[role]));
|
||||
this.$set(this.rowToggle, resolver, Object.values(this.data1[resolver]).some(enabled => enabled));
|
||||
},
|
||||
initColumnCheckBox() {
|
||||
for (let role of this.roles) {
|
||||
this.columnToggle[role] = Object.values(this.data1).some(roles => roles[role]);
|
||||
}
|
||||
},
|
||||
initRowCheckBox() {
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = Object.entries(this.data1[path]).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) this.roles = [...this.roles, role];
|
||||
return v;
|
||||
}).length;
|
||||
}
|
||||
},
|
||||
async aclInit() {
|
||||
this.disableSaveButton = true;
|
||||
this.policyPath = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'projectGetGqlPolicyPath', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}]);
|
||||
try {
|
||||
console.log(this.policyPath, this.data1)
|
||||
this.data1 = JSON.parse(
|
||||
JSON.stringify(
|
||||
(
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'importFresh', {path: this.policyPath}])
|
||||
).permissions
|
||||
)
|
||||
);
|
||||
this.initColumnCheckBox();
|
||||
this.initRowCheckBox();
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
// await this.sqlMgr.writeFile({
|
||||
// path: this.policyPath,
|
||||
// data: `module.exports.permissions = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
// });
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'writeFile', {
|
||||
path: this.policyPath,
|
||||
data: `module.exports.permissions = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
}]);
|
||||
this.disableSaveButton = true;
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000);
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
disableSaveButton: true,
|
||||
search: '',
|
||||
policyPath: '',
|
||||
columnToggle: {},
|
||||
rowToggle: {},
|
||||
roles: [
|
||||
'creator',
|
||||
'editor',
|
||||
'guest'
|
||||
],
|
||||
data1: null
|
||||
toggleCell (resolver, role, checked) {
|
||||
this.disableSaveButton = false
|
||||
this.$set(this.columnToggle, role, Object.values(this.data1).some(roles => roles[role]))
|
||||
this.$set(this.rowToggle, resolver, Object.values(this.data1[resolver]).some(enabled => enabled))
|
||||
},
|
||||
initColumnCheckBox () {
|
||||
for (const role of this.roles) {
|
||||
this.columnToggle[role] = Object.values(this.data1).some(roles => roles[role])
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
allToggle: {
|
||||
get() {
|
||||
return this.data1 && Object.values(this.data1).some(roles => Object.values(roles).some(v => v))
|
||||
},
|
||||
set(checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
initRowCheckBox () {
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = Object.entries(this.data1[path]).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) { this.roles = [...this.roles, role] }
|
||||
return v
|
||||
}).length
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.aclInit();
|
||||
async aclInit () {
|
||||
this.disableSaveButton = true
|
||||
this.policyPath = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'projectGetGqlPolicyPath', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}])
|
||||
try {
|
||||
console.log(this.policyPath, this.data1)
|
||||
this.data1 = JSON.parse(
|
||||
JSON.stringify(
|
||||
(
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'importFresh', { path: this.policyPath }])
|
||||
).permissions
|
||||
)
|
||||
)
|
||||
this.initColumnCheckBox()
|
||||
this.initRowCheckBox()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
watch: {}
|
||||
async save () {
|
||||
try {
|
||||
// await this.sqlMgr.writeFile({
|
||||
// path: this.policyPath,
|
||||
// data: `module.exports.permissions = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
// });
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'writeFile', {
|
||||
path: this.policyPath,
|
||||
data: `module.exports.permissions = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
}])
|
||||
this.disableSaveButton = true
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
|
||||
allToggle: {
|
||||
get () {
|
||||
return this.data1 && Object.values(this.data1).some(roles => Object.values(roles).some(v => v))
|
||||
},
|
||||
set (checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
async created () {
|
||||
await this.aclInit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,272 +1,204 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
<v-card style="">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['acl-gql','reload']"
|
||||
@click="aclInit"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['acl-gql','reload']"
|
||||
outlined
|
||||
tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
@click="aclInit"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small v-ge="['acl-gql','open-folder']"
|
||||
color="primary"
|
||||
@click="openFolder">
|
||||
<x-btn
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
color="primary"
|
||||
@click="openFolder"
|
||||
>
|
||||
Open Folder
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save ACL"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="save"
|
||||
:disabled="disableSaveButton"
|
||||
v-ge="['acl-gql','save']">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['acl-gql','save']"
|
||||
outlined
|
||||
tooltip="Save ACL"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search ${nodes.tn} resolvers`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search ${nodes.tn} resolvers`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<v-simple-table v-if="policies && policies.length" dense>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center" rowspan="2">
|
||||
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-1 flex-shrink-1" dense
|
||||
v-model="allToggle"></v-checkbox>
|
||||
</template>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} resolvers for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{ nodes.tn }} RPC Services</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
<th v-for="role in roles"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<th v-for="role in roles"
|
||||
<tr>
|
||||
<th colspan="2" class="text-center" rowspan="2">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="allToggle"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-1 flex-shrink-1"
|
||||
dense
|
||||
v-on="on"
|
||||
/>
|
||||
</template>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} resolvers for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{ nodes.tn }} RPC Services</span>
|
||||
</div>
|
||||
</th>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
class="pa-1"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-0" dense v-model="columnToggle[role]"
|
||||
@change="toggleColumn(role,columnToggle[role])"></v-checkbox>
|
||||
</template>
|
||||
<span>
|
||||
<span>{{ columnToggle[role] ? 'Disable' : 'Enable' }} all resolvers for {{ role }}</span></span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="columnToggle[role]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleColumn(role,columnToggle[role])"
|
||||
/>
|
||||
</template>
|
||||
<span>
|
||||
<span>{{ columnToggle[role] ? 'Disable' : 'Enable' }} all resolvers for {{ role }}</span></span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(resolver,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1">
|
||||
<td width="20" class="pl-6 pr-3">
|
||||
<tr v-for="(resolver,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1">
|
||||
<td width="20" class="pl-6 pr-3">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="rowToggle[path]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0 ml-3"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-0 ml-3" v-model="rowToggle[path]"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
dense></v-checkbox>
|
||||
</template>
|
||||
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this resolver for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(role,i) in roles">
|
||||
<td style="border-left: 1px solid grey" class="pa-1" :key="`${path}_${role}`">
|
||||
<div class="d-flex justify-center">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" class="mt-0" dense
|
||||
v-model="data1[path][role]"
|
||||
@change="toggleCell(path,role,data1[path][role])"
|
||||
></v-checkbox>
|
||||
</div>
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this resolver for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
</tr>
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(role,i) in roles">
|
||||
<td :key="`${path}_${role}`" style="border-left: 1px solid grey" class="pa-1">
|
||||
<div class="d-flex justify-center">
|
||||
<v-checkbox
|
||||
v-model="data1[path][role]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0"
|
||||
dense
|
||||
@change="toggleCell(path,role,data1[path][role])"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else-if="policies" outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else-if="policies" outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
|
||||
export default {
|
||||
name: "acl-grpc-db",
|
||||
name: 'AclGrpcDb',
|
||||
|
||||
props: ["nodes"],
|
||||
methods: {
|
||||
openFolder() {
|
||||
shell.openItem(path.dirname(this.policyPath));
|
||||
},
|
||||
toggleColumn(role, checked) {
|
||||
for (let [resolver, roles] of Object.entries(this.data1)) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleRow(resolver, checked) {
|
||||
for (let role in this.data1[resolver]) {
|
||||
this.$set(this.data1[resolver], role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.disableSaveButton = false;
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = checked;
|
||||
}
|
||||
for (let role of this.roles) {
|
||||
this.columnToggle[role] = checked;
|
||||
}
|
||||
|
||||
for (let roles of Object.values(this.data1)) {
|
||||
for (let role of this.roles) {
|
||||
this.$set(roles, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell(resolver, role, checked) {
|
||||
this.disableSaveButton = false;
|
||||
this.$set(this.columnToggle, role, Object.values(this.data1).some(roles => roles[role]));
|
||||
this.$set(this.rowToggle, resolver, Object.values(this.data1[resolver]).some(enabled => enabled));
|
||||
},
|
||||
initColumnCheckBox() {
|
||||
for (let role of this.roles) {
|
||||
this.columnToggle[role] = Object.values(this.data1).some(roles => roles[role]);
|
||||
}
|
||||
},
|
||||
initRowCheckBox() {
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = Object.entries(this.data1[path]).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) this.roles = [...this.roles, role];
|
||||
return v;
|
||||
}).length;
|
||||
}
|
||||
},
|
||||
async aclInit() {
|
||||
try {
|
||||
console.log(this.sqlMgr)
|
||||
this.disableSaveButton = true;
|
||||
// this.policies = (await this.sqlMgr.projectGetGrpcPolicyFromDb({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn
|
||||
// })).data.list;
|
||||
this.policies = (await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'projectGetGrpcPolicyFromDb', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}])).data.list;
|
||||
|
||||
//.data.list;
|
||||
this.data = JSON.parse(JSON.stringify(this.policies.filter(({service}) => service)));
|
||||
this.data1 = this.data.reduce((aclObj, resolver) => {
|
||||
aclObj[resolver.service] = resolver.acl;
|
||||
return aclObj;
|
||||
}, {});
|
||||
|
||||
this.initColumnCheckBox();
|
||||
this.initRowCheckBox();
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
|
||||
//
|
||||
// await this.sqlMgr.xcRpcPolicyUpdate({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn,
|
||||
// data: this.data
|
||||
// })
|
||||
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcRpcPolicyUpdate', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn,
|
||||
data: this.data
|
||||
}])
|
||||
|
||||
|
||||
this.disableSaveButton = true;
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000);
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
props: ['nodes'],
|
||||
data () {
|
||||
return {
|
||||
disableSaveButton: true,
|
||||
search: '',
|
||||
@@ -282,21 +214,123 @@ export default {
|
||||
data1: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openFolder () {
|
||||
// shell.openItem(path.dirname(this.policyPath))
|
||||
},
|
||||
toggleColumn (role, checked) {
|
||||
for (const [resolver, roles] of Object.entries(this.data1)) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleRow (resolver, checked) {
|
||||
for (const role in this.data1[resolver]) {
|
||||
this.$set(this.data1[resolver], role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleAll (checked) {
|
||||
this.disableSaveButton = false
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = checked
|
||||
}
|
||||
for (const role of this.roles) {
|
||||
this.columnToggle[role] = checked
|
||||
}
|
||||
|
||||
for (const roles of Object.values(this.data1)) {
|
||||
for (const role of this.roles) {
|
||||
this.$set(roles, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell (resolver, role, checked) {
|
||||
this.disableSaveButton = false
|
||||
this.$set(this.columnToggle, role, Object.values(this.data1).some(roles => roles[role]))
|
||||
this.$set(this.rowToggle, resolver, Object.values(this.data1[resolver]).some(enabled => enabled))
|
||||
},
|
||||
initColumnCheckBox () {
|
||||
for (const role of this.roles) {
|
||||
this.columnToggle[role] = Object.values(this.data1).some(roles => roles[role])
|
||||
}
|
||||
},
|
||||
initRowCheckBox () {
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = Object.entries(this.data1[path]).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) { this.roles = [...this.roles, role] }
|
||||
return v
|
||||
}).length
|
||||
}
|
||||
},
|
||||
async aclInit () {
|
||||
try {
|
||||
console.log(this.sqlMgr)
|
||||
this.disableSaveButton = true
|
||||
// this.policies = (await this.sqlMgr.projectGetGrpcPolicyFromDb({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn
|
||||
// })).data.list;
|
||||
this.policies = (await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'projectGetGrpcPolicyFromDb', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}])).data.list
|
||||
|
||||
// .data.list;
|
||||
this.data = JSON.parse(JSON.stringify(this.policies.filter(({ service }) => service)))
|
||||
this.data1 = this.data.reduce((aclObj, resolver) => {
|
||||
aclObj[resolver.service] = resolver.acl
|
||||
return aclObj
|
||||
}, {})
|
||||
|
||||
this.initColumnCheckBox()
|
||||
this.initRowCheckBox()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
async save () {
|
||||
try {
|
||||
//
|
||||
// await this.sqlMgr.xcRpcPolicyUpdate({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn,
|
||||
// data: this.data
|
||||
// })
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcRpcPolicyUpdate', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn,
|
||||
data: this.data
|
||||
}])
|
||||
|
||||
this.disableSaveButton = true
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
|
||||
allToggle: {
|
||||
get() {
|
||||
get () {
|
||||
return this.data1 && Object.values(this.data1).some(roles => Object.values(roles).some(v => v))
|
||||
},
|
||||
set(checked) {
|
||||
set (checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.aclInit();
|
||||
},
|
||||
watch: {}
|
||||
watch: {},
|
||||
async mounted () {
|
||||
await this.aclInit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,328 +1,371 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
<v-card style="">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['acl','reload']"
|
||||
@click="aclInit"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['acl','reload']"
|
||||
outlined
|
||||
tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
@click="aclInit"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
color="primary"
|
||||
v-ge="['acl','open-folder']"
|
||||
@click="openFolder">
|
||||
<x-btn
|
||||
v-ge="['acl','open-folder']"
|
||||
tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
color="primary"
|
||||
@click="openFolder"
|
||||
>
|
||||
Open Folder
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="save"
|
||||
:disabled="disableSaveButton"
|
||||
v-ge="['acl','save']">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['acl','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search ${nodes.tn} routes`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search ${nodes.tn} routes`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<v-simple-table v-if="data1" dense>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center" rowspan="3">
|
||||
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-1 flex-shrink-1" dense
|
||||
v-model="allToggle"></v-checkbox>
|
||||
</template>
|
||||
<span>{{allToggle ? 'Disable' : 'Enable'}} all {{nodes.tn}} routes for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{nodes.tn}} Routes</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
<th v-for="role in roles" :colspan="methods.length"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{role}}</span>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<!-- <th colspan="2"></th>-->
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th width="25" class="caption px-1" :key="`${method}_${role}`"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'">{{method}}
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
<tr>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th width="25" class="caption px-1" :key="`${method}_${role}`"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'">
|
||||
|
||||
<tr>
|
||||
<th colspan="2" class="text-center" rowspan="3">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-0" dense
|
||||
v-model="columnToggle[`${method}_${role}`]"
|
||||
@change="toggleColumn(role,method,columnToggle[`${method}_${role}`])"></v-checkbox>
|
||||
v-model="allToggle"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-1 flex-shrink-1"
|
||||
dense
|
||||
v-on="on"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<span>{{columnToggle[`${method}_${role}`] ? 'Disable' : 'Enable'}} all {{method}} routes for {{role}}</span>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} routes for all roles</span>
|
||||
</v-tooltip>
|
||||
</th>
|
||||
<span class="title">{{ nodes.tn }} Routes</span>
|
||||
</div>
|
||||
</th>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
:key="role"
|
||||
:colspan="methods.length"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<!-- <th colspan="2"></th>-->
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th
|
||||
:key="`${method}_${role}`"
|
||||
width="25"
|
||||
class="caption px-1"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'"
|
||||
>
|
||||
{{ method }}
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th
|
||||
:key="`${method}_${role}`"
|
||||
width="25"
|
||||
class="caption px-1"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="columnToggle[`${method}_${role}`]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleColumn(role,method,columnToggle[`${method}_${role}`])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<span>{{ columnToggle[`${method}_${role}`] ? 'Disable' : 'Enable' }} all {{ method }} routes for {{ role }}</span>
|
||||
</v-tooltip>
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(route,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1">
|
||||
<td width="20" class="px-0">
|
||||
<tr v-for="(route,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1" :key="path">
|
||||
<td width="20" class="px-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="rowToggle[path]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0 ml-3"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-0 ml-3" v-model="rowToggle[path]"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
dense></v-checkbox>
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this route for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<td :key="`${path}_${method}_${role}`" :style="i ? '' : 'border-left: 1px solid grey'" class="pa-1">
|
||||
<v-checkbox
|
||||
v-if="data1[path][method]"
|
||||
v-model="data1[path][method][role]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
:color="methodColor[method]"
|
||||
:input-value="data1[path][method][role]"
|
||||
@change="toggleCell(path,method,role,data1[path][method][role])"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
@dblclick="$set(data1[path],method , {})"
|
||||
>
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
:disabled="true"
|
||||
/></span>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<span>{{rowToggle[path] ? 'Disable' : 'Enable'}} this route for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{path}}</span>
|
||||
</template>
|
||||
<span>{{path}}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<td :style="i ? '' : 'border-left: 1px solid grey'" class="pa-1" :key="`${path}_${method}_${role}`">
|
||||
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
v-if="data1[path][method]" class="mt-0" dense
|
||||
:color="methodColor[method]"
|
||||
:input-value="data1[path][method][role]"
|
||||
v-model="data1[path][method][role]"
|
||||
@change="toggleCell(path,method,role,data1[path][method][role])"
|
||||
></v-checkbox>
|
||||
<span
|
||||
v-else
|
||||
@dblclick="$set(data1[path],method , {})">
|
||||
<v-checkbox v-ge="['acl','toggle-checkbox']" class="mt-0" dense
|
||||
:disabled="true">
|
||||
</v-checkbox></span>
|
||||
</td>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</tr>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
<v-alert v-else outlined type="info">Permission file not found</v-alert>
|
||||
|
||||
<v-alert v-else outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
// const {fs, importFresh,shell,path} = require("electron").remote.require('./libs');
|
||||
|
||||
// const {fs, importFresh,shell,path} = require("electron").remote.require('./libs');
|
||||
export default {
|
||||
name: 'AclJs',
|
||||
|
||||
export default {
|
||||
name: "acl-js",
|
||||
props: ['nodes'],
|
||||
data () {
|
||||
return {
|
||||
disableSaveButton: true,
|
||||
search: '',
|
||||
policyPath: '',
|
||||
columnToggle: {},
|
||||
rowToggle: {},
|
||||
// allToggle: false,
|
||||
methodColor: {
|
||||
get: 'green',
|
||||
post: 'orange',
|
||||
put: 'deep-orange',
|
||||
patch: 'pink lighten-1',
|
||||
delete: 'red darken-3'
|
||||
},
|
||||
roles: [
|
||||
'creator',
|
||||
'editor',
|
||||
'guest'
|
||||
],
|
||||
methods: [
|
||||
'get', 'post', 'put', 'patch', 'delete'
|
||||
],
|
||||
data1: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
props: ["nodes"],
|
||||
methods: {
|
||||
|
||||
openFolder() {
|
||||
shell.openItem(path.dirname(this.policyPath));
|
||||
},
|
||||
toggleColumn(role, method, checked) {
|
||||
for (let [path, methods] of Object.entries(this.data1)) {
|
||||
if (methods[method]) {
|
||||
this.$set(methods[method], role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleRow(path, checked) {
|
||||
for (let [method, roles] of Object.entries(this.data1[path])) {
|
||||
for (let role in roles) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.disableSaveButton = false;
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = checked;
|
||||
}
|
||||
for (let role of this.roles) {
|
||||
for (let method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = checked;
|
||||
}
|
||||
}
|
||||
|
||||
for (let methods of Object.values(this.data1)) {
|
||||
for (let method of Object.values(methods)) {
|
||||
for (let role of this.roles) {
|
||||
this.$set(method, role, checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell(path, method, role, checked) {
|
||||
this.disableSaveButton = false;
|
||||
this.$set(this.columnToggle, `${method}_${role}`, Object.values(this.data1).some(methods => methods[method] && methods[method][role]));
|
||||
this.$set(this.rowToggle, path, Object.values(this.data1[path]).some(roles => Object.values(roles).some(v => v)));
|
||||
},
|
||||
initColumnCheckBox() {
|
||||
for (let role of this.roles) {
|
||||
for (let method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = Object.values(this.data1).some(methods => methods[method] && methods[method][role]);
|
||||
}
|
||||
}
|
||||
},
|
||||
initRowCheckBox() {
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = Object.values(this.data1[path]).filter(roles => Object.entries(roles).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) this.roles = [...this.roles, role];
|
||||
return v;
|
||||
}).length).length;
|
||||
}
|
||||
},
|
||||
async aclInit() {
|
||||
this.disableSaveButton = true;
|
||||
this.policyPath = await this.sqlMgr.projectGetPolicyPath({
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
});
|
||||
try {
|
||||
console.log(this.policyPath, this.data1)
|
||||
// this.data1 = JSON.parse(JSON.stringify((await this.sqlMgr.importFresh({path: this.policyPath})).permissions));
|
||||
this.data1 = JSON.parse(JSON.stringify((await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'importFresh', {path: this.policyPath}])).permissions));
|
||||
this.initColumnCheckBox();
|
||||
this.initRowCheckBox();
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
// await this.sqlMgr.writeFile({
|
||||
// path: this.policyPath,
|
||||
// data: `module.exports.permissions = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
// });
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'writeFile', {
|
||||
path: this.policyPath,
|
||||
data: `module.exports.permissions = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
}]);
|
||||
|
||||
this.disableSaveButton = true;
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000);
|
||||
openFolder () {
|
||||
// shell.openItem(path.dirname(this.policyPath))
|
||||
},
|
||||
toggleColumn (role, method, checked) {
|
||||
for (const [path, methods] of Object.entries(this.data1)) {
|
||||
if (methods[method]) {
|
||||
this.$set(methods[method], role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
disableSaveButton: true,
|
||||
search: '',
|
||||
policyPath: '',
|
||||
columnToggle: {},
|
||||
rowToggle: {},
|
||||
// allToggle: false,
|
||||
methodColor: {
|
||||
get: 'green',
|
||||
post: 'orange',
|
||||
put: 'deep-orange',
|
||||
patch: 'pink lighten-1',
|
||||
delete: 'red darken-3',
|
||||
},
|
||||
roles: [
|
||||
'creator',
|
||||
'editor',
|
||||
'guest'
|
||||
],
|
||||
methods: [
|
||||
'get', 'post', 'put', 'patch', 'delete'
|
||||
],
|
||||
data1: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
allToggle: {
|
||||
get() {
|
||||
return this.data1 && Object.values(this.data1).some(methods => Object.values(methods).some(roles => Object.values(roles).some(v => v)))
|
||||
},
|
||||
set(checked) {
|
||||
this.toggleAll(checked)
|
||||
toggleRow (path, checked) {
|
||||
for (const [method, roles] of Object.entries(this.data1[path])) {
|
||||
for (const role in roles) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.aclInit();
|
||||
toggleAll (checked) {
|
||||
this.disableSaveButton = false
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = checked
|
||||
}
|
||||
for (const role of this.roles) {
|
||||
for (const method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = checked
|
||||
}
|
||||
}
|
||||
|
||||
for (const methods of Object.values(this.data1)) {
|
||||
for (const method of Object.values(methods)) {
|
||||
for (const role of this.roles) {
|
||||
this.$set(method, role, checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {}
|
||||
toggleCell (path, method, role, checked) {
|
||||
this.disableSaveButton = false
|
||||
this.$set(this.columnToggle, `${method}_${role}`, Object.values(this.data1).some(methods => methods[method] && methods[method][role]))
|
||||
this.$set(this.rowToggle, path, Object.values(this.data1[path]).some(roles => Object.values(roles).some(v => v)))
|
||||
},
|
||||
initColumnCheckBox () {
|
||||
for (const role of this.roles) {
|
||||
for (const method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = Object.values(this.data1).some(methods => methods[method] && methods[method][role])
|
||||
}
|
||||
}
|
||||
},
|
||||
initRowCheckBox () {
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = Object.values(this.data1[path]).filter(roles => Object.entries(roles).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) { this.roles = [...this.roles, role] }
|
||||
return v
|
||||
}).length).length
|
||||
}
|
||||
},
|
||||
async aclInit () {
|
||||
this.disableSaveButton = true
|
||||
this.policyPath = await this.sqlMgr.projectGetPolicyPath({
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
})
|
||||
try {
|
||||
console.log(this.policyPath, this.data1)
|
||||
// this.data1 = JSON.parse(JSON.stringify((await this.sqlMgr.importFresh({path: this.policyPath})).permissions));
|
||||
this.data1 = JSON.parse(JSON.stringify((await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'importFresh', { path: this.policyPath }])).permissions))
|
||||
this.initColumnCheckBox()
|
||||
this.initRowCheckBox()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
async save () {
|
||||
try {
|
||||
// await this.sqlMgr.writeFile({
|
||||
// path: this.policyPath,
|
||||
// data: `module.exports.permissions = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
// });
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'writeFile', {
|
||||
path: this.policyPath,
|
||||
data: `module.exports.permissions = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
}])
|
||||
|
||||
this.disableSaveButton = true
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
|
||||
allToggle: {
|
||||
get () {
|
||||
return this.data1 && Object.values(this.data1).some(methods => Object.values(methods).some(roles => Object.values(roles).some(v => v)))
|
||||
},
|
||||
set (checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
async created () {
|
||||
this.aclInit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,133 +1,159 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
<v-card style="">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['acl','reload']"
|
||||
@click="reload"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['acl','reload']"
|
||||
outlined
|
||||
tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
@click="reload"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn tooltip="Open Corresponding Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
:disabled="!policyPaths || !policyPaths.length"
|
||||
color="primary"
|
||||
v-ge="['acl','open-folder']"
|
||||
@click="openFolder">
|
||||
<x-btn
|
||||
v-ge="['acl','open-folder']"
|
||||
tooltip="Open Corresponding Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
:disabled="!policyPaths || !policyPaths.length"
|
||||
color="primary"
|
||||
@click="openFolder"
|
||||
>
|
||||
Open Folder
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="save"
|
||||
:disabled="disableSaveButton"
|
||||
v-ge="['acl','save']">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['acl','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search ${nodes.tn} routes`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search ${nodes.tn} routes`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<acl-ts-file-child
|
||||
style="border-bottom: 1px solid grey"
|
||||
v-for="(policyPath,k) in policyPaths"
|
||||
:key="k"
|
||||
ref="acl" :nodes="nodes" :search="search" :policyPath="policyPath"></acl-ts-file-child>
|
||||
ref="acl"
|
||||
style="border-bottom: 1px solid grey"
|
||||
:nodes="nodes"
|
||||
:search="search"
|
||||
:policy-path="policyPath"
|
||||
/>
|
||||
|
||||
<v-alert v-if="policyPaths && !policyPaths.length" outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-if="policyPaths && !policyPaths.length" outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import aclTsFileChild from './aclTsFileChild'
|
||||
import { mapGetters } from 'vuex'
|
||||
import aclTsFileChild from './aclTsFileChild'
|
||||
|
||||
// const {shell, path} = require("electron").remote.require('./libs');
|
||||
|
||||
// const {shell, path} = require("electron").remote.require('./libs');
|
||||
export default {
|
||||
name: 'AclTypeorm',
|
||||
components: { aclTsFileChild },
|
||||
props: ['nodes'],
|
||||
data () {
|
||||
return {
|
||||
policyPaths: null,
|
||||
search: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
export default {
|
||||
name: "acl-typeorm",
|
||||
components: {aclTsFileChild},
|
||||
props: ["nodes"],
|
||||
methods: {
|
||||
async aclInit () {
|
||||
// this.disableSaveButton = true;
|
||||
// this.policyPaths = await this.sqlMgr.projectGetTsPolicyPath({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn
|
||||
// });
|
||||
|
||||
async aclInit() {
|
||||
// this.disableSaveButton = true;
|
||||
// this.policyPaths = await this.sqlMgr.projectGetTsPolicyPath({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn
|
||||
// });
|
||||
|
||||
this.policyPaths = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
}, 'projectGetTsPolicyPath', {
|
||||
tn: this.nodes.tn
|
||||
}]);
|
||||
},
|
||||
reload() {
|
||||
for (const $acl of this.$refs.acl) {
|
||||
$acl.aclInit();
|
||||
}
|
||||
},
|
||||
save() {
|
||||
for (const $acl of this.$refs.acl) {
|
||||
$acl.save();
|
||||
}
|
||||
},
|
||||
openFolder() {
|
||||
// shell.openItem(path.dirname(this.policyPaths[0]));
|
||||
},
|
||||
this.policyPaths = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'projectGetTsPolicyPath', {
|
||||
tn: this.nodes.tn
|
||||
}])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
policyPaths: null,
|
||||
search: ''
|
||||
reload () {
|
||||
for (const $acl of this.$refs.acl) {
|
||||
$acl.aclInit()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
save () {
|
||||
for (const $acl of this.$refs.acl) {
|
||||
$acl.save()
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.aclInit();
|
||||
},
|
||||
watch: {}
|
||||
openFolder () {
|
||||
// shell.openItem(path.dirname(this.policyPaths[0]));
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' })
|
||||
},
|
||||
watch: {},
|
||||
async created () {
|
||||
await this.aclInit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
<v-card style="" v-if="filteredGroupedData.length">
|
||||
|
||||
<v-card v-if="filteredGroupedData.length" style="">
|
||||
<!-- <v-toolbar flat height="42" class="toolbar-border-bottom">-->
|
||||
<!-- <v-toolbar-title>-->
|
||||
<!-- <v-breadcrumbs :items="[{-->
|
||||
@@ -61,291 +61,317 @@
|
||||
<!-- outlined></v-text-field>-->
|
||||
<v-simple-table v-if="data1" dense>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center" rowspan="3">
|
||||
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-1 flex-shrink-1" dense
|
||||
v-model="allToggle"></v-checkbox>
|
||||
</template>
|
||||
<span>{{allToggle ? 'Disable' : 'Enable'}} all {{nodes.tn}} routes for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{routesName}} Routes</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
<th v-for="role in roles" :colspan="methods.length"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{role}}</span>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<!-- <th colspan="2"></th>-->
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th width="25" class="caption px-1" :key="`${method}_${role}`"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'">{{method}}
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
<tr>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th width="25" class="caption px-1" :key="`${method}_${role}`"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'">
|
||||
|
||||
<tr>
|
||||
<th colspan="2" class="text-center" rowspan="3">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-0" dense
|
||||
v-model="columnToggle[`${method}_${role}`]"
|
||||
@change="toggleColumn(role,method,columnToggle[`${method}_${role}`])"></v-checkbox>
|
||||
v-model="allToggle"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-1 flex-shrink-1"
|
||||
dense
|
||||
v-on="on"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<span>{{columnToggle[`${method}_${role}`] ? 'Disable' : 'Enable'}} all {{method}} routes for {{role}}</span>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} routes for all roles</span>
|
||||
</v-tooltip>
|
||||
</th>
|
||||
<span class="title">{{ routesName }} Routes</span>
|
||||
</div>
|
||||
</th>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
:key="role"
|
||||
:colspan="methods.length"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<!-- <th colspan="2"></th>-->
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th
|
||||
:key="`${method}_${role}`"
|
||||
width="25"
|
||||
class="caption px-1"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'"
|
||||
>
|
||||
{{ method }}
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th
|
||||
:key="`${method}_${role}`"
|
||||
width="25"
|
||||
class="caption px-1"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="columnToggle[`${method}_${role}`]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleColumn(role,method,columnToggle[`${method}_${role}`])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<span>{{ columnToggle[`${method}_${role}`] ? 'Disable' : 'Enable' }} all {{ method }} routes for {{ role }}</span>
|
||||
</v-tooltip>
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="[path,route] in filteredGroupedData"
|
||||
>
|
||||
<tr
|
||||
v-for="([path,route], i) in filteredGroupedData"
|
||||
:key="i"
|
||||
>
|
||||
<td width="20" class="px-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="rowToggle[path]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0 ml-3"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<td width="20" class="px-0">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-0 ml-3" v-model="rowToggle[path]"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
dense></v-checkbox>
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this route for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<td :key="`${path}_${method}_${role}`" :style="i ? '' : 'border-left: 1px solid grey'" class="pa-1">
|
||||
<v-checkbox
|
||||
v-if="route[method]"
|
||||
v-model="route[method].acl[role]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
:color="methodColor[method]"
|
||||
:input-value="route[method].acl[role]"
|
||||
@change="toggleCell(path,method,role,route[method].acl[role])"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
<!-- todo: @dblclick="$set(data1[path],method , {})"-->
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
:disabled="true"
|
||||
/></span>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<span>{{rowToggle[path] ? 'Disable' : 'Enable'}} this route for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{path}}</span>
|
||||
</template>
|
||||
<span>{{path}}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<td :style="i ? '' : 'border-left: 1px solid grey'" class="pa-1" :key="`${path}_${method}_${role}`">
|
||||
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
v-if="route[method]" class="mt-0" dense
|
||||
:color="methodColor[method]"
|
||||
:input-value="route[method].acl[role]"
|
||||
v-model="route[method].acl[role]"
|
||||
@change="toggleCell(path,method,role,route[method].acl[role])">
|
||||
</v-checkbox>
|
||||
<span
|
||||
v-else>
|
||||
<!-- todo: @dblclick="$set(data1[path],method , {})"-->
|
||||
<v-checkbox v-ge="['acl','toggle-checkbox']" class="mt-0" dense
|
||||
:disabled="true">
|
||||
</v-checkbox></span>
|
||||
</td>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</tr>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
export default {
|
||||
name: 'AclTsFileChild',
|
||||
|
||||
export default {
|
||||
name: "acl-ts-file-child",
|
||||
props: ['nodes', 'policyPath', 'search'],
|
||||
data () {
|
||||
return {
|
||||
groupedData: null,
|
||||
disableSaveButton: true,
|
||||
// policyPath: '',
|
||||
columnToggle: {},
|
||||
rowToggle: {},
|
||||
// allToggle: false,
|
||||
methodColor: {
|
||||
get: 'green',
|
||||
post: 'orange',
|
||||
put: 'deep-orange',
|
||||
patch: 'pink lighten-1',
|
||||
delete: 'red darken-3'
|
||||
},
|
||||
roles: [
|
||||
'creator',
|
||||
'editor',
|
||||
'guest'
|
||||
],
|
||||
methods: [
|
||||
'get', 'post', 'put', 'delete'
|
||||
],
|
||||
data1: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
props: ["nodes", "policyPath", "search"],
|
||||
methods: {
|
||||
async aclInit () {
|
||||
this.disableSaveButton = true
|
||||
|
||||
async aclInit() {
|
||||
this.disableSaveButton = true;
|
||||
|
||||
try {
|
||||
console.log(this.policyPath, this.data1)
|
||||
// this.data1 = JSON.parse(JSON.stringify(await this.sqlMgr.importFresh({path: this.policyPath})));
|
||||
this.data1 = JSON.parse(JSON.stringify(await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'importFresh', {path: this.policyPath}])));
|
||||
this.groupRoutes();
|
||||
this.initColumnCheckBox();
|
||||
this.initRowCheckBox();
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
groupRoutes() {
|
||||
const groupedData = {};
|
||||
for (const route of this.data1) {
|
||||
groupedData[route.path] = groupedData[route.path] || {};
|
||||
groupedData[route.path][route.type] = route;
|
||||
}
|
||||
this.groupedData = groupedData;
|
||||
},
|
||||
toggleColumn(role, method, checked) {
|
||||
for (let [path, methods] of Object.entries(this.groupedData)) {
|
||||
if (methods[method]) {
|
||||
this.$set(methods[method].acl, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleRow(path, checked) {
|
||||
for (let [method, route] of Object.entries(this.groupedData[path])) {
|
||||
for (let role in route.acl) {
|
||||
this.$set(route.acl, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.disableSaveButton = false;
|
||||
for (let path in this.groupedData) {
|
||||
this.rowToggle[path] = checked;
|
||||
}
|
||||
for (let role of this.roles) {
|
||||
for (let method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = checked;
|
||||
}
|
||||
}
|
||||
|
||||
for (let methods of Object.values(this.groupedData)) {
|
||||
for (let router of Object.values(methods)) {
|
||||
for (let role of this.roles) {
|
||||
this.$set(router.acl, role, checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell(path, method, role, checked) {
|
||||
this.disableSaveButton = false;
|
||||
this.$set(this.columnToggle, `${method}_${role}`, Object.values(this.groupedData).some(methods => methods[method] && methods[method].acl[role]));
|
||||
this.$set(this.rowToggle, path, Object.values(this.groupedData[path]).some(route => Object.values(route.acl).some(v => v)));
|
||||
},
|
||||
initColumnCheckBox() {
|
||||
for (let role of this.roles) {
|
||||
for (let method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = Object.values(this.groupedData).some(methods => methods[method] && methods[method].acl[role]);
|
||||
}
|
||||
}
|
||||
},
|
||||
initRowCheckBox() {
|
||||
for (let path in this.groupedData) {
|
||||
this.rowToggle[path] = Object.values(this.groupedData[path])
|
||||
.filter(route =>
|
||||
Object.entries(route.acl).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) this.roles = [...this.roles, role];
|
||||
return v;
|
||||
}).length
|
||||
).length;
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
// await this.sqlMgr.writeFile({
|
||||
// path: this.policyPath,
|
||||
// data: `module.exports = ${JSON.stringify(this.data1, null, 2)}`
|
||||
// })
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'writeFile', {
|
||||
path: this.policyPath,
|
||||
data: `module.exports = ${JSON.stringify(this.data1, null, 2)}`
|
||||
}])
|
||||
this.disableSaveButton = true;
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000);
|
||||
try {
|
||||
console.log(this.policyPath, this.data1)
|
||||
// this.data1 = JSON.parse(JSON.stringify(await this.sqlMgr.importFresh({path: this.policyPath})));
|
||||
this.data1 = JSON.parse(JSON.stringify(await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'importFresh', { path: this.policyPath }])))
|
||||
this.groupRoutes()
|
||||
this.initColumnCheckBox()
|
||||
this.initRowCheckBox()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
groupRoutes () {
|
||||
const groupedData = {}
|
||||
for (const route of this.data1) {
|
||||
groupedData[route.path] = groupedData[route.path] || {}
|
||||
groupedData[route.path][route.type] = route
|
||||
}
|
||||
this.groupedData = groupedData
|
||||
},
|
||||
toggleColumn (role, method, checked) {
|
||||
for (const [path, methods] of Object.entries(this.groupedData)) {
|
||||
if (methods[method]) {
|
||||
this.$set(methods[method].acl, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
groupedData: null,
|
||||
disableSaveButton: true,
|
||||
policyPath: '',
|
||||
columnToggle: {},
|
||||
rowToggle: {},
|
||||
// allToggle: false,
|
||||
methodColor: {
|
||||
get: 'green',
|
||||
post: 'orange',
|
||||
put: 'deep-orange',
|
||||
patch: 'pink lighten-1',
|
||||
delete: 'red darken-3',
|
||||
},
|
||||
roles: [
|
||||
'creator',
|
||||
'editor',
|
||||
'guest'
|
||||
],
|
||||
methods: [
|
||||
'get', 'post', 'put', 'delete'
|
||||
],
|
||||
data1: null
|
||||
toggleRow (path, checked) {
|
||||
for (const [method, route] of Object.entries(this.groupedData[path])) {
|
||||
for (const role in route.acl) {
|
||||
this.$set(route.acl, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
allToggle: {
|
||||
get() {
|
||||
return this.groupedData && Object.values(this.groupedData)
|
||||
.some(methods => Object.values(methods)
|
||||
.some(route => Object.values(route.acl)
|
||||
.some(v => v)
|
||||
)
|
||||
toggleAll (checked) {
|
||||
this.disableSaveButton = false
|
||||
for (const path in this.groupedData) {
|
||||
this.rowToggle[path] = checked
|
||||
}
|
||||
for (const role of this.roles) {
|
||||
for (const method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = checked
|
||||
}
|
||||
}
|
||||
|
||||
for (const methods of Object.values(this.groupedData)) {
|
||||
for (const router of Object.values(methods)) {
|
||||
for (const role of this.roles) {
|
||||
this.$set(router.acl, role, checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell (path, method, role, checked) {
|
||||
this.disableSaveButton = false
|
||||
this.$set(this.columnToggle, `${method}_${role}`, Object.values(this.groupedData).some(methods => methods[method] && methods[method].acl[role]))
|
||||
this.$set(this.rowToggle, path, Object.values(this.groupedData[path]).some(route => Object.values(route.acl).some(v => v)))
|
||||
},
|
||||
initColumnCheckBox () {
|
||||
for (const role of this.roles) {
|
||||
for (const method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = Object.values(this.groupedData).some(methods => methods[method] && methods[method].acl[role])
|
||||
}
|
||||
}
|
||||
},
|
||||
initRowCheckBox () {
|
||||
for (const path in this.groupedData) {
|
||||
this.rowToggle[path] = Object.values(this.groupedData[path])
|
||||
.filter(route =>
|
||||
Object.entries(route.acl).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) { this.roles = [...this.roles, role] }
|
||||
return v
|
||||
}).length
|
||||
).length
|
||||
}
|
||||
},
|
||||
async save () {
|
||||
try {
|
||||
// await this.sqlMgr.writeFile({
|
||||
// path: this.policyPath,
|
||||
// data: `module.exports = ${JSON.stringify(this.data1, null, 2)}`
|
||||
// })
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'writeFile', {
|
||||
path: this.policyPath,
|
||||
data: `module.exports = ${JSON.stringify(this.data1, null, 2)}`
|
||||
}])
|
||||
this.disableSaveButton = true
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
|
||||
allToggle: {
|
||||
get () {
|
||||
return this.groupedData && Object.values(this.groupedData)
|
||||
.some(methods => Object.values(methods)
|
||||
.some(route => Object.values(route.acl)
|
||||
.some(v => v)
|
||||
)
|
||||
},
|
||||
set(checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
)
|
||||
},
|
||||
routesName() {
|
||||
return this.policyPath && this.policyPath
|
||||
.split('/').pop()
|
||||
.replace(/\.routes.js$/, '')
|
||||
.replace(/(?:^|\.)(\w+)/g, (_, m) => {
|
||||
if (m === 'bt') return ' BelongsTo';
|
||||
if (m === 'hm') return ' HasMany';
|
||||
return ' ' + m[0].toUpperCase() + m.slice(1)
|
||||
})
|
||||
},
|
||||
filteredGroupedData() {
|
||||
return this.groupedData ? Object.entries(this.groupedData)
|
||||
.filter(([path]) => !this.search || path.toLowerCase().indexOf(this.search.toLowerCase()) > -1) : [];
|
||||
set (checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.aclInit();
|
||||
routesName () {
|
||||
return this.policyPath && this.policyPath
|
||||
.split('/').pop()
|
||||
.replace(/\.routes.js$/, '')
|
||||
.replace(/(?:^|\.)(\w+)/g, (_, m) => {
|
||||
if (m === 'bt') { return ' BelongsTo' }
|
||||
if (m === 'hm') { return ' HasMany' }
|
||||
return ' ' + m[0].toUpperCase() + m.slice(1)
|
||||
})
|
||||
},
|
||||
watch: {}
|
||||
filteredGroupedData () {
|
||||
return this.groupedData
|
||||
? Object.entries(this.groupedData)
|
||||
.filter(([path]) => !this.search || path.toLowerCase().includes(this.search.toLowerCase()))
|
||||
: []
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
async created () {
|
||||
await this.aclInit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,79 +1,100 @@
|
||||
<template>
|
||||
<!-- eslint-disable --><template>
|
||||
<div>
|
||||
<v-card style="">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['acl','reload']"
|
||||
@click="reload"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['acl','reload']"
|
||||
outlined
|
||||
tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
@click="reload"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn tooltip="Open Corresponding Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
:disabled="!policies || !policies.length"
|
||||
color="primary"
|
||||
v-ge="['acl','open-folder']"
|
||||
@click="openFolder">
|
||||
<x-btn
|
||||
v-ge="['acl','open-folder']"
|
||||
tooltip="Open Corresponding Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
:disabled="!policies || !policies.length"
|
||||
color="primary"
|
||||
@click="openFolder"
|
||||
>
|
||||
Open Folder
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="save"
|
||||
:disabled="disableSaveButton"
|
||||
v-ge="['acl','save']">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['acl','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<template v-if="loading">
|
||||
<v-skeleton-loader
|
||||
type="table"
|
||||
width="100%"></v-skeleton-loader>
|
||||
|
||||
width="100%"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search ${nodes.tn} routes`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search ${nodes.tn} routes`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
<acl-typeorm-db-child
|
||||
v-if="policies && policies.length"
|
||||
ref="acl"
|
||||
:nodes="nodes" :search="search" :policies="policies"
|
||||
></acl-typeorm-db-child>
|
||||
|
||||
:nodes="nodes"
|
||||
:search="search"
|
||||
:policies="policies"
|
||||
/>
|
||||
</template>
|
||||
<!-- <acl-ts-file-child-->
|
||||
<!-- style="border-bottom: 1px solid grey"-->
|
||||
@@ -85,19 +106,26 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import AclTypeormDbChild from "./aclTsFileDbChild";
|
||||
|
||||
import { mapGetters } from 'vuex'
|
||||
import AclTypeormDbChild from './aclTsFileDbChild'
|
||||
|
||||
// const {shell, path} = require("electron").remote.require('./libs');
|
||||
|
||||
export default {
|
||||
name: "acl-typeorm-db",
|
||||
components: {AclTypeormDbChild},
|
||||
props: ["nodes"],
|
||||
name: 'AclTypeormDb',
|
||||
components: { AclTypeormDbChild },
|
||||
props: ['nodes'],
|
||||
data () {
|
||||
return {
|
||||
disableSaveButton: false,
|
||||
policies: [],
|
||||
search: '',
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
async aclInit() {
|
||||
async aclInit () {
|
||||
// // this.disableSaveButton = true;
|
||||
// this.policies = (await this.sqlMgr.xcRoutesPolicyGet({
|
||||
// env: this.nodes.env,
|
||||
@@ -109,40 +137,31 @@ export default {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}])).data.list;
|
||||
}])).data.list
|
||||
},
|
||||
reload() {
|
||||
this.$refs.acl.aclInit();
|
||||
reload () {
|
||||
this.$refs.acl.aclInit()
|
||||
},
|
||||
save() {
|
||||
this.$refs.acl.save();
|
||||
save () {
|
||||
this.$refs.acl.save()
|
||||
},
|
||||
openFolder() {
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
disableSaveButton: false,
|
||||
policies: [],
|
||||
search: '',
|
||||
loading: false
|
||||
openFolder () {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
},
|
||||
mounted() {
|
||||
this.$nuxt.$loading.start();
|
||||
setTimeout(async () => {
|
||||
await this.aclInit();
|
||||
this.$nuxt.$loading.finish();
|
||||
this.loading = false;
|
||||
|
||||
}, 500);
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' })
|
||||
},
|
||||
watch: {},
|
||||
created() {
|
||||
this.loading = true;
|
||||
mounted () {
|
||||
this.$nuxt.$loading.start()
|
||||
setTimeout(async () => {
|
||||
await this.aclInit()
|
||||
this.$nuxt.$loading.finish()
|
||||
this.loading = false
|
||||
}, 500)
|
||||
},
|
||||
created () {
|
||||
this.loading = true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
<v-card class="elevation-0" style="" v-if="filteredGroupedData.length">
|
||||
|
||||
<v-card v-if="filteredGroupedData.length" class="elevation-0" style="">
|
||||
<!-- <v-toolbar flat height="42" class="toolbar-border-bottom">-->
|
||||
<!-- <v-toolbar-title>-->
|
||||
<!-- <v-breadcrumbs :items="[{-->
|
||||
@@ -61,251 +61,169 @@
|
||||
<!-- outlined></v-text-field>-->
|
||||
<v-simple-table v-if="data1" dense>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center" rowspan="3">
|
||||
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-1 flex-shrink-1" dense
|
||||
v-model="allToggle"></v-checkbox>
|
||||
</template>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} routes for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{ routesName }} Routes</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
<th v-for="role in roles" :colspan="methods.length"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<!-- <th colspan="2"></th>-->
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th width="25" class="caption px-1" :key="`${method}_${role}`"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'">{{ method }}
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
<tr>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th width="25" class="caption px-1" :key="`${method}_${role}`"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'">
|
||||
|
||||
<tr>
|
||||
<th colspan="2" class="text-center" rowspan="3">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-0" dense
|
||||
v-model="columnToggle[`${method}_${role}`]"
|
||||
@change="toggleColumn(role,method,columnToggle[`${method}_${role}`])"></v-checkbox>
|
||||
v-model="allToggle"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-1 flex-shrink-1"
|
||||
dense
|
||||
v-on="on"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<span>{{ columnToggle[`${method}_${role}`] ? 'Disable' : 'Enable' }} all {{ method }} routes for {{ role }}</span>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} routes for all roles</span>
|
||||
</v-tooltip>
|
||||
</th>
|
||||
<span class="title">{{ routesName }} Routes</span>
|
||||
</div>
|
||||
</th>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
:key="role"
|
||||
:colspan="methods.length"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<!-- <th colspan="2"></th>-->
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th
|
||||
:key="`${method}_${role}`"
|
||||
width="25"
|
||||
class="caption px-1"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'"
|
||||
>
|
||||
{{ method }}
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<th
|
||||
:key="`${method}_${role}`"
|
||||
width="25"
|
||||
class="caption px-1"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="columnToggle[`${method}_${role}`]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleColumn(role,method,columnToggle[`${method}_${role}`])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<span>{{ columnToggle[`${method}_${role}`] ? 'Disable' : 'Enable' }} all {{
|
||||
method
|
||||
}} routes for {{ role }}</span>
|
||||
</v-tooltip>
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="[path,route] in filteredGroupedData"
|
||||
>
|
||||
<tr
|
||||
v-for="([path,route],i) in filteredGroupedData"
|
||||
:key="i"
|
||||
>
|
||||
<td width="20" class="px-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="rowToggle[path]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0 ml-3"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<td width="20" class="px-0">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']" v-on="on" class="mt-0 ml-3" v-model="rowToggle[path]"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
dense></v-checkbox>
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this route for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<td
|
||||
:key="`${path}_${method}_${role}`"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'"
|
||||
class="pa-1"
|
||||
@dblclick="route[method] && showSourceCode(route,method)"
|
||||
>
|
||||
<v-checkbox
|
||||
v-if="route[method]"
|
||||
v-model="route[method].acl[role]"
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
:color="methodColor[method]"
|
||||
:input-value="route[method].acl[role]"
|
||||
@change="toggleCell(path,method,role,route[method].acl[role])"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
<!-- todo: @dblclick="$set(data1[path],method , {})"-->
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
class="mt-0"
|
||||
dense
|
||||
:disabled="true"
|
||||
/></span>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this route for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="role in roles">
|
||||
<template v-for="(method,i) in methods">
|
||||
<td @dblclick="route[method] && showSourceCode(route,method)"
|
||||
:style="i ? '' : 'border-left: 1px solid grey'" class="pa-1" :key="`${path}_${method}_${role}`">
|
||||
|
||||
<v-checkbox
|
||||
v-ge="['acl','toggle-checkbox']"
|
||||
v-if="route[method]" class="mt-0" dense
|
||||
:color="methodColor[method]"
|
||||
:input-value="route[method].acl[role]"
|
||||
v-model="route[method].acl[role]"
|
||||
@change="toggleCell(path,method,role,route[method].acl[role])">
|
||||
</v-checkbox>
|
||||
<span
|
||||
v-else>
|
||||
<!-- todo: @dblclick="$set(data1[path],method , {})"-->
|
||||
<v-checkbox v-ge="['acl','toggle-checkbox']" class="mt-0" dense
|
||||
:disabled="true">
|
||||
</v-checkbox></span>
|
||||
</td>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</tr>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
|
||||
|
||||
<handler-code-editor :nodes="nodes" :route="editRoute"
|
||||
:method="editMethod"
|
||||
v-model="showCodeEditor"></handler-code-editor>
|
||||
|
||||
<handler-code-editor
|
||||
v-model="showCodeEditor"
|
||||
:nodes="nodes"
|
||||
:route="editRoute"
|
||||
:method="editMethod"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import HandlerCodeEditor from "../restHandlerCodeEditor";
|
||||
|
||||
import { mapGetters } from 'vuex'
|
||||
import HandlerCodeEditor from '../restHandlerCodeEditor'
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
|
||||
export default {
|
||||
name: "acl-ts-file-db-child",
|
||||
components: {HandlerCodeEditor},
|
||||
props: ["nodes", "policies", "search"],
|
||||
methods: {
|
||||
showSourceCode(route, method) {
|
||||
this.editRoute = route;
|
||||
this.editMethod = method;
|
||||
this.showCodeEditor = true;
|
||||
},
|
||||
aclInit() {
|
||||
this.disableSaveButton = true;
|
||||
try {
|
||||
// console.log(this.policyPath, this.data1)
|
||||
// this.data1 = JSON.parse(JSON.stringify(importFresh(this.policyPath)));
|
||||
this.groupRoutes();
|
||||
this.initColumnCheckBox();
|
||||
this.initRowCheckBox();
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
groupRoutes() {
|
||||
const groupedData = {};
|
||||
for (const route of this.data1) {
|
||||
if (route.path) {
|
||||
groupedData[route.path] = groupedData[route.path] || {};
|
||||
groupedData[route.path][route.type] = route;
|
||||
}
|
||||
}
|
||||
this.groupedData = groupedData;
|
||||
},
|
||||
toggleColumn(role, method, checked) {
|
||||
for (let [path, methods] of Object.entries(this.groupedData)) {
|
||||
if (methods[method]) {
|
||||
this.$set(methods[method].acl, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleRow(path, checked) {
|
||||
for (let [method, route] of Object.entries(this.groupedData[path])) {
|
||||
for (let role in route.acl) {
|
||||
this.$set(route.acl, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.disableSaveButton = false;
|
||||
for (let path in this.groupedData) {
|
||||
this.rowToggle[path] = checked;
|
||||
}
|
||||
for (let role of this.roles) {
|
||||
for (let method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = checked;
|
||||
}
|
||||
}
|
||||
|
||||
for (let methods of Object.values(this.groupedData)) {
|
||||
for (let router of Object.values(methods)) {
|
||||
for (let role of this.roles) {
|
||||
this.$set(router.acl, role, checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell(path, method, role, checked) {
|
||||
this.disableSaveButton = false;
|
||||
this.$set(this.columnToggle, `${method}_${role}`, Object.values(this.groupedData).some(methods => methods[method] && methods[method].acl[role]));
|
||||
this.$set(this.rowToggle, path, Object.values(this.groupedData[path]).some(route => Object.values(route.acl).some(v => v)));
|
||||
},
|
||||
initColumnCheckBox() {
|
||||
for (let role of this.roles) {
|
||||
for (let method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = Object.values(this.groupedData).some(methods => methods[method] && methods[method].acl[role]);
|
||||
}
|
||||
}
|
||||
},
|
||||
initRowCheckBox() {
|
||||
for (let path in this.groupedData) {
|
||||
this.rowToggle[path] = Object.values(this.groupedData[path])
|
||||
.filter(route =>
|
||||
Object.entries(route.acl).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) this.roles = [...this.roles, role];
|
||||
return v;
|
||||
}).length
|
||||
).length;
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
//
|
||||
// await this.sqlMgr.xcRoutesPolicyUpdate({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn,
|
||||
// data: this.data1
|
||||
// })
|
||||
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcRoutesPolicyUpdate', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn,
|
||||
data: this.data1
|
||||
}])
|
||||
|
||||
|
||||
this.disableSaveButton = true;
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000);
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
name: 'AclTsFileDbChild',
|
||||
components: { HandlerCodeEditor },
|
||||
props: ['nodes', 'policies', 'search'],
|
||||
data () {
|
||||
return {
|
||||
showCodeEditor: false,
|
||||
editRoute: null,
|
||||
@@ -321,7 +239,7 @@ export default {
|
||||
post: 'orange',
|
||||
put: 'deep-orange',
|
||||
patch: 'pink lighten-1',
|
||||
delete: 'red darken-3',
|
||||
delete: 'red darken-3'
|
||||
},
|
||||
roles: [
|
||||
'creator',
|
||||
@@ -334,10 +252,123 @@ export default {
|
||||
data1: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showSourceCode (route, method) {
|
||||
this.editRoute = route
|
||||
this.editMethod = method
|
||||
this.showCodeEditor = true
|
||||
},
|
||||
aclInit () {
|
||||
this.disableSaveButton = true
|
||||
try {
|
||||
// console.log(this.policyPath, this.data1)
|
||||
// this.data1 = JSON.parse(JSON.stringify(importFresh(this.policyPath)));
|
||||
this.groupRoutes()
|
||||
this.initColumnCheckBox()
|
||||
this.initRowCheckBox()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
groupRoutes () {
|
||||
const groupedData = {}
|
||||
for (const route of this.data1) {
|
||||
if (route.path) {
|
||||
groupedData[route.path] = groupedData[route.path] || {}
|
||||
groupedData[route.path][route.type] = route
|
||||
}
|
||||
}
|
||||
this.groupedData = groupedData
|
||||
},
|
||||
toggleColumn (role, method, checked) {
|
||||
for (const [path, methods] of Object.entries(this.groupedData)) {
|
||||
if (methods[method]) {
|
||||
this.$set(methods[method].acl, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleRow (path, checked) {
|
||||
for (const [method, route] of Object.entries(this.groupedData[path])) {
|
||||
for (const role in route.acl) {
|
||||
this.$set(route.acl, role, checked)
|
||||
this.toggleCell(path, method, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleAll (checked) {
|
||||
this.disableSaveButton = false
|
||||
for (const path in this.groupedData) {
|
||||
this.rowToggle[path] = checked
|
||||
}
|
||||
for (const role of this.roles) {
|
||||
for (const method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = checked
|
||||
}
|
||||
}
|
||||
|
||||
for (const methods of Object.values(this.groupedData)) {
|
||||
for (const router of Object.values(methods)) {
|
||||
for (const role of this.roles) {
|
||||
this.$set(router.acl, role, checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell (path, method, role, checked) {
|
||||
this.disableSaveButton = false
|
||||
this.$set(this.columnToggle, `${method}_${role}`, Object.values(this.groupedData).some(methods => methods[method] && methods[method].acl[role]))
|
||||
this.$set(this.rowToggle, path, Object.values(this.groupedData[path]).some(route => Object.values(route.acl).some(v => v)))
|
||||
},
|
||||
initColumnCheckBox () {
|
||||
for (const role of this.roles) {
|
||||
for (const method of this.methods) {
|
||||
this.columnToggle[`${method}_${role}`] = Object.values(this.groupedData).some(methods => methods[method] && methods[method].acl[role])
|
||||
}
|
||||
}
|
||||
},
|
||||
initRowCheckBox () {
|
||||
for (const path in this.groupedData) {
|
||||
this.rowToggle[path] = Object.values(this.groupedData[path])
|
||||
.filter(route =>
|
||||
Object.entries(route.acl).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) {
|
||||
this.roles = [...this.roles, role]
|
||||
}
|
||||
return v
|
||||
}).length
|
||||
).length
|
||||
}
|
||||
},
|
||||
async save () {
|
||||
try {
|
||||
//
|
||||
// await this.sqlMgr.xcRoutesPolicyUpdate({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn,
|
||||
// data: this.data1
|
||||
// })
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcRoutesPolicyUpdate', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn,
|
||||
data: this.data1
|
||||
}])
|
||||
|
||||
this.disableSaveButton = true
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
|
||||
allToggle: {
|
||||
get() {
|
||||
get () {
|
||||
return this.groupedData && Object.values(this.groupedData)
|
||||
.some(methods => Object.values(methods)
|
||||
.some(route => Object.values(route.acl)
|
||||
@@ -345,35 +376,39 @@ export default {
|
||||
)
|
||||
)
|
||||
},
|
||||
set(checked) {
|
||||
set (checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
},
|
||||
routesName() {
|
||||
routesName () {
|
||||
return this.policyPath && this.policyPath
|
||||
.split('/').pop()
|
||||
.replace(/\.routes.js$/, '')
|
||||
.replace(/(?:^|\.)(\w+)/g, (_, m) => {
|
||||
if (m === 'bt') return ' BelongsTo';
|
||||
if (m === 'hm') return ' HasMany';
|
||||
if (m === 'bt') {
|
||||
return ' BelongsTo'
|
||||
}
|
||||
if (m === 'hm') {
|
||||
return ' HasMany'
|
||||
}
|
||||
return ' ' + m[0].toUpperCase() + m.slice(1)
|
||||
})
|
||||
},
|
||||
filteredGroupedData() {
|
||||
filteredGroupedData () {
|
||||
return Object.entries(this.groupedData)
|
||||
.filter(([path]) => !this.search || path.toLowerCase().indexOf(this.search.toLowerCase()) > -1);
|
||||
.filter(([path]) => !this.search || path.toLowerCase().includes(this.search.toLowerCase()))
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
policies(d) {
|
||||
this.data1 = JSON.parse(JSON.stringify(d));
|
||||
this.aclInit();
|
||||
policies (d) {
|
||||
this.data1 = JSON.parse(JSON.stringify(d))
|
||||
this.aclInit()
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.data1 = JSON.parse(JSON.stringify(this.policies));
|
||||
this.aclInit();
|
||||
},
|
||||
async mounted () {
|
||||
this.data1 = JSON.parse(JSON.stringify(this.policies))
|
||||
this.aclInit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,274 +1,204 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
<v-card style="">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['acl-gql','reload']"
|
||||
@click="aclInit"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['acl-gql','reload']"
|
||||
outlined
|
||||
tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
@click="aclInit"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small v-ge="['acl-gql','open-folder']"
|
||||
color="primary"
|
||||
@click="openFolder">
|
||||
<x-btn
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
color="primary"
|
||||
@click="openFolder"
|
||||
>
|
||||
Open Folder
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save ACL"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="save"
|
||||
:disabled="disableSaveButton"
|
||||
v-ge="['acl-gql','save']">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['acl-gql','save']"
|
||||
outlined
|
||||
tooltip="Save ACL"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search ${nodes.tn} resolvers`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search ${nodes.tn} resolvers`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<v-simple-table v-if="policies && policies.length" dense>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center" rowspan="2">
|
||||
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-1 flex-shrink-1" dense
|
||||
v-model="allToggle"></v-checkbox>
|
||||
</template>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} resolvers for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{ nodes.tn }} Resolvers</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
<th v-for="role in roles"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<th v-for="role in roles"
|
||||
<tr>
|
||||
<th colspan="2" class="text-center" rowspan="2">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="allToggle"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-1 flex-shrink-1"
|
||||
dense
|
||||
v-on="on"
|
||||
/>
|
||||
</template>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} resolvers for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{ nodes.tn }} Resolvers</span>
|
||||
</div>
|
||||
</th>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
class="pa-1"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-0" dense v-model="columnToggle[role]"
|
||||
@change="toggleColumn(role,columnToggle[role])"></v-checkbox>
|
||||
</template>
|
||||
<span>
|
||||
<span>{{ columnToggle[role] ? 'Disable' : 'Enable' }} all resolvers for {{ role }}</span></span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="columnToggle[role]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleColumn(role,columnToggle[role])"
|
||||
/>
|
||||
</template>
|
||||
<span>
|
||||
<span>{{ columnToggle[role] ? 'Disable' : 'Enable' }} all resolvers for {{ role }}</span></span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(resolver,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1">
|
||||
<td width="20" class="pl-6 pr-3">
|
||||
<tr v-for="(resolver,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1" key="path" :>
|
||||
<td width="20" class="pl-6 pr-3">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="rowToggle[path]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0 ml-3"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-0 ml-3" v-model="rowToggle[path]"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
dense></v-checkbox>
|
||||
</template>
|
||||
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this resolver for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(role,i) in roles">
|
||||
<td style="border-left: 1px solid grey" class="pa-1" :key="`${path}_${role}`">
|
||||
<div class="d-flex justify-center">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" class="mt-0" dense
|
||||
v-model="data1[path][role]"
|
||||
@change="toggleCell(path,role,data1[path][role])"
|
||||
></v-checkbox>
|
||||
</div>
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this resolver for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
</tr>
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(role) in roles">
|
||||
<td :key="`${path}_${role}`" style="border-left: 1px solid grey" class="pa-1">
|
||||
<div class="d-flex justify-center">
|
||||
<v-checkbox
|
||||
v-model="data1[path][role]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0"
|
||||
dense
|
||||
@change="toggleCell(path,role,data1[path][role])"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else-if="policies" outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else-if="policies" outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
|
||||
export default {
|
||||
name: "acl-ts-file-db-gql",
|
||||
name: 'AclTsFileDbGql',
|
||||
|
||||
props: ["nodes"],
|
||||
methods: {
|
||||
openFolder() {
|
||||
// shell.openItem(path.dirname(this.policyPath));
|
||||
},
|
||||
toggleColumn(role, checked) {
|
||||
for (let [resolver, roles] of Object.entries(this.data1)) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleRow(resolver, checked) {
|
||||
for (let role in this.data1[resolver]) {
|
||||
this.$set(this.data1[resolver], role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.disableSaveButton = false;
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = checked;
|
||||
}
|
||||
for (let role of this.roles) {
|
||||
this.columnToggle[role] = checked;
|
||||
}
|
||||
|
||||
for (let roles of Object.values(this.data1)) {
|
||||
for (let role of this.roles) {
|
||||
this.$set(roles, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell(resolver, role, checked) {
|
||||
this.disableSaveButton = false;
|
||||
this.$set(this.columnToggle, role, Object.values(this.data1).some(roles => roles[role]));
|
||||
this.$set(this.rowToggle, resolver, Object.values(this.data1[resolver]).some(enabled => enabled));
|
||||
},
|
||||
initColumnCheckBox() {
|
||||
for (let role of this.roles) {
|
||||
this.columnToggle[role] = Object.values(this.data1).some(roles => roles[role]);
|
||||
}
|
||||
},
|
||||
initRowCheckBox() {
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = Object.entries(this.data1[path]).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) this.roles = [...this.roles, role];
|
||||
return v;
|
||||
}).length;
|
||||
}
|
||||
},
|
||||
async aclInit() {
|
||||
try {
|
||||
console.log(this.sqlMgr)
|
||||
this.disableSaveButton = true;
|
||||
// this.policies = (await this.sqlMgr.xcResolverPolicyGet({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn
|
||||
// })).data.list;
|
||||
this.policies = (await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcResolverPolicyGet', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}])).data.list;
|
||||
|
||||
//.data.list;
|
||||
this.data = JSON.parse(JSON.stringify(this.policies));
|
||||
this.data1 = this.data.reduce((aclObj, resolver) => {
|
||||
if (resolver.resolver) {
|
||||
aclObj[resolver.resolver] = resolver.acl;
|
||||
}
|
||||
return aclObj;
|
||||
}, {});
|
||||
|
||||
this.initColumnCheckBox();
|
||||
this.initRowCheckBox();
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
|
||||
|
||||
// await this.sqlMgr.xcResolverPolicyUpdate({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn,
|
||||
// data: this.data
|
||||
// })
|
||||
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcResolverPolicyUpdate', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn,
|
||||
data: this.data
|
||||
}])
|
||||
|
||||
|
||||
this.disableSaveButton = true;
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000);
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
props: ['nodes'],
|
||||
data () {
|
||||
return {
|
||||
disableSaveButton: true,
|
||||
search: '',
|
||||
@@ -284,21 +214,124 @@ export default {
|
||||
data1: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openFolder () {
|
||||
// shell.openItem(path.dirname(this.policyPath));
|
||||
},
|
||||
toggleColumn (role, checked) {
|
||||
for (const [resolver, roles] of Object.entries(this.data1)) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleRow (resolver, checked) {
|
||||
for (const role in this.data1[resolver]) {
|
||||
this.$set(this.data1[resolver], role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleAll (checked) {
|
||||
this.disableSaveButton = false
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = checked
|
||||
}
|
||||
for (const role of this.roles) {
|
||||
this.columnToggle[role] = checked
|
||||
}
|
||||
|
||||
for (const roles of Object.values(this.data1)) {
|
||||
for (const role of this.roles) {
|
||||
this.$set(roles, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell (resolver, role, checked) {
|
||||
this.disableSaveButton = false
|
||||
this.$set(this.columnToggle, role, Object.values(this.data1).some(roles => roles[role]))
|
||||
this.$set(this.rowToggle, resolver, Object.values(this.data1[resolver]).some(enabled => enabled))
|
||||
},
|
||||
initColumnCheckBox () {
|
||||
for (const role of this.roles) {
|
||||
this.columnToggle[role] = Object.values(this.data1).some(roles => roles[role])
|
||||
}
|
||||
},
|
||||
initRowCheckBox () {
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = Object.entries(this.data1[path]).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) { this.roles = [...this.roles, role] }
|
||||
return v
|
||||
}).length
|
||||
}
|
||||
},
|
||||
async aclInit () {
|
||||
try {
|
||||
console.log(this.sqlMgr)
|
||||
this.disableSaveButton = true
|
||||
// this.policies = (await this.sqlMgr.xcResolverPolicyGet({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn
|
||||
// })).data.list;
|
||||
this.policies = (await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcResolverPolicyGet', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}])).data.list
|
||||
|
||||
// .data.list;
|
||||
this.data = JSON.parse(JSON.stringify(this.policies))
|
||||
this.data1 = this.data.reduce((aclObj, resolver) => {
|
||||
if (resolver.resolver) {
|
||||
aclObj[resolver.resolver] = resolver.acl
|
||||
}
|
||||
return aclObj
|
||||
}, {})
|
||||
|
||||
this.initColumnCheckBox()
|
||||
this.initRowCheckBox()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
async save () {
|
||||
try {
|
||||
// await this.sqlMgr.xcResolverPolicyUpdate({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn,
|
||||
// data: this.data
|
||||
// })
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcResolverPolicyUpdate', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn,
|
||||
data: this.data
|
||||
}])
|
||||
|
||||
this.disableSaveButton = true
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
|
||||
allToggle: {
|
||||
get() {
|
||||
get () {
|
||||
return this.data1 && Object.values(this.data1).some(roles => Object.values(roles).some(v => v))
|
||||
},
|
||||
set(checked) {
|
||||
set (checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.aclInit();
|
||||
},
|
||||
watch: {}
|
||||
watch: {},
|
||||
async mounted () {
|
||||
await this.aclInit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,283 +1,322 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
<v-card style="">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (ACL)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['acl-gql','reload']"
|
||||
@click="aclInit"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['acl-gql','reload']"
|
||||
outlined
|
||||
tooltip="Reload ACL"
|
||||
color="primary"
|
||||
small
|
||||
@click="aclInit"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small v-ge="['acl-gql','open-folder']"
|
||||
color="primary"
|
||||
@click="openFolder">
|
||||
<x-btn
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
tooltip="Open ACL Folder"
|
||||
icon="mdi-folder-open"
|
||||
outlined
|
||||
small
|
||||
color="primary"
|
||||
@click="openFolder"
|
||||
>
|
||||
Open Folder
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save ACL"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="save"
|
||||
:disabled="disableSaveButton"
|
||||
v-ge="['acl-gql','save']">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['acl-gql','save']"
|
||||
outlined
|
||||
tooltip="Save ACL"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search ${nodes.tn} resolvers`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search ${nodes.tn} resolvers`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<v-simple-table v-if="data1" dense>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center" rowspan="2">
|
||||
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-1 flex-shrink-1" dense
|
||||
v-model="allToggle"></v-checkbox>
|
||||
</template>
|
||||
<span>{{allToggle ? 'Disable' : 'Enable'}} all {{nodes.tn}} resolvers for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{nodes.tn}} Resolvers</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
<th v-for="role in roles"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{role}}</span>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<th v-for="role in roles"
|
||||
<tr>
|
||||
<th colspan="2" class="text-center" rowspan="2">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="allToggle"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-1 flex-shrink-1"
|
||||
dense
|
||||
v-on="on"
|
||||
/>
|
||||
</template>
|
||||
<span>{{ allToggle ? 'Disable' : 'Enable' }} all {{ nodes.tn }} resolvers for all roles</span>
|
||||
</v-tooltip>
|
||||
<span class="title">{{ nodes.tn }} Resolvers</span>
|
||||
</div>
|
||||
</th>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
:key="role"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex align-center justify-center">
|
||||
<span>{{ role }}</span>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
v-for="role in roles"
|
||||
:key="role"
|
||||
class="pa-1"
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey">
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-0" dense v-model="columnToggle[role]"
|
||||
@change="toggleColumn(role,columnToggle[role])"></v-checkbox>
|
||||
</template>
|
||||
<span>
|
||||
<span>{{columnToggle[role] ? 'Disable' : 'Enable'}} all resolvers for {{role}}</span></span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
style="border-left: 1px solid grey;border-bottom: 1px solid grey"
|
||||
>
|
||||
<div class="d-flex justify-center">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="columnToggle[role]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleColumn(role,columnToggle[role])"
|
||||
/>
|
||||
</template>
|
||||
<span>
|
||||
<span>{{ columnToggle[role] ? 'Disable' : 'Enable' }} all resolvers for {{ role }}</span></span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(resolver,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1">
|
||||
<td width="20" class="pl-6 pr-3">
|
||||
<tr v-for="(resolver,path) in data1" v-show="!search || path.toLowerCase().indexOf(search.toLowerCase()) > -1" :key="path">
|
||||
<td width="20" class="pl-6 pr-3">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="rowToggle[path]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0 ml-3"
|
||||
dense
|
||||
v-on="on"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" v-on="on" class="mt-0 ml-3" v-model="rowToggle[path]"
|
||||
@change="toggleRow(path,rowToggle[path])"
|
||||
dense></v-checkbox>
|
||||
</template>
|
||||
|
||||
<span>{{rowToggle[path] ? 'Disable' : 'Enable'}} this resolver for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{path}}</span>
|
||||
</template>
|
||||
<span>{{path}}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(role,i) in roles">
|
||||
<td style="border-left: 1px solid grey" class="pa-1" :key="`${path}_${role}`">
|
||||
<div class="d-flex justify-center">
|
||||
<v-checkbox
|
||||
small v-ge="['acl-gql','open-folder']" class="mt-0" dense
|
||||
v-model="data1[path][role]"
|
||||
@change="toggleCell(path,role,data1[path][role])"
|
||||
></v-checkbox>
|
||||
</div>
|
||||
<span>{{ rowToggle[path] ? 'Disable' : 'Enable' }} this resolver for all roles</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
</tr>
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(role) in roles">
|
||||
<td :key="`${path}_${role}`" style="border-left: 1px solid grey" class="pa-1">
|
||||
<div class="d-flex justify-center">
|
||||
<v-checkbox
|
||||
v-model="data1[path][role]"
|
||||
v-ge="['acl-gql','open-folder']"
|
||||
small
|
||||
class="mt-0"
|
||||
dense
|
||||
@change="toggleCell(path,role,data1[path][role])"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
|
||||
// const {fs, importFresh, shell, path} = require("electron").remote.require('./libs');
|
||||
export default {
|
||||
name: 'AclTsFileGql',
|
||||
|
||||
export default {
|
||||
name: "acl-ts-file-gql",
|
||||
props: ['nodes'],
|
||||
data () {
|
||||
return {
|
||||
disableSaveButton: true,
|
||||
search: '',
|
||||
policyPath: '',
|
||||
columnToggle: {},
|
||||
rowToggle: {},
|
||||
roles: [
|
||||
'creator',
|
||||
'editor',
|
||||
'guest'
|
||||
],
|
||||
data1: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openFolder () {
|
||||
// shell.openItem(path.dirname(this.policyPath))
|
||||
},
|
||||
toggleColumn (role, checked) {
|
||||
for (const [resolver, roles] of Object.entries(this.data1)) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleRow (resolver, checked) {
|
||||
for (const role in this.data1[resolver]) {
|
||||
this.$set(this.data1[resolver], role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleAll (checked) {
|
||||
this.disableSaveButton = false
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = checked
|
||||
}
|
||||
for (const role of this.roles) {
|
||||
this.columnToggle[role] = checked
|
||||
}
|
||||
|
||||
props: ["nodes"],
|
||||
methods: {
|
||||
openFolder() {
|
||||
shell.openItem(path.dirname(this.policyPath));
|
||||
},
|
||||
toggleColumn(role, checked) {
|
||||
for (let [resolver, roles] of Object.entries(this.data1)) {
|
||||
for (const roles of Object.values(this.data1)) {
|
||||
for (const role of this.roles) {
|
||||
this.$set(roles, role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleRow(resolver, checked) {
|
||||
for (let role in this.data1[resolver]) {
|
||||
this.$set(this.data1[resolver], role, checked)
|
||||
this.toggleCell(resolver, role, checked)
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.disableSaveButton = false;
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = checked;
|
||||
}
|
||||
for (let role of this.roles) {
|
||||
this.columnToggle[role] = checked;
|
||||
}
|
||||
|
||||
for (let roles of Object.values(this.data1)) {
|
||||
for (let role of this.roles) {
|
||||
this.$set(roles, role, checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleCell(resolver, role, checked) {
|
||||
this.disableSaveButton = false;
|
||||
this.$set(this.columnToggle, role, Object.values(this.data1).some(roles => roles[role]));
|
||||
this.$set(this.rowToggle, resolver, Object.values(this.data1[resolver]).some(enabled => enabled));
|
||||
},
|
||||
initColumnCheckBox() {
|
||||
for (let role of this.roles) {
|
||||
this.columnToggle[role] = Object.values(this.data1).some(roles => roles[role]);
|
||||
}
|
||||
},
|
||||
initRowCheckBox() {
|
||||
for (let path in this.data1) {
|
||||
this.rowToggle[path] = Object.entries(this.data1[path]).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) this.roles = [...this.roles, role];
|
||||
return v;
|
||||
}).length;
|
||||
}
|
||||
},
|
||||
async aclInit() {
|
||||
this.disableSaveButton = true;
|
||||
// this.policyPath = await this.sqlMgr.projectGetGqlPolicyPath({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn
|
||||
// });
|
||||
this.policyPath = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'projectGetGqlPolicyPath', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}]);
|
||||
try {
|
||||
console.log(this.policyPath, this.data1)
|
||||
// this.data1 = JSON.parse(JSON.stringify(await this.sqlMgr.importFresh({path: this.policyPath})));
|
||||
this.data1 = JSON.parse(JSON.stringify(await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'importFresh', {path: this.policyPath}])));
|
||||
this.initColumnCheckBox();
|
||||
this.initRowCheckBox();
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
// this.sqlMgr.writeFile({path: this.policyPath, data: `module.exports = ${JSON.stringify(this.data1, 0, 2)}`})
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'writeFile', {
|
||||
path: this.policyPath,
|
||||
data: `module.exports = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
}])
|
||||
this.disableSaveButton = true;
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000);
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
disableSaveButton: true,
|
||||
search: '',
|
||||
policyPath: '',
|
||||
columnToggle: {},
|
||||
rowToggle: {},
|
||||
roles: [
|
||||
'creator',
|
||||
'editor',
|
||||
'guest'
|
||||
],
|
||||
data1: null
|
||||
toggleCell (resolver, role, checked) {
|
||||
this.disableSaveButton = false
|
||||
this.$set(this.columnToggle, role, Object.values(this.data1).some(roles => roles[role]))
|
||||
this.$set(this.rowToggle, resolver, Object.values(this.data1[resolver]).some(enabled => enabled))
|
||||
},
|
||||
initColumnCheckBox () {
|
||||
for (const role of this.roles) {
|
||||
this.columnToggle[role] = Object.values(this.data1).some(roles => roles[role])
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
allToggle: {
|
||||
get() {
|
||||
return this.data1 && Object.values(this.data1).some(roles => Object.values(roles).some(v => v))
|
||||
},
|
||||
set(checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
initRowCheckBox () {
|
||||
for (const path in this.data1) {
|
||||
this.rowToggle[path] = Object.entries(this.data1[path]).filter(([role, v]) => {
|
||||
if (!this.roles.includes(role)) { this.roles = [...this.roles, role] }
|
||||
return v
|
||||
}).length
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.aclInit();
|
||||
async aclInit () {
|
||||
this.disableSaveButton = true
|
||||
// this.policyPath = await this.sqlMgr.projectGetGqlPolicyPath({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias,
|
||||
// tn: this.nodes.tn
|
||||
// });
|
||||
this.policyPath = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'projectGetGqlPolicyPath', {
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
tn: this.nodes.tn
|
||||
}])
|
||||
try {
|
||||
console.log(this.policyPath, this.data1)
|
||||
// this.data1 = JSON.parse(JSON.stringify(await this.sqlMgr.importFresh({path: this.policyPath})));
|
||||
this.data1 = JSON.parse(JSON.stringify(await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'importFresh', { path: this.policyPath }])))
|
||||
this.initColumnCheckBox()
|
||||
this.initRowCheckBox()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
watch: {}
|
||||
async save () {
|
||||
try {
|
||||
// this.sqlMgr.writeFile({path: this.policyPath, data: `module.exports = ${JSON.stringify(this.data1, 0, 2)}`})
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'writeFile', {
|
||||
path: this.policyPath,
|
||||
data: `module.exports = ${JSON.stringify(this.data1, 0, 2)}`
|
||||
}])
|
||||
this.disableSaveButton = true
|
||||
this.$toast.success(`${this.policyPath} updated successfully`).goAway(3000)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.$toast.error(`${this.policyPath} updating failed`).goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
|
||||
allToggle: {
|
||||
get () {
|
||||
return this.data1 && Object.values(this.data1).some(roles => Object.values(roles).some(v => v))
|
||||
},
|
||||
set (checked) {
|
||||
this.toggleAll(checked)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
async created () {
|
||||
await this.aclInit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,84 +1,83 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
v-model="dialogShow"
|
||||
width="60%"
|
||||
v-model="dialogShow">
|
||||
>
|
||||
<v-card>
|
||||
|
||||
<h5 class="body-1 pa-1 text-center">Paste JSON/JSON5 String</h5>
|
||||
<h5 class="body-1 pa-1 text-center">
|
||||
Paste JSON/JSON5 String
|
||||
</h5>
|
||||
|
||||
<div class="d-flex" style="height: 100%; width:100%">
|
||||
|
||||
<div style="" class="text-center flex-shrink-1 d-flex flex-column">
|
||||
|
||||
<x-icon
|
||||
icon-class="mx-2 mt-3 elevation-1"
|
||||
color="success success"
|
||||
@click="$emit('load',jsonContent)"
|
||||
>mdi-send
|
||||
>
|
||||
mdi-send
|
||||
</x-icon>
|
||||
|
||||
</div>
|
||||
<div class="flex-grow-1" style="overflow:auto;height:100%">
|
||||
|
||||
<monaco-json-editor
|
||||
:validate="false"
|
||||
v-model="jsonContent"
|
||||
lang="json" style="height: 500px;width: 100%;min-width: 250px"
|
||||
></monaco-json-editor>
|
||||
:validate="false"
|
||||
lang="json"
|
||||
style="height: 500px;width: 100%;min-width: 250px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</v-card>
|
||||
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {MonacoJsonEditor} from '../../../monaco/index'
|
||||
import { MonacoJsonEditor } from '../../../monaco/index'
|
||||
|
||||
export default {
|
||||
name: "jsonToColumn",
|
||||
data() {
|
||||
return {
|
||||
jsonContent: JSON.stringify({first_name: "James", last_name: "Bond"}, 0, 2),
|
||||
activeTab: 0
|
||||
};
|
||||
},
|
||||
methods: {},
|
||||
beforeCreated() {
|
||||
},
|
||||
created() {
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
},
|
||||
destroy() {
|
||||
},
|
||||
validate({params}) {
|
||||
return true;
|
||||
},
|
||||
head() {
|
||||
return {};
|
||||
},
|
||||
props: {
|
||||
value: Boolean,
|
||||
show: Boolean
|
||||
},
|
||||
computed: {
|
||||
dialogShow: {
|
||||
get() {
|
||||
return this.show;
|
||||
}, set(val) {
|
||||
this.$emit('update:show', val);
|
||||
}
|
||||
export default {
|
||||
name: 'JsonToColumn',
|
||||
directives: {},
|
||||
components: { MonacoJsonEditor },
|
||||
validate ({ params }) {
|
||||
return true
|
||||
},
|
||||
props: {
|
||||
value: Boolean,
|
||||
show: Boolean
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
jsonContent: JSON.stringify({ first_name: 'James', last_name: 'Bond' }, 0, 2),
|
||||
activeTab: 0
|
||||
}
|
||||
},
|
||||
head () {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
dialogShow: {
|
||||
get () {
|
||||
return this.show
|
||||
},
|
||||
set (val) {
|
||||
this.$emit('update:show', val)
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
directives: {},
|
||||
components: {MonacoJsonEditor}
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
created () {
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
beforeDestroy () {
|
||||
},
|
||||
methods: {},
|
||||
beforeCreated () {
|
||||
},
|
||||
destroy () {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,52 +2,57 @@
|
||||
<div class="">
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (table)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small >
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (table)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
small
|
||||
color="primary"
|
||||
class="primary"
|
||||
@click="loadConstraintList"
|
||||
>
|
||||
<v-icon left>refresh</v-icon>
|
||||
<v-icon left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Refresh
|
||||
</v-btn
|
||||
>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
small
|
||||
color="error "
|
||||
@click="deleteTable('showDialog')"
|
||||
class="error text-right"
|
||||
>Delete Table
|
||||
</v-btn
|
||||
@click="deleteTable('showDialog')"
|
||||
>
|
||||
Delete Table
|
||||
</v-btn>
|
||||
<v-btn
|
||||
icon
|
||||
class="text-right">
|
||||
class="text-right"
|
||||
>
|
||||
<v-icon>mdi-help-circle-outline</v-icon>
|
||||
</v-btn>
|
||||
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-data-table
|
||||
@@ -56,7 +61,7 @@
|
||||
:items="constraints"
|
||||
footer-props.items-per-page-options="30"
|
||||
>
|
||||
<template v-slot:item="props">
|
||||
<template #item="props">
|
||||
<td>{{ props.item.cstn }}</td>
|
||||
<td>{{ props.item.cst }}</td>
|
||||
<td>{{ props.item.cn }}</td>
|
||||
@@ -67,62 +72,62 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters, mapActions} from "vuex";
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
constraints: [],
|
||||
headers: [
|
||||
{
|
||||
text: "Constraint",
|
||||
sortable: false
|
||||
},
|
||||
{text: "Constraint Type", sortable: false},
|
||||
{text: "Column Name", sortable: false},
|
||||
{text: "Constraint Ordinal Position", sortable: false}
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async loadConstraintList() {
|
||||
if (this.newTable) return;
|
||||
// console.log("env: this.nodes.env", this.nodes.env, this.nodes.dbAlias);
|
||||
const client = await this.sqlMgr.projectGetSqlClient({
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
});
|
||||
const result = await client.constraintList({
|
||||
tn: this.nodes.tn
|
||||
});
|
||||
// console.log("cons", result.data.list);
|
||||
this.constraints = result.data.list;
|
||||
}
|
||||
},
|
||||
computed: {...mapGetters({sqlMgr: "sqlMgr/sqlMgr"})},
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
constraints: [],
|
||||
headers: [
|
||||
{
|
||||
text: 'Constraint',
|
||||
sortable: false
|
||||
},
|
||||
{ text: 'Constraint Type', sortable: false },
|
||||
{ text: 'Column Name', sortable: false },
|
||||
{ text: 'Constraint Ordinal Position', sortable: false }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadConstraintList () {
|
||||
if (this.newTable) { return }
|
||||
// console.log("env: this.nodes.env", this.nodes.env, this.nodes.dbAlias);
|
||||
const client = await this.sqlMgr.projectGetSqlClient({
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
})
|
||||
const result = await client.constraintList({
|
||||
tn: this.nodes.tn
|
||||
})
|
||||
// console.log("cons", result.data.list);
|
||||
this.constraints = result.data.list
|
||||
}
|
||||
},
|
||||
computed: { ...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }) },
|
||||
|
||||
beforeCreated() {
|
||||
},
|
||||
created() {
|
||||
this.loadConstraintList();
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
},
|
||||
destroy() {
|
||||
},
|
||||
validate({params}) {
|
||||
return true;
|
||||
},
|
||||
head() {
|
||||
return {};
|
||||
},
|
||||
props: ["nodes", "newTable", "deleteTable"],
|
||||
watch: {},
|
||||
directives: {},
|
||||
components: {}
|
||||
};
|
||||
beforeCreated () {
|
||||
},
|
||||
watch: {},
|
||||
created () {
|
||||
this.loadConstraintList()
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
beforeDestroy () {
|
||||
},
|
||||
destroy () {
|
||||
},
|
||||
directives: {},
|
||||
components: {},
|
||||
validate ({ params }) {
|
||||
return true
|
||||
},
|
||||
head () {
|
||||
return {}
|
||||
},
|
||||
props: ['nodes', 'newTable', 'deleteTable']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,65 +1,92 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<v-skeleton-loader v-if="loading" type="text@3"></v-skeleton-loader>
|
||||
<div class="caption text-left" v-else>{{ Array.isArray(value) ? '[' : '{' }}
|
||||
<v-skeleton-loader v-if="loading" type="text@3" />
|
||||
<div v-else class="caption text-left">
|
||||
{{ Array.isArray(value) ? '[' : '{' }}
|
||||
|
||||
<ul>
|
||||
<template v-if="Array.isArray(value)">
|
||||
<li v-for="(v,i) in value">
|
||||
<custom-acl :nodes="nodes" :table="table" v-model="value[i]"></custom-acl>
|
||||
<custom-acl v-model="value[i]" :nodes="nodes" :table="table" />
|
||||
</li>
|
||||
<li class="caption add" @click="addConditionObj">
|
||||
add +
|
||||
</li>
|
||||
<li @click="addConditionObj" class="caption add">add +</li>
|
||||
</template>
|
||||
<template v-else>
|
||||
<li v-for="(key,i) in keys" :key="key" v-if="key !== 'relationType'" :class="{empty: !keys[i]}">
|
||||
<li v-for="(key,i) in keys" v-if="key !== 'relationType'" :key="key" :class="{empty: !keys[i]}">
|
||||
<div class="d-inline">
|
||||
<!-- <span contenteditable v-text="key" class="key"></span>-->
|
||||
<select class="caption" v-model="keys[i]" :ref="'keySelect'+i" @change="onKeyChange(i,key)">
|
||||
<select :ref="'keySelect'+i" v-model="keys[i]" class="caption" @change="onKeyChange(i,key)">
|
||||
<template v-if="table">
|
||||
<optgroup label="columns" v-if="columns && columns.length">
|
||||
<option v-for="col in columns" v-show="!keys.includes(col)" :data-value="col">{{ col }}</option>
|
||||
<optgroup v-if="columns && columns.length" label="columns">
|
||||
<option v-for="col in columns" v-show="!keys.includes(col)" :data-value="col">
|
||||
{{ col }}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup label="Has Many" v-if="hmList && hmList.length">
|
||||
<option v-for="hm in hmList" v-show="!keys.includes(hm)" data-relation-type="hm" :data-table="hm">{{
|
||||
<optgroup v-if="hmList && hmList.length" label="Has Many">
|
||||
<option v-for="hm in hmList" v-show="!keys.includes(hm)" data-relation-type="hm" :data-table="hm">
|
||||
{{
|
||||
hm
|
||||
}}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup label="BelongsTo" v-if="btList && btList.length">
|
||||
<option v-for="bt in btList" v-show="!keys.includes(bt)" data-relation-type="bt" :data-table="bt">{{
|
||||
<optgroup v-if="btList && btList.length" label="BelongsTo">
|
||||
<option v-for="bt in btList" v-show="!keys.includes(bt)" data-relation-type="bt" :data-table="bt">
|
||||
{{
|
||||
bt
|
||||
}}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup label="Logical Operators">
|
||||
<option v-for="op in logicOp" data-logical-op="true" :data-op="op">{{ op }}</option>
|
||||
<option v-for="op in logicOp" data-logical-op="true" :data-op="op">
|
||||
{{ op }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</template>
|
||||
<optgroup label="Comparison Operators" v-else>
|
||||
<option v-for="op in compOp" v-show="!keys.includes(op)" :data-op="op">{{ op }}</option>
|
||||
<optgroup v-else label="Comparison Operators">
|
||||
<option v-for="op in compOp" v-show="!keys.includes(op)" :data-op="op">
|
||||
{{ op }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<div class="delete-wrapper">
|
||||
<x-icon color="red" icon-class="delete" v-if="typeof value[key] !== 'string'" x-small
|
||||
@click="deleteCondition(key)">
|
||||
<x-icon
|
||||
v-if="typeof value[key] !== 'string'"
|
||||
color="red"
|
||||
icon-class="delete"
|
||||
x-small
|
||||
@click="deleteCondition(key)"
|
||||
>
|
||||
mdi-delete-outline
|
||||
</x-icon>
|
||||
</div>
|
||||
<span class="separator"> : </span>
|
||||
</div>
|
||||
<template v-if="typeof value[key] === 'string'"><input type="text" v-model="value[key]"
|
||||
class="value caption"/></template>
|
||||
<template v-if="typeof value[key] === 'string'">
|
||||
<input
|
||||
v-model="value[key]"
|
||||
type="text"
|
||||
class="value caption"
|
||||
>
|
||||
</template>
|
||||
<!-- @input="e => $set(value,key,e.target.innerHTML)" -->
|
||||
|
||||
<template v-else>
|
||||
<span class="caption grey--text" v-if="value[key].relationType">
|
||||
<span v-if="value[key].relationType" class="caption grey--text">
|
||||
{{ `'${table}' ${value[key].relationType === 'bt' ? 'BelongsTo' : 'HasMany'} '${key}'` }}
|
||||
</span>
|
||||
<custom-acl :nodes="nodes" v-model="value[key]" :table="(value[key].relationType ? key : null)
|
||||
|| (logicOp.includes(key) ? table : null)"
|
||||
></custom-acl>
|
||||
<custom-acl
|
||||
v-model="value[key]"
|
||||
:nodes="nodes"
|
||||
:table="(value[key].relationType ? key : null)
|
||||
|| (logicOp.includes(key) ? table : null)"
|
||||
/>
|
||||
</template>
|
||||
</li>
|
||||
<li v-if="table" @click="addConditionProp" class="caption add">add +</li>
|
||||
<li v-if="table" class="caption add" @click="addConditionProp">
|
||||
add +
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
{{ Array.isArray(value) ? '] ,' : '} ,' }}
|
||||
@@ -68,11 +95,16 @@
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import {insertKey} from "../../../helpers/xutils";
|
||||
import { insertKey } from '../../../helpers/xutils'
|
||||
|
||||
export default {
|
||||
name: "custom-acl",
|
||||
name: 'CustomAcl',
|
||||
props: [
|
||||
'value',
|
||||
'table',
|
||||
'column',
|
||||
'nodes'
|
||||
],
|
||||
data: () => ({
|
||||
columns: null,
|
||||
hmList: null,
|
||||
@@ -85,111 +117,102 @@ export default {
|
||||
],
|
||||
loading: false
|
||||
}),
|
||||
computed: {
|
||||
keys () {
|
||||
return Object.keys(this.value)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
async mounted () {
|
||||
await this.loadTableMetaDetails()
|
||||
},
|
||||
methods: {
|
||||
onKeyChange(i, key) {
|
||||
let value = JSON.parse(JSON.stringify(this.value));
|
||||
onKeyChange (i, key) {
|
||||
let value = JSON.parse(JSON.stringify(this.value))
|
||||
|
||||
const selected = this.$refs[`keySelect${i}`][0].selectedOptions;
|
||||
let selectedVal = '';
|
||||
if (selected && selected[0])
|
||||
selectedVal = selected[0].dataset;
|
||||
const selected = this.$refs[`keySelect${i}`][0].selectedOptions
|
||||
let selectedVal = ''
|
||||
if (selected && selected[0]) { selectedVal = selected[0].dataset }
|
||||
if (selectedVal.value) {
|
||||
delete value[key];
|
||||
value = insertKey(this.keys[i], {eq: ""}, value, i);
|
||||
delete value[key]
|
||||
value = insertKey(this.keys[i], { eq: '' }, value, i)
|
||||
} else if (selectedVal.relationType === 'hm') {
|
||||
delete value[key];
|
||||
delete value[key]
|
||||
value = insertKey(selectedVal.table, {
|
||||
relationType: "hm",
|
||||
"": ""
|
||||
}, value, i);
|
||||
relationType: 'hm',
|
||||
'': ''
|
||||
}, value, i)
|
||||
} else if (selectedVal.relationType === 'bt') {
|
||||
delete value[key];
|
||||
delete value[key]
|
||||
value = insertKey(selectedVal.table, {
|
||||
relationType: "bt",
|
||||
"": ""
|
||||
}, value, i);
|
||||
relationType: 'bt',
|
||||
'': ''
|
||||
}, value, i)
|
||||
} else if (selectedVal.op) {
|
||||
const oldVal = value[key];
|
||||
delete value[key];
|
||||
const oldVal = value[key]
|
||||
delete value[key]
|
||||
if (selectedVal.logicalOp) {
|
||||
if (selectedVal.op === '_not') {
|
||||
value = insertKey(selectedVal.op, {
|
||||
"": ""
|
||||
}, value, i);
|
||||
'': ''
|
||||
}, value, i)
|
||||
} else {
|
||||
value = insertKey(selectedVal.op, [{
|
||||
"": ""
|
||||
}], value, i);
|
||||
'': ''
|
||||
}], value, i)
|
||||
}
|
||||
} else {
|
||||
value[selectedVal.op] = oldVal;
|
||||
value[selectedVal.op] = oldVal
|
||||
}
|
||||
}
|
||||
this.$emit('input', value);
|
||||
this.$emit('input', value)
|
||||
},
|
||||
addConditionProp() {
|
||||
const value = JSON.parse(JSON.stringify(this.value));
|
||||
value[""] = "";
|
||||
this.$emit('input', value);
|
||||
addConditionProp () {
|
||||
const value = JSON.parse(JSON.stringify(this.value))
|
||||
value[''] = ''
|
||||
this.$emit('input', value)
|
||||
},
|
||||
addConditionObj() {
|
||||
const value = JSON.parse(JSON.stringify(this.value));
|
||||
addConditionObj () {
|
||||
const value = JSON.parse(JSON.stringify(this.value))
|
||||
value.push({
|
||||
"": ""
|
||||
'': ''
|
||||
})
|
||||
this.$emit('input', value);
|
||||
this.$emit('input', value)
|
||||
},
|
||||
deleteCondition(key) {
|
||||
const value = JSON.parse(JSON.stringify(this.value));
|
||||
delete value[key];
|
||||
this.$emit('input', value);
|
||||
deleteCondition (key) {
|
||||
const value = JSON.parse(JSON.stringify(this.value))
|
||||
delete value[key]
|
||||
this.$emit('input', value)
|
||||
},
|
||||
async loadTableMetaDetails() {
|
||||
async loadTableMetaDetails () {
|
||||
if (this.table) {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
try {
|
||||
const meta = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcModelGet', {
|
||||
tn: this.table
|
||||
}]);
|
||||
}])
|
||||
const metaObj = JSON.parse(meta.meta)
|
||||
this.columns = metaObj.columns.map(v => v.cn);
|
||||
this.columns = metaObj.columns.map(v => v.cn)
|
||||
console.log(metaObj)
|
||||
this.hmList = metaObj.hasMany.map(v => v.tn)
|
||||
this.btList = metaObj.belongsTo.map(v => v.rtn)
|
||||
|
||||
} catch (e) {
|
||||
console.log('load meta', this.table, e);
|
||||
console.log('load meta', this.table, e)
|
||||
} finally {
|
||||
this.loading = false;
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
props: [
|
||||
'value',
|
||||
'table',
|
||||
'column',
|
||||
'nodes'
|
||||
],
|
||||
created() {
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadTableMetaDetails();
|
||||
},
|
||||
computed: {
|
||||
keys() {
|
||||
return Object.keys(this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
|
||||
.key, .value {
|
||||
min-width: 40px;
|
||||
border-bottom: 1px dotted #bbbbbb;
|
||||
@@ -246,12 +269,10 @@ div:hover > .delete-wrapper .delete {
|
||||
//opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
select, input {
|
||||
color: var(--v-primary-text);
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<!--
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,228 +1,244 @@
|
||||
<template>
|
||||
<div class="graphql-logic">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: (nodes.tn || nodes.view_name) + ' (APIs)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: (nodes.tn || nodes.view_name) + ' (APIs)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn small outlined @click="showSwagger = !showSwagger" class="caption text-capitalize" color="primary">
|
||||
<v-icon small color="primary"> {{showSwagger ?'mdi-eye-off-outline' : 'mdi-eye-outline'}}</v-icon>
|
||||
<v-spacer />
|
||||
<v-btn small outlined class="caption text-capitalize" color="primary" @click="showSwagger = !showSwagger">
|
||||
<v-icon small color="primary">
|
||||
{{ showSwagger ?'mdi-eye-off-outline' : 'mdi-eye-outline' }}
|
||||
</v-icon>
|
||||
|
||||
{{ showSwagger ? 'Hide Schema' : 'Show Schema' }}</v-btn>
|
||||
<x-btn outlined tooltip="Reload Rows"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['rows','reload']"
|
||||
@click="loadSchema(); loadResolvers();">
|
||||
<v-icon small left>refresh</v-icon>
|
||||
{{ showSwagger ? 'Hide Schema' : 'Show Schema' }}
|
||||
</v-btn>
|
||||
<x-btn
|
||||
v-ge="['rows','reload']"
|
||||
outlined
|
||||
tooltip="Reload Rows"
|
||||
color="primary"
|
||||
small
|
||||
@click="loadSchema(); loadResolvers();"
|
||||
>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-row class="mx-0" align="stretch">
|
||||
<v-col v-if="showSwagger">
|
||||
<v-card class="flex-shrink-1">
|
||||
<div class="text-center" style="padding: 3px">
|
||||
|
||||
<span class="title schema-card-title">Schema</span>
|
||||
</div>
|
||||
<div class="d-flex pa-3">
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
|
||||
<x-btn outlined :tooltip="`Compare GQL schema history of ${nodes.tn}`"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading || !schemaHistory.length"
|
||||
@click.prevent="schemaDiffDialog = true">
|
||||
<v-icon small left>mdi-source-branch</v-icon>
|
||||
History <span class="history-count" v-if="schemaHistory.length">({{ schemaHistory.length }})</span>
|
||||
<x-btn
|
||||
outlined
|
||||
:tooltip="`Compare GQL schema history of ${nodes.tn}`"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading || !schemaHistory.length"
|
||||
@click.prevent="schemaDiffDialog = true"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-source-branch
|
||||
</v-icon>
|
||||
History <span v-if="schemaHistory.length" class="history-count">({{ schemaHistory.length }})</span>
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading"
|
||||
v-ge="['rows','save']"
|
||||
@click.prevent="saveSchema">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['rows','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading"
|
||||
@click.prevent="saveSchema"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</div>
|
||||
<monaco-editor
|
||||
v-model="schema"
|
||||
theme=""
|
||||
style="min-height:500px;"
|
||||
|
||||
>
|
||||
|
||||
</monaco-editor>
|
||||
/>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-card class="flex-shrink-1" style="" v-if="filteredData.length">
|
||||
<v-card v-if="filteredData.length" class="flex-shrink-1" style="">
|
||||
<div class="text-center" style="padding: 3px">
|
||||
|
||||
<span class="title schema-card-title">Resolvers & Middlewares</span>
|
||||
</div>
|
||||
<v-simple-table v-if="resolvers" dense>
|
||||
<!-- style="width: auto; min-width: 500px">-->
|
||||
<thead>
|
||||
<!-- <tr>-->
|
||||
<!-- <tr>-->
|
||||
|
||||
<!-- <th colspan="3" class="text-center">-->
|
||||
<!-- <th colspan="3" class="text-center">-->
|
||||
|
||||
<!-- <div class="text-center">-->
|
||||
<!-- <div class="text-center">-->
|
||||
|
||||
<!-- <span class="title card-title">Resolvers</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <span class="title card-title">Resolvers</span>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- </th>-->
|
||||
|
||||
<!-- </tr>-->
|
||||
<tr>
|
||||
|
||||
<th colspan="3" class="text-center">
|
||||
|
||||
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search '${nodes.tn}' resolvers`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
|
||||
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
<!-- </th>-->
|
||||
|
||||
<!-- </tr>-->
|
||||
<tr>
|
||||
<th colspan="3" class="text-center">
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search '${nodes.tn}' resolvers`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="({resolver,title,functions},i) in filteredData">
|
||||
<tr v-if="resolver" :key="i"
|
||||
>
|
||||
|
||||
<td width="20" class="px-0">
|
||||
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{ resolver }}</span>
|
||||
</template>
|
||||
<span>{{ resolver }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td
|
||||
width="60" class="pa-1 text-center method-cell">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-icon @click="showSourceCode(resolver,functions)" small
|
||||
:color="hover ? 'primary':''" v-on="on">mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr v-else :key="i"
|
||||
>
|
||||
|
||||
<td width="20" class="px-0">
|
||||
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on" class="">{{ title }} - Middleware</span>
|
||||
</template>
|
||||
<span>{{ title }} - Middleware</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td
|
||||
width="60" class="pa-1 text-center method-cell">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-icon @click="showMiddlewareSourceCode(title,functions)" small
|
||||
:color="hover ? 'primary':''" v-on="on">mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</template>
|
||||
<template v-for="({resolver,title,functions},i) in filteredData">
|
||||
<tr
|
||||
v-if="resolver"
|
||||
:key="i"
|
||||
>
|
||||
<td width="20" class="px-0" />
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ resolver }}</span>
|
||||
</template>
|
||||
<span>{{ resolver }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td
|
||||
width="60"
|
||||
class="pa-1 text-center method-cell"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-hover v-slot="{ hover }">
|
||||
<v-icon
|
||||
small
|
||||
:color="hover ? 'primary':''"
|
||||
@click="showSourceCode(resolver,functions)"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-else
|
||||
:key="i"
|
||||
>
|
||||
<td width="20" class="px-0" />
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span class="" v-on="on">{{ title }} - Middleware</span>
|
||||
</template>
|
||||
<span>{{ title }} - Middleware</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td
|
||||
width="60"
|
||||
class="pa-1 text-center method-cell"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-hover v-slot="{ hover }">
|
||||
<v-icon
|
||||
small
|
||||
:color="hover ? 'primary':''"
|
||||
@click="showMiddlewareSourceCode(title,functions)"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
</v-row>
|
||||
|
||||
|
||||
<gql-handler-code-editor :nodes="nodes"
|
||||
:functions="selectedFunctions"
|
||||
:resolver="editResolver"
|
||||
:is-middleware="isMiddleware"
|
||||
v-model="showCodeEditor"></gql-handler-code-editor>
|
||||
|
||||
<gql-handler-code-editor
|
||||
v-model="showCodeEditor"
|
||||
:nodes="nodes"
|
||||
:functions="selectedFunctions"
|
||||
:resolver="editResolver"
|
||||
:is-middleware="isMiddleware"
|
||||
/>
|
||||
|
||||
<v-dialog v-model="schemaDiffDialog" scrollable min-width="600px">
|
||||
<v-card>
|
||||
<xc-diff
|
||||
v-model="schema"
|
||||
:history="schemaHistory"
|
||||
></xc-diff>
|
||||
/>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GqlHandlerCodeEditor from "@/components/project/gqlHandlerCodeEditor";
|
||||
import MonacoTsEditor from "@/components/monaco/MonacoTsEditor";
|
||||
import MonacoEditor from "@/components/monaco/MonacoEditor";
|
||||
import XcDiff from "@/components/xcDiff";
|
||||
import GqlHandlerCodeEditor from '@/components/project/gqlHandlerCodeEditor'
|
||||
import MonacoEditor from '@/components/monaco/MonacoEditor'
|
||||
import XcDiff from '@/components/xcDiff'
|
||||
|
||||
export default {
|
||||
name: "logic-gql",
|
||||
components: {XcDiff, MonacoEditor, MonacoTsEditor, GqlHandlerCodeEditor},
|
||||
name: 'LogicGql',
|
||||
components: { XcDiff, MonacoEditor, GqlHandlerCodeEditor },
|
||||
props: ['nodes'],
|
||||
data: () => ({
|
||||
showSwagger:false,
|
||||
showSwagger: false,
|
||||
selectedFunctions: null,
|
||||
schema: '',
|
||||
schemaHistory: [''],
|
||||
@@ -236,22 +252,31 @@ export default {
|
||||
schemaDiffDialog: false,
|
||||
isMiddleware: false
|
||||
}),
|
||||
computed: {
|
||||
filteredData () {
|
||||
return this.resolvers.filter(({ resolver }) => !resolver || (!this.search || resolver.toLowerCase().includes(this.search.toLowerCase())))
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.loadResolvers()
|
||||
await this.loadSchema()
|
||||
},
|
||||
methods: {
|
||||
showSourceCode(resolver, functions) {
|
||||
this.selectedFunctions = functions;
|
||||
this.editResolver = resolver;
|
||||
this.isMiddleware = false;
|
||||
this.showCodeEditor = true;
|
||||
showSourceCode (resolver, functions) {
|
||||
this.selectedFunctions = functions
|
||||
this.editResolver = resolver
|
||||
this.isMiddleware = false
|
||||
this.showCodeEditor = true
|
||||
},
|
||||
showMiddlewareSourceCode(table, functions) {
|
||||
this.selectedFunctions = functions;
|
||||
this.editResolver = table;
|
||||
this.isMiddleware = true;
|
||||
this.showCodeEditor = true;
|
||||
showMiddlewareSourceCode (table, functions) {
|
||||
this.selectedFunctions = functions
|
||||
this.editResolver = table
|
||||
this.isMiddleware = true
|
||||
this.showCodeEditor = true
|
||||
},
|
||||
|
||||
async saveSchema() {
|
||||
this.edited = false;
|
||||
async saveSchema () {
|
||||
this.edited = false
|
||||
try {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
@@ -259,43 +284,34 @@ export default {
|
||||
}, 'xcModelSchemaSet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name,
|
||||
schema: this.schema
|
||||
}]);
|
||||
this.$toast.success('Successfully updated validations').goAway(3000);
|
||||
}])
|
||||
this.$toast.success('Successfully updated validations').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Failed to update validations').goAway(3000);
|
||||
this.$toast.error('Failed to update validations').goAway(3000)
|
||||
}
|
||||
},
|
||||
async loadSchema() {
|
||||
async loadSchema () {
|
||||
const tableMeta = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcModelGet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name
|
||||
}]);
|
||||
this.schema = tableMeta.schema;
|
||||
}])
|
||||
this.schema = tableMeta.schema
|
||||
if (tableMeta.schema_previous) {
|
||||
this.schemaHistory = JSON.parse(tableMeta.schema_previous).reverse();
|
||||
this.schemaHistory = JSON.parse(tableMeta.schema_previous).reverse()
|
||||
} else {
|
||||
this.schemaHistory = [];
|
||||
this.schemaHistory = []
|
||||
}
|
||||
},
|
||||
async loadResolvers() {
|
||||
async loadResolvers () {
|
||||
this.resolvers = (await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'xcResolverPolicyGet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name
|
||||
}])).data.list;
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.loadResolvers();
|
||||
await this.loadSchema();
|
||||
},
|
||||
computed: {
|
||||
filteredData() {
|
||||
return this.resolvers.filter(({resolver}) => !resolver || (!this.search || resolver.toLowerCase().indexOf(this.search.toLowerCase()) > -1));
|
||||
}])).data.list
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,7 +319,6 @@ export default {
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
|
||||
@import "~vuetify/src/styles/styles";
|
||||
|
||||
$text-field-outlined-fieldset-padding: 0px;
|
||||
|
||||
@@ -1,181 +1,199 @@
|
||||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn || nodes.view_name + ' (APIs)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn || nodes.view_name + ' (APIs)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn small outlined @click="showSwagger = !showSwagger" class="caption text-capitalize" color="primary">
|
||||
<v-icon small color="primary"> {{showSwagger ?'mdi-eye-off-outline' : 'mdi-eye-outline'}}</v-icon>
|
||||
<v-spacer />
|
||||
<v-btn small outlined class="caption text-capitalize" color="primary" @click="showSwagger = !showSwagger">
|
||||
<v-icon small color="primary">
|
||||
{{ showSwagger ?'mdi-eye-off-outline' : 'mdi-eye-outline' }}
|
||||
</v-icon>
|
||||
|
||||
{{ showSwagger ? 'Hide Protobuf' : 'Show Protobuf' }}</v-btn>
|
||||
<x-btn outlined tooltip="Reload Rows"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['rows','reload']"
|
||||
@click="loadSchema(); loadRpcs();">
|
||||
<v-icon small left>refresh</v-icon>
|
||||
{{ showSwagger ? 'Hide Protobuf' : 'Show Protobuf' }}
|
||||
</v-btn>
|
||||
<x-btn
|
||||
v-ge="['rows','reload']"
|
||||
outlined
|
||||
tooltip="Reload Rows"
|
||||
color="primary"
|
||||
small
|
||||
@click="loadSchema(); loadRpcs();"
|
||||
>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-container fluid>
|
||||
<v-row>
|
||||
<v-col v-if="showSwagger">
|
||||
|
||||
<v-card class="flex-shrink-1">
|
||||
|
||||
<div class="text-center" style="padding: 3px">
|
||||
|
||||
<span class="title schema-card-title">Protobuf</span>
|
||||
</div>
|
||||
<div class="d-flex pa-3">
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined :tooltip="`Compare GQL schema history of ${nodes.tn}`"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading || !schemaHistory.length"
|
||||
@click.prevent="schemaDiffDialog = true">
|
||||
<v-icon small left>mdi-source-branch</v-icon>
|
||||
History <span class="history-count" v-if="schemaHistory.length">({{ schemaHistory.length }})</span>
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
outlined
|
||||
:tooltip="`Compare GQL schema history of ${nodes.tn}`"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading || !schemaHistory.length"
|
||||
@click.prevent="schemaDiffDialog = true"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-source-branch
|
||||
</v-icon>
|
||||
History <span v-if="schemaHistory.length" class="history-count">({{ schemaHistory.length }})</span>
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading"
|
||||
v-ge="['rows','save']"
|
||||
@click.prevent="saveMessageAndRpc">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['rows','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading"
|
||||
@click.prevent="saveMessageAndRpc"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</div>
|
||||
<p class="caption pa-1">Messages</p>
|
||||
<p class="caption pa-1">
|
||||
Messages
|
||||
</p>
|
||||
<monaco-editor
|
||||
v-model="messages"
|
||||
theme=""
|
||||
style="min-height:250px;"
|
||||
|
||||
/>
|
||||
<p class="caption pa-1 mt-2">rpcs</p>
|
||||
<p class="caption pa-1 mt-2">
|
||||
rpcs
|
||||
</p>
|
||||
<monaco-editor
|
||||
v-model="services"
|
||||
theme=""
|
||||
style="min-height:250px;"
|
||||
|
||||
/>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<!-- <div class="d-flex justify-center">-->
|
||||
<v-card class="flex-shrink-1" style="" v-if="rpcServices && filteredData.length">
|
||||
|
||||
|
||||
|
||||
<v-text-field dense hide-details class="ma-2 mt-2"
|
||||
:placeholder="`Search ${nodes.tn || nodes.view_name} rpc services`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
|
||||
<v-card v-if="rpcServices && filteredData.length" class="flex-shrink-1" style="">
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2 mt-2"
|
||||
:placeholder="`Search ${nodes.tn || nodes.view_name} rpc services`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<v-simple-table v-if="rpcServices" dense style="width: auto; min-width: 500px">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center">
|
||||
|
||||
<div class="text-center">
|
||||
|
||||
<span class="title">RPC Services</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
|
||||
<th
|
||||
width="60"
|
||||
class="text-center">
|
||||
|
||||
<span class="title"></span>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2" class="text-center">
|
||||
<div class="text-center">
|
||||
<span class="title">RPC Services</span>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th
|
||||
width="60"
|
||||
class="text-center"
|
||||
>
|
||||
<span class="title" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="{service,...rest} in filteredData"
|
||||
>
|
||||
|
||||
<td width="20" class="px-0">
|
||||
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{ service }}</span>
|
||||
</template>
|
||||
<span>{{ service }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td
|
||||
width="60" class="pa-1 text-center method-cell">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-icon @click="showSourceCode(service,rest)" small
|
||||
:color="hover ? 'primary':''" v-on="on">mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr
|
||||
v-for="{service,...rest} in filteredData"
|
||||
>
|
||||
<td width="20" class="px-0" />
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ service }}</span>
|
||||
</template>
|
||||
<span>{{ service }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td
|
||||
width="60"
|
||||
class="pa-1 text-center method-cell"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-hover v-slot="{ hover }">
|
||||
<v-icon
|
||||
small
|
||||
:color="hover ? 'primary':''"
|
||||
@click="showSourceCode(service,rest)"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<!-- </div>-->
|
||||
</v-row>
|
||||
</v-container>
|
||||
<grpc-handler-code-editor :nodes="nodes"
|
||||
:service="editService"
|
||||
:serviceData="editServiceData"
|
||||
v-model="showCodeEditor"></grpc-handler-code-editor>
|
||||
|
||||
<grpc-handler-code-editor
|
||||
v-model="showCodeEditor"
|
||||
:nodes="nodes"
|
||||
:service="editService"
|
||||
:service-data="editServiceData"
|
||||
/>
|
||||
|
||||
<v-dialog v-model="schemaDiffDialog" scrollable min-width="600px">
|
||||
<v-card>
|
||||
<xc-diff
|
||||
v-model="messages"
|
||||
:history="schemaHistory"
|
||||
></xc-diff>
|
||||
/>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
@@ -183,15 +201,15 @@
|
||||
|
||||
<script>
|
||||
|
||||
import GrpcHandlerCodeEditor from "@/components/project/grpcHandlerCodeEditor";
|
||||
import MonacoEditor from "~/components/monaco/MonacoEditor";
|
||||
import GrpcHandlerCodeEditor from '@/components/project/grpcHandlerCodeEditor'
|
||||
import MonacoEditor from '~/components/monaco/MonacoEditor'
|
||||
|
||||
export default {
|
||||
name: "logic-grpc",
|
||||
components: {GrpcHandlerCodeEditor, MonacoEditor},
|
||||
name: 'LogicGrpc',
|
||||
components: { GrpcHandlerCodeEditor, MonacoEditor },
|
||||
props: ['nodes'],
|
||||
data: () => ({
|
||||
showSwagger:false,
|
||||
showSwagger: false,
|
||||
editServiceData: null,
|
||||
loading: false,
|
||||
search: '',
|
||||
@@ -200,11 +218,11 @@ export default {
|
||||
'get', 'post', 'put', 'delete'
|
||||
],
|
||||
methodColor: {
|
||||
'get': 'success',
|
||||
'post': 'warning',
|
||||
'put': 'info',
|
||||
'patch': 'secondary',
|
||||
'delete': 'error'
|
||||
get: 'success',
|
||||
post: 'warning',
|
||||
put: 'info',
|
||||
patch: 'secondary',
|
||||
delete: 'error'
|
||||
},
|
||||
editService: '',
|
||||
showCodeEditor: false,
|
||||
@@ -213,38 +231,47 @@ export default {
|
||||
schemaHistory: [],
|
||||
schemaDiffDialog: false
|
||||
}),
|
||||
computed: {
|
||||
filteredData () {
|
||||
return this.rpcServices.filter(({ service }) => service && (!this.search || service.toLowerCase().includes(this.search.toLowerCase())))
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.loadRpcs()
|
||||
await this.loadSchema()
|
||||
},
|
||||
methods: {
|
||||
|
||||
showSourceCode(service, serviceData) {
|
||||
this.editService = service;
|
||||
this.showCodeEditor = true;
|
||||
this.editServiceData = serviceData;
|
||||
showSourceCode (service, serviceData) {
|
||||
this.editService = service
|
||||
this.showCodeEditor = true
|
||||
this.editServiceData = serviceData
|
||||
},
|
||||
async loadSchema() {
|
||||
async loadSchema () {
|
||||
const tableMeta = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcModelGet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name
|
||||
}]);
|
||||
this.messages = tableMeta.messages;
|
||||
this.services = tableMeta.services;
|
||||
}])
|
||||
this.messages = tableMeta.messages
|
||||
this.services = tableMeta.services
|
||||
if (tableMeta.schema_previous) {
|
||||
this.schemaHistory = JSON.parse(tableMeta.schema_previous).reverse();
|
||||
this.schemaHistory = JSON.parse(tableMeta.schema_previous).reverse()
|
||||
} else {
|
||||
this.schemaHistory = [];
|
||||
this.schemaHistory = []
|
||||
}
|
||||
},
|
||||
async loadRpcs() {
|
||||
async loadRpcs () {
|
||||
this.rpcServices = (await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'xcRpcPolicyGet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name
|
||||
}])).data.list;
|
||||
}])).data.list
|
||||
},
|
||||
async saveMessageAndRpc() {
|
||||
this.edited = false;
|
||||
async saveMessageAndRpc () {
|
||||
this.edited = false
|
||||
try {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
@@ -252,21 +279,12 @@ export default {
|
||||
}, 'xcModelMessagesAndServicesSet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name,
|
||||
messages: this.messages,
|
||||
services: this.services,
|
||||
}]);
|
||||
this.$toast.success('Successfully updated protobuf messages and rpcs').goAway(3000);
|
||||
services: this.services
|
||||
}])
|
||||
this.$toast.success('Successfully updated protobuf messages and rpcs').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Failed to update validations').goAway(3000);
|
||||
this.$toast.error('Failed to update validations').goAway(3000)
|
||||
}
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.loadRpcs();
|
||||
await this.loadSchema();
|
||||
},
|
||||
computed: {
|
||||
filteredData() {
|
||||
return this.rpcServices.filter(({service}) => service && (!this.search || service.toLowerCase().indexOf(this.search.toLowerCase()) > -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,205 +1,221 @@
|
||||
<!-- eslint-disable -->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: name + ' (APIs)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: name + ' (APIs)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
|
||||
<v-btn small outlined @click="showSwagger = !showSwagger" class="caption text-capitalize" color="primary">
|
||||
<v-icon small color="primary"> {{ showSwagger ? 'mdi-eye-off-outline' : 'mdi-eye-outline' }}</v-icon>
|
||||
<v-btn small outlined class="caption text-capitalize" color="primary" @click="showSwagger = !showSwagger">
|
||||
<v-icon small color="primary">
|
||||
{{ showSwagger ? 'mdi-eye-off-outline' : 'mdi-eye-outline' }}
|
||||
</v-icon>
|
||||
|
||||
{{ showSwagger ? 'Hide Swagger' : 'Show Swagger' }}
|
||||
</v-btn>
|
||||
|
||||
<x-btn outlined tooltip="Reload Rows"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['rows','reload']" btn.class="caption text-capitalize"
|
||||
@click="loadSwaggerDoc(); loadRoutes();">
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<x-btn
|
||||
v-ge="['rows','reload']"
|
||||
outlined
|
||||
tooltip="Reload Rows"
|
||||
color="primary"
|
||||
small
|
||||
btn.class="caption text-capitalize"
|
||||
@click="loadSwaggerDoc(); loadRoutes();"
|
||||
>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
|
||||
<v-text-field dense hide-details class="ma-2" :placeholder="`Search ${name} routes`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
outlined></v-text-field>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
dense
|
||||
hide-details
|
||||
class="ma-2"
|
||||
:placeholder="`Search ${name} routes`"
|
||||
prepend-inner-icon="search"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<!-- <div class="d-flex justify-center">-->
|
||||
<v-container fluid>
|
||||
<v-row>
|
||||
|
||||
<v-col v-if="showSwagger">
|
||||
|
||||
<v-card>
|
||||
|
||||
<div class="text-center" style="padding: 3px">
|
||||
|
||||
<span class="title schema-card-title">Swagger JSON</span>
|
||||
</div>
|
||||
<div class="d-flex pa-3">
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined :tooltip="`Compare GQL schema history of ${nodes.tn}`"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading || !swaggerDocHistory.length"
|
||||
@click.prevent="schemaDiffDialog = true">
|
||||
<v-icon small left>mdi-source-branch</v-icon>
|
||||
History <span class="history-count" v-if="swaggerDocHistory.length">({{
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
outlined
|
||||
:tooltip="`Compare GQL schema history of ${nodes.tn}`"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading || !swaggerDocHistory.length"
|
||||
@click.prevent="schemaDiffDialog = true"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-source-branch
|
||||
</v-icon>
|
||||
History <span v-if="swaggerDocHistory.length" class="history-count">({{
|
||||
swaggerDocHistory.length
|
||||
}})</span>
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading"
|
||||
v-ge="['rows','save']"
|
||||
@click.prevent="saveSwaggerDoc">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-ge="['rows','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
x-small
|
||||
:disabled="loading"
|
||||
@click.prevent="saveSwaggerDoc"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</div>
|
||||
<monaco-json-editor
|
||||
v-model="swaggerDoc"
|
||||
theme=""
|
||||
style="min-height:500px;"
|
||||
|
||||
/>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col>
|
||||
|
||||
<v-card class="flex-shrink-1" style="" v-if="filteredGroupedData.length">
|
||||
|
||||
<v-skeleton-loader v-if="loading" type="table"></v-skeleton-loader>
|
||||
|
||||
<v-card v-if="filteredGroupedData.length" class="flex-shrink-1" style="">
|
||||
<v-skeleton-loader v-if="loading" type="table" />
|
||||
|
||||
<v-simple-table v-else-if="routers" dense style="width: auto; min-width: 500px">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th colspan="2" class="text-center">
|
||||
|
||||
<div class="d-flex justify-center">
|
||||
|
||||
<span class="title">Routes</span>
|
||||
</div>
|
||||
|
||||
</th>
|
||||
|
||||
<template v-for="(method,i) in methods">
|
||||
<th
|
||||
width="60"
|
||||
class=" method-cell caption px-1 text-center text-uppercase font-weight-bold" :key="`${method}`"
|
||||
:class="`${methodColor[method]}--text`">{{ method }}
|
||||
<tr>
|
||||
<th colspan="2" class="text-center">
|
||||
<div class="d-flex justify-center">
|
||||
<span class="title">Routes</span>
|
||||
</div>
|
||||
</th>
|
||||
</template>
|
||||
</tr>
|
||||
|
||||
<template v-for="(method,i) in methods">
|
||||
<th
|
||||
:key="`${method}`"
|
||||
width="60"
|
||||
class=" method-cell caption px-1 text-center text-uppercase font-weight-bold"
|
||||
:class="`${methodColor[method]}--text`"
|
||||
>
|
||||
{{ method }}
|
||||
</th>
|
||||
</template>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="[path,route] in filteredGroupedData"
|
||||
>
|
||||
|
||||
<td width="20" class="px-0">
|
||||
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(method,i) in methods">
|
||||
<td
|
||||
|
||||
width="60" class="pa-1 text-center method-cell" :key="`${path}_${method}}`">
|
||||
|
||||
<tr
|
||||
v-for="[path,route] in filteredGroupedData"
|
||||
>
|
||||
<td width="20" class="px-0" />
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ path }}</span>
|
||||
</template>
|
||||
<span>{{ path }}</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<template v-for="(method,i) in methods">
|
||||
<td
|
||||
|
||||
<v-hover v-if="route[method]" v-slot:default="{ hover }">
|
||||
<v-icon @click="showSourceCode(route,method)" small
|
||||
:color="hover ? methodColor[method]:''" v-on="on">mdi-pencil
|
||||
:key="`${path}_${method}}`"
|
||||
width="60"
|
||||
class="pa-1 text-center method-cell"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-hover v-if="route[method]" v-slot="{ hover }">
|
||||
<v-icon
|
||||
small
|
||||
:color="hover ? methodColor[method]:''"
|
||||
@click="showSourceCode(route,method)"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
|
||||
<tr
|
||||
v-for="mw in middlewares"
|
||||
>
|
||||
<td width="20" class="px-0" />
|
||||
<td class="pl-0">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<span v-on="on">{{ mw.title }} - Middleware</span>
|
||||
</template>
|
||||
<span>{{ mw.title }} - Middleware</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td
|
||||
:colspan="methods.length"
|
||||
width="60"
|
||||
class="pa-1 text-center method-cell"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-hover v-slot="{ hover }">
|
||||
<v-icon
|
||||
small
|
||||
:color="hover ? methodColor[method]:''"
|
||||
@click="showMiddlewareSourceCode(mw)"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit business logic
|
||||
Edit middleware business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
<tr v-for="mw in middlewares"
|
||||
>
|
||||
|
||||
<td width="20" class="px-0">
|
||||
|
||||
</td>
|
||||
<td class="pl-0">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<span v-on="on">{{ mw.title }} - Middleware</span>
|
||||
</template>
|
||||
<span>{{ mw.title }} - Middleware</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td
|
||||
:colspan="methods.length"
|
||||
width="60" class="pa-1 text-center method-cell">
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-icon small
|
||||
@click="showMiddlewareSourceCode(mw)"
|
||||
:color="hover ? methodColor[method]:''" v-on="on">mdi-pencil
|
||||
</v-icon>
|
||||
</v-hover>
|
||||
</template>
|
||||
Edit middleware business logic
|
||||
</v-tooltip>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-alert v-else outlined type="info">Permission file not found</v-alert>
|
||||
<v-alert v-else outlined type="info">
|
||||
Permission file not found
|
||||
</v-alert>
|
||||
</v-card>
|
||||
<!-- </div>-->
|
||||
</v-col>
|
||||
@@ -207,32 +223,31 @@
|
||||
</v-row>
|
||||
</v-container>
|
||||
<handler-code-editor
|
||||
v-model="showCodeEditor"
|
||||
:is-middleware="isMiddleware"
|
||||
:nodes="nodes"
|
||||
:route="editRoute"
|
||||
:method="editMethod"
|
||||
v-model="showCodeEditor"></handler-code-editor>
|
||||
|
||||
/>
|
||||
|
||||
<v-dialog v-model="schemaDiffDialog" scrollable min-width="600px">
|
||||
<v-card>
|
||||
<xc-diff
|
||||
v-model="swaggerDoc"
|
||||
:history="swaggerDocHistory"
|
||||
></xc-diff>
|
||||
/>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HandlerCodeEditor from "@/components/project/restHandlerCodeEditor";
|
||||
import MonacoJsonEditor from "@/components/monaco/MonacoJsonEditor";
|
||||
import HandlerCodeEditor from '@/components/project/restHandlerCodeEditor'
|
||||
import MonacoJsonEditor from '@/components/monaco/MonacoJsonEditor'
|
||||
|
||||
export default {
|
||||
name: "logic-rest",
|
||||
components: {MonacoJsonEditor, HandlerCodeEditor},
|
||||
name: 'LogicRest',
|
||||
components: { MonacoJsonEditor, HandlerCodeEditor },
|
||||
props: ['nodes'],
|
||||
data: () => ({
|
||||
showSwagger: false,
|
||||
@@ -245,11 +260,11 @@ export default {
|
||||
'get', 'post', 'put', 'delete'
|
||||
],
|
||||
methodColor: {
|
||||
'get': 'success',
|
||||
'post': 'warning',
|
||||
'put': 'info',
|
||||
'patch': 'secondary',
|
||||
'delete': 'error'
|
||||
get: 'success',
|
||||
post: 'warning',
|
||||
put: 'info',
|
||||
patch: 'secondary',
|
||||
delete: 'error'
|
||||
},
|
||||
editRoute: '',
|
||||
editMethod: '',
|
||||
@@ -259,48 +274,62 @@ export default {
|
||||
swaggerDoc: '',
|
||||
schemaDiffDialog: false
|
||||
}),
|
||||
computed: {
|
||||
filteredGroupedData () {
|
||||
return Object.entries(this.groupedData)
|
||||
.filter(([path]) => !this.search || path.toLowerCase().includes(this.search.toLowerCase()))
|
||||
},
|
||||
name () {
|
||||
return this.nodes.tn || this.nodes.view_name
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.loadRoutes()
|
||||
this.groupRoutes()
|
||||
await this.loadSwaggerDoc()
|
||||
},
|
||||
methods: {
|
||||
groupRoutes() {
|
||||
const groupedData = {};
|
||||
this.middlewares = [];
|
||||
groupRoutes () {
|
||||
const groupedData = {}
|
||||
this.middlewares = []
|
||||
for (const route of this.routers) {
|
||||
if (route.path) {
|
||||
groupedData[route.path] = groupedData[route.path] || {};
|
||||
groupedData[route.path][route.type] = route;
|
||||
groupedData[route.path] = groupedData[route.path] || {}
|
||||
groupedData[route.path][route.type] = route
|
||||
} else if (route.handler_type === 2) {
|
||||
this.middlewares.push(route)
|
||||
}
|
||||
}
|
||||
this.groupedData = groupedData;
|
||||
this.groupedData = groupedData
|
||||
},
|
||||
showSourceCode(route, method) {
|
||||
this.editRoute = route;
|
||||
this.editMethod = method;
|
||||
this.isMiddleware = false;
|
||||
this.showCodeEditor = true;
|
||||
showSourceCode (route, method) {
|
||||
this.editRoute = route
|
||||
this.editMethod = method
|
||||
this.isMiddleware = false
|
||||
this.showCodeEditor = true
|
||||
},
|
||||
showMiddlewareSourceCode(mw) {
|
||||
this.editRoute = mw;
|
||||
this.editMethod = null;
|
||||
this.isMiddleware = true;
|
||||
this.showCodeEditor = true;
|
||||
showMiddlewareSourceCode (mw) {
|
||||
this.editRoute = mw
|
||||
this.editMethod = null
|
||||
this.isMiddleware = true
|
||||
this.showCodeEditor = true
|
||||
},
|
||||
async loadSwaggerDoc() {
|
||||
async loadSwaggerDoc () {
|
||||
const tableMeta = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcModelGet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name
|
||||
}]);
|
||||
this.swaggerDoc = JSON.stringify(JSON.parse(tableMeta.schema), 0, 2);
|
||||
}])
|
||||
this.swaggerDoc = JSON.stringify(JSON.parse(tableMeta.schema), 0, 2)
|
||||
if (tableMeta.schema_previous) {
|
||||
this.swaggerDocHistory = JSON.parse(tableMeta.schema_previous).reverse().map(o => JSON.stringify(o, null, 2));
|
||||
this.swaggerDocHistory = JSON.parse(tableMeta.schema_previous).reverse().map(o => JSON.stringify(o, null, 2))
|
||||
} else {
|
||||
this.swaggerDocHistory = [];
|
||||
this.swaggerDocHistory = []
|
||||
}
|
||||
},
|
||||
async saveSwaggerDoc() {
|
||||
this.edited = false;
|
||||
async saveSwaggerDoc () {
|
||||
this.edited = false
|
||||
try {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
@@ -308,35 +337,21 @@ export default {
|
||||
}, 'xcModelSwaggerDocSet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name,
|
||||
swaggerDoc: JSON.parse(this.swaggerDoc)
|
||||
}]);
|
||||
this.$toast.success('Successfully updated swagger doc').goAway(3000);
|
||||
}])
|
||||
this.$toast.success('Successfully updated swagger doc').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Failed to update swagger doc').goAway(3000);
|
||||
this.$toast.error('Failed to update swagger doc').goAway(3000)
|
||||
}
|
||||
},
|
||||
async loadRoutes() {
|
||||
this.loading = true;
|
||||
async loadRoutes () {
|
||||
this.loading = true
|
||||
this.routers = (await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'xcRoutesPolicyGet', {
|
||||
tn: this.name
|
||||
}])).data.list;
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.loadRoutes();
|
||||
this.groupRoutes();
|
||||
await this.loadSwaggerDoc();
|
||||
},
|
||||
computed: {
|
||||
filteredGroupedData() {
|
||||
return Object.entries(this.groupedData)
|
||||
.filter(([path]) => !this.search || path.toLowerCase().indexOf(this.search.toLowerCase()) > -1);
|
||||
},
|
||||
name() {
|
||||
return this.nodes.tn || this.nodes.view_name;
|
||||
}])).data.list
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,260 +1,266 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<v-card style="">
|
||||
|
||||
<v-toolbar height="42" flat class="toolbar-border-bottom">
|
||||
<v-toolbar height="42" flat class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes.tn + ' (mocks)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small>forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (mocks)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small>
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload Rows"
|
||||
small
|
||||
color="primary"
|
||||
class="primary"
|
||||
@click="loadColumnList"
|
||||
v-ge="['mocks','load']"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['mocks','load']"
|
||||
outlined
|
||||
tooltip="Reload Rows"
|
||||
small
|
||||
color="primary"
|
||||
class="primary"
|
||||
@click="loadColumnList"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
|
||||
<x-btn outlined tooltip="Load suggested faker function based on field name"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
v-ge="['mocks','load-faker-fns']"
|
||||
@click="mapFieldWithSuggestedFakerFn">
|
||||
<v-icon left small>mdi-function</v-icon>
|
||||
<x-btn
|
||||
v-ge="['mocks','load-faker-fns']"
|
||||
outlined
|
||||
tooltip="Load suggested faker function based on field name"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="mapFieldWithSuggestedFakerFn"
|
||||
>
|
||||
<v-icon left small>
|
||||
mdi-function
|
||||
</v-icon>
|
||||
Predict Faker Functions
|
||||
</x-btn>
|
||||
|
||||
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="success"
|
||||
class="success"
|
||||
v-ge="['mocks','save']"
|
||||
small @click="saveFakeFunctions"
|
||||
:disabled="disableSaveButton"
|
||||
<x-btn
|
||||
v-ge="['mocks','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="success"
|
||||
class="success"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click="saveFakeFunctions"
|
||||
>
|
||||
<v-icon small left
|
||||
|
||||
>save
|
||||
<v-icon
|
||||
small
|
||||
left
|
||||
>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-data-table
|
||||
dense
|
||||
:headers="colsHeader"
|
||||
:items="cols"
|
||||
class="column-table">
|
||||
<template v-slot:item="{item,index}">
|
||||
class="column-table"
|
||||
>
|
||||
<template #item="{item}">
|
||||
<tr>
|
||||
<td>
|
||||
{{item.cn}}<span class="font-weight-thin"> - {{item.dt}}</span>
|
||||
{{ item.cn }}<span class="font-weight-thin"> - {{ item.dt }}</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<span class="font-weight-thin" v-if="item.pk"> (Primary Key)</span>
|
||||
<span class="font-weight-thin" v-else-if="item.rcn"> (Foreign Key)</span>
|
||||
<span v-if="item.pk" class="font-weight-thin"> (Primary Key)</span>
|
||||
<span v-else-if="item.rcn" class="font-weight-thin"> (Foreign Key)</span>
|
||||
<v-autocomplete
|
||||
v-else
|
||||
v-model="item.fakerFunction"
|
||||
v-ge="['mocks','change-faker-fn']"
|
||||
:items="fakerFunctionList | filterFakerList(item.dt)"
|
||||
item-text="name"
|
||||
item-value="value"
|
||||
v-model="item.fakerFunction"
|
||||
@change="disableSaveButton = false"
|
||||
v-ge="['mocks','change-faker-fn']"
|
||||
>
|
||||
|
||||
<template v-slot:selection="{ item }">
|
||||
<div class="body-2"> {{item.name}}<span class="font-weight-thin " v-if="item.type"> - {{item.type}}</span></div>
|
||||
<template #selection="{ item }">
|
||||
<div class="body-2">
|
||||
{{ item.name }}<span v-if="item.type" class="font-weight-thin "> - {{ item.type }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<template v-slot:item="data">
|
||||
<template #item="data">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-html="data.item.name"></v-list-item-title>
|
||||
<v-list-item-subtitle v-html="data.item.group"></v-list-item-subtitle>
|
||||
<v-list-item-title v-html="data.item.name" />
|
||||
<v-list-item-subtitle v-html="data.item.group" />
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
|
||||
|
||||
</v-autocomplete>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import fakerFunctionList from '../../../helpers/fakerFunctionList'
|
||||
import dataTypeMapping from '../../../helpers/findDataTypeMapping'
|
||||
const levenshtein = require('fast-levenshtein');
|
||||
import { mapGetters } from 'vuex'
|
||||
import fakerFunctionList from '../../../helpers/fakerFunctionList'
|
||||
import dataTypeMapping from '../../../helpers/findDataTypeMapping'
|
||||
const levenshtein = require('fast-levenshtein')
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
colsHeader: [{text: 'Column Name'}, {text: 'Mapper Function'}],
|
||||
cols: [],
|
||||
primaryKeys: [],
|
||||
fakerFunctionList,
|
||||
disableSaveButton: true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async handleKeyDown({metaKey, key, altKey, shiftKey, ctrlKey}) {
|
||||
console.log(metaKey, key, altKey, shiftKey, ctrlKey)
|
||||
// cmd + s -> save
|
||||
// cmd + l -> reload
|
||||
// cmd + n -> new
|
||||
// cmd + d -> delete
|
||||
// cmd + enter -> send api
|
||||
export default {
|
||||
components: {},
|
||||
data () {
|
||||
return {
|
||||
colsHeader: [{ text: 'Column Name' }, { text: 'Mapper Function' }],
|
||||
cols: [],
|
||||
primaryKeys: [],
|
||||
fakerFunctionList,
|
||||
disableSaveButton: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleKeyDown ({ metaKey, key, altKey, shiftKey, ctrlKey }) {
|
||||
console.log(metaKey, key, altKey, shiftKey, ctrlKey)
|
||||
// cmd + s -> save
|
||||
// cmd + l -> reload
|
||||
// cmd + n -> new
|
||||
// cmd + d -> delete
|
||||
// cmd + enter -> send api
|
||||
|
||||
switch ([metaKey, key].join('_')) {
|
||||
case 'true_s' :
|
||||
await this.saveFakeFunctions();
|
||||
break;
|
||||
case 'true_l' :
|
||||
await this.loadColumnList();
|
||||
break;
|
||||
switch ([metaKey, key].join('_')) {
|
||||
case 'true_s' :
|
||||
await this.saveFakeFunctions()
|
||||
break
|
||||
case 'true_l' :
|
||||
await this.loadColumnList()
|
||||
break
|
||||
// case 'true_n' :
|
||||
// this.addColumn();
|
||||
// break;
|
||||
// case 'true_d' :
|
||||
// await this.deleteTable('showDialog');
|
||||
// break;
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
async loadColumnList () {
|
||||
this.disableSaveButton = true
|
||||
const columnsList = await this.client.fakerColumnsList({
|
||||
tn: this.nodes.tn,
|
||||
seedsFolder: this.seedsFolder
|
||||
})
|
||||
console.log(columnsList)
|
||||
this.cols = columnsList.data.list
|
||||
|
||||
async loadColumnList() {
|
||||
this.disableSaveButton = true;
|
||||
const columnsList = await this.client.fakerColumnsList({
|
||||
tn: this.nodes.tn,
|
||||
seedsFolder: this.seedsFolder
|
||||
});
|
||||
console.log(columnsList)
|
||||
this.cols = columnsList.data.list;
|
||||
// columnsList.data.list.map(({cn, dt, ai, pk}) => {
|
||||
// if (pk) this.primaryKeys.push(cn);
|
||||
// return {
|
||||
// text: cn, value: cn, type: dt, ai
|
||||
// }
|
||||
// })
|
||||
},
|
||||
mapFieldWithSuggestedFakerFn () {
|
||||
this.cols = this.cols.map((col) => {
|
||||
let suggestion = null
|
||||
let lScore = Infinity
|
||||
const nativeType = dataTypeMapping(col.dt)
|
||||
fakerFunctionList.forEach((fakerFn, i) => {
|
||||
if (nativeType !== 'string' && nativeType !== fakerFn.type) { return }
|
||||
|
||||
|
||||
// columnsList.data.list.map(({cn, dt, ai, pk}) => {
|
||||
// if (pk) this.primaryKeys.push(cn);
|
||||
// return {
|
||||
// text: cn, value: cn, type: dt, ai
|
||||
// }
|
||||
// })
|
||||
|
||||
},
|
||||
mapFieldWithSuggestedFakerFn() {
|
||||
this.cols = this.cols.map(col => {
|
||||
let suggestion = null;
|
||||
let l_score = Infinity;
|
||||
let nativeType = dataTypeMapping(col.dt);
|
||||
fakerFunctionList.forEach((fakerFn, i) => {
|
||||
if(nativeType !== 'string' && nativeType !== fakerFn.type) return;
|
||||
|
||||
if (i) {
|
||||
const ls = levenshtein.get(col.cn.toLowerCase(), fakerFn.name.toLowerCase())
|
||||
if (l_score > ls) {
|
||||
l_score = ls;
|
||||
suggestion = fakerFn;
|
||||
}
|
||||
} else {
|
||||
suggestion = fakerFn;
|
||||
l_score = levenshtein.get(col.cn.toLowerCase(), fakerFn.name.toLowerCase());
|
||||
if (i) {
|
||||
const ls = levenshtein.get(col.cn.toLowerCase(), fakerFn.name.toLowerCase())
|
||||
if (lScore > ls) {
|
||||
lScore = ls
|
||||
suggestion = fakerFn
|
||||
}
|
||||
})
|
||||
|
||||
if (l_score < 3) {
|
||||
this.disableSaveButton = false;
|
||||
return {...col, fakerFunction: suggestion.value};
|
||||
} else {
|
||||
suggestion = fakerFn
|
||||
lScore = levenshtein.get(col.cn.toLowerCase(), fakerFn.name.toLowerCase())
|
||||
}
|
||||
return col;
|
||||
})
|
||||
},
|
||||
async saveFakeFunctions() {
|
||||
try {
|
||||
let result = await this.client.fakerColumnsCreate({fakerColumns: this.cols, seedsFolder: this.seedsFolder,tn:this.nodes.tn});
|
||||
} catch (e) {
|
||||
this.$toast.error('Saving changes to faker functions failed').goAway(3000);
|
||||
throw e;
|
||||
|
||||
if (lScore < 3) {
|
||||
this.disableSaveButton = false
|
||||
return { ...col, fakerFunction: suggestion.value }
|
||||
}
|
||||
|
||||
}
|
||||
return col
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"})
|
||||
},
|
||||
beforeCreated() {
|
||||
},
|
||||
async created() {
|
||||
async saveFakeFunctions () {
|
||||
try {
|
||||
this.seedsFolder = this.sqlMgr.projectGetFolder({
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
});
|
||||
this.client = await this.sqlMgr.projectGetSqlClient({
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
});
|
||||
await this.loadColumnList();
|
||||
await this.client.fakerColumnsCreate({ fakerColumns: this.cols, seedsFolder: this.seedsFolder, tn: this.nodes.tn })
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error('Loading columns and faker functions failed').goAway(3000);
|
||||
throw e;
|
||||
}
|
||||
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
},
|
||||
destroy() {
|
||||
},
|
||||
validate({params}) {
|
||||
return true;
|
||||
},
|
||||
head() {
|
||||
return {};
|
||||
},
|
||||
props: ["nodes", "newTable", "mtdNewTableUpdate", "deleteTable"],
|
||||
watch: {},
|
||||
directives: {},
|
||||
filters:{
|
||||
filterFakerList(list,type){
|
||||
const nativeType = dataTypeMapping(type);
|
||||
return list.filter(item=> (nativeType === 'string') || (nativeType === item.type));
|
||||
this.$toast.error('Saving changes to faker functions failed').goAway(3000)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' })
|
||||
},
|
||||
beforeCreated () {
|
||||
},
|
||||
watch: {},
|
||||
async created () {
|
||||
try {
|
||||
this.seedsFolder = this.sqlMgr.projectGetFolder({
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
})
|
||||
this.client = await this.sqlMgr.projectGetSqlClient({
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
})
|
||||
await this.loadColumnList()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.$toast.error('Loading columns and faker functions failed').goAway(3000)
|
||||
throw e
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
beforeDestroy () {
|
||||
},
|
||||
destroy () {
|
||||
},
|
||||
directives: {},
|
||||
filters: {
|
||||
filterFakerList (list, type) {
|
||||
const nativeType = dataTypeMapping(type)
|
||||
return list.filter(item => (nativeType === 'string') || (nativeType === item.type))
|
||||
}
|
||||
},
|
||||
validate ({ params }) {
|
||||
return true
|
||||
},
|
||||
head () {
|
||||
return {}
|
||||
},
|
||||
props: ['nodes', 'newTable', 'mtdNewTableUpdate', 'deleteTable']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<h1>Relation List</h1>
|
||||
<v-btn @click="loadRelationList" color="primary"
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="loadRelationList"
|
||||
>
|
||||
<v-icon left>refresh</v-icon>
|
||||
<v-icon left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</v-btn
|
||||
</v-btn>
|
||||
<v-btn
|
||||
small
|
||||
class=" text-right"
|
||||
@click="deleteTable('showDialog')"
|
||||
>
|
||||
<v-btn small @click="deleteTable('showDialog')" class=" text-right"
|
||||
>Delete Table
|
||||
</v-btn
|
||||
>
|
||||
<v-btn @click="throwError()">error</v-btn>
|
||||
Delete Table
|
||||
</v-btn>
|
||||
<v-btn @click="throwError()">
|
||||
error
|
||||
</v-btn>
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
<v-data-table
|
||||
@@ -19,7 +27,7 @@
|
||||
:items="relations"
|
||||
footer-props.items-per-page-options="30"
|
||||
>
|
||||
<template v-slot:item="props">
|
||||
<template #item="props">
|
||||
<td>{{ props.item.cstn }}</td>
|
||||
<td>{{ props.item.rtn }}</td>
|
||||
</template>
|
||||
@@ -31,129 +39,124 @@
|
||||
:items="columns"
|
||||
footer-props.items-per-page-options="30"
|
||||
>
|
||||
<template v-slot:items="props">
|
||||
<template #items="props">
|
||||
<td>{{ props.item.cn }}</td>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container
|
||||
>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters, mapActions} from "vuex";
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
relations: [],
|
||||
columns: [],
|
||||
relationHeaders: [
|
||||
{
|
||||
text: "Relation",
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
text: "Referenced Table",
|
||||
sortable: false
|
||||
}
|
||||
],
|
||||
columnHeaders: [
|
||||
{
|
||||
text: "Column",
|
||||
sortable: false
|
||||
}
|
||||
],
|
||||
max25chars: v => v.length <= 25 || "Input too long!"
|
||||
};
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
relations: [],
|
||||
columns: [],
|
||||
relationHeaders: [
|
||||
{
|
||||
text: 'Relation',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
text: 'Referenced Table',
|
||||
sortable: false
|
||||
}
|
||||
],
|
||||
columnHeaders: [
|
||||
{
|
||||
text: 'Column',
|
||||
sortable: false
|
||||
}
|
||||
],
|
||||
max25chars: v => v.length <= 25 || 'Input too long!'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
throwError () {
|
||||
throw new Error('new erroror ')
|
||||
},
|
||||
methods: {
|
||||
throwError() {
|
||||
throw new Error("new erroror ");
|
||||
},
|
||||
async loadRelationList() {
|
||||
if (this.newTable) return;
|
||||
async loadRelationList () {
|
||||
if (this.newTable) { return }
|
||||
|
||||
// console.log("env: this.nodes.env", this.nodes.env, this.nodes.dbAlias);
|
||||
// const client = await this.sqlMgr.projectGetSqlClient({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// });
|
||||
// const result = await client.relationList({
|
||||
// tn: this.nodes.tn
|
||||
// });
|
||||
//
|
||||
// console.log("env: this.nodes.env", this.nodes.env, this.nodes.dbAlias);
|
||||
// const client = await this.sqlMgr.projectGetSqlClient({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// });
|
||||
// const result = await client.relationList({
|
||||
// tn: this.nodes.tn
|
||||
// });
|
||||
//
|
||||
|
||||
// const result = await this.sqlMgr.sqlOp({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// }, 'relationList', { tn: this.nodes.tn})
|
||||
// const result = await this.sqlMgr.sqlOp({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// }, 'relationList', { tn: this.nodes.tn})
|
||||
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'relationList', { tn: this.nodes.tn }])
|
||||
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'relationList', {tn: this.nodes.tn}])
|
||||
|
||||
|
||||
// console.log(result, "relations");
|
||||
this.relations = result.data.list;
|
||||
// this.loadColumnList(result.data.list[0].rtn);
|
||||
},
|
||||
async loadColumnList(tn = "") {
|
||||
// console.log("env: this.nodes.env", this.nodes.env, this.nodes.dbAlias);
|
||||
// const client = await this.sqlMgr.projectGetSqlClient({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// });
|
||||
// const result = await client.columnList({
|
||||
// tn
|
||||
// });
|
||||
|
||||
|
||||
// const result = await this.sqlMgr.sqlOp({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// }, 'columnList', {
|
||||
// tn
|
||||
// });
|
||||
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'columnList', {
|
||||
tn
|
||||
}]);
|
||||
|
||||
|
||||
this.columns = result.data.list;
|
||||
}
|
||||
// console.log(result, "relations");
|
||||
this.relations = result.data.list
|
||||
// this.loadColumnList(result.data.list[0].rtn);
|
||||
},
|
||||
computed: {...mapGetters({sqlMgr: "sqlMgr/sqlMgr"})},
|
||||
async loadColumnList (tn = '') {
|
||||
// console.log("env: this.nodes.env", this.nodes.env, this.nodes.dbAlias);
|
||||
// const client = await this.sqlMgr.projectGetSqlClient({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// });
|
||||
// const result = await client.columnList({
|
||||
// tn
|
||||
// });
|
||||
|
||||
beforeCreated() {
|
||||
},
|
||||
created() {
|
||||
this.loadRelationList();
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
},
|
||||
destroy() {
|
||||
},
|
||||
validate({params}) {
|
||||
return true;
|
||||
},
|
||||
head() {
|
||||
return {};
|
||||
},
|
||||
props: ["nodes", "newTable", "deleteTable"],
|
||||
watch: {},
|
||||
directives: {},
|
||||
components: {}
|
||||
};
|
||||
// const result = await this.sqlMgr.sqlOp({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// }, 'columnList', {
|
||||
// tn
|
||||
// });
|
||||
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'columnList', {
|
||||
tn
|
||||
}])
|
||||
|
||||
this.columns = result.data.list
|
||||
}
|
||||
},
|
||||
computed: { ...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }) },
|
||||
|
||||
beforeCreated () {
|
||||
},
|
||||
watch: {},
|
||||
created () {
|
||||
this.loadRelationList()
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
beforeDestroy () {
|
||||
},
|
||||
destroy () {
|
||||
},
|
||||
directives: {},
|
||||
components: {},
|
||||
validate ({ params }) {
|
||||
return true
|
||||
},
|
||||
head () {
|
||||
return {}
|
||||
},
|
||||
props: ['nodes', 'newTable', 'deleteTable']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,61 +1,78 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<v-card class="elevation-0">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: (nodes.tn || nodes.view_name) + ' (rows)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: (nodes.tn || nodes.view_name) + ' (rows)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload Rows"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['rows','reload']"
|
||||
@click="refreshTable">
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['rows','reload']"
|
||||
outlined
|
||||
tooltip="Reload Rows"
|
||||
color="primary"
|
||||
small
|
||||
@click="refreshTable"
|
||||
>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
v-if="!isView"
|
||||
:disabled="disableSaveButton"
|
||||
v-ge="['rows','save']"
|
||||
@click.prevent="saveChanges">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
v-if="!isView"
|
||||
v-ge="['rows','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="disableSaveButton"
|
||||
@click.prevent="saveChanges"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Add New Row"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
v-if="!isView"
|
||||
v-ge="['rows','new']"
|
||||
@click="addNewRow">
|
||||
<v-icon small left>mdi-plus</v-icon>
|
||||
<x-btn
|
||||
v-if="!isView"
|
||||
v-ge="['rows','new']"
|
||||
outlined
|
||||
tooltip="Add New Row"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
@click="addNewRow"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
New Row
|
||||
</x-btn>
|
||||
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-data-table
|
||||
@@ -68,110 +85,107 @@
|
||||
:options.sync="tableOptions"
|
||||
class=" column-table"
|
||||
:footer-props="{
|
||||
itemsPerPageOptions:[5,10,25,50,100]
|
||||
itemsPerPageOptions:[5,10,25,50,100]
|
||||
}"
|
||||
>
|
||||
|
||||
<template v-slot:header="{props:{headers}}">
|
||||
<th class="py-2 px-1 text-center text-capitalize" v-for="header in headers" :key="header.title">
|
||||
<template #header="{props:{headers}}">
|
||||
<th v-for="header in headers" :key="header.title" class="py-2 px-1 text-center text-capitalize">
|
||||
{{ header.text }}
|
||||
</th>
|
||||
</template>
|
||||
|
||||
|
||||
<template v-slot:item="{item,index}">
|
||||
<template #item="{item,index}">
|
||||
<tr v-if="!item.isNewRow">
|
||||
<td v-for="({text,type,ai:ai},i) in cols" :key="i" class="caption">
|
||||
<span v-if="isView">
|
||||
{{ item.data[text] }}
|
||||
{{ item.data[text] }}
|
||||
</span>
|
||||
<template v-else-if="text">
|
||||
<v-edit-dialog
|
||||
|
||||
v-ge="['rows','edit-save']"
|
||||
:return-value.sync="item.data[text]"
|
||||
@save="save(type,text,item)"
|
||||
v-ge="['rows','edit-save']"
|
||||
>
|
||||
{{ item.data[text] }}
|
||||
<template v-slot:input>
|
||||
<template #input>
|
||||
<v-text-field
|
||||
class="mt-0 caption"
|
||||
v-model="item.data[text]"
|
||||
class="mt-0 caption"
|
||||
label="Edit"
|
||||
:type="getType(type)"
|
||||
single-line
|
||||
hide-details
|
||||
dense
|
||||
:disabled="ai"
|
||||
></v-text-field>
|
||||
/>
|
||||
</template>
|
||||
</v-edit-dialog>
|
||||
</template>
|
||||
<template v-else>
|
||||
<x-icon small
|
||||
color="error grey"
|
||||
@click="deleteRow('showDialog', index, item)"
|
||||
v-ge="['rows','delete']"
|
||||
>mdi-delete-forever
|
||||
</x-icon
|
||||
<x-icon
|
||||
v-ge="['rows','delete']"
|
||||
small
|
||||
color="error grey"
|
||||
@click="deleteRow('showDialog', index, item)"
|
||||
>
|
||||
mdi-delete-forever
|
||||
</x-icon>
|
||||
</template>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr v-else>
|
||||
<td v-for="({text,type,ai:ai},i) in cols" :key="i">
|
||||
<template v-if="text">
|
||||
<v-text-field
|
||||
v-model="item.data[text]"
|
||||
v-ge="['rows','save']"
|
||||
dense
|
||||
hide-details
|
||||
@input.passive="save(type,text,item)"
|
||||
v-model="item.data[text]"
|
||||
label="Edit"
|
||||
:type="getType(type)"
|
||||
:placeholder="text"
|
||||
:disabled="ai"
|
||||
single-line
|
||||
v-ge="['rows','save']"
|
||||
class="caption mt-n1 "
|
||||
></v-text-field>
|
||||
@input.passive="save(type,text,item)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<x-icon small
|
||||
color="error"
|
||||
@click="deleteRow('showDialog',index ,item)"
|
||||
v-ge="['rows','delete']"
|
||||
>mdi-delete-forever
|
||||
</x-icon
|
||||
<x-icon
|
||||
v-ge="['rows','delete']"
|
||||
small
|
||||
color="error"
|
||||
@click="deleteRow('showDialog',index ,item)"
|
||||
>
|
||||
mdi-delete-forever
|
||||
</x-icon>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
</v-card>
|
||||
<dlgLabelSubmitCancel
|
||||
type="primary"
|
||||
v-if="rowDeleteDlg"
|
||||
:dialogShow="rowDeleteDlg"
|
||||
:actionsMtd="deleteRow"
|
||||
type="primary"
|
||||
:dialog-show="rowDeleteDlg"
|
||||
:actions-mtd="deleteRow"
|
||||
heading="Click Submit to Delete the Row"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import dlgLabelSubmitCancel from "../../utils/dlgLabelSubmitCancel.vue";
|
||||
import findDataTypeMapping from '../../../helpers/findDataTypeMapping.js';
|
||||
import { mapGetters } from 'vuex'
|
||||
import dlgLabelSubmitCancel from '../../utils/dlgLabelSubmitCancel.vue'
|
||||
import findDataTypeMapping from '../../../helpers/findDataTypeMapping.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
dlgLabelSubmitCancel: dlgLabelSubmitCancel
|
||||
dlgLabelSubmitCancel
|
||||
},
|
||||
data() {
|
||||
data () {
|
||||
return {
|
||||
rows: [],
|
||||
cols: [],
|
||||
@@ -184,10 +198,10 @@ export default {
|
||||
totalCount: 0,
|
||||
tableOptions: {},
|
||||
disableSaveButton: true
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleKeyDown({metaKey, key, altKey, shiftKey, ctrlKey}) {
|
||||
async handleKeyDown ({ metaKey, key, altKey, shiftKey, ctrlKey }) {
|
||||
console.log(metaKey, key, altKey, shiftKey, ctrlKey)
|
||||
// cmd + s -> save
|
||||
// cmd + l -> reload
|
||||
@@ -197,59 +211,53 @@ export default {
|
||||
|
||||
switch ([metaKey, key].join('_')) {
|
||||
case 'true_s' :
|
||||
await this.saveChanges();
|
||||
break;
|
||||
await this.saveChanges()
|
||||
break
|
||||
case 'true_l' :
|
||||
await this.refreshTable();
|
||||
break;
|
||||
await this.refreshTable()
|
||||
break
|
||||
case 'true_n' :
|
||||
this.addNewRow();
|
||||
break;
|
||||
this.addNewRow()
|
||||
break
|
||||
// case 'true_d' :
|
||||
// await this.deleteTable('showDialog');
|
||||
// break;
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
async refreshTable() {
|
||||
async refreshTable () {
|
||||
try {
|
||||
await this.loadColumnList();
|
||||
await this.loadRowList();
|
||||
await this.loadColumnList()
|
||||
await this.loadRowList()
|
||||
} catch (e) {
|
||||
this.$toast.error('error loading rows').goAway(4000);
|
||||
throw e;
|
||||
this.$toast.error('error loading rows').goAway(4000)
|
||||
throw e
|
||||
}
|
||||
},
|
||||
async loadColumnList() {
|
||||
async loadColumnList () {
|
||||
// const columnsList = await this.client.columnList({tn: this.nodes.tn});
|
||||
|
||||
|
||||
// const columnsList = await this.sqlMgr.sqlOp({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// }, 'columnList', {tn: this.nodes.tn})
|
||||
|
||||
|
||||
const columnsList = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'columnList', {tn: this.nodes.tn || this.nodes.view_name}])
|
||||
}, 'columnList', { tn: this.nodes.tn || this.nodes.view_name }])
|
||||
|
||||
|
||||
this.cols = columnsList.data.list.map(({cn, dt, ai, pk}) => {
|
||||
if (pk) this.primaryKeys.push(cn);
|
||||
this.cols = columnsList.data.list.map(({ cn, dt, ai, pk }) => {
|
||||
if (pk) { this.primaryKeys.push(cn) }
|
||||
return {
|
||||
text: cn, value: cn, type: findDataTypeMapping(dt), ai
|
||||
}
|
||||
})
|
||||
// column for action buttons
|
||||
if (!this.isView)
|
||||
this.cols.push({text: '', value: ''})
|
||||
if (!this.isView) { this.cols.push({ text: '', value: '' }) }
|
||||
},
|
||||
async loadRowList() {
|
||||
|
||||
const {page, itemsPerPage} = this.tableOptions;
|
||||
async loadRowList () {
|
||||
const { page, itemsPerPage } = this.tableOptions
|
||||
|
||||
// const result = await this.sqlMgr.sqlOp({
|
||||
// env: this.nodes.env,
|
||||
@@ -261,7 +269,6 @@ export default {
|
||||
// orderBy: this.primaryKeys.map(key => ({column: key, order: 'desc'}))
|
||||
// })
|
||||
|
||||
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
@@ -269,10 +276,9 @@ export default {
|
||||
tn: this.nodes.tn || this.nodes.view_name,
|
||||
size: itemsPerPage,
|
||||
page,
|
||||
orderBy: this.primaryKeys.map(key => ({column: key, order: 'desc'}))
|
||||
orderBy: this.primaryKeys.map(key => ({ column: key, order: 'desc' }))
|
||||
}])
|
||||
|
||||
|
||||
// const result = await this.client.list({
|
||||
// tn: this.nodes.tn,
|
||||
// size: itemsPerPage,
|
||||
@@ -280,44 +286,42 @@ export default {
|
||||
// orderBy: this.primaryKeys.map(key => ({column: key, order: 'desc'}))
|
||||
// });
|
||||
|
||||
this.totalCount = result.data.count;
|
||||
this.totalCount = result.data.count
|
||||
|
||||
this.rows = result.data.list.map(row => {
|
||||
const keys = this.primaryKeys.reduce((obj, key) => Object.assign(obj, {[key]: row[key]}), {})
|
||||
return {keys, data: {...row}, dataCopy: {...row}};
|
||||
});
|
||||
this.rows = result.data.list.map((row) => {
|
||||
const keys = this.primaryKeys.reduce((obj, key) => Object.assign(obj, { [key]: row[key] }), {})
|
||||
return { keys, data: { ...row }, dataCopy: { ...row } }
|
||||
})
|
||||
},
|
||||
save(type, text, item) {
|
||||
save (type, text, item) {
|
||||
// console.log(type, text, item)
|
||||
item.changed = true;
|
||||
const {data, dataCopy} = item;
|
||||
item.changed = true
|
||||
const { data, dataCopy } = item
|
||||
if (type === 'date') {
|
||||
dataCopy[text] = new Date(data[text]);
|
||||
dataCopy[text] = new Date(data[text])
|
||||
} else {
|
||||
dataCopy[text] = data[text];
|
||||
dataCopy[text] = data[text]
|
||||
}
|
||||
},
|
||||
getType(dt) {
|
||||
if (dt == 'number')
|
||||
return 'number';
|
||||
getType (dt) {
|
||||
if (dt === 'number') { return 'number' }
|
||||
return 'text'
|
||||
},
|
||||
async deleteRow(action = "", index, row) {
|
||||
async deleteRow (action = '', index, row) {
|
||||
try {
|
||||
if (action === "showDialog") {
|
||||
this.rowDeleteDlg = true;
|
||||
this.selectedRowForDelete = {index, row};
|
||||
} else if (action === "hideDialog") {
|
||||
this.rowDeleteDlg = false;
|
||||
if (action === 'showDialog') {
|
||||
this.rowDeleteDlg = true
|
||||
this.selectedRowForDelete = { index, row }
|
||||
} else if (action === 'hideDialog') {
|
||||
this.rowDeleteDlg = false
|
||||
} else {
|
||||
this.rowDeleteDlg = false;
|
||||
const {index, row} = this.selectedRowForDelete;
|
||||
this.rowDeleteDlg = false
|
||||
const { index, row } = this.selectedRowForDelete
|
||||
if (row.isNewRow) {
|
||||
this.rows.splice(index, 1);
|
||||
this.rows.splice(index, 1)
|
||||
} else {
|
||||
// this.client.delete(this.nodes.tn, row.keys)
|
||||
|
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
@@ -326,7 +330,6 @@ export default {
|
||||
whereConditions: row.keys
|
||||
}])
|
||||
|
||||
|
||||
// await this.sqlMgr.sqlOp({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
@@ -335,31 +338,29 @@ export default {
|
||||
// whereConditions: row.keys
|
||||
// });
|
||||
|
||||
|
||||
this.rows.splice(index, 1);
|
||||
this.rows.splice(index, 1)
|
||||
}
|
||||
this.$toast.success('Row deleted successfully').goAway(3000);
|
||||
this.$toast.success('Row deleted successfully').goAway(3000)
|
||||
}
|
||||
this.totalCount--;
|
||||
this.totalCount--
|
||||
} catch (e) {
|
||||
this.$toast.error('Deleting row failed').goAway(3000);
|
||||
throw e;
|
||||
this.$toast.error('Deleting row failed').goAway(3000)
|
||||
throw e
|
||||
}
|
||||
|
||||
},
|
||||
addNewRow() {
|
||||
this.rows.unshift({isNewRow: true, data: {}, dataCopy: {}})
|
||||
this.totalCount++;
|
||||
addNewRow () {
|
||||
this.rows.unshift({ isNewRow: true, data: {}, dataCopy: {} })
|
||||
this.totalCount++
|
||||
},
|
||||
async saveChanges() {
|
||||
async saveChanges () {
|
||||
try {
|
||||
const newRows = [];
|
||||
this.rows.map(async item => {
|
||||
const {keys, isNewRow, changed, dataCopy} = item;
|
||||
const newRows = []
|
||||
this.rows.map(async (item) => {
|
||||
const { keys, isNewRow, changed, dataCopy } = item
|
||||
if (isNewRow) {
|
||||
newRows.push(dataCopy);
|
||||
newRows.push(dataCopy)
|
||||
} else if (changed) {
|
||||
item.changed = false;
|
||||
item.changed = false
|
||||
// const res = await this.client.update(this.nodes.tn, dataCopy, keys);
|
||||
|
||||
const res = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
@@ -369,79 +370,76 @@ export default {
|
||||
tn: this.nodes.tn,
|
||||
data: dataCopy,
|
||||
whereConditions: keys
|
||||
}]);
|
||||
}])
|
||||
|
||||
console.log(res);
|
||||
this.$toast.success('Row updated successfully').goAway(3000);
|
||||
console.log(res)
|
||||
this.$toast.success('Row updated successfully').goAway(3000)
|
||||
}
|
||||
});
|
||||
})
|
||||
if (newRows.length) {
|
||||
console.log(newRows);
|
||||
console.log(newRows)
|
||||
// todo : multiargs to single object
|
||||
// const res = await this.client.insert(this.nodes.tn, newRows)
|
||||
|
||||
|
||||
const res = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'insert', {
|
||||
tn: this.nodes.tn,
|
||||
data: newRows
|
||||
}]);
|
||||
|
||||
}])
|
||||
|
||||
console.log(res)
|
||||
}
|
||||
this.$toast.success('Row saved successfully').goAway(3000);
|
||||
this.$toast.success('Row saved successfully').goAway(3000)
|
||||
this.loadRowList()
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$toast.error('Saving changes to table failed').goAway(3000);
|
||||
throw e;
|
||||
console.log(e)
|
||||
this.$toast.error('Saving changes to table failed').goAway(3000)
|
||||
throw e
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}),
|
||||
isView() {
|
||||
...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
|
||||
isView () {
|
||||
return !!this.nodes.view_name
|
||||
}
|
||||
},
|
||||
beforeCreated() {
|
||||
beforeCreated () {
|
||||
},
|
||||
async created() {
|
||||
await this.refreshTable();
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
},
|
||||
destroy() {
|
||||
},
|
||||
validate({params}) {
|
||||
return true;
|
||||
},
|
||||
head() {
|
||||
return {};
|
||||
},
|
||||
props: ["nodes", "newTable", "mtdNewTableUpdate", "deleteTable"],
|
||||
watch: {
|
||||
tableOptions: {
|
||||
handler() {
|
||||
this.loadRowList();
|
||||
handler () {
|
||||
this.loadRowList()
|
||||
},
|
||||
deep: true,
|
||||
deep: true
|
||||
},
|
||||
rows: {
|
||||
handler() {
|
||||
handler () {
|
||||
this.disableSaveButton = !this.rows.some(row => row.isNewRow || row.changed)
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
directives: {}
|
||||
};
|
||||
async created () {
|
||||
await this.refreshTable()
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
beforeDestroy () {
|
||||
},
|
||||
destroy () {
|
||||
},
|
||||
directives: {},
|
||||
validate ({ params }) {
|
||||
return true
|
||||
},
|
||||
head () {
|
||||
return {}
|
||||
},
|
||||
props: ['nodes', 'newTable', 'mtdNewTableUpdate', 'deleteTable']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,213 +1,264 @@
|
||||
<template>
|
||||
<div class="h-100">
|
||||
|
||||
|
||||
<v-card style="" class="h-100">
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: (nodes._tn || nodes.view_name|| nodes.tn) + ' (RBAC)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: (nodes._tn || nodes.view_name|| nodes.tn) + ' (RBAC)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Reload RBAC"
|
||||
color="primary"
|
||||
small
|
||||
@click="load"
|
||||
v-ge="['acl','reload']"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['acl','reload']"
|
||||
outlined
|
||||
tooltip="Reload RBAC"
|
||||
color="primary"
|
||||
small
|
||||
@click="load"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
v-ge="['acl','save']"
|
||||
@click="save"
|
||||
:disabled="!edited"
|
||||
<x-btn
|
||||
v-ge="['acl','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
class="primary"
|
||||
small
|
||||
:disabled="!edited"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon small left>save</v-icon>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<p class="title mt-6 mb-6">
|
||||
Table : <span class="text-capitalize">{{ nodes._tn || nodes.view_name }}</span><br>
|
||||
<span class="font-weight-thin">Role Based Access Control (RBAC) For Columns</span>
|
||||
</p>
|
||||
|
||||
<p class="title mt-6 mb-6"> Table : <span class="text-capitalize">{{ nodes._tn || nodes.view_name }}</span><br>
|
||||
<span class="font-weight-thin">Role Based Access Control (RBAC) For Columns</span></p>
|
||||
|
||||
|
||||
|
||||
<v-skeleton-loader v-if="loading || !data" type="table">
|
||||
|
||||
</v-skeleton-loader>
|
||||
|
||||
<div v-else class="pb-10">
|
||||
<v-overlay absolute v-model="showCustomAcl">
|
||||
<template v-slot:default>
|
||||
<v-card :light="!$store.state.windows.darkTheme" class="ma-2" style="max-height: 100%; overflow: auto; min-height:70vh">
|
||||
<v-skeleton-loader v-if="loading || !data" type="table" />
|
||||
|
||||
<div v-else class="pb-10">
|
||||
<v-overlay v-model="showCustomAcl" absolute>
|
||||
<template #default>
|
||||
<v-card
|
||||
:light="!$store.state.windows.darkTheme"
|
||||
class="ma-2"
|
||||
style="max-height: 100%; overflow: auto; min-height:70vh"
|
||||
>
|
||||
<v-card-actions>
|
||||
<p class="body-1 mb-0 mr-2">Custom Rules : {{ custoAclTitle[0] }}<span class="grey--text caption">(table)</span>
|
||||
<p class="body-1 mb-0 mr-2">
|
||||
Custom Rules : {{ custoAclTitle[0] }}<span class="grey--text caption">(table)</span>
|
||||
> {{ custoAclTitle[1] }}<span class="grey--text caption">(role)</span> > {{ custoAclTitle[2] }}<span
|
||||
class="grey--text caption">(operation)</span></p>
|
||||
<v-spacer>
|
||||
</v-spacer>
|
||||
class="grey--text caption"
|
||||
>(operation)</span>
|
||||
</p>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
outlined
|
||||
small
|
||||
@click="showCustomAcl=false"
|
||||
>Cancel
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
outlined
|
||||
color="primary"
|
||||
small
|
||||
@click="save"
|
||||
>Save
|
||||
>
|
||||
Save
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
<v-card-text>
|
||||
<custom-acl :nodes="nodes" :table="nodes.tn || nodes.view_name"
|
||||
v-model="customAcl"></custom-acl>
|
||||
<custom-acl
|
||||
v-model="customAcl"
|
||||
:nodes="nodes"
|
||||
:table="nodes.tn || nodes.view_name"
|
||||
/>
|
||||
</v-card-text>
|
||||
|
||||
</v-card>
|
||||
</template>
|
||||
</v-overlay>
|
||||
<v-simple-table dense v-slot:default class=" mx-10">
|
||||
<v-simple-table dense class=" mx-10">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="text-center">
|
||||
<!-- <div class="d-flex justify-center align-end">-->
|
||||
<!-- <v-checkbox dense v-model="aclAll"></v-checkbox>-->
|
||||
<tr>
|
||||
<th rowspan="2" class="text-center">
|
||||
<!-- <div class="d-flex justify-center align-end">-->
|
||||
<!-- <v-checkbox dense v-model="aclAll"></v-checkbox>-->
|
||||
|
||||
<span>Columns x RBAC</span>
|
||||
<!-- <v-text-field dense hide-details class="my-2 caption font-weight-regular"
|
||||
flat
|
||||
outlined
|
||||
:placeholder="`Search columns in '${nodes._tn|| nodes.view_name}'`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
></v-text-field>-->
|
||||
<span>Columns x RBAC</span>
|
||||
<!-- <v-text-field dense hide-details class="my-2 caption font-weight-regular"
|
||||
flat
|
||||
outlined
|
||||
:placeholder="`Search columns in '${nodes._tn|| nodes.view_name}'`"
|
||||
prepend-inner-icon="search" v-model="search"
|
||||
></v-text-field>-->
|
||||
<!-- </div>-->
|
||||
</th>
|
||||
<th :colspan="operations.length" class="text-center"
|
||||
v-for="role in roles" :key="role" v-if="role !== 'creator'">{{ role }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<template v-for="role in roles" v-if="role !== 'creator'">
|
||||
<th v-for="op in operations" :class="` pa-0 caption text-capitalize ${op.color}--text`"
|
||||
class="permission role-op-header"
|
||||
:key="`${role}-${op.name}--11`"
|
||||
>
|
||||
</th>
|
||||
<template v-for="role in roles">
|
||||
<th
|
||||
v-if="role !== 'creator'"
|
||||
:key="role"
|
||||
:colspan="operations.length"
|
||||
class="text-center"
|
||||
>
|
||||
{{ role }}
|
||||
</th>
|
||||
</template>
|
||||
</tr>
|
||||
<tr>
|
||||
<template v-for="role in roles">
|
||||
<template v-if="role !== 'creator'">
|
||||
<th
|
||||
v-for="op in operations"
|
||||
:key="`${role}-${op.name}--11`"
|
||||
:class="` pa-0 caption text-capitalize ${op.color}--text`"
|
||||
class="permission role-op-header"
|
||||
>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{on}">
|
||||
<div class="d-flex flex-column justify-center align-center d-100 h-100 mt-0" v-on="on">
|
||||
<v-checkbox
|
||||
v-model="aclRoleOpAll[`${role}___${op.name}`]"
|
||||
hide-details
|
||||
class="mt-n1"
|
||||
dense
|
||||
:color="op.color"
|
||||
@change="onAclRoleOpAllChange(aclRoleOpAll[`${role}___${op.name}`],`${role}___${op.name}`)"
|
||||
/>
|
||||
<span>{{ op.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<span class="caption"><span
|
||||
class="text-capitalize"
|
||||
>{{
|
||||
role
|
||||
}}</span> {{ aclRoleOpAll[`${role}___${op.name}`] ? 'can' : 'can\'t' }} {{
|
||||
op.name
|
||||
}} '{{ nodes.tn }}' rows</span>
|
||||
</v-tooltip>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{on}">
|
||||
<div class="d-flex flex-column justify-center align-center d-100 h-100 mt-0" v-on="on">
|
||||
<v-checkbox
|
||||
hide-details
|
||||
class="mt-n1" dense v-model="aclRoleOpAll[`${role}___${op.name}`]"
|
||||
@change="onAclRoleOpAllChange(aclRoleOpAll[`${role}___${op.name}`],`${role}___${op.name}`)"
|
||||
:color="op.color"></v-checkbox>
|
||||
<span>{{ op.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<span class="caption"><span
|
||||
class="text-capitalize">{{
|
||||
role
|
||||
}}</span> {{ aclRoleOpAll[`${role}___${op.name}`] ? 'can' : 'can\'t' }} {{
|
||||
op.name
|
||||
}} '{{ nodes.tn }}' rows</span>
|
||||
</v-tooltip>
|
||||
<v-icon
|
||||
v-if="op.name !== 'delete'"
|
||||
x-small
|
||||
class="custom-acl"
|
||||
@click="(
|
||||
showCustomAcl = true,
|
||||
custoAclTitle = [nodes.tn,role,op.name],
|
||||
customAcl=(data[role] && data[role][op.name] && data[role][op.name].custom ) || {}
|
||||
)"
|
||||
>
|
||||
mdi-pencil-outline
|
||||
</v-icon>
|
||||
|
||||
<v-icon v-if="op.name !== 'delete'" x-small class="custom-acl"
|
||||
@click="(
|
||||
showCustomAcl = true,
|
||||
custoAclTitle = [nodes.tn,role,op.name],
|
||||
customAcl=(data[role] && data[role][op.name] && data[role][op.name].custom ) || {}
|
||||
)">
|
||||
mdi-pencil-outline
|
||||
</v-icon>
|
||||
|
||||
<v-icon
|
||||
x-small
|
||||
class="custom-acl-found"
|
||||
v-if="data[role]
|
||||
<v-icon
|
||||
v-if="data[role]
|
||||
&& data[role][op.name]
|
||||
&& data[role][op.name].custom
|
||||
&& Object.keys(data[role][op.name].custom).length"
|
||||
>mdi-filter-menu
|
||||
</v-icon>
|
||||
|
||||
</th>
|
||||
</template>
|
||||
</tr>
|
||||
x-small
|
||||
class="custom-acl-found"
|
||||
>
|
||||
mdi-filter-menu
|
||||
</v-icon>
|
||||
</th>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr class="caption" v-for="column in columns"
|
||||
<tr
|
||||
v-for="column in columns"
|
||||
v-show="column._cn.toLowerCase().indexOf(search.toLowerCase()) > -1"
|
||||
:key="column._cn"
|
||||
v-show="column._cn.toLowerCase().indexOf(search.toLowerCase()) > -1">
|
||||
<td
|
||||
>{{ column._cn }}
|
||||
</td>
|
||||
<template v-for="role in roles" v-if="role !== 'creator'">
|
||||
<td
|
||||
class="pa-0"
|
||||
style="position: relative"
|
||||
v-for="op in operations" :class="`caption text-capitalize`"
|
||||
:key="`${role}-${op.name}`">
|
||||
<v-tooltip bottom :disabled="op.ignore">
|
||||
<template v-slot:activator="{on}">
|
||||
<div class="d-100 h-100 d-flex align-center justify-center permission-checkbox-container" v-on="on">
|
||||
<v-checkbox class="mt-n1" v-if="!op.ignore" dense
|
||||
color="primary lighten-2"
|
||||
@change="onPermissionChange(aclObj[`${column._cn}___${role}___${op.name}`],`${role}___${op.name}`)"
|
||||
v-model="aclObj[`${column._cn}___${role}___${op.name}`]"
|
||||
style=""></v-checkbox>
|
||||
|
||||
<v-checkbox class="mt-n1" v-else dense
|
||||
color="primary lighten-2"
|
||||
disabled
|
||||
style=""></v-checkbox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<span class="caption"><span
|
||||
class="text-capitalize">{{
|
||||
role
|
||||
}}</span> {{ aclObj[`${column._cn}___${role}___${op.name}`] ? 'can' : 'can\'t' }} {{
|
||||
op.name
|
||||
}} column '{{ column._cn }}'</span>
|
||||
</v-tooltip>
|
||||
class="caption"
|
||||
>
|
||||
<td>
|
||||
{{ column._cn }}
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
<template v-for="role in roles">
|
||||
<template
|
||||
v-if="role !== 'creator'"
|
||||
>
|
||||
<td
|
||||
v-for="op in operations"
|
||||
:key="`${role}-${op.name}`"
|
||||
class="pa-0"
|
||||
style="position: relative"
|
||||
:class="`caption text-capitalize`"
|
||||
>
|
||||
<v-tooltip bottom :disabled="op.ignore">
|
||||
<template #activator="{on}">
|
||||
<div
|
||||
class="d-100 h-100 d-flex align-center justify-center permission-checkbox-container"
|
||||
v-on="on"
|
||||
>
|
||||
<v-checkbox
|
||||
v-if="!op.ignore"
|
||||
v-model="aclObj[`${column._cn}___${role}___${op.name}`]"
|
||||
class="mt-n1"
|
||||
dense
|
||||
color="primary lighten-2"
|
||||
style=""
|
||||
@change="onPermissionChange(aclObj[`${column._cn}___${role}___${op.name}`],`${role}___${op.name}`)"
|
||||
/>
|
||||
|
||||
<v-checkbox
|
||||
v-else
|
||||
class="mt-n1"
|
||||
dense
|
||||
color="primary lighten-2"
|
||||
disabled
|
||||
style=""
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<span class="caption"><span
|
||||
class="text-capitalize"
|
||||
>{{
|
||||
role
|
||||
}}</span> {{ aclObj[`${column._cn}___${role}___${op.name}`] ? 'can' : 'can\'t' }} {{
|
||||
op.name
|
||||
}} column '{{ column._cn }}'</span>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
</div>
|
||||
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
@@ -217,11 +268,11 @@
|
||||
// import debounce from "@/helpers/debounce";
|
||||
// import CustomAcl from "./customAcl";
|
||||
|
||||
import CustomAcl from "./customAcl";
|
||||
import CustomAcl from './customAcl'
|
||||
|
||||
export default {
|
||||
name: "tableAcl",
|
||||
components: {CustomAcl},
|
||||
name: 'TableAcl',
|
||||
components: { CustomAcl },
|
||||
// components: {CustomAcl},
|
||||
props: ['nodes'],
|
||||
data: () => ({
|
||||
@@ -252,80 +303,78 @@ export default {
|
||||
loading: false
|
||||
}),
|
||||
computed: {
|
||||
roles() {
|
||||
roles () {
|
||||
return (this.data ? Object.keys(this.data) : []).filter(r => r !== 'guest')
|
||||
},
|
||||
operations() {
|
||||
return this.allOperations.filter(({name}) => this.nodes.tn || name === 'read')
|
||||
operations () {
|
||||
return this.allOperations.filter(({ name }) => this.nodes.tn || name === 'read')
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.load();
|
||||
async created () {
|
||||
await this.load()
|
||||
},
|
||||
methods: {
|
||||
async load() {
|
||||
await this.loadColumnList();
|
||||
await this.loadAcl();
|
||||
this.generateAclObj();
|
||||
this.edited = false;
|
||||
async load () {
|
||||
await this.loadColumnList()
|
||||
await this.loadAcl()
|
||||
this.generateAclObj()
|
||||
this.edited = false
|
||||
},
|
||||
generateAclObj() {
|
||||
|
||||
const aclObj = {};
|
||||
const aclRoleOpAll = {};
|
||||
generateAclObj () {
|
||||
const aclObj = {}
|
||||
const aclRoleOpAll = {}
|
||||
console.log(this.data)
|
||||
// generate aclObj with merged key value
|
||||
for (const [role, roleObj] of Object.entries(this.data)) {
|
||||
for (const [operation, acl] of Object.entries(roleObj)) {
|
||||
aclRoleOpAll[`${role}___${operation}`] = false;
|
||||
for (const {_cn: cn} of this.columns) {
|
||||
aclRoleOpAll[`${role}___${operation}`] = false
|
||||
for (const { _cn: cn } of this.columns) {
|
||||
if (typeof acl === 'boolean') {
|
||||
aclObj[`${cn}___${role}___${operation}`] = acl;
|
||||
aclObj[`${cn}___${role}___${operation}`] = acl
|
||||
} else if (acl) {
|
||||
aclObj[`${cn}___${role}___${operation}`] = acl.columns[cn];
|
||||
aclObj[`${cn}___${role}___${operation}`] = acl.columns[cn]
|
||||
}
|
||||
if (!aclRoleOpAll[`${role}___${operation}`] && aclObj[`${cn}___${role}___${operation}`]) {
|
||||
aclRoleOpAll[`${role}___${operation}`] = true;
|
||||
aclRoleOpAll[`${role}___${operation}`] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.aclRoleOpAll = aclRoleOpAll;
|
||||
this.$nextTick(() => this.aclObj = aclObj);
|
||||
|
||||
this.aclRoleOpAll = aclRoleOpAll
|
||||
this.$nextTick(() => {
|
||||
this.aclObj = aclObj
|
||||
})
|
||||
},
|
||||
async save() {
|
||||
const obj = {};
|
||||
async save () {
|
||||
const obj = {}
|
||||
for (const [key, isAllowed] of Object.entries(this.aclObj)) {
|
||||
const [column, role, operation] = key.split('___');
|
||||
const [column, role, operation] = key.split('___')
|
||||
if (operation !== 'delete') {
|
||||
obj[role] = obj[role] || {};
|
||||
obj[role][operation] = obj[role][operation] || {};
|
||||
obj[role][operation].columns = obj[role][operation].columns || {};
|
||||
obj[role][operation].columns[column] = isAllowed;
|
||||
obj[role] = obj[role] || {}
|
||||
obj[role][operation] = obj[role][operation] || {}
|
||||
obj[role][operation].columns = obj[role][operation].columns || {}
|
||||
obj[role][operation].columns[column] = isAllowed
|
||||
}
|
||||
if (this.data[role] && this.data[role][operation] && this.data[role][operation].custom) {
|
||||
obj[role][operation].custom = this.data[role][operation].custom;
|
||||
obj[role][operation].custom = this.data[role][operation].custom
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
for (const [key, isAllowed] of Object.entries(this.aclRoleOpAll)) {
|
||||
const [role, operation] = key.split('___');
|
||||
const [role, operation] = key.split('___')
|
||||
if (operation === 'delete' || !isAllowed) {
|
||||
obj[role] = obj[role] || {};
|
||||
obj[role][operation] = isAllowed;
|
||||
obj[role] = obj[role] || {}
|
||||
obj[role][operation] = isAllowed
|
||||
}
|
||||
}
|
||||
|
||||
if (this.showCustomAcl && this.custoAclTitle) {
|
||||
if (!obj[this.custoAclTitle[1]][this.custoAclTitle[2]] || typeof obj[this.custoAclTitle[1]][this.custoAclTitle[2]] !== 'object')
|
||||
obj[this.custoAclTitle[1]][this.custoAclTitle[2]] = {};
|
||||
obj[this.custoAclTitle[1]][this.custoAclTitle[2]].custom = this.customAcl;
|
||||
if (!obj[this.custoAclTitle[1]][this.custoAclTitle[2]] || typeof obj[this.custoAclTitle[1]][this.custoAclTitle[2]] !== 'object') {
|
||||
obj[this.custoAclTitle[1]][this.custoAclTitle[2]] = {}
|
||||
}
|
||||
obj[this.custoAclTitle[1]][this.custoAclTitle[2]].custom = this.customAcl
|
||||
}
|
||||
|
||||
|
||||
console.log(obj)
|
||||
try {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
@@ -334,20 +383,21 @@ export default {
|
||||
}, 'xcAclSave', {
|
||||
tn: this.nodes.tn || this.nodes.view_name,
|
||||
acl: obj
|
||||
}]);
|
||||
}])
|
||||
if (this.showCustomAcl) {
|
||||
this.$toast.success('Custom RBAC saved successfully').goAway(3000);
|
||||
this.showCustomAcl = false;
|
||||
} else
|
||||
this.$toast.success('RBAC saved successfully').goAway(3000);
|
||||
this.edited = false;
|
||||
this.$toast.success('Custom RBAC saved successfully').goAway(3000)
|
||||
this.showCustomAcl = false
|
||||
} else {
|
||||
this.$toast.success('RBAC saved successfully').goAway(3000)
|
||||
}
|
||||
this.edited = false
|
||||
await this.load()
|
||||
} catch (e) {
|
||||
this.$toast.error(e.message).goAway(3000);
|
||||
this.$toast.error(e.message).goAway(3000)
|
||||
}
|
||||
},
|
||||
|
||||
async loadColumnList() {
|
||||
async loadColumnList () {
|
||||
// const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
@@ -360,46 +410,45 @@ export default {
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcModelGet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name
|
||||
}]);
|
||||
}])
|
||||
|
||||
|
||||
const meta = JSON.parse(result.meta);
|
||||
this.columns = meta.columns;
|
||||
const meta = JSON.parse(result.meta)
|
||||
this.columns = meta.columns
|
||||
},
|
||||
async loadAcl() {
|
||||
this.loading = true;
|
||||
async loadAcl () {
|
||||
this.loading = true
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'xcAclGet', {
|
||||
tn: this.nodes.tn || this.nodes.view_name
|
||||
}]);
|
||||
this.data = JSON.parse(result.acl);
|
||||
}])
|
||||
this.data = JSON.parse(result.acl)
|
||||
|
||||
this.loading = false;
|
||||
this.loading = false
|
||||
},
|
||||
onAclRoleOpAllChange(isEnabled, name) {
|
||||
this.edited = true;
|
||||
const obj = {};
|
||||
onAclRoleOpAllChange (isEnabled, name) {
|
||||
this.edited = true
|
||||
const obj = {}
|
||||
for (const key in this.aclObj) {
|
||||
if (key.split('___').slice(1).join('___') === name) {
|
||||
obj[key] = isEnabled;
|
||||
obj[key] = isEnabled
|
||||
} else {
|
||||
obj[key] = this.aclObj[key];
|
||||
obj[key] = this.aclObj[key]
|
||||
}
|
||||
}
|
||||
this.aclObj = obj;
|
||||
this.aclObj = obj
|
||||
},
|
||||
onPermissionChange(isEnabled, name) {
|
||||
this.edited = true;
|
||||
onPermissionChange (isEnabled, name) {
|
||||
this.edited = true
|
||||
if (isEnabled && !this.aclRoleOpAll[name]) {
|
||||
this.$set(this.aclRoleOpAll, name, true);
|
||||
this.$set(this.aclRoleOpAll, name, true)
|
||||
}
|
||||
if (!isEnabled && this.aclRoleOpAll[name]) {
|
||||
this.$set(this.aclRoleOpAll, name, Object.entries(this.aclObj).some(([key, enabled]) => key.endsWith(name) && enabled));
|
||||
this.$set(this.aclRoleOpAll, name, Object.entries(this.aclObj).some(([key, enabled]) => key.endsWith(name) && enabled))
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
// watch: {
|
||||
// aclRoleOpAll: {
|
||||
// // todo: fix toggle issue
|
||||
@@ -418,9 +467,10 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
tr,th{
|
||||
tr, th {
|
||||
border: 1px solid grey;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border-left: 1px solid grey;
|
||||
}
|
||||
@@ -448,7 +498,6 @@ th.permission {
|
||||
// filter: none;
|
||||
//}
|
||||
|
||||
|
||||
::v-deep {
|
||||
.permission-checkbox-container .v-input {
|
||||
transform: scale(.8);
|
||||
@@ -459,7 +508,8 @@ th.permission {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
table{
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,81 @@
|
||||
<template>
|
||||
<v-row class="pa-0 ma-0">
|
||||
|
||||
<v-overlay absolute v-if="isMetaTable">
|
||||
<v-alert type="info">Meta tables are not editable</v-alert>
|
||||
<v-overlay v-if="isMetaTable" absolute>
|
||||
<v-alert type="info">
|
||||
Meta tables are not editable
|
||||
</v-alert>
|
||||
</v-overlay>
|
||||
|
||||
<v-col cols="12 pa-0">
|
||||
<v-card class="elevation-0">
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: this.nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: this.nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: this.nodes._tn + ' (table)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes._tn + ' (table)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Load Triggers"
|
||||
small
|
||||
class="primary"
|
||||
color="primary"
|
||||
@click="loadTriggerList"
|
||||
v-ge="['triggers','load']"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['triggers','load']"
|
||||
outlined
|
||||
tooltip="Load Triggers"
|
||||
small
|
||||
class="primary"
|
||||
color="primary"
|
||||
@click="loadTriggerList"
|
||||
>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Create New Trigger"
|
||||
small
|
||||
@click="showTriggerDlg()"
|
||||
class="primary"
|
||||
color="primary"
|
||||
icon="mdi-plus"
|
||||
v-ge="['triggers','new']"
|
||||
>New Trigger
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Delete Table"
|
||||
small
|
||||
icon="mdi-delete-outline"
|
||||
@click="deleteTable('showDialog')"
|
||||
class="error text-right"
|
||||
color="error "
|
||||
v-ge="['triggers','delete']"
|
||||
>Delete Table
|
||||
</x-btn
|
||||
<x-btn
|
||||
v-ge="['triggers','new']"
|
||||
outlined
|
||||
tooltip="Create New Trigger"
|
||||
small
|
||||
class="primary"
|
||||
color="primary"
|
||||
icon="mdi-plus"
|
||||
@click="showTriggerDlg()"
|
||||
>
|
||||
|
||||
|
||||
</v-toolbar
|
||||
>
|
||||
<v-skeleton-loader type="table" v-if="loading"></v-skeleton-loader>
|
||||
New Trigger
|
||||
</x-btn>
|
||||
<x-btn
|
||||
v-ge="['triggers','delete']"
|
||||
outlined
|
||||
tooltip="Delete Table"
|
||||
small
|
||||
icon="mdi-delete-outline"
|
||||
class="error text-right"
|
||||
color="error "
|
||||
@click="deleteTable('showDialog')"
|
||||
>
|
||||
Delete Table
|
||||
</x-btn>
|
||||
</v-toolbar>
|
||||
<v-skeleton-loader v-if="loading" type="table" />
|
||||
<v-data-table
|
||||
v-else
|
||||
dense
|
||||
@@ -70,7 +83,7 @@
|
||||
:items="triggers"
|
||||
footer-props.items-per-page-options="30"
|
||||
>
|
||||
<template v-slot:item="props">
|
||||
<template #item="props">
|
||||
<tr>
|
||||
<td>{{ props.item.trigger }}</td>
|
||||
<td>{{ props.item.event }}</td>
|
||||
@@ -78,17 +91,21 @@
|
||||
<td>{{ props.item.statement }}</td>
|
||||
<td>
|
||||
<div>
|
||||
<x-icon color="primary" @click="showTriggerDlg(props.item)"
|
||||
small
|
||||
v-ge="['triggers','edit']"
|
||||
>mdi-square-edit-outline
|
||||
<x-icon
|
||||
v-ge="['triggers','edit']"
|
||||
color="primary"
|
||||
small
|
||||
@click="showTriggerDlg(props.item)"
|
||||
>
|
||||
mdi-square-edit-outline
|
||||
</x-icon>
|
||||
<x-icon
|
||||
v-ge="['triggers','delete']"
|
||||
small
|
||||
color="error"
|
||||
@click="deleteTrigger('showDialog', props.item)"
|
||||
v-ge="['triggers','delete']"
|
||||
>mdi-delete-forever
|
||||
>
|
||||
mdi-delete-forever
|
||||
</x-icon>
|
||||
</div>
|
||||
</td>
|
||||
@@ -99,17 +116,17 @@
|
||||
<triggerAddEditDlg
|
||||
v-if="dialogShow"
|
||||
:nodes="nodes"
|
||||
:triggerObject="selectedTrigger"
|
||||
:newTrigger="!selectedTrigger.trigger"
|
||||
:dialogShow="dialogShow"
|
||||
:mtdDialogSubmit="mtdTriggerDlgSubmit"
|
||||
:mtdDialogCancel="mtdTriggerDlgCancel"
|
||||
:trigger-object="selectedTrigger"
|
||||
:new-trigger="!selectedTrigger.trigger"
|
||||
:dialog-show="dialogShow"
|
||||
:mtd-dialog-submit="mtdTriggerDlgSubmit"
|
||||
:mtd-dialog-cancel="mtdTriggerDlgCancel"
|
||||
/>
|
||||
<dlgLabelSubmitCancel
|
||||
type="error"
|
||||
v-if="showTriggerDeleteDialog"
|
||||
:dialogShow="showTriggerDeleteDialog"
|
||||
:actionsMtd="deleteTrigger"
|
||||
type="error"
|
||||
:dialog-show="showTriggerDeleteDialog"
|
||||
:actions-mtd="deleteTrigger"
|
||||
heading="Click Submit to Delete the Trigger"
|
||||
/>
|
||||
</v-col>
|
||||
@@ -117,34 +134,34 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters, mapActions} from "vuex";
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import triggerAddEditDlg from "../dlgs/dlgTriggerAddEdit";
|
||||
import dlgLabelSubmitCancel from "../../utils/dlgLabelSubmitCancel";
|
||||
import triggerAddEditDlg from '../dlgs/dlgTriggerAddEdit'
|
||||
import dlgLabelSubmitCancel from '../../utils/dlgLabelSubmitCancel'
|
||||
|
||||
export default {
|
||||
components: {triggerAddEditDlg, dlgLabelSubmitCancel},
|
||||
data() {
|
||||
components: { triggerAddEditDlg, dlgLabelSubmitCancel },
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
showTriggerDeleteDialog: false,
|
||||
triggers: [],
|
||||
headers: [
|
||||
{
|
||||
text: "Trigger Name",
|
||||
text: 'Trigger Name',
|
||||
sortable: false
|
||||
},
|
||||
{text: "Event", sortable: false},
|
||||
{text: "Timing", sortable: false},
|
||||
{text: "Statement", sortable: false},
|
||||
{text: "", sortable: false}
|
||||
{ text: 'Event', sortable: false },
|
||||
{ text: 'Timing', sortable: false },
|
||||
{ text: 'Statement', sortable: false },
|
||||
{ text: '', sortable: false }
|
||||
],
|
||||
dialogShow: false,
|
||||
selectedTrigger: null
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleKeyDown({metaKey, key, altKey, shiftKey, ctrlKey}) {
|
||||
async handleKeyDown ({ metaKey, key, altKey, shiftKey, ctrlKey }) {
|
||||
console.log(metaKey, key, altKey, shiftKey, ctrlKey)
|
||||
// cmd + s -> save
|
||||
// cmd + l -> reload
|
||||
@@ -157,25 +174,24 @@ export default {
|
||||
// await this.applyChanges();
|
||||
// break;
|
||||
case 'true_l' :
|
||||
await this.loadTriggerList();
|
||||
break;
|
||||
await this.loadTriggerList()
|
||||
break
|
||||
case 'true_n' :
|
||||
this.showTriggerDlg();
|
||||
break;
|
||||
this.showTriggerDlg()
|
||||
break
|
||||
case 'true_d' :
|
||||
await this.deleteTable('showDialog');
|
||||
break;
|
||||
|
||||
await this.deleteTable('showDialog')
|
||||
break
|
||||
}
|
||||
},
|
||||
|
||||
async loadTriggerList() {
|
||||
this.loading = true;
|
||||
async loadTriggerList () {
|
||||
this.loading = true
|
||||
try {
|
||||
this.$store.commit('notification/MutToggleProgressBar', true);
|
||||
this.$store.commit('notification/MutToggleProgressBar', true)
|
||||
if (this.newTable) {
|
||||
this.$store.commit('notification/MutToggleProgressBar', false);
|
||||
return;
|
||||
this.$store.commit('notification/MutToggleProgressBar', false)
|
||||
return
|
||||
}
|
||||
// const client = await this.sqlMgr.projectGetSqlClient({
|
||||
// env: this.nodes.env,
|
||||
@@ -200,122 +216,116 @@ export default {
|
||||
tn: this.nodes.tn
|
||||
}])
|
||||
|
||||
console.log("triggers", result.data.list);
|
||||
this.triggers = result.data.list;
|
||||
console.log('triggers', result.data.list)
|
||||
this.triggers = result.data.list
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log(e)
|
||||
} finally {
|
||||
this.$store.commit('notification/MutToggleProgressBar', false);
|
||||
this.$store.commit('notification/MutToggleProgressBar', false)
|
||||
}
|
||||
this.loading = false;
|
||||
|
||||
this.loading = false
|
||||
},
|
||||
showTriggerDlg(trigger) {
|
||||
if (trigger) this.selectedTrigger = trigger;
|
||||
else this.selectedTrigger = {};
|
||||
this.dialogShow = true;
|
||||
showTriggerDlg (trigger) {
|
||||
if (trigger) { this.selectedTrigger = trigger } else { this.selectedTrigger = {} }
|
||||
this.dialogShow = true
|
||||
},
|
||||
async mtdTriggerDlgSubmit(triggerObject, newTrigger) {
|
||||
async mtdTriggerDlgSubmit (triggerObject, newTrigger) {
|
||||
try {
|
||||
// const client = await this.sqlMgr.projectGetSqlClient({
|
||||
// env: this.nodes.env,
|
||||
// dbAlias: this.nodes.dbAlias
|
||||
// });
|
||||
if (newTrigger) {
|
||||
|
||||
|
||||
let result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [
|
||||
{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
},
|
||||
"triggerCreate",
|
||||
'triggerCreate',
|
||||
triggerObject
|
||||
]);
|
||||
console.log("triggerCreate result: ", result);
|
||||
this.$toast.success('Trigger created successfully').goAway(3000);
|
||||
])
|
||||
console.log('triggerCreate result: ', result)
|
||||
this.$toast.success('Trigger created successfully').goAway(3000)
|
||||
} else {
|
||||
|
||||
let result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [
|
||||
{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
},
|
||||
"triggerUpdate",
|
||||
'triggerUpdate',
|
||||
{
|
||||
...triggerObject,
|
||||
oldStatement: this.selectedTrigger.statement
|
||||
}]);
|
||||
}])
|
||||
|
||||
console.log("triggerUpdate result: ", result);
|
||||
this.$toast.success('Trigger updated successfully').goAway(3000);
|
||||
console.log('triggerUpdate result: ', result)
|
||||
this.$toast.success('Trigger updated successfully').goAway(3000)
|
||||
}
|
||||
|
||||
await this.loadTriggerList();
|
||||
this.selectedTrigger = null;
|
||||
this.dialogShow = false;
|
||||
await this.loadTriggerList()
|
||||
this.selectedTrigger = null
|
||||
this.dialogShow = false
|
||||
} catch (error) {
|
||||
console.error("triggerCreate error: ", error);
|
||||
console.error('triggerCreate error: ', error)
|
||||
}
|
||||
},
|
||||
mtdTriggerDlgCancel() {
|
||||
this.dialogShow = false;
|
||||
this.selectedTrigger = null;
|
||||
mtdTriggerDlgCancel () {
|
||||
this.dialogShow = false
|
||||
this.selectedTrigger = null
|
||||
},
|
||||
async deleteTrigger(action = "", trigger) {
|
||||
if (action === "showDialog") {
|
||||
this.showTriggerDeleteDialog = true;
|
||||
this.selectedTriggerForDelete = trigger;
|
||||
} else if (action === "hideDialog") {
|
||||
this.showTriggerDeleteDialog = false;
|
||||
this.selectedTriggerForDelete = null;
|
||||
async deleteTrigger (action = '', trigger) {
|
||||
if (action === 'showDialog') {
|
||||
this.showTriggerDeleteDialog = true
|
||||
this.selectedTriggerForDelete = trigger
|
||||
} else if (action === 'hideDialog') {
|
||||
this.showTriggerDeleteDialog = false
|
||||
this.selectedTriggerForDelete = null
|
||||
} else {
|
||||
|
||||
let result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [
|
||||
const result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [
|
||||
{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
},
|
||||
"triggerDelete",
|
||||
'triggerDelete',
|
||||
{
|
||||
...this.selectedTriggerForDelete,
|
||||
tn: this.nodes.tn,
|
||||
oldStatement: this.selectedTriggerForDelete.statement
|
||||
}]);
|
||||
}])
|
||||
|
||||
console.log("triggerDelete result ", result);
|
||||
await this.loadTriggerList();
|
||||
this.showTriggerDeleteDialog = false;
|
||||
this.selectedTriggerForDelete = null;
|
||||
console.log('triggerDelete result ', result)
|
||||
await this.loadTriggerList()
|
||||
this.showTriggerDeleteDialog = false
|
||||
this.selectedTriggerForDelete = null
|
||||
|
||||
this.$toast.success('Trigger deleted successfully').goAway(3000);
|
||||
this.$toast.success('Trigger deleted successfully').goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {...mapGetters({sqlMgr: "sqlMgr/sqlMgr"})},
|
||||
computed: { ...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }) },
|
||||
|
||||
beforeCreated() {
|
||||
beforeCreated () {
|
||||
},
|
||||
created() {
|
||||
this.loadTriggerList();
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
console.log("triggerlist before destroy");
|
||||
},
|
||||
destroy() {
|
||||
},
|
||||
validate({params}) {
|
||||
return true;
|
||||
},
|
||||
head() {
|
||||
return {};
|
||||
},
|
||||
props: ["nodes", "newTable", "deleteTable", 'isMetaTable'],
|
||||
watch: {},
|
||||
directives: {}
|
||||
};
|
||||
created () {
|
||||
this.loadTriggerList()
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
beforeDestroy () {
|
||||
console.log('triggerlist before destroy')
|
||||
},
|
||||
destroy () {
|
||||
},
|
||||
directives: {},
|
||||
validate ({ params }) {
|
||||
return true
|
||||
},
|
||||
head () {
|
||||
return {}
|
||||
},
|
||||
props: ['nodes', 'newTable', 'deleteTable', 'isMetaTable']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,36 +1,51 @@
|
||||
<template>
|
||||
<v-card class="pb-2">
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Validation Documentation"
|
||||
color="primary"
|
||||
small
|
||||
href="https://docs.nocodb.com/en/v0.5/database/database-model-validation" target="_blank">
|
||||
<v-icon small left>mdi-book-open-variant</v-icon>
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
outlined
|
||||
tooltip="Validation Documentation"
|
||||
color="primary"
|
||||
small
|
||||
href="https://docs.nocodb.com/en/v0.5/database/database-model-validation"
|
||||
target="_blank"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-book-open-variant
|
||||
</v-icon>
|
||||
Validation Docs
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Reload validation"
|
||||
color="primary"
|
||||
small
|
||||
@click="loadTableModelMeta">
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<x-btn
|
||||
outlined
|
||||
tooltip="Reload validation"
|
||||
color="primary"
|
||||
small
|
||||
@click="loadTableModelMeta"
|
||||
>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="!edited || loading"
|
||||
@click.prevent="saveValidations">
|
||||
<v-icon small left>save</v-icon>
|
||||
<x-btn
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="!edited || loading"
|
||||
@click.prevent="saveValidations"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
</v-toolbar>
|
||||
<template v-if="columns">
|
||||
|
||||
|
||||
<p class="title mt-6 mb-6"> Table : <span class="text-capitalize">{{ columns._tn }}</span><br>
|
||||
<span class="font-weight-thin">Write Validations For Columns</span></p>
|
||||
<p class="title mt-6 mb-6">
|
||||
Table : <span class="text-capitalize">{{ columns._tn }}</span><br>
|
||||
<span class="font-weight-thin">Write Validations For Columns</span>
|
||||
</p>
|
||||
|
||||
<!-- <v-row justify="center">
|
||||
<v-col cols="4" class="d-flex align-center">
|
||||
@@ -41,45 +56,51 @@
|
||||
</v-col>
|
||||
</v-row>-->
|
||||
|
||||
|
||||
<v-simple-table style="max-width:800px; margin:0 auto" class="mb-10" dense v-slot:default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Column Name</th>
|
||||
<th>Alias</th>
|
||||
<th>Validators</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item,i) in columns.columns">
|
||||
<td>{{ item.cn }}</td>
|
||||
<td>
|
||||
<v-edit-dialog lazy>
|
||||
<span> {{ item._cn }}</span>
|
||||
<template v-slot:input>
|
||||
<v-text-field
|
||||
@input="edited=true"
|
||||
v-model="item._cn"
|
||||
label="Edit"
|
||||
single-line
|
||||
></v-text-field>
|
||||
</template>
|
||||
</v-edit-dialog>
|
||||
</td>
|
||||
<td>
|
||||
<x-btn
|
||||
@click="editOrAddValidation(item)"
|
||||
:tooltip="`Edit/Add validation for '${item.cn}' column`" color="primary"
|
||||
style="text-transform:capitalize" x-small outlined>
|
||||
<v-icon class=" mr-1" x-small>mdi-lead-pencil</v-icon>
|
||||
Validation ({{ item.validate.func.length }})
|
||||
</x-btn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<v-simple-table style="max-width:800px; margin:0 auto" class="mb-10" dense>
|
||||
<template #default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Column Name</th>
|
||||
<th>Alias</th>
|
||||
<th>Validators</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item,i) in columns.columns" :key="i">
|
||||
<td>{{ item.cn }}</td>
|
||||
<td>
|
||||
<v-edit-dialog lazy>
|
||||
<span> {{ item._cn }}</span>
|
||||
<template #input>
|
||||
<v-text-field
|
||||
v-model="item._cn"
|
||||
label="Edit"
|
||||
single-line
|
||||
@input="edited=true"
|
||||
/>
|
||||
</template>
|
||||
</v-edit-dialog>
|
||||
</td>
|
||||
<td>
|
||||
<x-btn
|
||||
:tooltip="`Edit/Add validation for '${item.cn}' column`"
|
||||
color="primary"
|
||||
style="text-transform:capitalize"
|
||||
x-small
|
||||
outlined
|
||||
@click="editOrAddValidation(item)"
|
||||
>
|
||||
<v-icon class=" mr-1" x-small>
|
||||
mdi-lead-pencil
|
||||
</v-icon>
|
||||
Validation ({{ item.validate.func.length }})
|
||||
</x-btn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<!-- <v-expansion-panels accordion style="width: 70%; min-width: 500px; margin:5px auto">-->
|
||||
<!-- <v-expansion-panel-->
|
||||
<!-- v-for="(item,i) in columns.columns"-->
|
||||
@@ -158,7 +179,6 @@
|
||||
<!-- <!– </v-edit-dialog>–>-->
|
||||
<!-- <!– </td>–>-->
|
||||
|
||||
|
||||
<!-- <td>-->
|
||||
<!-- <x-icon-->
|
||||
<!-- small-->
|
||||
@@ -180,98 +200,115 @@
|
||||
<!-- </v-expansion-panels>-->
|
||||
</template>
|
||||
|
||||
|
||||
<v-dialog v-model="validatorEditDialog" max-width="700px">
|
||||
|
||||
<v-card v-if="clickedItem">
|
||||
<v-card-title class="headline justify-center mb-5">Validations for '{{ clickedItem.cn }}({{ clickedItem.dt }})'
|
||||
<v-card-title class="headline justify-center mb-5">
|
||||
Validations for '{{ clickedItem.cn }}({{ clickedItem.dt }})'
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
|
||||
<div class="d-flex">
|
||||
<v-spacer>
|
||||
</v-spacer>
|
||||
<v-spacer />
|
||||
|
||||
<v-btn outlined x-small @click="validatorEditDialog = false">Cancel</v-btn>
|
||||
<x-btn outlined tooltip="Add new validation"
|
||||
color="primary"
|
||||
x-small
|
||||
@click.prevent="(clickedItem.validate.func.push(''),edited=true,scrollAndFocusLastRowInModal())">
|
||||
<v-icon small left>mdi-plus</v-icon>
|
||||
<v-btn outlined x-small @click="validatorEditDialog = false">
|
||||
Cancel
|
||||
</v-btn>
|
||||
<x-btn
|
||||
outlined
|
||||
tooltip="Add new validation"
|
||||
color="primary"
|
||||
x-small
|
||||
@click.prevent="(clickedItem.validate.func.push(''),edited=true,scrollAndFocusLastRowInModal())"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
Add Validation
|
||||
</x-btn>
|
||||
<v-btn outlined color="primary" x-small @click.prevent="saveValidationForColumn(clickedItem)">Save</v-btn>
|
||||
<v-btn outlined color="primary" x-small @click.prevent="saveValidationForColumn(clickedItem)">
|
||||
Save
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-simple-table v-if="clickedItem.validate.func && clickedItem.validate.func.length" dense>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="caption font-weight-normal">Validation Function</th>
|
||||
<th class="caption font-weight-normal">Error Message</th>
|
||||
<!-- <th class="caption font-weight-normal">Optional Argument</th>-->
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="caption font-weight-normal">
|
||||
Validation Function
|
||||
</th>
|
||||
<th class="caption font-weight-normal">
|
||||
Error Message
|
||||
</th>
|
||||
<!-- <th class="caption font-weight-normal">Optional Argument</th>-->
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(func,i) in clickedItem.validate.func">
|
||||
<td>
|
||||
<v-edit-dialog
|
||||
lazy
|
||||
>
|
||||
<span>{{ func }}</span>
|
||||
<template v-slot:input>
|
||||
<tr v-for="(func,i) in clickedItem.validate.func" :key="i">
|
||||
<td>
|
||||
<v-edit-dialog
|
||||
lazy
|
||||
>
|
||||
<span>{{ func }}</span>
|
||||
<template #input>
|
||||
<v-autocomplete
|
||||
v-model="clickedItem.validate.func[i]"
|
||||
dense
|
||||
:items="fnList"
|
||||
item-text="func"
|
||||
@change="onFunctionChange(i,clickedItem)"
|
||||
/>
|
||||
</template>
|
||||
</v-edit-dialog>
|
||||
</td>
|
||||
<td>
|
||||
<v-edit-dialog lazy>
|
||||
<span> {{ clickedItem.validate.msg[i] }}</span>
|
||||
<template #input>
|
||||
<v-text-field
|
||||
v-model="clickedItem.validate.msg[i]"
|
||||
label="Edit"
|
||||
single-line
|
||||
@input="edited=true"
|
||||
/>
|
||||
</template>
|
||||
</v-edit-dialog>
|
||||
</td>
|
||||
<!-- <td>-->
|
||||
<!-- <v-edit-dialog lazy>-->
|
||||
<!-- <span> {{ clickedItem.validate.args[i] }}</span>-->
|
||||
<!-- <template v-slot:input>-->
|
||||
<!-- <v-text-field-->
|
||||
<!-- @input="edited=true"-->
|
||||
<!-- v-model="clickedItem.validate.args[i]"-->
|
||||
<!-- label="Edit"-->
|
||||
<!-- single-line-->
|
||||
<!-- ></v-text-field>-->
|
||||
<!-- </template>-->
|
||||
<!-- </v-edit-dialog>-->
|
||||
<!-- </td>-->
|
||||
|
||||
<v-autocomplete
|
||||
@change="onFunctionChange(i,clickedItem)"
|
||||
dense
|
||||
v-model="clickedItem.validate.func[i]"
|
||||
:items="fnList"
|
||||
item-text="func"
|
||||
></v-autocomplete>
|
||||
</template>
|
||||
</v-edit-dialog>
|
||||
</td>
|
||||
<td>
|
||||
<v-edit-dialog lazy>
|
||||
<span> {{ clickedItem.validate.msg[i] }}</span>
|
||||
<template v-slot:input>
|
||||
<v-text-field
|
||||
@input="edited=true"
|
||||
v-model="clickedItem.validate.msg[i]"
|
||||
label="Edit"
|
||||
single-line
|
||||
></v-text-field>
|
||||
</template>
|
||||
</v-edit-dialog>
|
||||
</td>
|
||||
<!-- <td>-->
|
||||
<!-- <v-edit-dialog lazy>-->
|
||||
<!-- <span> {{ clickedItem.validate.args[i] }}</span>-->
|
||||
<!-- <template v-slot:input>-->
|
||||
<!-- <v-text-field-->
|
||||
<!-- @input="edited=true"-->
|
||||
<!-- v-model="clickedItem.validate.args[i]"-->
|
||||
<!-- label="Edit"-->
|
||||
<!-- single-line-->
|
||||
<!-- ></v-text-field>-->
|
||||
<!-- </template>-->
|
||||
<!-- </v-edit-dialog>-->
|
||||
<!-- </td>-->
|
||||
|
||||
|
||||
<td>
|
||||
<x-icon
|
||||
small
|
||||
color="error" tooltip="Delete role" @click="deleteValidation(clickedItem,i)">
|
||||
mdi-delete-forever
|
||||
</x-icon>
|
||||
</td>
|
||||
</tr>
|
||||
<td>
|
||||
<x-icon
|
||||
small
|
||||
color="error"
|
||||
tooltip="Delete role"
|
||||
@click="deleteValidation(clickedItem,i)"
|
||||
>
|
||||
mdi-delete-forever
|
||||
</x-icon>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
<div v-else class="d-flex justify-center">
|
||||
<v-alert dense outlined type="info" color="grey lighten-1" icon="mdi-information-outline"
|
||||
class="caption mt-4"
|
||||
style="width:auto">
|
||||
<v-alert
|
||||
dense
|
||||
outlined
|
||||
type="info"
|
||||
color="grey lighten-1"
|
||||
icon="mdi-information-outline"
|
||||
class="caption mt-4"
|
||||
style="width:auto"
|
||||
>
|
||||
No validation for '{{ clickedItem.cn }}'
|
||||
</v-alert>
|
||||
</div>
|
||||
@@ -282,175 +319,171 @@
|
||||
<!-- </v-card-actions>-->
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {SqlUI} from "@/helpers/SqlUiFactory";
|
||||
|
||||
const validatorFnList = [{"func": "contains", "args": '', msg: 'Error contains'}, {
|
||||
"func": "equals",
|
||||
"args": '',
|
||||
const validatorFnList = [{ func: 'contains', args: '', msg: 'Error contains' }, {
|
||||
func: 'equals',
|
||||
args: '',
|
||||
msg: 'Error equals'
|
||||
}, {
|
||||
"func": "isAfter",
|
||||
"args": '',
|
||||
func: 'isAfter',
|
||||
args: '',
|
||||
msg: 'Error isAfter'
|
||||
}, {"func": "isAlpha", "args": '', msg: 'Error isAlpha'}, {
|
||||
"func": "isAlphanumeric",
|
||||
"args": '',
|
||||
}, { func: 'isAlpha', args: '', msg: 'Error isAlpha' }, {
|
||||
func: 'isAlphanumeric',
|
||||
args: '',
|
||||
msg: 'Error isAlphanumeric'
|
||||
}, {
|
||||
"func": "isAscii",
|
||||
"args": '',
|
||||
func: 'isAscii',
|
||||
args: '',
|
||||
msg: 'Error isAscii'
|
||||
}, {"func": "isBase32", "args": '', msg: 'Error isBase32'}, {"func": "isBase64", "args": '', msg: 'Error isBase64'}, {
|
||||
"func": "isBefore",
|
||||
"args": '',
|
||||
}, { func: 'isBase32', args: '', msg: 'Error isBase32' }, { func: 'isBase64', args: '', msg: 'Error isBase64' }, {
|
||||
func: 'isBefore',
|
||||
args: '',
|
||||
msg: 'Error isBefore'
|
||||
}, {"func": "isBIC", "args": '', msg: 'Error isBIC'}, {"func": "isBoolean", "args": '', msg: 'Error isBoolean'}, {
|
||||
"func": "isBtcAddress",
|
||||
"args": '',
|
||||
}, { func: 'isBIC', args: '', msg: 'Error isBIC' }, { func: 'isBoolean', args: '', msg: 'Error isBoolean' }, {
|
||||
func: 'isBtcAddress',
|
||||
args: '',
|
||||
msg: 'Error isBtcAddress'
|
||||
}, {"func": "isByteLength", "args": '', msg: 'Error isByteLength'}, {
|
||||
"func": "isCreditCard",
|
||||
"args": '',
|
||||
}, { func: 'isByteLength', args: '', msg: 'Error isByteLength' }, {
|
||||
func: 'isCreditCard',
|
||||
args: '',
|
||||
msg: 'Error isCreditCard'
|
||||
}, {
|
||||
"func": "isCurrency",
|
||||
"args": '',
|
||||
func: 'isCurrency',
|
||||
args: '',
|
||||
msg: 'Error isCurrency'
|
||||
}, {"func": "isDataURI", "args": '', msg: 'Error isDataURI'}, {"func": "isDate", "args": '', msg: 'Error isDate'}, {
|
||||
"func": "isDecimal",
|
||||
"args": '',
|
||||
}, { func: 'isDataURI', args: '', msg: 'Error isDataURI' }, { func: 'isDate', args: '', msg: 'Error isDate' }, {
|
||||
func: 'isDecimal',
|
||||
args: '',
|
||||
msg: 'Error isDecimal'
|
||||
}, {"func": "isDivisibleBy", "args": '', msg: 'Error isDivisibleBy'}, {
|
||||
"func": "isEAN",
|
||||
"args": '',
|
||||
}, { func: 'isDivisibleBy', args: '', msg: 'Error isDivisibleBy' }, {
|
||||
func: 'isEAN',
|
||||
args: '',
|
||||
msg: 'Error isEAN'
|
||||
}, {
|
||||
"func": "isEmail",
|
||||
"args": '',
|
||||
func: 'isEmail',
|
||||
args: '',
|
||||
msg: 'Error isEmail'
|
||||
}, {"func": "isEmpty", "args": '', msg: 'Error isEmpty'}, {
|
||||
"func": "isEthereumAddress",
|
||||
"args": '',
|
||||
}, { func: 'isEmpty', args: '', msg: 'Error isEmpty' }, {
|
||||
func: 'isEthereumAddress',
|
||||
args: '',
|
||||
msg: 'Error isEthereumAddress'
|
||||
}, {
|
||||
"func": "isFloat",
|
||||
"args": '',
|
||||
func: 'isFloat',
|
||||
args: '',
|
||||
msg: 'Error isFloat'
|
||||
}, {"func": "isFQDN", "args": '', msg: 'Error isFQDN'}, {"func": "isFullWidth", "args": '', msg: 'Error isFullWidth'}, {
|
||||
"func": "isHalfWidth",
|
||||
"args": '',
|
||||
}, { func: 'isFQDN', args: '', msg: 'Error isFQDN' }, { func: 'isFullWidth', args: '', msg: 'Error isFullWidth' }, {
|
||||
func: 'isHalfWidth',
|
||||
args: '',
|
||||
msg: 'Error isHalfWidth'
|
||||
}, {"func": "isHash", "args": '', msg: 'Error isHash'}, {
|
||||
"func": "isHexadecimal",
|
||||
"args": '',
|
||||
}, { func: 'isHash', args: '', msg: 'Error isHash' }, {
|
||||
func: 'isHexadecimal',
|
||||
args: '',
|
||||
msg: 'Error isHexadecimal'
|
||||
}, {
|
||||
"func": "isHexColor",
|
||||
"args": '',
|
||||
func: 'isHexColor',
|
||||
args: '',
|
||||
msg: 'Error isHexColor'
|
||||
}, {"func": "isHSL", "args": '', msg: 'Error isHSL'}, {"func": "isIBAN", "args": '', msg: 'Error isIBAN'}, {
|
||||
"func": "isIdentityCard",
|
||||
"args": '',
|
||||
}, { func: 'isHSL', args: '', msg: 'Error isHSL' }, { func: 'isIBAN', args: '', msg: 'Error isIBAN' }, {
|
||||
func: 'isIdentityCard',
|
||||
args: '',
|
||||
msg: 'Error isIdentityCard'
|
||||
}, {"func": "isIMEI", "args": '', msg: 'Error isIMEI'}, {
|
||||
"func": "isIn",
|
||||
"args": '',
|
||||
}, { func: 'isIMEI', args: '', msg: 'Error isIMEI' }, {
|
||||
func: 'isIn',
|
||||
args: '',
|
||||
msg: 'Error isIn'
|
||||
}, {"func": "isInt", "args": '', msg: 'Error isInt'}, {
|
||||
"func": "isIP",
|
||||
"args": '',
|
||||
}, { func: 'isInt', args: '', msg: 'Error isInt' }, {
|
||||
func: 'isIP',
|
||||
args: '',
|
||||
msg: 'Error isIP'
|
||||
}, {"func": "isIPRange", "args": '', msg: 'Error isIPRange'}, {"func": "isISBN", "args": '', msg: 'Error isISBN'}, {
|
||||
"func": "isISIN",
|
||||
"args": '',
|
||||
}, { func: 'isIPRange', args: '', msg: 'Error isIPRange' }, { func: 'isISBN', args: '', msg: 'Error isISBN' }, {
|
||||
func: 'isISIN',
|
||||
args: '',
|
||||
msg: 'Error isISIN'
|
||||
}, {"func": "isISO8601", "args": '', msg: 'Error isISO8601'}, {
|
||||
"func": "isISO31661Alpha2",
|
||||
"args": '',
|
||||
}, { func: 'isISO8601', args: '', msg: 'Error isISO8601' }, {
|
||||
func: 'isISO31661Alpha2',
|
||||
args: '',
|
||||
msg: 'Error isISO31661Alpha2'
|
||||
}, {
|
||||
"func": "isISO31661Alpha3",
|
||||
"args": '',
|
||||
func: 'isISO31661Alpha3',
|
||||
args: '',
|
||||
msg: 'Error isISO31661Alpha3'
|
||||
}, {"func": "isISRC", "args": '', msg: 'Error isISRC'}, {
|
||||
"func": "isISSN",
|
||||
"args": '',
|
||||
}, { func: 'isISRC', args: '', msg: 'Error isISRC' }, {
|
||||
func: 'isISSN',
|
||||
args: '',
|
||||
msg: 'Error isISSN'
|
||||
}, {"func": "isJSON", "args": '', msg: 'Error isJSON'}, {
|
||||
"func": "isJWT",
|
||||
"args": '',
|
||||
}, { func: 'isJSON', args: '', msg: 'Error isJSON' }, {
|
||||
func: 'isJWT',
|
||||
args: '',
|
||||
msg: 'Error isJWT'
|
||||
}, {"func": "isLatLong", "args": '', msg: 'Error isLatLong'}, {"func": "isLength", "args": '', msg: 'Error isLength'}, {
|
||||
"func": "isLocale",
|
||||
"args": '',
|
||||
}, { func: 'isLatLong', args: '', msg: 'Error isLatLong' }, { func: 'isLength', args: '', msg: 'Error isLength' }, {
|
||||
func: 'isLocale',
|
||||
args: '',
|
||||
msg: 'Error isLocale'
|
||||
}, {"func": "isLowercase", "args": '', msg: 'Error isLowercase'}, {
|
||||
"func": "isMACAddress",
|
||||
"args": '',
|
||||
}, { func: 'isLowercase', args: '', msg: 'Error isLowercase' }, {
|
||||
func: 'isMACAddress',
|
||||
args: '',
|
||||
msg: 'Error isMACAddress'
|
||||
}, {
|
||||
"func": "isMagnetURI",
|
||||
"args": '',
|
||||
func: 'isMagnetURI',
|
||||
args: '',
|
||||
msg: 'Error isMagnetURI'
|
||||
}, {"func": "isMD5", "args": '', msg: 'Error isMD5'}, {"func": "isMimeType", "args": '', msg: 'Error isMimeType'}, {
|
||||
"func": "isMobilePhone",
|
||||
"args": '',
|
||||
}, { func: 'isMD5', args: '', msg: 'Error isMD5' }, { func: 'isMimeType', args: '', msg: 'Error isMimeType' }, {
|
||||
func: 'isMobilePhone',
|
||||
args: '',
|
||||
msg: 'Error isMobilePhone'
|
||||
}, {"func": "isMongoId", "args": '', msg: 'Error isMongoId'}, {
|
||||
"func": "isMultibyte",
|
||||
"args": '',
|
||||
}, { func: 'isMongoId', args: '', msg: 'Error isMongoId' }, {
|
||||
func: 'isMultibyte',
|
||||
args: '',
|
||||
msg: 'Error isMultibyte'
|
||||
}, {
|
||||
"func": "isNumeric",
|
||||
"args": '',
|
||||
func: 'isNumeric',
|
||||
args: '',
|
||||
msg: 'Error isNumeric'
|
||||
}, {"func": "isOctal", "args": '', msg: 'Error isOctal'}, {
|
||||
"func": "isPassportNumber",
|
||||
"args": '',
|
||||
}, { func: 'isOctal', args: '', msg: 'Error isOctal' }, {
|
||||
func: 'isPassportNumber',
|
||||
args: '',
|
||||
msg: 'Error isPassportNumber'
|
||||
}, {
|
||||
"func": "isPort",
|
||||
"args": '',
|
||||
func: 'isPort',
|
||||
args: '',
|
||||
msg: 'Error isPort'
|
||||
}, {"func": "isPostalCode", "args": '', msg: 'Error isPostalCode'}, {
|
||||
"func": "isRFC3339",
|
||||
"args": '',
|
||||
}, { func: 'isPostalCode', args: '', msg: 'Error isPostalCode' }, {
|
||||
func: 'isRFC3339',
|
||||
args: '',
|
||||
msg: 'Error isRFC3339'
|
||||
}, {
|
||||
"func": "isRgbColor",
|
||||
"args": '',
|
||||
func: 'isRgbColor',
|
||||
args: '',
|
||||
msg: 'Error isRgbColor'
|
||||
}, {"func": "isSemVer", "args": '', msg: 'Error isSemVer'}, {
|
||||
"func": "isSurrogatePair",
|
||||
"args": '',
|
||||
}, { func: 'isSemVer', args: '', msg: 'Error isSemVer' }, {
|
||||
func: 'isSurrogatePair',
|
||||
args: '',
|
||||
msg: 'Error isSurrogatePair'
|
||||
}, {
|
||||
"func": "isUppercase",
|
||||
"args": '',
|
||||
func: 'isUppercase',
|
||||
args: '',
|
||||
msg: 'Error isUppercase'
|
||||
}, {"func": "isSlug", "args": '', msg: 'Error isSlug'}, {
|
||||
"func": "isTaxID",
|
||||
"args": '',
|
||||
}, { func: 'isSlug', args: '', msg: 'Error isSlug' }, {
|
||||
func: 'isTaxID',
|
||||
args: '',
|
||||
msg: 'Error isTaxID'
|
||||
}, {"func": "isURL", "args": '', msg: 'Error isURL'}, {
|
||||
"func": "isUUID",
|
||||
"args": '',
|
||||
}, { func: 'isURL', args: '', msg: 'Error isURL' }, {
|
||||
func: 'isUUID',
|
||||
args: '',
|
||||
msg: 'Error isUUID'
|
||||
}, {"func": "isVariableWidth", "args": '', msg: 'Error isVariableWidth'}, {
|
||||
"func": "isWhitelisted",
|
||||
"args": '',
|
||||
}, { func: 'isVariableWidth', args: '', msg: 'Error isVariableWidth' }, {
|
||||
func: 'isWhitelisted',
|
||||
args: '',
|
||||
msg: 'Error isWhitelisted'
|
||||
}, {"func": "matches", "args": '', msg: 'Error matches'}];
|
||||
}, { func: 'matches', args: '', msg: 'Error matches' }]
|
||||
|
||||
export default {
|
||||
name: "validation",
|
||||
name: 'Validation',
|
||||
props: ['nodes'],
|
||||
data: () => ({
|
||||
fnList: validatorFnList,
|
||||
@@ -462,14 +495,23 @@ export default {
|
||||
clickedItem: null,
|
||||
validatorEditDialog: false
|
||||
}),
|
||||
async created () {
|
||||
// try {
|
||||
// await this.loadColumnList();
|
||||
await this.loadTableModelMeta()
|
||||
// } catch (e) {
|
||||
// throw e
|
||||
// } finally {
|
||||
//
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
|
||||
editOrAddValidation(item) {
|
||||
this.clickedItem = JSON.parse(JSON.stringify(item));
|
||||
this.validatorEditDialog = true;
|
||||
editOrAddValidation (item) {
|
||||
this.clickedItem = JSON.parse(JSON.stringify(item))
|
||||
this.validatorEditDialog = true
|
||||
},
|
||||
|
||||
|
||||
// async loadColumnList() {
|
||||
// const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
// env: this.nodes.env,
|
||||
@@ -480,45 +522,45 @@ export default {
|
||||
// console.log("table ", result.data.list);
|
||||
// this.columns = result.data.list;
|
||||
// },
|
||||
async loadTableModelMeta() {
|
||||
this.edited = false;
|
||||
async loadTableModelMeta () {
|
||||
this.edited = false
|
||||
this.tableMeta = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcModelGet', {
|
||||
tn: this.nodes.tn
|
||||
}]);
|
||||
}])
|
||||
this.columns = JSON.parse(this.tableMeta.meta)
|
||||
},
|
||||
|
||||
scrollAndFocusLastRow() {
|
||||
scrollAndFocusLastRow () {
|
||||
this.$nextTick(() => {
|
||||
const menuActivator = this.$el && this.$el.querySelector('.v-expansion-panel--active table tr:last-child .v-small-dialog__activator__content');
|
||||
const menuActivator = this.$el && this.$el.querySelector('.v-expansion-panel--active table tr:last-child .v-small-dialog__activator__content')
|
||||
if (menuActivator) {
|
||||
menuActivator.click();
|
||||
menuActivator.click()
|
||||
this.$nextTick(() => {
|
||||
const inputField = document.querySelector('.menuable__content__active input');
|
||||
const inputField = document.querySelector('.menuable__content__active input')
|
||||
inputField && inputField.select()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
scrollAndFocusLastRowInModal() {
|
||||
scrollAndFocusLastRowInModal () {
|
||||
this.$nextTick(() => {
|
||||
const modal = document.querySelector('.v-dialog--active');
|
||||
modal.scrollTop = 99999;
|
||||
const menuActivator = modal.querySelector('table tr:last-child .v-small-dialog__activator__content');
|
||||
const modal = document.querySelector('.v-dialog--active')
|
||||
modal.scrollTop = 99999
|
||||
const menuActivator = modal.querySelector('table tr:last-child .v-small-dialog__activator__content')
|
||||
if (menuActivator) {
|
||||
menuActivator.click();
|
||||
menuActivator.click()
|
||||
this.$nextTick(() => {
|
||||
const inputField = document.querySelector('.menuable__content__active input');
|
||||
const inputField = document.querySelector('.menuable__content__active input')
|
||||
inputField && inputField.select()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
async saveValidations() {
|
||||
this.edited = false;
|
||||
async saveValidations () {
|
||||
this.edited = false
|
||||
try {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
@@ -526,47 +568,35 @@ export default {
|
||||
}, 'xcModelSet', {
|
||||
tn: this.nodes.tn,
|
||||
meta: this.columns
|
||||
}]);
|
||||
this.$toast.success('Successfully updated validations').goAway(3000);
|
||||
}])
|
||||
this.$toast.success('Successfully updated validations').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Failed to update validations').goAway(3000);
|
||||
this.$toast.error('Failed to update validations').goAway(3000)
|
||||
}
|
||||
},
|
||||
async saveValidationForColumn(clickedItem) {
|
||||
|
||||
async saveValidationForColumn (clickedItem) {
|
||||
if (clickedItem) {
|
||||
const item = this.columns.columns.find(it => it.cn === clickedItem.cn);
|
||||
const item = this.columns.columns.find(it => it.cn === clickedItem.cn)
|
||||
if (item) {
|
||||
Object.assign(item, clickedItem);
|
||||
await this.saveValidations();
|
||||
this.validatorEditDialog = false;
|
||||
this.clickedItem = null;
|
||||
Object.assign(item, clickedItem)
|
||||
await this.saveValidations()
|
||||
this.validatorEditDialog = false
|
||||
this.clickedItem = null
|
||||
}
|
||||
}
|
||||
},
|
||||
onFunctionChange(i, item) {
|
||||
this.edited = true;
|
||||
const fn = validatorFnList.find(({func}) => func === item.validate.func[i]);
|
||||
item.validate.msg[i] = `Validation failed : ${item.validate.func[i]}(${this.nodes.tn}.${item.cn})`;
|
||||
item.validate.args[i] = fn.args;
|
||||
onFunctionChange (i, item) {
|
||||
this.edited = true
|
||||
const fn = validatorFnList.find(({ func }) => func === item.validate.func[i])
|
||||
item.validate.msg[i] = `Validation failed : ${item.validate.func[i]}(${this.nodes.tn}.${item.cn})`
|
||||
item.validate.args[i] = fn.args
|
||||
},
|
||||
deleteValidation(item, i) {
|
||||
this.edited = true;
|
||||
item.validate.func.splice(i, 1);
|
||||
item.validate.args.splice(i, 1);
|
||||
item.validate.msg.splice(i, 1);
|
||||
deleteValidation (item, i) {
|
||||
this.edited = true
|
||||
item.validate.func.splice(i, 1)
|
||||
item.validate.args.splice(i, 1)
|
||||
item.validate.msg.splice(i, 1)
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
try {
|
||||
// await this.loadColumnList();
|
||||
await this.loadTableModelMeta();
|
||||
} catch (e) {
|
||||
throw e;
|
||||
} finally {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,96 +1,102 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<div class="d-flex">
|
||||
<v-select
|
||||
v-model="api.method"
|
||||
outlined
|
||||
dense
|
||||
class="caption"
|
||||
v-model="api.method"
|
||||
:items="Object.keys(apiMethodMeta)" style="max-width:100px;"></v-select>
|
||||
:items="Object.keys(apiMethodMeta)"
|
||||
style="max-width:100px;"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="api.path"
|
||||
outlined
|
||||
placeholder="http://example.com"
|
||||
v-model="api.path"
|
||||
dense class="flex-grow-1 ml-2 caption"></v-text-field>
|
||||
dense
|
||||
class="flex-grow-1 ml-2 caption"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<v-tabs
|
||||
v-model="tab"
|
||||
class="req-tabs"
|
||||
height="24"
|
||||
>
|
||||
<v-tab v-ge="['api-client','params']" class="caption"><span class="text-capitalize"> Params <b
|
||||
v-if="paramsCount"
|
||||
class="green--text">({{ paramsCount }})</b></span>
|
||||
<v-tab v-ge="['api-client','params']" class="caption">
|
||||
<span class="text-capitalize"> Params <b
|
||||
v-if="paramsCount"
|
||||
class="green--text"
|
||||
>({{ paramsCount }})</b></span>
|
||||
</v-tab>
|
||||
<v-tab class="caption" v-ge="['api-client','headers']"><span class="text-capitalize">Headers <b
|
||||
v-if="headersCount"
|
||||
class="green--text">({{
|
||||
<v-tab v-ge="['api-client','headers']" class="caption">
|
||||
<span class="text-capitalize">Headers <b
|
||||
v-if="headersCount"
|
||||
class="green--text"
|
||||
>({{
|
||||
headersCount
|
||||
}})</b></span>
|
||||
</v-tab>
|
||||
<v-tab class="caption" v-ge="['api-client','body']"><span class="text-capitalize">Body</span></v-tab>
|
||||
<v-tab class="caption" v-ge="['api-client','auth']"><span class="text-capitalize">Auth</span></v-tab>
|
||||
<v-tab v-ge="['api-client','body']" class="caption">
|
||||
<span class="text-capitalize">Body</span>
|
||||
</v-tab>
|
||||
<v-tab v-ge="['api-client','auth']" class="caption">
|
||||
<span class="text-capitalize">Auth</span>
|
||||
</v-tab>
|
||||
<v-tab-item>
|
||||
|
||||
<params v-model="api.parameters"
|
||||
:env.sync="selectedEnv"
|
||||
></params>
|
||||
<params
|
||||
v-model="api.parameters"
|
||||
:env.sync="selectedEnv"
|
||||
/>
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<headers v-model="api.headers"
|
||||
:env.sync="selectedEnv"
|
||||
></headers>
|
||||
<headers
|
||||
v-model="api.headers"
|
||||
:env.sync="selectedEnv"
|
||||
/>
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<monaco-json-editor
|
||||
style="height: 250px"
|
||||
class="editor card text-left"
|
||||
theme="vs-dark"
|
||||
v-model="api.body"
|
||||
lang="json"
|
||||
:options="{validate:true,documentFormattingEdits:true,foldingRanges:true}"
|
||||
>
|
||||
</monaco-json-editor>
|
||||
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<monaco-json-editor
|
||||
style="height: 250px"
|
||||
class="editor card text-left"
|
||||
theme="vs-dark"
|
||||
v-model="api.auth"
|
||||
lang="json"
|
||||
:options="{validate:true,documentFormattingEdits:true,foldingRanges:true}"
|
||||
>
|
||||
</monaco-json-editor>
|
||||
/>
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<monaco-json-editor
|
||||
v-model="api.auth"
|
||||
style="height: 250px"
|
||||
class="editor card text-left"
|
||||
theme="vs-dark"
|
||||
lang="json"
|
||||
:options="{validate:true,documentFormattingEdits:true,foldingRanges:true}"
|
||||
/>
|
||||
<span class="caption grey--text">For more about auth option refer <a href="https://github.com/axios/axios#request-config" target="_blank">axios docs</a>.</span>
|
||||
</v-tab-item>
|
||||
|
||||
|
||||
</v-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import params from "../../../apiClient/params";
|
||||
import headers from "../../../apiClient/headers";
|
||||
import params from '../../../apiClient/params'
|
||||
import headers from '../../../apiClient/headers'
|
||||
|
||||
import {MonacoJsonEditor} from "../../../monaco/index";
|
||||
import { MonacoJsonEditor } from '../../../monaco/index'
|
||||
|
||||
export default {
|
||||
tab:0,
|
||||
props: {
|
||||
value: Object
|
||||
},
|
||||
tab: 0,
|
||||
name: 'HttpWebhook',
|
||||
components: {
|
||||
params,
|
||||
headers,
|
||||
MonacoJsonEditor
|
||||
},
|
||||
name: "httpWebhook",
|
||||
props: {
|
||||
value: Object
|
||||
},
|
||||
data: () => ({
|
||||
apiMethodMeta: {
|
||||
GET: {
|
||||
@@ -110,7 +116,7 @@ export default {
|
||||
},
|
||||
PATCH: {
|
||||
color: 'info'
|
||||
},
|
||||
}
|
||||
},
|
||||
selectedEnv: 'dev',
|
||||
environmentList: ['dev'],
|
||||
@@ -125,32 +131,31 @@ export default {
|
||||
response: {},
|
||||
perf: {},
|
||||
meta: {}
|
||||
},
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
this.api = this.value || this.api;
|
||||
computed: {
|
||||
|
||||
paramsCount () {
|
||||
return this.api.parameters && this.api.parameters.filter(p => p.name && p.enabled).length
|
||||
},
|
||||
headersCount () {
|
||||
return this.api.headers && this.api.headers.filter(h => h.name && h.enabled).length
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
value () {
|
||||
if (this.api !== this.value) {
|
||||
this.api = this.value || this.api;
|
||||
this.api = this.value || this.api
|
||||
}
|
||||
},
|
||||
api: {
|
||||
handler() {
|
||||
handler () {
|
||||
this.$emit('input', this.api)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
paramsCount() {
|
||||
return this.api.parameters && this.api.parameters.filter(p => p.name && p.enabled).length;
|
||||
},
|
||||
headersCount() {
|
||||
|
||||
return this.api.headers && this.api.headers.filter(h => h.name && h.enabled).length;
|
||||
},
|
||||
created () {
|
||||
this.api = this.value || this.api
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,42 +1,41 @@
|
||||
<template>
|
||||
|
||||
<v-select
|
||||
v-model="hookEvent"
|
||||
class="caption"
|
||||
outlined
|
||||
dense
|
||||
v-model="hookEvent"
|
||||
label="Event"
|
||||
required
|
||||
:items="eventList"
|
||||
:item-text="v => v.text.join(' ')"
|
||||
:item-value="v => v.value.join(' ')"
|
||||
:rules="[v => !!v || 'Event Required']"
|
||||
>
|
||||
</v-select>
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "webhookEvent",
|
||||
name: 'WebhookEvent',
|
||||
props: ['operation', 'event'],
|
||||
data: () => ({
|
||||
eventList: [
|
||||
// {text: ["Before", "Insert"], value: ['before', 'insert']},
|
||||
{text: ["After", "Insert"], value: ['after', 'insert']},
|
||||
{ text: ['After', 'Insert'], value: ['after', 'insert'] },
|
||||
// {text: ["Before", "Update"], value: ['before', 'update']},
|
||||
{text: ["After", "Update"], value: ['after', 'update']},
|
||||
{ text: ['After', 'Update'], value: ['after', 'update'] },
|
||||
// {text: ["Before", "Delete"], value: ['before', 'delete']},
|
||||
{text: ["After", "Delete"], value: ['after', 'delete']},
|
||||
],
|
||||
{ text: ['After', 'Delete'], value: ['after', 'delete'] }
|
||||
]
|
||||
}),
|
||||
computed: {
|
||||
hookEvent: {
|
||||
get() {
|
||||
get () {
|
||||
return `${this.event} ${this.operation}`
|
||||
}, set(v) {
|
||||
const [event, operation] = v.split(' ');
|
||||
this.$emit('update:event', event);
|
||||
this.$emit('update:operation', operation);
|
||||
},
|
||||
set (v) {
|
||||
const [event, operation] = v.split(' ')
|
||||
this.$emit('update:event', event)
|
||||
this.$emit('update:operation', operation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,55 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (Webhooks)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes.tn + ' (Webhooks)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="loading || !valid || !hook.event"
|
||||
<x-btn
|
||||
v-ge="['rows','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
|
||||
v-ge="['rows','save']"
|
||||
@click.prevent="saveHooks">
|
||||
<v-icon small left>save</v-icon>
|
||||
:disabled="loading || !valid || !hook.event"
|
||||
@click.prevent="saveHooks"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-form
|
||||
ref="form"
|
||||
v-model="valid"
|
||||
class="mx-auto"
|
||||
ref="form"
|
||||
lazy-validation
|
||||
>
|
||||
<v-card>
|
||||
@@ -50,29 +57,33 @@
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
<v-radio-group v-model="hook.event" @change="onEventChange">
|
||||
|
||||
<template v-slot:default>
|
||||
<template #default>
|
||||
<v-simple-table dense>
|
||||
<template v-slot:default>
|
||||
<template #default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Operation</th>
|
||||
<th>Event</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th />
|
||||
<th>Operation</th>
|
||||
<th>Event</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for="(e,i) in eventList" :key="i"
|
||||
:class="{'primary lighten-4 black--text': e.value === hook.event}">
|
||||
<td>
|
||||
<v-radio :value="e.value"></v-radio>
|
||||
</td>
|
||||
<td> {{ e.text[1] }}
|
||||
</td>
|
||||
<td> {{ e.text[0] }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="(e,i) in eventList"
|
||||
:key="i"
|
||||
:class="{'primary lighten-4 black--text': e.value === hook.event}"
|
||||
>
|
||||
<td>
|
||||
<v-radio :value="e.value" />
|
||||
</td>
|
||||
<td>
|
||||
{{ e.text[1] }}
|
||||
</td>
|
||||
<td>
|
||||
{{ e.text[0] }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
@@ -83,7 +94,6 @@
|
||||
<!-- <v-radio v-for="(e,i) in eventList" :key="i" :label="e.text" :value="e.v"></v-radio>-->
|
||||
<!-- </v-radio-group>-->
|
||||
|
||||
|
||||
<!-- <v-select-->
|
||||
<!-- v-model="hook.event"-->
|
||||
<!-- :items="['Before','After']"-->
|
||||
@@ -103,21 +113,20 @@
|
||||
<v-card-title>Webhook</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
:disabled="!hook.event"
|
||||
v-model="hook.title"
|
||||
:disabled="!hook.event"
|
||||
label="Title"
|
||||
required
|
||||
:rules="[v => !!v || 'Title Required']"
|
||||
></v-text-field>
|
||||
/>
|
||||
<v-text-field
|
||||
:disabled="!hook.event"
|
||||
v-model="hook.url"
|
||||
:disabled="!hook.event"
|
||||
label="URL"
|
||||
required
|
||||
type="url"
|
||||
:rules="urlRules"
|
||||
></v-text-field>
|
||||
|
||||
/>
|
||||
|
||||
<!-- <v-textarea-->
|
||||
<!-- v-model="hook.header"-->
|
||||
@@ -131,35 +140,33 @@
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-form>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "webhooks",
|
||||
name: 'Webhooks',
|
||||
props: ['nodes'],
|
||||
data: () => ({
|
||||
valid: false,
|
||||
loading: false,
|
||||
eventList: [
|
||||
{text: ["Before", "Insert"], value: ['before', 'insert']},
|
||||
{text: ["After", "Insert"], value: ['after', 'insert']},
|
||||
{text: ["Before", "Update"], value: ['before', 'update']},
|
||||
{text: ["After", "Update"], value: ['after', 'update']},
|
||||
{text: ["Before", "Delete"], value: ['before', 'delete']},
|
||||
{text: ["After", "Delete"], value: ['after', 'delete']},
|
||||
{ text: ['Before', 'Insert'], value: ['before', 'insert'] },
|
||||
{ text: ['After', 'Insert'], value: ['after', 'insert'] },
|
||||
{ text: ['Before', 'Update'], value: ['before', 'update'] },
|
||||
{ text: ['After', 'Update'], value: ['after', 'update'] },
|
||||
{ text: ['Before', 'Delete'], value: ['before', 'delete'] },
|
||||
{ text: ['After', 'Delete'], value: ['after', 'delete'] }
|
||||
],
|
||||
hook: {},
|
||||
urlRules: [
|
||||
v => !v || !v.trim() || /^https?:\/\/.{1,}/.test(v) || 'Not a valid URL',
|
||||
v => !v || !v.trim() || /^https?:\/\/.{1,}/.test(v) || 'Not a valid URL'
|
||||
]
|
||||
|
||||
}),
|
||||
methods: {
|
||||
async onEventChange() {
|
||||
this.loading = true;
|
||||
async onEventChange () {
|
||||
this.loading = true
|
||||
this.hook = {
|
||||
...this.hook,
|
||||
url: '',
|
||||
@@ -169,16 +176,16 @@ export default {
|
||||
const result = (await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcHooksGet', {
|
||||
tn: this.nodes.tn,
|
||||
data: {
|
||||
event: this.hook.event[0],
|
||||
operation: this.hook.event[1],
|
||||
operation: this.hook.event[1]
|
||||
}
|
||||
}
|
||||
]));
|
||||
const hooksDetails = result && result.data.list && result.data.list[0];
|
||||
]))
|
||||
const hooksDetails = result && result.data.list && result.data.list[0]
|
||||
|
||||
if (hooksDetails) {
|
||||
this.hook = {
|
||||
@@ -187,28 +194,28 @@ export default {
|
||||
title: hooksDetails.title
|
||||
}
|
||||
}
|
||||
this.loading = false;
|
||||
this.loading = false
|
||||
},
|
||||
async saveHooks() {
|
||||
async saveHooks () {
|
||||
if (!this.valid || !this.hook.event) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
this.loading = true;
|
||||
let hooksDetails = (await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
this.loading = true
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcHooksSet', {
|
||||
tn: this.nodes.tn,
|
||||
data: {
|
||||
...this.hook,
|
||||
event: this.hook.event[0],
|
||||
operation: this.hook.event[1],
|
||||
operation: this.hook.event[1]
|
||||
}
|
||||
}
|
||||
])).data;
|
||||
this.$toast.success('Webhook details updated successfully').goAway(3000);
|
||||
this.loading = false;
|
||||
])
|
||||
this.$toast.success('Webhook details updated successfully').goAway(3000)
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,59 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<v-toolbar flat height="42" class="toolbar-border-bottom">
|
||||
<v-toolbar-title>
|
||||
<v-breadcrumbs :items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes._tn + ' (Webhooks)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]" divider=">" small>
|
||||
<template v-slot:divider>
|
||||
<v-icon small color="grey lighten-2">forward</v-icon>
|
||||
<v-breadcrumbs
|
||||
:items="[{
|
||||
text: nodes.env,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},{
|
||||
text: nodes.dbAlias,
|
||||
disabled: true,
|
||||
href: '#'
|
||||
},
|
||||
{
|
||||
text: nodes._tn + ' (Webhooks)',
|
||||
disabled: true,
|
||||
href: '#'
|
||||
}]"
|
||||
divider=">"
|
||||
small
|
||||
>
|
||||
<template #divider>
|
||||
<v-icon small color="grey lighten-2">
|
||||
forward
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
|
||||
|
||||
<x-btn outlined tooltip="Reload hooks"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['hooks','reload']"
|
||||
@click.prevent="loadHooksList">
|
||||
<v-icon small left>mdi-reload</v-icon>
|
||||
<x-btn
|
||||
v-ge="['hooks','reload']"
|
||||
outlined
|
||||
tooltip="Reload hooks"
|
||||
color="primary"
|
||||
small
|
||||
@click.prevent="loadHooksList"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-reload
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
|
||||
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['hooks','add new']"
|
||||
@click.prevent="addNewHook">
|
||||
<v-icon small left>mdi-plus</v-icon>
|
||||
<x-btn
|
||||
v-ge="['hooks','add new']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
@click.prevent="addNewHook"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
Add New
|
||||
</x-btn>
|
||||
|
||||
@@ -55,163 +67,171 @@
|
||||
<v-icon small left>save</v-icon>
|
||||
Save
|
||||
</x-btn>-->
|
||||
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-form
|
||||
ref="form"
|
||||
v-model="valid"
|
||||
class="mx-auto"
|
||||
ref="form"
|
||||
lazy-validation
|
||||
>
|
||||
<v-card>
|
||||
<v-container fluid>
|
||||
|
||||
|
||||
<v-row>
|
||||
<v-col cols="7">
|
||||
<v-radio-group v-model="selectedHook" @change="onEventChange" v-slot:default>
|
||||
<v-simple-table dense v-slot:default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
</th>
|
||||
<th>Title</th>
|
||||
<th>Event</th>
|
||||
<th>Condition</th>
|
||||
<th>Notify Via</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<v-radio-group v-model="selectedHook" @change="onEventChange">
|
||||
<template #default>
|
||||
<v-simple-table dense>
|
||||
<template #default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
<th>Title</th>
|
||||
<th>Event</th>
|
||||
<th>Condition</th>
|
||||
<th>Notify Via</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<template v-if="hooks && hooks.length">
|
||||
<tr v-for="(item,i) in hooks">
|
||||
<td>
|
||||
<v-radio :value="i"></v-radio>
|
||||
</td>
|
||||
<td>{{ item.title }}</td>
|
||||
<td>{{ item.event }} {{ item.operation }}</td>
|
||||
<td>
|
||||
<v-icon v-if="item.condition" color="success" small>mdi-check-bold</v-icon>
|
||||
</td>
|
||||
<td>{{ item.notification && item.notification.type }}</td>
|
||||
<td>
|
||||
<x-icon small color="error" @click.stop="deleteHook(item, i)">mdi-delete</x-icon>
|
||||
<!-- <x-icon small :color="loading || !valid || !hook.event ? 'grey' : 'primary'"
|
||||
@click.stop="(!loading && valid && hook.event) && saveHooks()">save
|
||||
</x-icon>-->
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</template>
|
||||
<tr v-else>
|
||||
<td colspan="6" class="text-center py-5">
|
||||
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
v-ge="['hooks','add new']"
|
||||
@click.prevent="addNewHook">
|
||||
<v-icon small left>mdi-plus</v-icon>
|
||||
Add New Webhook
|
||||
</x-btn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
</v-simple-table>
|
||||
<tbody>
|
||||
<template v-if="hooks && hooks.length">
|
||||
<tr v-for="(item,i) in hooks" :key="i">
|
||||
<td>
|
||||
<v-radio :value="i" />
|
||||
</td>
|
||||
<td>{{ item.title }}</td>
|
||||
<td>{{ item.event }} {{ item.operation }}</td>
|
||||
<td>
|
||||
<v-icon v-if="item.condition" color="success" small>
|
||||
mdi-check-bold
|
||||
</v-icon>
|
||||
</td>
|
||||
<td>{{ item.notification && item.notification.type }}</td>
|
||||
<td>
|
||||
<x-icon small color="error" @click.stop="deleteHook(item, i)">
|
||||
mdi-delete
|
||||
</x-icon>
|
||||
<!-- <x-icon small :color="loading || !valid || !hook.event ? 'grey' : 'primary'"
|
||||
@click.stop="(!loading && valid && hook.event) && saveHooks()">save
|
||||
</x-icon>-->
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr v-else>
|
||||
<td colspan="6" class="text-center py-5">
|
||||
<x-btn
|
||||
v-ge="['hooks','add new']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
@click.prevent="addNewHook"
|
||||
>
|
||||
<v-icon small left>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
Add New Webhook
|
||||
</x-btn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
</template>
|
||||
</v-radio-group>
|
||||
</v-col>
|
||||
<v-col cols="5">
|
||||
<v-card class="" v-if="hook">
|
||||
<v-card v-if="hook" class="">
|
||||
<v-card-title>
|
||||
Webhook
|
||||
<v-spacer></v-spacer>
|
||||
<x-btn outlined tooltip="Save"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="loading || !valid || !hook.event"
|
||||
<v-spacer />
|
||||
<x-btn
|
||||
v-ge="['hooks','save']"
|
||||
outlined
|
||||
tooltip="Save"
|
||||
color="primary"
|
||||
small
|
||||
|
||||
v-ge="['hooks','save']"
|
||||
@click.prevent="saveHooks">
|
||||
<v-icon small left>save</v-icon>
|
||||
:disabled="loading || !valid || !hook.event"
|
||||
@click.prevent="saveHooks"
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
|
||||
<v-text-field
|
||||
v-model="hook.title"
|
||||
class="caption"
|
||||
outlined
|
||||
dense
|
||||
v-model="hook.title"
|
||||
label="Title"
|
||||
required
|
||||
:rules="[v => !!v || 'Title Required']"
|
||||
></v-text-field>
|
||||
|
||||
<webhook-event :event.sync="hook.event"
|
||||
:operation.sync="hook.operation"
|
||||
></webhook-event>
|
||||
/>
|
||||
|
||||
<webhook-event
|
||||
:event.sync="hook.event"
|
||||
:operation.sync="hook.operation"
|
||||
/>
|
||||
|
||||
<v-card class="mb-8">
|
||||
<v-card-text>
|
||||
<v-checkbox
|
||||
v-model="enableCondition"
|
||||
dense
|
||||
@change="checkConditionAvail"
|
||||
hide-details
|
||||
class="mt-1"
|
||||
label="On Condition"
|
||||
v-model="enableCondition"
|
||||
></v-checkbox>
|
||||
@change="checkConditionAvail"
|
||||
/>
|
||||
|
||||
|
||||
<column-filter v-if="enableCondition && _isEE"
|
||||
:field-list="fieldList"
|
||||
v-model="hook.condition"
|
||||
dense style="max-width: 100%">
|
||||
</column-filter>
|
||||
<column-filter
|
||||
v-if="enableCondition && _isEE"
|
||||
v-model="hook.condition"
|
||||
:field-list="fieldList"
|
||||
dense
|
||||
style="max-width: 100%"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-select
|
||||
v-model="hook.notification.type"
|
||||
outlined
|
||||
dense
|
||||
v-model="hook.notification.type"
|
||||
label="Notification"
|
||||
required
|
||||
:items="notificationList"
|
||||
:rules="[v => !!v || 'Title Required']"
|
||||
class="caption"
|
||||
@change="onNotTypeChange"
|
||||
:prepend-inner-icon="notificationIcon[hook.notification.type]"
|
||||
@change="onNotTypeChange"
|
||||
>
|
||||
|
||||
<template v-slot:item="{item}">
|
||||
<template #item="{item}">
|
||||
<v-list-item-icon>
|
||||
<v-icon small>{{ notificationIcon[item] }}</v-icon>
|
||||
<v-icon small>
|
||||
{{ notificationIcon[item] }}
|
||||
</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>
|
||||
{{ item }}
|
||||
</v-list-item-title>
|
||||
|
||||
</template>
|
||||
|
||||
</v-select>
|
||||
|
||||
|
||||
<template v-if="hook.notification.type === 'URL'">
|
||||
<http-webhook v-model="notification"></http-webhook>
|
||||
<http-webhook v-model="notification" />
|
||||
</template>
|
||||
|
||||
<template v-if="hook.notification.type === 'Slack'">
|
||||
<v-combobox
|
||||
v-if="slackChannels"
|
||||
:rules="[v => !!v || 'Required']"
|
||||
v-model="notification.channels"
|
||||
:rules="[v => !!v || 'Required']"
|
||||
:items="slackChannels"
|
||||
item-text="channel"
|
||||
label="Select Slack channels"
|
||||
@@ -219,14 +239,13 @@
|
||||
outlined
|
||||
dense
|
||||
class="caption"
|
||||
>
|
||||
</v-combobox>
|
||||
/>
|
||||
</template>
|
||||
<template v-if="hook.notification.type === 'Microsoft Teams'">
|
||||
<v-combobox
|
||||
v-if="teamsChannels"
|
||||
:rules="[v => !!v || 'Required']"
|
||||
v-model="notification.channels"
|
||||
:rules="[v => !!v || 'Required']"
|
||||
:items="teamsChannels"
|
||||
item-text="channel"
|
||||
label="Select Teams channels"
|
||||
@@ -234,14 +253,13 @@
|
||||
outlined
|
||||
dense
|
||||
class="caption"
|
||||
>
|
||||
</v-combobox>
|
||||
/>
|
||||
</template>
|
||||
<template v-if="hook.notification.type === 'Discord'">
|
||||
<v-combobox
|
||||
v-if="discordChannels"
|
||||
:rules="[v => !!v || 'Required']"
|
||||
v-model="notification.channels"
|
||||
:rules="[v => !!v || 'Required']"
|
||||
:items="discordChannels"
|
||||
item-text="channel"
|
||||
label="Select Discord channels"
|
||||
@@ -249,14 +267,13 @@
|
||||
outlined
|
||||
dense
|
||||
class="caption"
|
||||
>
|
||||
</v-combobox>
|
||||
/>
|
||||
</template>
|
||||
<template v-if="hook.notification.type === 'Mattermost'">
|
||||
<v-combobox
|
||||
v-if="mattermostChannels"
|
||||
:rules="[v => !!v || 'Required']"
|
||||
v-model="notification.channels"
|
||||
:rules="[v => !!v || 'Required']"
|
||||
:items="mattermostChannels"
|
||||
item-text="channel"
|
||||
label="Select Mattermost channels"
|
||||
@@ -264,73 +281,80 @@
|
||||
outlined
|
||||
dense
|
||||
class="caption"
|
||||
>
|
||||
</v-combobox>
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-if="inputs[hook.notification.type] && notification">
|
||||
<template v-for="input in inputs[hook.notification.type]">
|
||||
|
||||
|
||||
<v-textarea class="caption" :key="input.key"
|
||||
dense outlined v-if="input.type === 'LongText'"
|
||||
:label="input.label"
|
||||
v-model="notification[input.key]"
|
||||
:rules="[v => !input.required || !!v || 'Required']"
|
||||
></v-textarea>
|
||||
<v-text-field class="caption" :key="input.key"
|
||||
dense outlined v-else :label="input.label"
|
||||
v-model="notification[input.key]"
|
||||
:rules="[v => !input.required || !!v || 'Required']"
|
||||
></v-text-field>
|
||||
<v-textarea
|
||||
v-if="input.type === 'LongText'"
|
||||
:key="input.key"
|
||||
v-model="notification[input.key]"
|
||||
class="caption"
|
||||
dense
|
||||
outlined
|
||||
:label="input.label"
|
||||
:rules="[v => !input.required || !!v || 'Required']"
|
||||
/>
|
||||
<v-text-field
|
||||
v-else
|
||||
:key="input.key"
|
||||
v-model="notification[input.key]"
|
||||
class="caption"
|
||||
dense
|
||||
outlined
|
||||
:label="input.label"
|
||||
:rules="[v => !input.required || !!v || 'Required']"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</v-card-text>
|
||||
|
||||
|
||||
<v-card-text>
|
||||
<span class="caption grey--text">
|
||||
<em>Available context variables are <strong>data, user, payload and env</strong></em>
|
||||
<v-tooltip top>
|
||||
<template #activator="{on}">
|
||||
<v-icon small
|
||||
v-on="on"
|
||||
color="grey"
|
||||
class="ml-2">mdi-information</v-icon>
|
||||
</template>
|
||||
<span class="caption">
|
||||
<strong>data</strong> : Row data <br>
|
||||
<strong>user</strong> : User information<br>
|
||||
<strong>payload</strong> : Plugin settings payload<br>
|
||||
<strong>env</strong> : Environment values (process.env)
|
||||
<v-icon
|
||||
small
|
||||
color="grey"
|
||||
class="ml-2"
|
||||
v-on="on"
|
||||
>mdi-information</v-icon>
|
||||
</template>
|
||||
<span class="caption">
|
||||
<strong>data</strong> : Row data <br>
|
||||
<strong>user</strong> : User information<br>
|
||||
<strong>payload</strong> : Plugin settings payload<br>
|
||||
<strong>env</strong> : Environment values (process.env)
|
||||
|
||||
</span>
|
||||
</span>
|
||||
</v-tooltip>
|
||||
</span>
|
||||
</v-card-text>
|
||||
|
||||
</v-card>
|
||||
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-form>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ColumnFilter from "~/components/project/spreadsheet/components/columnFilter";
|
||||
import FormInput from "~/components/project/appStore/FormInput";
|
||||
import WebhookEvent from "~/components/project/tableTabs/webhookEvent";
|
||||
import HttpWebhook from "./webhook/httpWebhook";
|
||||
import HttpWebhook from './webhook/httpWebhook'
|
||||
import ColumnFilter from '~/components/project/spreadsheet/components/columnFilter'
|
||||
// import FormInput from '~/components/project/appStore/FormInput'
|
||||
import WebhookEvent from '~/components/project/tableTabs/webhookEvent'
|
||||
|
||||
export default {
|
||||
name: "webhooks",
|
||||
components: {HttpWebhook, WebhookEvent, FormInput, ColumnFilter},
|
||||
name: 'Webhooks',
|
||||
components: {
|
||||
HttpWebhook,
|
||||
WebhookEvent,
|
||||
// FormInput,
|
||||
ColumnFilter
|
||||
},
|
||||
props: ['nodes'],
|
||||
data: () => ({
|
||||
slackChannels: null,
|
||||
@@ -350,23 +374,23 @@ export default {
|
||||
'Mattermost',
|
||||
'Twilio',
|
||||
'Whatsapp Twilio',
|
||||
'URL',
|
||||
'URL'
|
||||
],
|
||||
filters: [],
|
||||
hook: null,
|
||||
notification: {},
|
||||
notificationIcon: {
|
||||
'URL': 'mdi-link',
|
||||
'Email': 'mdi-email',
|
||||
'Slack': 'mdi-slack',
|
||||
URL: 'mdi-link',
|
||||
Email: 'mdi-email',
|
||||
Slack: 'mdi-slack',
|
||||
'Microsoft Teams': 'mdi-microsoft-teams',
|
||||
'Discord': 'mdi-discord',
|
||||
'Mattermost': 'mdi-chat',
|
||||
Discord: 'mdi-discord',
|
||||
Mattermost: 'mdi-chat',
|
||||
'Whatsapp Twilio': 'mdi-whatsapp',
|
||||
'Twilio': 'mdi-cellphone-message',
|
||||
Twilio: 'mdi-cellphone-message'
|
||||
},
|
||||
urlRules: [
|
||||
v => !v || !v.trim() || /^https?:\/\/.{1,}/.test(v) || 'Not a valid URL',
|
||||
v => !v || !v.trim() || /^https?:\/\/.{1,}/.test(v) || 'Not a valid URL'
|
||||
],
|
||||
fieldList: [],
|
||||
inputs: {
|
||||
@@ -391,35 +415,40 @@ export default {
|
||||
type: 'LongText',
|
||||
required: true
|
||||
}
|
||||
], Slack: [{
|
||||
],
|
||||
Slack: [{
|
||||
key: 'body',
|
||||
label: 'Body',
|
||||
placeholder: 'Body',
|
||||
type: 'LongText',
|
||||
required: true
|
||||
}
|
||||
], 'Microsoft Teams': [{
|
||||
],
|
||||
'Microsoft Teams': [{
|
||||
key: 'body',
|
||||
label: 'Body',
|
||||
placeholder: 'Body',
|
||||
type: 'LongText',
|
||||
required: true
|
||||
}
|
||||
], Discord: [{
|
||||
],
|
||||
Discord: [{
|
||||
key: 'body',
|
||||
label: 'Body',
|
||||
placeholder: 'Body',
|
||||
type: 'LongText',
|
||||
required: true
|
||||
}
|
||||
], Mattermost: [{
|
||||
],
|
||||
Mattermost: [{
|
||||
key: 'body',
|
||||
label: 'Body',
|
||||
placeholder: 'Body',
|
||||
type: 'LongText',
|
||||
required: true
|
||||
}
|
||||
], 'Twilio': [{
|
||||
],
|
||||
Twilio: [{
|
||||
key: 'body',
|
||||
label: 'Body',
|
||||
placeholder: 'Body',
|
||||
@@ -445,86 +474,95 @@ export default {
|
||||
type: 'LongText',
|
||||
required: true
|
||||
}]
|
||||
},
|
||||
}
|
||||
}),
|
||||
async created () {
|
||||
await this.loadMeta()
|
||||
await this.loadHooksList()
|
||||
this.selectedHook = 0
|
||||
this.onEventChange()
|
||||
},
|
||||
methods: {
|
||||
checkConditionAvail() {
|
||||
checkConditionAvail () {
|
||||
if (!process.env.EE) {
|
||||
this.enableCondition = false;
|
||||
this.enableCondition = false
|
||||
this.$toast.info('For webhook condition : Upgrade to Enterprise Edition').goAway(3000)
|
||||
}
|
||||
this.hook.condition = []
|
||||
},
|
||||
async onNotTypeChange() {
|
||||
this.notification = {};
|
||||
async onNotTypeChange () {
|
||||
this.notification = {}
|
||||
if (this.hook.notification.type === 'Slack') {
|
||||
const plugin = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcPluginRead', {
|
||||
title: 'Slack'
|
||||
}]);
|
||||
this.slackChannels = JSON.parse(plugin.input) || [];
|
||||
}])
|
||||
this.slackChannels = JSON.parse(plugin.input) || []
|
||||
}
|
||||
if (this.hook.notification.type === 'Microsoft Teams') {
|
||||
const plugin = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcPluginRead', {
|
||||
title: 'Microsoft Teams'
|
||||
}]);
|
||||
this.teamsChannels = JSON.parse(plugin.input) || [];
|
||||
}])
|
||||
this.teamsChannels = JSON.parse(plugin.input) || []
|
||||
}
|
||||
if (this.hook.notification.type === 'Discord') {
|
||||
const plugin = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcPluginRead', {
|
||||
title: 'Discord'
|
||||
}]);
|
||||
this.discordChannels = JSON.parse(plugin.input) || [];
|
||||
}])
|
||||
this.discordChannels = JSON.parse(plugin.input) || []
|
||||
}
|
||||
if (this.hook.notification.type === 'Mattermost') {
|
||||
const plugin = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcPluginRead', {
|
||||
title: 'Mattermost'
|
||||
}]);
|
||||
this.mattermostChannels = JSON.parse(plugin.input) || [];
|
||||
}])
|
||||
this.mattermostChannels = JSON.parse(plugin.input) || []
|
||||
}
|
||||
},
|
||||
async onEventChange() {
|
||||
if (!this.hooks || !this.hooks.length) return
|
||||
const {notification: {payload, type}, ...hook} = this.hooks[this.selectedHook];
|
||||
async onEventChange () {
|
||||
if (!this.hooks || !this.hooks.length) {
|
||||
return
|
||||
}
|
||||
const { notification: { payload, type }, ...hook } = this.hooks[this.selectedHook]
|
||||
|
||||
this.hook = {
|
||||
...hook,
|
||||
notification: {
|
||||
type
|
||||
}
|
||||
};
|
||||
}
|
||||
this.enableCondition = !!this.hook.condition
|
||||
await this.onNotTypeChange();
|
||||
this.notification = payload;
|
||||
await this.onNotTypeChange()
|
||||
this.notification = payload
|
||||
if (this.hook.notification.type === 'Slack') {
|
||||
this.notification.webhook_url = this.notification.webhook_url
|
||||
&& this.notification.webhook_url.map(v => this.slackChannels.find(s => v.webhook_url === s.webhook_url))
|
||||
this.notification.webhook_url = this.notification.webhook_url &&
|
||||
this.notification.webhook_url.map(v => this.slackChannels.find(s => v.webhook_url === s.webhook_url))
|
||||
}
|
||||
if (this.hook.notification.type === 'Microsoft Teams') {
|
||||
this.notification.webhook_url = this.notification.webhook_url
|
||||
&& this.notification.webhook_url.map(v => this.teamsChannels.find(s => v.webhook_url === s.webhook_url))
|
||||
this.notification.webhook_url = this.notification.webhook_url &&
|
||||
this.notification.webhook_url.map(v => this.teamsChannels.find(s => v.webhook_url === s.webhook_url))
|
||||
}
|
||||
if (this.hook.notification.type === 'Discord') {
|
||||
this.notification.webhook_url = this.notification.webhook_url
|
||||
&& this.notification.webhook_url.map(v => this.discordChannels.find(s => v.webhook_url === s.webhook_url))
|
||||
this.notification.webhook_url = this.notification.webhook_url &&
|
||||
this.notification.webhook_url.map(v => this.discordChannels.find(s => v.webhook_url === s.webhook_url))
|
||||
}
|
||||
if (this.hook.notification.type === 'Mattermost') {
|
||||
this.notification.webhook_url = this.notification.webhook_url
|
||||
&& this.notification.webhook_url.map(v => this.mattermostChannels.find(s => v.webhook_url === s.webhook_url))
|
||||
this.notification.webhook_url = this.notification.webhook_url &&
|
||||
this.notification.webhook_url.map(v => this.mattermostChannels.find(s => v.webhook_url === s.webhook_url))
|
||||
}
|
||||
if (this.hook.notification.type === 'URL') {
|
||||
// eslint-disable-next-line no-self-assign
|
||||
this.notification.api = this.notification.api
|
||||
}
|
||||
},
|
||||
async saveHooks() {
|
||||
async saveHooks () {
|
||||
if (!this.$refs.form.validate() || !this.valid || !this.hook.event) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcHooksSet', {
|
||||
tn: this.nodes.tn,
|
||||
data: {
|
||||
@@ -535,58 +573,58 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
])
|
||||
|
||||
if (!this.hook.id && res) {
|
||||
this.hook.id = Array.isArray(res) ? res[0] : res;
|
||||
this.hook.id = Array.isArray(res) ? res[0] : res
|
||||
}
|
||||
|
||||
this.$toast.success('Webhook details updated successfully').goAway(3000);
|
||||
this.$toast.success('Webhook details updated successfully').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error(e.message).goAway(3000);
|
||||
this.$toast.error(e.message).goAway(3000)
|
||||
}
|
||||
this.loading = false;
|
||||
await this.loadHooksList();
|
||||
this.loading = false
|
||||
await this.loadHooksList()
|
||||
},
|
||||
async loadMeta() {
|
||||
this.loadingMeta = true;
|
||||
async loadMeta () {
|
||||
this.loadingMeta = true
|
||||
const tableMeta = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcModelGet', {
|
||||
tn: this.nodes.tn
|
||||
}]);
|
||||
this.meta = JSON.parse(tableMeta.meta);
|
||||
this.fieldList = this.meta.columns.map(c => c.cn);
|
||||
this.loadingMeta = false;
|
||||
}])
|
||||
this.meta = JSON.parse(tableMeta.meta)
|
||||
this.fieldList = this.meta.columns.map(c => c.cn)
|
||||
this.loadingMeta = false
|
||||
},
|
||||
async loadHooksList() {
|
||||
this.loading = true;
|
||||
async loadHooksList () {
|
||||
this.loading = true
|
||||
const hooks = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
env: this.nodes.env,
|
||||
dbAlias: this.nodes.dbAlias
|
||||
}, 'tableXcHooksList', {
|
||||
tn: this.nodes.tn
|
||||
}]);
|
||||
this.hooks = hooks.data.list.map(h => {
|
||||
h.notification = h.notification && JSON.parse(h.notification);
|
||||
h.condition = h.condition && JSON.parse(h.condition);
|
||||
}])
|
||||
this.hooks = hooks.data.list.map((h) => {
|
||||
h.notification = h.notification && JSON.parse(h.notification)
|
||||
h.condition = h.condition && JSON.parse(h.condition)
|
||||
|
||||
return h;
|
||||
});
|
||||
this.loading = false;
|
||||
return h
|
||||
})
|
||||
this.loading = false
|
||||
},
|
||||
addNewHook() {
|
||||
this.selectedHook = this.hooks.length;
|
||||
addNewHook () {
|
||||
this.selectedHook = this.hooks.length
|
||||
this.hooks.push({
|
||||
notification: {
|
||||
// type:'Email'
|
||||
}
|
||||
});
|
||||
this.onEventChange();
|
||||
})
|
||||
this.onEventChange()
|
||||
this.$refs.form.resetValidation()
|
||||
},
|
||||
async deleteHook(item, i) {
|
||||
async deleteHook (item, i) {
|
||||
try {
|
||||
if (item.id) {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||||
@@ -596,25 +634,19 @@ export default {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
tn: this.nodes.tn
|
||||
}]);
|
||||
this.hooks.splice(i, 1);
|
||||
}])
|
||||
this.hooks.splice(i, 1)
|
||||
} else {
|
||||
this.hooks.splice(i, 1);
|
||||
this.hooks.splice(i, 1)
|
||||
}
|
||||
this.$toast.success('Hook deleted successfully').goAway(3000);
|
||||
this.$toast.success('Hook deleted successfully').goAway(3000)
|
||||
if (!this.hooks.length) {
|
||||
this.hook = null;
|
||||
this.hook = null
|
||||
}
|
||||
} catch (e) {
|
||||
this.$toast.error(e.message).goAway(3000);
|
||||
this.$toast.error(e.message).goAway(3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.loadMeta();
|
||||
await this.loadHooksList();
|
||||
this.selectedHook = 0;
|
||||
this.onEventChange();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user