mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
546 lines
19 KiB
546 lines
19 KiB
4 years ago
|
<template>
|
||
|
<v-card min-width="300px" max-width="400px" max-height="95vh" style="overflow: auto"
|
||
|
class="elevation-0 card">
|
||
|
<v-container fluid @click.stop.prevent>
|
||
|
<v-row>
|
||
|
<v-col cols="12" class="d-flex pb-0">
|
||
|
|
||
|
<v-spacer></v-spacer>
|
||
|
<v-btn small outlined @click="close">Cancel</v-btn>
|
||
|
<v-btn small color="primary" @click="save">Save</v-btn>
|
||
|
</v-col>
|
||
|
<v-col cols="12">
|
||
|
<v-text-field
|
||
|
ref="column"
|
||
|
hide-details
|
||
|
color="primary"
|
||
|
v-model="newColumn.cn"
|
||
|
@input="newColumn.altered = newColumn.altered || 8"
|
||
|
class="caption"
|
||
|
label="Column name"
|
||
|
dense outlined></v-text-field>
|
||
|
|
||
|
</v-col>
|
||
|
|
||
|
|
||
|
<v-col cols="12" v-if="relation">
|
||
|
<div class="caption">
|
||
|
|
||
|
<p class="mb-1">Foreign Key </p>
|
||
|
|
||
|
<v-icon small class="mt-n1">mdi-table</v-icon>
|
||
|
<span class="text-capitalize font-weight-bold body-1"> {{ relation._rtn }}</span>
|
||
|
<v-icon small
|
||
|
class="ml-3 mt-n1"
|
||
|
@click="deleteRelation('showDialog', column)"
|
||
|
color="error"
|
||
|
v-ge="['columns','fk-delete']"
|
||
|
>mdi-delete-forever
|
||
|
</v-icon>
|
||
|
<span v-if="relation.type=== 'virtual'" class="caption">(v)</span>
|
||
|
</div>
|
||
|
</v-col>
|
||
|
<template v-else>
|
||
|
<v-col cols="12">
|
||
|
<v-autocomplete
|
||
|
@change="onUiTypeChange"
|
||
|
v-model="newColumn.uidt"
|
||
|
hide-details
|
||
|
item-value="name"
|
||
|
item-text="name"
|
||
|
class="caption ui-type"
|
||
|
:class="{'primary lighten-5' : newColumn.uidt }"
|
||
|
label="Column type"
|
||
|
dense
|
||
|
outlined
|
||
|
:items="uiTypes">
|
||
|
<template v-slot:selection="{item}">
|
||
|
<div>
|
||
|
<v-icon color="grey darken-4" small class="mr-1">{{ item.icon }}</v-icon>
|
||
|
<span class="caption grey--text text--darken-4"> {{ item.name }}</span>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
|
||
|
<template v-slot:item="{item}">
|
||
|
<div class="caption">
|
||
|
<v-icon small class="mr-1">{{ item.icon }}</v-icon>
|
||
|
{{ item.name }}
|
||
|
</div>
|
||
|
</template>
|
||
|
</v-autocomplete>
|
||
|
|
||
|
|
||
|
<!-- <v-list dense max-height="calc(100vh - 300px)" style="overflow: auto">-->
|
||
|
<!-- <v-list-item v-for="item in uiTypes" @click.stop :key="item">-->
|
||
|
<!-- <span class="caption">{{ item }}</span>-->
|
||
|
<!-- </v-list-item>-->
|
||
|
<!-- </v-list>-->
|
||
|
</v-col>
|
||
|
|
||
|
<template v-if="newColumn.uidt !== 'Formula'">
|
||
|
<v-col cols="12"
|
||
|
v-if="isLinkToAnotherRecord">
|
||
|
|
||
|
<linked-to-another-options
|
||
|
ref="relation"
|
||
|
:column="newColumn"
|
||
|
:nodes="nodes"
|
||
|
@onColumnSelect="onRelColumnSelect"
|
||
|
></linked-to-another-options>
|
||
|
</v-col>
|
||
|
<v-col cols="12"
|
||
|
v-if="isRelation">
|
||
|
<relation-options
|
||
|
ref="relation"
|
||
|
:column="newColumn"
|
||
|
:nodes="nodes"
|
||
|
@onColumnSelect="onRelColumnSelect"
|
||
|
></relation-options>
|
||
|
</v-col>
|
||
|
|
||
|
<v-col cols="12" v-if="isSelect">
|
||
|
<custom-select-options
|
||
|
v-model="newColumn.dtxp"
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
></custom-select-options>
|
||
|
</v-col>
|
||
|
|
||
|
|
||
|
<template v-if="newColumn.cn && newColumn.uidt && !isLinkToAnotherRecord">
|
||
|
<v-col cols="12">
|
||
|
<v-container fluid class="wrapper">
|
||
|
<v-row>
|
||
|
<v-col cols="12">
|
||
|
<div class="d-flex justify-space-between caption">
|
||
|
<v-tooltip bottom z-index="99999">
|
||
|
<template v-slot:activator="{on}">
|
||
|
<div v-on="on">
|
||
|
<v-checkbox
|
||
|
:disabled="newColumn.pk || !sqlUi.columnEditable(newColumn)"
|
||
|
class="mr-2 mt-0" dense hide-details label="NN"
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
v-model="newColumn.rqd">
|
||
|
<template v-slot:label>
|
||
|
<span class="caption font-weight-bold">NN</span>
|
||
|
</template>
|
||
|
</v-checkbox>
|
||
|
</div>
|
||
|
</template>
|
||
|
<span>Not Null</span>
|
||
|
</v-tooltip>
|
||
|
<v-tooltip bottom z-index="99999">
|
||
|
<template v-slot:activator="{on}">
|
||
|
<div v-on="on">
|
||
|
<v-checkbox
|
||
|
|
||
|
v-model="newColumn.pk"
|
||
|
:disabled="!sqlUi.columnEditable(newColumn)"
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
class="mr-2 mt-0" dense hide-details label="PK">
|
||
|
<template v-slot:label>
|
||
|
<span class="caption font-weight-bold">PK</span>
|
||
|
</template>
|
||
|
</v-checkbox>
|
||
|
</div>
|
||
|
</template>
|
||
|
<span>Primary Key</span>
|
||
|
</v-tooltip>
|
||
|
|
||
|
<v-tooltip bottom z-index="99999">
|
||
|
<template v-slot:activator="{on}">
|
||
|
<div v-on="on">
|
||
|
<v-checkbox
|
||
|
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
:disabled="sqlUi.colPropUNDisabled(newColumn) || !sqlUi.columnEditable(newColumn)"
|
||
|
class="mr-2 mt-0" dense hide-details label="AI"
|
||
|
v-model="newColumn.ai">
|
||
|
<template v-slot:label>
|
||
|
<span class="caption font-weight-bold">AI</span>
|
||
|
</template>
|
||
|
</v-checkbox>
|
||
|
</div>
|
||
|
</template>
|
||
|
<span>Auto Increment</span>
|
||
|
</v-tooltip>
|
||
|
|
||
|
|
||
|
<v-tooltip bottom z-index="99999">
|
||
|
<template v-slot:activator="{on}">
|
||
|
<div v-on="on">
|
||
|
<v-checkbox class="mr-2 mt-0" dense hide-details label="UN"
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
:disabled="sqlUi.colPropUNDisabled(newColumn) || !sqlUi.columnEditable(newColumn)"
|
||
|
v-model="newColumn.un">
|
||
|
<template v-slot:label>
|
||
|
<span class="caption font-weight-bold">UN</span>
|
||
|
</template>
|
||
|
</v-checkbox>
|
||
|
</div>
|
||
|
</template>
|
||
|
<span>Unsigned</span>
|
||
|
</v-tooltip>
|
||
|
|
||
|
<v-tooltip bottom z-index="99999">
|
||
|
<template v-slot:activator="{on}">
|
||
|
<div v-on="on">
|
||
|
<v-checkbox class="mr-2 mt-0" dense hide-details label="UN"
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
:disabled=" sqlUi.colPropAuDisabled(newColumn) || !sqlUi.columnEditable(newColumn)"
|
||
|
v-model="newColumn.au">
|
||
|
<template v-slot:label>
|
||
|
<span class="caption font-weight-bold">AU</span>
|
||
|
</template>
|
||
|
</v-checkbox>
|
||
|
</div>
|
||
|
</template>
|
||
|
<span>Auto Update Timestamp</span>
|
||
|
</v-tooltip>
|
||
|
</div>
|
||
|
</v-col>
|
||
|
<v-col cols="12">
|
||
|
<v-autocomplete
|
||
|
v-model="newColumn.dt"
|
||
|
hide-details
|
||
|
class="caption data-type"
|
||
|
label="Type in Database"
|
||
|
dense
|
||
|
outlined
|
||
|
:items="dataTypes">
|
||
|
</v-autocomplete>
|
||
|
</v-col>
|
||
|
|
||
|
<v-col :cols="sqlUi.showScale(newColumn) && !isSelect ? 6 : 12">
|
||
|
<v-text-field
|
||
|
v-if="!isSelect"
|
||
|
dense
|
||
|
:disabled="sqlUi.getDefaultLengthIsDisabled(newColumn.dt) || !sqlUi.columnEditable(newColumn)"
|
||
|
class="caption"
|
||
|
label="Length / Values"
|
||
|
outlined
|
||
|
hide-details v-model="newColumn.dtxp"
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
></v-text-field>
|
||
|
</v-col>
|
||
|
<v-col :cols="isSelect ?12 : 6" v-if="sqlUi.showScale(newColumn)">
|
||
|
|
||
|
<v-text-field
|
||
|
dense
|
||
|
:disabled=" !sqlUi.columnEditable(newColumn)"
|
||
|
class="caption"
|
||
|
label="Scale"
|
||
|
outlined
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
hide-details v-model="newColumn.dtxs"></v-text-field>
|
||
|
</v-col>
|
||
|
|
||
|
<v-col cols="12">
|
||
|
<v-textarea v-model="newColumn.cdf"
|
||
|
@input="newColumn.altered = newColumn.altered || 2"
|
||
|
label="Default value"
|
||
|
:hint="sqlUi.getDefaultValueForDatatype(newColumn.dt)"
|
||
|
persistent-hint
|
||
|
rows="3"
|
||
|
outlined dense class="caption"></v-textarea>
|
||
|
</v-col>
|
||
|
</v-row>
|
||
|
</v-container>
|
||
|
</v-col>
|
||
|
</template>
|
||
|
</template>
|
||
|
<template v-else>
|
||
|
<v-col cols12>
|
||
|
<v-autocomplete
|
||
|
label="Formula"
|
||
|
hide-details
|
||
|
class="caption formula-type"
|
||
|
outlined
|
||
|
dense
|
||
|
:items="formulas"
|
||
|
>
|
||
|
|
||
|
<template v-slot:item="{item}">
|
||
|
<span class="green--text text--darken-2 caption font-weight-regular">{{ item }}</span>
|
||
|
</template>
|
||
|
|
||
|
</v-autocomplete>
|
||
|
</v-col>
|
||
|
</template>
|
||
|
</template>
|
||
|
|
||
|
</v-row>
|
||
|
</v-container>
|
||
|
|
||
|
<dlg-label-submit-cancel
|
||
|
type="primary"
|
||
|
v-if="relationDeleteDlg"
|
||
|
:dialogShow="relationDeleteDlg"
|
||
|
:actionsMtd="deleteRelation"
|
||
|
heading="Click Submit to Delete the Relation"
|
||
|
/>
|
||
|
</v-card>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import {uiTypes} from "@/components/project/spreadsheet/helpers/uiTypes";
|
||
|
import CustomSelectOptions from "@/components/project/spreadsheet/editColumn/customSelectOptions";
|
||
|
import RelationOptions from "@/components/project/spreadsheet/editColumn/relationOptions";
|
||
|
import DlgLabelSubmitCancel from "@/components/utils/dlgLabelSubmitCancel";
|
||
|
import LinkedToAnotherOptions from "@/components/project/spreadsheet/editColumn/linkedToAnotherOptions";
|
||
|
|
||
|
export default {
|
||
|
name: "editColumn",
|
||
|
components: {LinkedToAnotherOptions, DlgLabelSubmitCancel, RelationOptions, CustomSelectOptions},
|
||
|
props: {
|
||
|
nodes: Object,
|
||
|
sqlUi: [Object, Function],
|
||
|
meta: Object,
|
||
|
editColumn: Boolean,
|
||
|
column: Object,
|
||
|
columnIndex: Number,
|
||
|
value: Boolean
|
||
|
},
|
||
|
data: () => ({
|
||
|
relationDeleteDlg: false,
|
||
|
newColumn: {},
|
||
|
uiTypes,
|
||
|
// dataTypes: [],
|
||
|
formulas: ["AVERAGE()", "COUNT()", "COUNTA()", "COUNTALL()", "SUM()", "MIN()", "MAX()", "AND()", "OR()", "TRUE()", "FALSE()", "NOT()", "XOR()", "ISERROR()", "IF()", "LEN()", "MID()", "LEFT()", "RIGHT()", "FIND()", "CONCATENATE()", "T()", "VALUE()", "ARRAYJOIN()", "ARRAYUNIQUE()", "ARRAYCOMPACT()", "ARRAYFLATTEN()", "ROUND()", "ROUNDUP()", "ROUNDDOWN()", "INT()", "EVEN()", "ODD()", "MOD()", "LOG()", "EXP()", "POWER()", "SQRT()", "CEILING()", "FLOOR()", "ABS()", "RECORD_ID()", "CREATED_TIME()", "ERROR()", "BLANK()", "YEAR()", "MONTH()", "DAY()", "HOUR()", "MINUTE()", "SECOND()", "TODAY()", "NOW()", "WORKDAY()", "DATETIME_PARSE()", "DATETIME_FORMAT()", "SET_LOCALE()", "SET_TIMEZONE()", "DATESTR()", "TIMESTR()", "TONOW()", "FROMNOW()", "DATEADD()", "WEEKDAY()", "WEEKNUM()", "DATETIME_DIFF()", "WORKDAY_DIFF()", "IS_BEFORE()", "IS_SAME()", "IS_AFTER()", "REPLACE()", "REPT()", "LOWER()", "UPPER()", "TRIM()", "SUBSTITUTE()", "SEARCH()", "SWITCH()", "LAST_MODIFIED_TIME()", "ENCODE_URL_COMPONENT()", "REGEX_EXTRACT()", "REGEX_MATCH()", "REGEX_REPLACE()"]
|
||
|
}),
|
||
|
async created() {
|
||
|
this.genColumnData();
|
||
|
// await this.loadDataTypes();
|
||
|
},
|
||
|
methods: {
|
||
|
onRelColumnSelect(colMeta) {
|
||
|
Object.assign(this.newColumn, {
|
||
|
dt: colMeta.dt,
|
||
|
dtxp: colMeta.dtxp,
|
||
|
dtxs: colMeta.dtxs,
|
||
|
un: colMeta.un
|
||
|
});
|
||
|
},
|
||
|
genColumnData() {
|
||
|
this.newColumn = this.column ? {...this.column} : this.sqlUi.getNewColumn(this.meta.columns.length + 1);
|
||
|
this.newColumn.cno = this.newColumn.cn;
|
||
|
},
|
||
|
/*
|
||
|
async loadDataTypes() {
|
||
|
try {
|
||
|
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
|
||
|
env: this.nodes.env,
|
||
|
dbAlias: this.nodes.dbAlias
|
||
|
}, 'getKnexDataTypes', {}])
|
||
|
|
||
|
this.dataTypes = result.data.list;
|
||
|
} catch (e) {
|
||
|
this.$toast.error('Error loading datatypes :' + e).goAway(4000);
|
||
|
throw e;
|
||
|
}
|
||
|
},
|
||
|
*/
|
||
|
close() {
|
||
|
this.$emit('close');
|
||
|
this.newColumn = {};
|
||
|
},
|
||
|
async save() {
|
||
|
try {
|
||
|
|
||
|
if (this.newColumn.uidt === 'Formula') {
|
||
|
return this.$toast.info('Coming Soon...').goAway(3000)
|
||
|
}
|
||
|
|
||
|
this.newColumn.tn = this.nodes.tn;
|
||
|
this.newColumn._cn = this.newColumn.cn;
|
||
|
|
||
|
const columns = [...this.meta.columns];
|
||
|
|
||
|
if (columns.length) {
|
||
|
columns[0].tn = this.nodes.tn;
|
||
|
}
|
||
|
|
||
|
if (this.editColumn) {
|
||
|
columns[this.columnIndex] = this.newColumn;
|
||
|
} else {
|
||
|
columns.push(this.newColumn)
|
||
|
}
|
||
|
|
||
|
let result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [{
|
||
|
env: this.nodes.env,
|
||
|
dbAlias: this.nodes.dbAlias
|
||
|
}, "tableUpdate", {
|
||
|
tn: this.nodes.tn,
|
||
|
_tn: this.meta._tn,
|
||
|
originalColumns: this.meta.columns,
|
||
|
columns
|
||
|
}]);
|
||
|
|
||
|
|
||
|
if (this.isRelation && this.$refs.relation) {
|
||
|
await this.$refs.relation.saveRelation();
|
||
|
}
|
||
|
|
||
|
|
||
|
this.$emit('saved');
|
||
|
} catch (e) {
|
||
|
console.log(e)
|
||
|
}
|
||
|
|
||
|
this.$emit('close');
|
||
|
},
|
||
|
onDataTypeChange() {
|
||
|
|
||
|
this.newColumn.rqd = false;
|
||
|
this.newColumn.pk = false;
|
||
|
this.newColumn.ai = false;
|
||
|
this.newColumn.cdf = null;
|
||
|
this.newColumn.un = false;
|
||
|
this.newColumn.dtxp = this.sqlUi.getDefaultLengthForDatatype(this.newColumn.dt);
|
||
|
this.newColumn.dtxs = this.sqlUi.getDefaultScaleForDatatype(this.newColumn.dt);
|
||
|
|
||
|
this.newColumn.dtx = 'specificType';
|
||
|
|
||
|
this.$set(this.newColumn, 'uidt', this.sqlUi.getUIType(this.newColumn));
|
||
|
|
||
|
this.newColumn.altered = this.newColumn.altered || 2;
|
||
|
},
|
||
|
onUiTypeChange() {
|
||
|
const colProp = this.sqlUi.getDataTypeForUiType(this.newColumn);
|
||
|
this.newColumn = {
|
||
|
...this.newColumn,
|
||
|
rqd: false,
|
||
|
pk: false,
|
||
|
ai: false,
|
||
|
cdf: null,
|
||
|
un: false,
|
||
|
dtx: 'specificType',
|
||
|
...colProp
|
||
|
};
|
||
|
|
||
|
this.newColumn.dtxp = this.sqlUi.getDefaultLengthForDatatype(this.newColumn.dt);
|
||
|
this.newColumn.dtxs = this.sqlUi.getDefaultScaleForDatatype(this.newColumn.dt);
|
||
|
|
||
|
this.newColumn.altered = this.newColumn.altered || 2;
|
||
|
},
|
||
|
focusInput() {
|
||
|
setTimeout(() => {
|
||
|
if (this.$refs.column && this.$refs.column.$el) {
|
||
|
this.$refs.column.$el.querySelector('input').focus()
|
||
|
}
|
||
|
}, 100);
|
||
|
},
|
||
|
async deleteRelation(action = "", column) {
|
||
|
|
||
|
try {
|
||
|
if (action === "showDialog") {
|
||
|
this.relationDeleteDlg = true;
|
||
|
} else if (action === "hideDialog") {
|
||
|
this.relationDeleteDlg = false;
|
||
|
} else {
|
||
|
let result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [
|
||
|
{
|
||
|
env: this.nodes.env,
|
||
|
dbAlias: this.nodes.dbAlias
|
||
|
},
|
||
|
this.relation.type === 'virtual' ? 'xcVirtualRelationDelete' : "relationDelete",
|
||
|
{
|
||
|
childColumn: this.relation.cn,
|
||
|
childTable: this.nodes.tn,
|
||
|
parentTable: this.relation
|
||
|
.rtn,
|
||
|
parentColumn: this.relation
|
||
|
.rcn,
|
||
|
}
|
||
|
]);
|
||
|
console.log("relationDelete result ", result);
|
||
|
// await this.loadColumnList();
|
||
|
this.relationDeleteDlg = false;
|
||
|
this.relation = null;
|
||
|
this.$toast.success('Foreign Key deleted successfully').goAway(3000);
|
||
|
this.$emit('onRelationDelete');
|
||
|
}
|
||
|
} catch (e) {
|
||
|
console.log(e);
|
||
|
this.$toast.error('Foreign key relation delete failed' + e).goAway(3000);
|
||
|
throw e;
|
||
|
}
|
||
|
|
||
|
|
||
|
},
|
||
|
}, watch: {
|
||
|
column() {
|
||
|
this.genColumnData();
|
||
|
},
|
||
|
}, mounted() {
|
||
|
this.focusInput()
|
||
|
},
|
||
|
computed: {
|
||
|
dataTypes() {
|
||
|
return this.sqlUi.getDataTypeListForUiType(this.newColumn)
|
||
|
},
|
||
|
isSelect() {
|
||
|
return this.newColumn && (this.newColumn.uidt === 'MultiSelect'
|
||
|
|| this.newColumn.uidt === 'SingleSelect');
|
||
|
},
|
||
|
isRelation() {
|
||
|
return this.newColumn && this.newColumn.uidt === 'ForeignKey';
|
||
|
},
|
||
|
isLinkToAnotherRecord() {
|
||
|
return this.newColumn && this.newColumn.uidt === 'LinkToAnotherRecord';
|
||
|
},
|
||
|
relation() {
|
||
|
return this.meta && this.column && this.meta.belongsTo && this.meta.belongsTo.find(bt => bt.cn === this.column.cn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<style scoped lang="scss">
|
||
|
|
||
|
::v-deep {
|
||
|
|
||
|
|
||
|
.v-input__slot {
|
||
|
min-height: auto !important;
|
||
|
}
|
||
|
|
||
|
.v-input:not(.v-input--is-focused) fieldset {
|
||
|
border-color: #7f828b33 !important;
|
||
|
}
|
||
|
|
||
|
.data-type, .ui-type, .formula-type {
|
||
|
.v-input__append-inner {
|
||
|
margin-top: 4px !important;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.ui-type input {
|
||
|
height: 24px;
|
||
|
}
|
||
|
|
||
|
.v-input--selection-controls__input > i {
|
||
|
transform: scale(.83);
|
||
|
}
|
||
|
|
||
|
label {
|
||
|
font-size: 0.75rem !important
|
||
|
}
|
||
|
|
||
|
.v-text-field--outlined.v-input--dense .v-label:not(.v-label--active) {
|
||
|
top: 6px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.card {
|
||
|
border: solid 2px #7f828b33;
|
||
|
}
|
||
|
|
||
|
.wrapper {
|
||
|
border: solid 2px #7f828b33;
|
||
|
border-radius: 4px;
|
||
|
}
|
||
|
|
||
|
</style>
|