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.
1713 lines
61 KiB
1713 lines
61 KiB
<template> |
|
<div class="h-100" style="min-height: 500px"> |
|
<v-toolbar v-if="!viewMode" class="elevation-0"> |
|
<slot name="toolbar" :valid="valid"> |
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-btn |
|
small |
|
outlined |
|
v-on="on" |
|
@click="$toast.info('Happy hacking!').goAway(3000)" |
|
> |
|
<v-icon small class="mr-1"> |
|
mdi-file-excel-outline |
|
</v-icon> |
|
Import |
|
</v-btn> |
|
</template> |
|
<span class="caption">Create template from Excel</span> |
|
</v-tooltip> |
|
|
|
<v-spacer /> |
|
|
|
<v-icon class="mr-3" @click="helpModal = true"> |
|
mdi-information-outline |
|
</v-icon> |
|
|
|
<v-btn small outlined class="mr-1" @click="project = { tables: [] }"> |
|
<v-icon small> |
|
mdi-close |
|
</v-icon> |
|
Reset |
|
</v-btn> |
|
<v-btn small outlined class="mr-1" @click="createTableClick"> |
|
<v-icon small> |
|
mdi-plus |
|
</v-icon> |
|
New table |
|
</v-btn> |
|
<v-btn |
|
color="primary" |
|
outlined |
|
small |
|
class="mr-1" |
|
:loading="loading" |
|
:disabled="loading" |
|
@click="saveTemplate" |
|
> |
|
{{ id || localId ? "Update in" : "Submit to" }} NocoDB |
|
</v-btn> |
|
</slot> |
|
</v-toolbar> |
|
<v-divider class="mt-6" /> |
|
<v-container |
|
class="text-center" |
|
style="height: calc(100% - 64px); overflow-y: auto" |
|
> |
|
<v-form ref="form" v-model="valid"> |
|
<v-row fluid class="justify-center"> |
|
<v-col cols="12"> |
|
<v-card class="elevation-0"> |
|
<v-card-text> |
|
<div v-if="!viewMode" class="mx-auto" style="max-width: 400px"> |
|
<div class="mt-1"> |
|
<v-text-field |
|
ref="project" |
|
v-model="project.title" |
|
class="title" |
|
outlined |
|
hide-details |
|
denses |
|
:rules="[(v) => !!v || 'Project name required']" |
|
> |
|
<template #label> |
|
<span class="caption">Project Name</span> |
|
</template> |
|
</v-text-field> |
|
</div> |
|
</div> |
|
|
|
<p v-if="project.tables" class="caption grey--text mt-4"> |
|
{{ project.tables.length }} sheet{{ |
|
project.tables.length > 1 ? "s" : "" |
|
}} |
|
available for import |
|
</p> |
|
|
|
<v-expansion-panels |
|
v-if="project.tables && project.tables.length" |
|
v-model="expansionPanel" |
|
:multiple="viewMode" |
|
accordion |
|
> |
|
<v-expansion-panel |
|
v-for="(table, i) in project.tables" |
|
:key="i" |
|
> |
|
<v-expansion-panel-header :id="`tn_${table.table_name}`"> |
|
<v-text-field |
|
v-if="editableTn[i]" |
|
:value="table.table_name" |
|
class="font-weight-bold" |
|
style="max-width: 300px" |
|
outlinedk |
|
autofocus |
|
dense |
|
hide-details |
|
@input="(e) => onTableNameUpdate(table, e)" |
|
@click="(e) => viewMode || e.stopPropagation()" |
|
@blur="$set(editableTn, i, false)" |
|
@keydown.enter="$set(editableTn, i, false)" |
|
/> |
|
<span |
|
v-else |
|
class="font-weight-bold" |
|
@click=" |
|
(e) => |
|
viewMode || |
|
(e.stopPropagation(), $set(editableTn, i, true)) |
|
" |
|
> |
|
<v-icon color="primary lighten-1">mdi-table</v-icon> |
|
{{ table.table_name }} |
|
</span> |
|
|
|
<v-spacer /> |
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
v-if="!viewMode" |
|
class="flex-grow-0 mr-2" |
|
small |
|
color="grey" |
|
@click.stop="deleteTable(i)" |
|
v-on="on" |
|
> |
|
mdi-delete-outline |
|
</v-icon> |
|
</template> |
|
<!-- TODO: i18n --> |
|
<span>Delete Table</span> |
|
</v-tooltip> |
|
</v-expansion-panel-header> |
|
<v-expansion-panel-content> |
|
<!-- <v-toolbar> |
|
<v-spacer></v-spacer> |
|
<v-btn outlined small @click='showColCreateDialog(table,i)'>New Column |
|
</v-btn> |
|
</v-toolbar>--> |
|
|
|
<template> |
|
<v-simple-table |
|
v-if="table.columns.length" |
|
dense |
|
class="my-4" |
|
> |
|
<thead> |
|
<tr> |
|
<th class="caption text-left pa-1"> |
|
<!--Column Name--> |
|
{{ $t("labels.columnName") }} |
|
</th> |
|
<th class="caption text-left pa-1" colspan="4"> |
|
<!--Column Type--> |
|
{{ $t("labels.columnType") }} |
|
</th> |
|
<th /> |
|
<!-- <th class='text-center'>Related Table</th>--> |
|
<!-- <th class='text-center'>Related Column</th>--> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
<tr |
|
v-for="(col, j) in table.columns" |
|
:key="j" |
|
:data-exp="i" |
|
> |
|
<td |
|
class="pa-1 text-left" |
|
:style="{ width: viewMode ? '33%' : '15%' }" |
|
> |
|
<span v-if="viewMode" class="body-1"> |
|
{{ col.column_name }} |
|
</span> |
|
|
|
<v-text-field |
|
v-else |
|
:ref="`cn_${table.table_name}_${j}`" |
|
:value="col.column_name" |
|
outlined |
|
dense |
|
class="caption" |
|
:placeholder="$t('labels.columnName')" |
|
hide-details="auto" |
|
:rules="[ |
|
(v) => !!v || 'Column name required', |
|
(v) => |
|
!table.columns.some( |
|
(c) => c !== col && c.column_name === v |
|
) || 'Duplicate column not allowed', |
|
]" |
|
@input=" |
|
(e) => |
|
onColumnNameUpdate( |
|
col, |
|
e, |
|
table.table_name |
|
) |
|
" |
|
/> |
|
</td> |
|
|
|
<template v-if="viewMode"> |
|
<td |
|
:style="{ |
|
width: |
|
(viewMode && isRelation(col)) || |
|
isLookupOrRollup(col) |
|
? '33%' |
|
: '', |
|
}" |
|
:colspan=" |
|
isRelation(col) || isLookupOrRollup(col) |
|
? 3 |
|
: 5 |
|
" |
|
class="text-left" |
|
> |
|
<v-icon small> |
|
{{ getIcon(col.uidt) }} |
|
</v-icon> |
|
<span class="caption">{{ col.uidt }}</span> |
|
</td> |
|
<td |
|
v-if=" |
|
isRelation(col) || isLookupOrRollup(col) |
|
" |
|
class="text-left" |
|
> |
|
<span |
|
v-if="isRelation(col)" |
|
class="caption pointer primary--text" |
|
@click="navigateToTable(col.ref_table_name)" |
|
> |
|
{{ col.ref_table_name }} |
|
</span> |
|
<template v-else-if="isLookup(col)"> |
|
<span |
|
class="caption pointer primary--text" |
|
@click=" |
|
navigateToTable( |
|
col.ref_table_name && col.ref_table_name.table_name |
|
) |
|
" |
|
> |
|
{{ col.ref_table_name && col.ref_table_name.table_name }} |
|
</span> |
|
<span class="caption">({{ col.ref_column_name }})</span> |
|
</template> |
|
|
|
<template v-else-if="isRollup(col)"> |
|
<span |
|
class="caption pointer primary--text" |
|
@click=" |
|
navigateToTable( |
|
col.ref_table_name && col.ref_table_name.table_name |
|
) |
|
" |
|
> |
|
{{ col.ref_table_name && col.ref_table_name.table_name }} |
|
</span> |
|
<span class="caption">({{ col.fn }})</span> |
|
</template> |
|
</td> |
|
</template> |
|
|
|
<template v-else> |
|
<td |
|
class="pa-1 text-left" |
|
style="width: 200px; max-width: 200px" |
|
> |
|
<v-autocomplete |
|
:ref="`uidt_${table.table_name}_${j}`" |
|
style="max-width: 200px" |
|
:value="col.uidt" |
|
placeholder="Column Datatype" |
|
outlined |
|
dense |
|
class="caption" |
|
hide-details="auto" |
|
:rules="[ |
|
(v) => !!v || 'Column data type required', |
|
]" |
|
:items=" |
|
col.uidt === 'ForeignKey' |
|
? [ |
|
...uiTypes, |
|
{ |
|
name: 'ForeignKey', |
|
icon: 'mdi-link-variant', |
|
virtual: 1, |
|
}, |
|
] |
|
: uiTypes |
|
" |
|
item-text="name" |
|
item-value="name" |
|
@input=" |
|
(v) => |
|
onUidtChange(col.uidt, v, col, table) |
|
" |
|
> |
|
<template #item="{ item: { name } }"> |
|
<v-chip |
|
v-if="colors[name]" |
|
:color="colors[name]" |
|
small |
|
> |
|
{{ name }} |
|
</v-chip> |
|
<span v-else class="caption">{{ |
|
name |
|
}}</span> |
|
</template> |
|
<template #selection="{ item: { name } }"> |
|
<v-chip |
|
v-if="colors[name]" |
|
:color="colors[name]" |
|
small |
|
style="max-width: 100px" |
|
> |
|
{{ name }} |
|
</v-chip> |
|
<span v-else class="caption">{{ |
|
name |
|
}}</span> |
|
</template> |
|
</v-autocomplete> |
|
</td> |
|
|
|
<template |
|
v-if=" |
|
isRelation(col) || isLookupOrRollup(col) |
|
" |
|
> |
|
<td class="pa-1 text-left"> |
|
<v-autocomplete |
|
:value="col.ref_table_name" |
|
placeholder="Related table" |
|
outlined |
|
class="caption" |
|
dense |
|
hide-details="auto" |
|
:rules="[ |
|
(v) => |
|
!!v || 'Related table name required', |
|
...getRules(col, table), |
|
]" |
|
:items=" |
|
isLookupOrRollup(col) |
|
? getRelatedTables( |
|
table.table_name, |
|
isRollup(col) |
|
) |
|
: project.tables |
|
" |
|
:item-text=" |
|
(t) => |
|
isLookupOrRollup(col) |
|
? `${t.table_name} (${t.type})` |
|
: t.table_name |
|
" |
|
:item-value=" |
|
(t) => |
|
isLookupOrRollup(col) |
|
? t |
|
: t.table_name |
|
" |
|
:value-comparator="compareRel" |
|
@input=" |
|
(v) => |
|
onRtnChange(col.ref_table_name, v, col, table) |
|
" |
|
/> |
|
</td> |
|
|
|
<td v-if="isRelation(col)" class="pa-1"> |
|
<template v-if="col.uidt !== 'ForeignKey'"> |
|
<span v-if="viewMode" class="caption"> |
|
<!-- {{ col.type }}--> |
|
</span> |
|
<v-autocomplete |
|
v-else |
|
:value="col.type" |
|
placeholder="Relation Type" |
|
outlined |
|
class="caption" |
|
dense |
|
hide-details="auto" |
|
:rules="[ |
|
(v) => |
|
!!v || 'Relation type required', |
|
]" |
|
:items="[ |
|
{ text: 'Many To Many', value: 'mm' }, |
|
{ text: 'Has Many', value: 'hm' }, |
|
]" |
|
@input=" |
|
(v) => |
|
onRTypeChange( |
|
col.type, |
|
v, |
|
col, |
|
table |
|
) |
|
" |
|
/> |
|
</template> |
|
</td> |
|
<td v-if="isLookupOrRollup(col)" class="pa-1"> |
|
<span v-if="viewMode" class="caption"> |
|
{{ col.ref_column_name }} |
|
</span> |
|
|
|
<v-autocomplete |
|
v-else |
|
v-model="col.ref_column_name" |
|
placeholder="Related table column" |
|
outlined |
|
dense |
|
class="caption" |
|
hide-details="auto" |
|
:rules="[ |
|
(v) => |
|
!!v || 'Related column name required', |
|
]" |
|
:items=" |
|
( |
|
project.tables.find( |
|
(t) => |
|
t.table_name === |
|
((col.ref_table_name && |
|
col.ref_table_name.table_name) || |
|
col.ref_table_name) |
|
) || { columns: [] } |
|
).columns.filter((v) => !isVirtual(v)) |
|
" |
|
item-text="column_name" |
|
item-value="column_name" |
|
/> |
|
</td> |
|
<td v-if="isRollup(col)" class="pa-1"> |
|
<span v-if="viewMode" class="caption"> |
|
{{ col.fn }} |
|
</span> |
|
|
|
<v-autocomplete |
|
v-else |
|
v-model="col.fn" |
|
placeholder="Rollup function" |
|
outlined |
|
dense |
|
class="caption" |
|
hide-details="auto" |
|
:rules="[ |
|
(v) => |
|
!!v || |
|
'Rollup aggregate function name required', |
|
]" |
|
:items="rollupFnList" |
|
/> |
|
</td> |
|
</template> |
|
<template v-if="isSelect(col)"> |
|
<td class="pa-1 text-left" colspan="2"> |
|
<span v-if="viewMode" class="caption"> |
|
{{ col.dtxp }} |
|
</span> |
|
<v-text-field |
|
v-model="col.dtxp" |
|
placeholder="Select options" |
|
outlined |
|
class="caption" |
|
dense |
|
hide-details |
|
/> |
|
</td> |
|
</template> |
|
<td |
|
v-if="!isRollup(col)" |
|
:colspan=" |
|
isLookupOrRollup(col) || |
|
isRelation(col) || |
|
isSelect(col) |
|
? isRollup(col) |
|
? 0 |
|
: 1 |
|
: 3 |
|
" |
|
/> |
|
<td style="max-width: 50px; width: 50px"> |
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
v-if="!viewMode" |
|
class="flex-grow-0" |
|
small |
|
color="grey" |
|
@click.stop=" |
|
deleteTableColumn(i, j, col, table) |
|
" |
|
v-on="on" |
|
> |
|
mdi-delete-outline |
|
</v-icon> |
|
</template> |
|
<!-- TODO: i18n --> |
|
<span>Delete Column</span> |
|
</v-tooltip> |
|
</td> |
|
</template> |
|
</tr> |
|
</tbody> |
|
</v-simple-table> |
|
|
|
<div v-if="!viewMode" class="text-center"> |
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
class="mx-2" |
|
small |
|
@click="addNewColumnRow(table, 'Number')" |
|
v-on="on" |
|
> |
|
{{ getIcon("Number") }} |
|
</v-icon> |
|
</template> |
|
<!-- TODO: i18n --> |
|
<span>Add Number Column</span> |
|
</v-tooltip> |
|
|
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
class="mx-2" |
|
small |
|
@click="addNewColumnRow(table, 'SingleLineText')" |
|
v-on="on" |
|
> |
|
{{ getIcon("SingleLineText") }} |
|
</v-icon> |
|
</template> |
|
<!-- TODO: i18n --> |
|
<span>Add SingleLineText Column</span> |
|
</v-tooltip> |
|
|
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
class="mx-2" |
|
small |
|
@click="addNewColumnRow(table, 'LongText')" |
|
v-on="on" |
|
> |
|
{{ getIcon("LongText") }} |
|
</v-icon> |
|
</template> |
|
<!-- TODO: i18n --> |
|
<span>Add LongText Column</span> |
|
</v-tooltip> |
|
|
|
<!-- <v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
class="mx-2" |
|
small |
|
@click="addNewColumnRow(table, 'LinkToAnotherRecord')" |
|
v-on="on" |
|
> |
|
{{ getIcon("LinkToAnotherRecord") }} |
|
</v-icon> |
|
</template> |
|
<span>Add LinkToAnotherRecord Column</span> |
|
</v-tooltip> |
|
|
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
class="mx-2" |
|
small |
|
@click="addNewColumnRow(table, 'Lookup')" |
|
v-on="on" |
|
> |
|
{{ getIcon("Lookup") }} |
|
</v-icon> |
|
</template> |
|
<span>Add Lookup Column</span> |
|
</v-tooltip> |
|
|
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
class="mx-2" |
|
small |
|
@click="addNewColumnRow(table, 'Rollup')" |
|
v-on="on" |
|
> |
|
{{ getIcon("Rollup") }} |
|
</v-icon> |
|
</template> |
|
<span>Add Rollup Column</span> |
|
</v-tooltip> --> |
|
|
|
<v-tooltip bottom> |
|
<template #activator="{ on }"> |
|
<v-btn |
|
class="mx-2" |
|
small |
|
@click="addNewColumnRow(table)" |
|
v-on="on" |
|
> |
|
+ column |
|
</v-btn> |
|
</template> |
|
<!-- TODO: i18n --> |
|
<span>Add Other Column</span> |
|
</v-tooltip> |
|
</div> |
|
</template> |
|
</v-expansion-panel-content> |
|
</v-expansion-panel> |
|
</v-expansion-panels> |
|
<div v-if="!viewMode" class="mx-auto" style="max-width: 600px"> |
|
<template v-if="!excelImport"> |
|
<gradient-generator |
|
v-model="project.image_url" |
|
class="d-100 mt-4" |
|
/> |
|
|
|
<v-row> |
|
<v-col> |
|
<v-text-field |
|
v-model="project.category" |
|
:rules="[(v) => !!v || 'Category name required']" |
|
class="caption" |
|
outlined |
|
dense |
|
label="Project Category" |
|
/> |
|
</v-col> |
|
<v-col> |
|
<v-text-field |
|
v-model="project.tags" |
|
class="caption" |
|
outlined |
|
dense |
|
label="Project Tags" |
|
/> |
|
</v-col> |
|
</v-row> |
|
<div> |
|
<v-textarea |
|
v-model="project.description" |
|
class="caption" |
|
outlined |
|
dense |
|
label="Project Description" |
|
@click="counter++" |
|
/> |
|
</div> |
|
</template> |
|
</div> |
|
</v-card-text> |
|
</v-card> |
|
</v-col> |
|
</v-row> |
|
</v-form> |
|
</v-container> |
|
|
|
<v-dialog v-model="createTablesDialog" max-width="500"> |
|
<v-card> |
|
<v-card-title> |
|
<!--Enter table name--> |
|
{{ $t("msg.info.enterTableName") }} |
|
</v-card-title> |
|
<v-card-text> |
|
<v-text-field |
|
v-model="tableNamesInput" |
|
autofocus |
|
hide-details |
|
dense |
|
outlined |
|
label="Enter comma separated table names" |
|
@keydown.enter="addTables" |
|
/> |
|
</v-card-text> |
|
<v-card-actions> |
|
<v-spacer /> |
|
<v-btn outlined small @click="createTablesDialog = false"> |
|
<!-- Cancel --> |
|
{{ $t("general.cancel") }} |
|
</v-btn> |
|
<v-btn outlined color="primary" small @click="addTables"> |
|
<!-- Save --> |
|
{{ $t("general.save") }} |
|
</v-btn> |
|
</v-card-actions> |
|
</v-card> |
|
</v-dialog> |
|
<v-dialog v-model="createTableColumnsDialog" max-width="500"> |
|
<v-card> |
|
<v-card-title>Enter column name</v-card-title> |
|
<v-card-text> |
|
<v-text-field |
|
v-model="columnNamesInput" |
|
autofocus |
|
dense |
|
outlined |
|
hide-details |
|
label="Enter comma separated column names" |
|
@keydown.enter="addColumns" |
|
/> |
|
</v-card-text> |
|
<v-card-actions> |
|
<v-spacer /> |
|
<v-btn outlined small @click="createTableColumnsDialog = false"> |
|
<!-- Cancel --> |
|
{{ $t("general.cancel") }} |
|
</v-btn> |
|
<v-btn outlined color="primary" small @click="addColumns"> |
|
<!-- Save --> |
|
{{ $t("general.save") }} |
|
</v-btn> |
|
</v-card-actions> |
|
</v-card> |
|
</v-dialog> |
|
|
|
<help v-model="helpModal" /> |
|
|
|
<v-tooltip v-if="!viewMode" left> |
|
<template #activator="{ on }"> |
|
<v-btn |
|
fixed |
|
fab |
|
large |
|
color="primary" |
|
right |
|
style="top: 45%" |
|
@click="createTableClick" |
|
v-on="on" |
|
> |
|
<v-icon>mdi-plus</v-icon> |
|
</v-btn> |
|
</template> |
|
<span class="caption"> |
|
<!--Add new table--> |
|
{{ $t("tooltip.addTable") }} |
|
</span> |
|
</v-tooltip> |
|
</div> |
|
</template> |
|
|
|
<script> |
|
import { |
|
uiTypes, |
|
getUIDTIcon, |
|
UITypes |
|
} from '~/components/project/spreadsheet/helpers/uiTypes' |
|
import GradientGenerator from '~/components/templates/gradientGenerator' |
|
import Help from '~/components/templates/help' |
|
|
|
const LinkToAnotherRecord = 'LinkToAnotherRecord' |
|
const Lookup = 'Lookup' |
|
const Rollup = 'Rollup' |
|
const defaultColProp = {} |
|
|
|
export default { |
|
name: 'TemplateEditor', |
|
components: { Help, GradientGenerator }, |
|
props: { |
|
id: [Number, String], |
|
viewMode: Boolean, |
|
projectTemplate: Object, |
|
excelImport: Boolean |
|
}, |
|
data: () => ({ |
|
loading: false, |
|
localId: null, |
|
valid: false, |
|
url: '', |
|
githubConfigForm: false, |
|
helpModal: false, |
|
editableTn: {}, |
|
expansionPanel: 0, |
|
project: { |
|
name: 'Project name', |
|
tables: [] |
|
}, |
|
tableNamesInput: '', |
|
columnNamesInput: '', |
|
createTablesDialog: false, |
|
createTableColumnsDialog: false, |
|
selectedTable: null, |
|
uiTypes: uiTypes.filter( |
|
t => ![UITypes.Formula, UITypes.SpecificDBType].includes(t.name) |
|
), |
|
rollupFnList: [ |
|
{ text: 'count', value: 'count' }, |
|
{ text: 'min', value: 'min' }, |
|
{ text: 'max', value: 'max' }, |
|
{ text: 'avg', value: 'avg' }, |
|
{ text: 'min', value: 'min' }, |
|
{ text: 'sum', value: 'sum' }, |
|
{ text: 'countDistinct', value: 'countDistinct' }, |
|
{ text: 'sumDistinct', value: 'sumDistinct' }, |
|
{ text: 'avgDistinct', value: 'avgDistinct' } |
|
], |
|
colors: { |
|
LinkToAnotherRecord: 'blue lighten-5', |
|
Rollup: 'pink lighten-5', |
|
Lookup: 'green lighten-5' |
|
} |
|
}), |
|
computed: { |
|
counter: { |
|
get() { |
|
return this.$store.state.templateC |
|
}, |
|
set(c) { |
|
this.$store.commit('mutTemplateC', c) |
|
} |
|
}, |
|
updateFilename() { |
|
return this.url && this.url.split('/').pop() |
|
} |
|
}, |
|
watch: { |
|
project: { |
|
deep: true, |
|
handler() { |
|
const template = { |
|
...this.project, |
|
tables: (this.project.tables || []).map((t) => { |
|
const table = { |
|
...t, |
|
columns: [], |
|
hasMany: [], |
|
manyToMany: [], |
|
belongsTo: [], |
|
v: [] |
|
} |
|
|
|
for (const column of t.columns || []) { |
|
if (this.isRelation(column)) { |
|
if (column.type === 'hm') { |
|
table.hasMany.push({ |
|
table_name: column.ref_table_name, |
|
title: column.column_name |
|
}) |
|
} else if (column.type === 'mm') { |
|
table.manyToMany.push({ |
|
ref_table_name: column.ref_table_name, |
|
title: column.column_name |
|
}) |
|
} else if (column.uidt === UITypes.ForeignKey) { |
|
table.belongsTo.push({ |
|
table_name: column.ref_table_name, |
|
title: column.column_name |
|
}) |
|
} |
|
} else if (this.isLookup(column)) { |
|
if (column.ref_table_name) { |
|
table.v.push({ |
|
title: column.column_name, |
|
lk: { |
|
ltn: column.ref_table_name.table_name, |
|
type: column.ref_table_name.type, |
|
lcn: column.ref_column_name |
|
} |
|
}) |
|
} |
|
} else if (this.isRollup(column)) { |
|
if (column.ref_table_name) { |
|
table.v.push({ |
|
title: column.column_name, |
|
rl: { |
|
rltn: column.ref_table_name.table_name, |
|
rlcn: column.ref_column_name, |
|
type: column.ref_table_name.type, |
|
fn: column.fn |
|
} |
|
}) |
|
} |
|
} else { |
|
table.columns.push(column) |
|
} |
|
} |
|
return table |
|
}) |
|
} |
|
this.$emit('update:projectTemplate', template) |
|
} |
|
} |
|
}, |
|
|
|
created() { |
|
document.addEventListener('keydown', this.handleKeyDown) |
|
}, |
|
destroyed() { |
|
document.removeEventListener('keydown', this.handleKeyDown) |
|
}, |
|
mounted() { |
|
this.parseAndLoadTemplate() |
|
const input = |
|
this.$refs.projec && this.$refs.project.$el.querySelector('input') |
|
if (input) { |
|
input.focus() |
|
input.select() |
|
} |
|
}, |
|
methods: { |
|
createTableClick() { |
|
this.createTablesDialog = true |
|
this.$e('c:table:create:navdraw') |
|
}, |
|
parseAndLoadTemplate() { |
|
if (this.projectTemplate) { |
|
this.parseTemplate(this.projectTemplate) |
|
this.expansionPanel = Array.from( |
|
{ length: this.project.tables.length }, |
|
(_, i) => i |
|
) |
|
} |
|
}, |
|
getIcon(type) { |
|
return getUIDTIcon(type) |
|
}, |
|
getRelatedTables(tableName, rollup = false) { |
|
const tables = [] |
|
for (const t of this.projectTemplate.tables) { |
|
if (tableName === t.table_name) { |
|
for (const hm of t.hasMany) { |
|
const rTable = this.project.tables.find( |
|
t1 => t1.table_name === hm.table_name |
|
) |
|
tables.push({ |
|
...rTable, |
|
type: 'hm' |
|
}) |
|
} |
|
for (const mm of t.manyToMany) { |
|
const rTable = this.project.tables.find( |
|
t1 => t1.table_name === mm.ref_table_name |
|
) |
|
tables.push({ |
|
...rTable, |
|
type: 'mm' |
|
}) |
|
} |
|
} else { |
|
for (const hm of t.hasMany) { |
|
if (hm.table_name === tableName && !rollup) { |
|
tables.push({ |
|
...t, |
|
type: 'bt' |
|
}) |
|
} |
|
} |
|
for (const mm of t.manyToMany) { |
|
if (mm.ref_table_name === tableName) { |
|
tables.push({ |
|
...t, |
|
type: 'mm' |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
|
|
return tables |
|
}, |
|
validateAndFocus() { |
|
if (!this.$refs.form.validate()) { |
|
const input = this.$el.querySelector('.v-input.error--text') |
|
this.expansionPanel = |
|
input && |
|
input.parentElement && |
|
input.parentElement.parentElement && |
|
+input.parentElement.parentElement.dataset.exp |
|
setTimeout(() => { |
|
input.querySelector('input,select').focus() |
|
}, 500) |
|
return false |
|
} |
|
return true |
|
}, |
|
deleteTable(i) { |
|
const deleteTable = this.project.tables[i] |
|
for (const table of this.project.tables) { |
|
if (table === deleteTable) { |
|
continue |
|
} |
|
table.columns = table.columns.filter( |
|
c => c.ref_table_name !== deleteTable.table_name |
|
) |
|
} |
|
this.project.tables.splice(i, 1) |
|
}, |
|
deleteTableColumn(i, j, col, table) { |
|
const deleteTable = this.project.tables[i] |
|
const deleteColumn = deleteTable.columns[j] |
|
|
|
let rTable, index |
|
// if relation column, delete the corresponding relation from other table |
|
if (col.uidt === UITypes.LinkToAnotherRecord) { |
|
if (col.type === 'hm') { |
|
rTable = this.project.tables.find(t => t.table_name === col.ref_table_name) |
|
index = |
|
rTable && |
|
rTable.columns.findIndex( |
|
c => c.uidt === UITypes.ForeignKey && c.ref_table_name === table.table_name |
|
) |
|
} else if (col.type === 'mm') { |
|
rTable = this.project.tables.find(t => t.table_name === col.ref_table_name) |
|
index = |
|
rTable && |
|
rTable.columns.findIndex( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'mm' |
|
) |
|
} |
|
} else if (col.uidt === UITypes.ForeignKey) { |
|
rTable = this.project.tables.find(t => t.table_name === col.ref_table_name) |
|
index = |
|
rTable && |
|
rTable.columns.findIndex( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'hm' |
|
) |
|
} |
|
|
|
if (rTable && index > -1) { |
|
rTable.columns.splice(index, 1) |
|
} |
|
|
|
for (const table of this.project.tables) { |
|
if (table === deleteTable) { |
|
continue |
|
} |
|
table.columns = table.columns.filter( |
|
c => |
|
c.ref_table_name !== deleteTable.table_name || |
|
c.ref_column_name !== deleteColumn.column_name |
|
) |
|
} |
|
deleteTable.columns.splice(j, 1) |
|
}, |
|
addTables() { |
|
if (!this.tableNamesInput) { |
|
return |
|
} |
|
// todo: fix |
|
const re = |
|
/(?:^|,\s*)(\w+)(?:\(((\w+)(?:\s*,\s*\w+)?)?\)){0,1}(?=\s*,|\s*$)/g |
|
let m |
|
// eslint-disable-next-line no-cond-assign |
|
while ((m = re.exec(this.tableNamesInput))) { |
|
if (this.project.tables.some(t => t.table_name === m[1])) { |
|
this.$toast.info(`Table '${m[1]}' is already exist`).goAway(1000) |
|
continue |
|
} |
|
|
|
this.project.tables.push({ |
|
table_name: m[1], |
|
columns: (m[2] ? m[2].split(/\s*,\s*/) : []) |
|
.map(col => ({ |
|
column_name: col, |
|
...defaultColProp |
|
})) |
|
.filter( |
|
(v, i, arr) => |
|
i === arr.findIndex(c => c.column_name === v.column_name) |
|
) |
|
}) |
|
} |
|
this.createTablesDialog = false |
|
this.tableNamesInput = '' |
|
}, |
|
compareRel(a, b) { |
|
return ( |
|
((a && a.table_name) || a) === ((b && b.table_name) || b) && |
|
(a && a.type) === (b && b.type) |
|
) |
|
}, |
|
addColumns() { |
|
if (!this.columnNamesInput) { |
|
return |
|
} |
|
const table = this.project.tables[this.expansionPanel] |
|
for (const col of this.columnNamesInput.split(/\s*,\s*/)) { |
|
if (table.columns.some(c => c.column_name === col)) { |
|
this.$toast.info(`Column '${col}' is already exist`).goAway(1000) |
|
continue |
|
} |
|
|
|
table.columns.push({ |
|
column_name: col, |
|
...defaultColProp |
|
}) |
|
} |
|
this.columnNamesInput = '' |
|
this.createTableColumnsDialog = false |
|
|
|
this.$nextTick(() => { |
|
const input = |
|
this.$refs[ |
|
`uidt_${table.table_name}_${table.columns.length - 1}` |
|
][0].$el.querySelector('input') |
|
input.focus() |
|
this.$nextTick(() => { |
|
input.select() |
|
}) |
|
}) |
|
}, |
|
showColCreateDialog(table) { |
|
this.createTableColumnsDialog = true |
|
this.selectedTable = table |
|
}, |
|
|
|
isRelation(col) { |
|
return col.uidt === 'LinkToAnotherRecord' || col.uidt === 'ForeignKey' |
|
}, |
|
isLookup(col) { |
|
return col.uidt === 'Lookup' |
|
}, |
|
isRollup(col) { |
|
return col.uidt === 'Rollup' |
|
}, |
|
isVirtual(col) { |
|
return col && uiTypes.some(ut => ut.name === col.uidt && ut.virtual) |
|
}, |
|
isLookupOrRollup(col) { |
|
return this.isLookup(col) || this.isRollup(col) |
|
}, |
|
isSelect(col) { |
|
return col.uidt === 'MultiSelect' || col.uidt === 'SingleSelect' |
|
}, |
|
addNewColumnRow(table, uidt) { |
|
table.columns.push({ |
|
column_name: `title${table.columns.length + 1}`, |
|
...defaultColProp, |
|
uidt, |
|
...(uidt === LinkToAnotherRecord |
|
? { |
|
type: 'mm' |
|
} |
|
: {}) |
|
}) |
|
this.$nextTick(() => { |
|
const input = |
|
this.$refs[ |
|
`cn_${table.table_name}_${table.columns.length - 1}` |
|
][0].$el.querySelector('input') |
|
input.focus() |
|
input.select() |
|
}) |
|
}, |
|
|
|
async handleKeyDown({ metaKey, key, altKey, shiftKey, ctrlKey }) { |
|
if (!(metaKey && ctrlKey) && !(altKey && shiftKey)) { |
|
return |
|
} |
|
switch (key && key.toLowerCase()) { |
|
case 't': |
|
this.createTablesDialog = true |
|
break |
|
case 'c': |
|
this.createTableColumnsDialog = true |
|
break |
|
case 'a': |
|
this.addNewColumnRow(this.project.tables[this.expansionPanel]) |
|
break |
|
case 'j': |
|
this.copyJSON() |
|
break |
|
case 's': |
|
await this.saveTemplate() |
|
break |
|
case 'arrowup': |
|
this.expansionPanel = this.expansionPanel |
|
? --this.expansionPanel |
|
: this.project.tables.length - 1 |
|
break |
|
case 'arrowdown': |
|
this.expansionPanel = |
|
++this.expansionPanel % this.project.tables.length |
|
break |
|
|
|
case '1': |
|
this.addNewColumnRow( |
|
this.project.tables[this.expansionPanel], |
|
'Number' |
|
) |
|
break |
|
case '2': |
|
this.addNewColumnRow( |
|
this.project.tables[this.expansionPanel], |
|
'SingleLineText' |
|
) |
|
break |
|
case '3': |
|
this.addNewColumnRow( |
|
this.project.tables[this.expansionPanel], |
|
'LongText' |
|
) |
|
break |
|
case '4': |
|
this.addNewColumnRow( |
|
this.project.tables[this.expansionPanel], |
|
'LinkToAnotherRecord' |
|
) |
|
break |
|
case '5': |
|
this.addNewColumnRow( |
|
this.project.tables[this.expansionPanel], |
|
'Lookup' |
|
) |
|
break |
|
case '6': |
|
this.addNewColumnRow( |
|
this.project.tables[this.expansionPanel], |
|
'Rollup' |
|
) |
|
break |
|
} |
|
}, |
|
copyJSON() { |
|
if (!this.validateAndFocus()) { |
|
this.$toast.info('Please fill all the required column!').goAway(5000) |
|
return |
|
} |
|
const el = document.createElement('textarea') |
|
el.addEventListener('focusin', e => e.stopPropagation()) |
|
el.value = JSON.stringify(this.projectTemplate, null, 2) |
|
el.style = { position: 'absolute', left: '-9999px' } |
|
document.body.appendChild(el) |
|
el.select() |
|
document.execCommand('copy') |
|
document.body.removeChild(el) |
|
this.$toast |
|
.success('Successfully copied JSON data to clipboard!') |
|
.goAway(3000) |
|
return true |
|
}, |
|
openUrl() { |
|
window.open(this.url, '_blank') |
|
}, |
|
async loadUrl() { |
|
try { |
|
let template = (await this.$axios.get(this.url)).data |
|
|
|
if (typeof template === 'string') { |
|
template = JSON.parse(template) |
|
} |
|
|
|
this.parseTemplate(template) |
|
} catch (e) { |
|
this.$toast.error(e.message).goAway(5000) |
|
} |
|
}, |
|
|
|
parseTemplate({ tables = [], ...rest }) { |
|
const parsedTemplate = { |
|
...rest, |
|
tables: tables.map( |
|
({ |
|
manyToMany = [], |
|
hasMany = [], |
|
belongsTo = [], |
|
v = [], |
|
columns = [], |
|
...rest |
|
}) => ({ |
|
...rest, |
|
columns: [ |
|
...columns, |
|
...manyToMany.map(mm => ({ |
|
column_name: mm.title || `${rest.table_name} <=> ${mm.ref_table_name}`, |
|
uidt: LinkToAnotherRecord, |
|
type: 'mm', |
|
...mm |
|
})), |
|
...hasMany.map(hm => ({ |
|
column_name: hm.title || `${rest.table_name} => ${hm.table_name}`, |
|
uidt: LinkToAnotherRecord, |
|
type: 'hm', |
|
ref_table_name: hm.table_name, |
|
...hm |
|
})), |
|
...belongsTo.map(bt => ({ |
|
column_name: bt.title || `${rest.table_name} => ${bt.ref_table_name}`, |
|
uidt: UITypes.ForeignKey, |
|
ref_table_name: bt.table_name, |
|
...bt |
|
})), |
|
...v.map((v) => { |
|
const res = { |
|
column_name: v.title, |
|
ref_table_name: { |
|
...v |
|
} |
|
} |
|
if (v.lk) { |
|
res.uidt = Lookup |
|
res.ref_table_name.table_name = v.lk.ltn |
|
res.ref_column_name = v.lk.lcn |
|
res.ref_table_name.type = v.lk.type |
|
} else if (v.rl) { |
|
res.uidt = Rollup |
|
res.ref_table_name.table_name = v.rl.rltn |
|
res.ref_column_name = v.rl.rlcn |
|
res.ref_table_name.type = v.rl.type |
|
res.fn = v.rl.fn |
|
} |
|
return res |
|
}) |
|
] |
|
}) |
|
) |
|
} |
|
|
|
this.project = parsedTemplate |
|
}, |
|
|
|
async projectTemplateCreate() { |
|
if (!this.validateAndFocus()) { |
|
this.$toast.info('Please fill all the required column!').goAway(5000) |
|
return |
|
} |
|
|
|
try { |
|
const githubConfig = this.$store.state.github |
|
|
|
// const token = await models.store.where({ key: 'GITHUB_TOKEN' }).first() |
|
// const branch = await models.store.where({ key: 'GITHUB_BRANCH' }).first() |
|
// const filePath = await models.store.where({ key: 'GITHUB_FILE_PATH' }).first() |
|
// const templateRepo = await models.store.where({ key: 'PROJECT_TEMPLATES_REPO' }).first() |
|
|
|
if (!githubConfig.token || !githubConfig.repo) { |
|
throw new Error('Missing token or template path') |
|
} |
|
|
|
const data = JSON.stringify(this.projectTemplate, 0, 2) |
|
const filename = |
|
this.updateFilename || |
|
`${this.projectTemplate.name}_${Date.now()}.json` |
|
const filePath = `${ |
|
githubConfig.filePath ? githubConfig.filePath + '/' : '' |
|
}${filename}` |
|
const apiPath = `https://api.github.com/repos/${githubConfig.repo}/contents/${filePath}` |
|
|
|
let sha |
|
if (this.updateFilename) { |
|
const { |
|
data: { sha: _sha } |
|
} = await this.$axios({ |
|
url: `https://api.github.com/repos/${githubConfig.repo}/contents/${filePath}`, |
|
method: 'get', |
|
headers: { |
|
Authorization: 'token ' + githubConfig.token |
|
} |
|
}) |
|
sha = _sha |
|
} |
|
|
|
await this.$axios({ |
|
url: apiPath, |
|
method: 'put', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
Authorization: 'token ' + githubConfig.token |
|
}, |
|
data: { |
|
message: `templates : init template ${filename}`, |
|
content: Base64.encode(data), |
|
sha, |
|
branch: githubConfig.branch |
|
} |
|
}) |
|
|
|
this.url = `https://raw.githubusercontent.com/${githubConfig.repo}/${githubConfig.branch}/${filePath}` |
|
|
|
this.$toast |
|
.success('Template generated and saved successfully!') |
|
.goAway(4000) |
|
} catch (e) { |
|
this.$toast.error(e.message).goAway(5000) |
|
} |
|
}, |
|
navigateToTable(tn) { |
|
const index = this.projectTemplate.tables.findIndex( |
|
t => t.table_name === tn |
|
) |
|
if (Array.isArray(this.expansionPanel)) { |
|
this.expansionPanel.push(index) |
|
} else { |
|
this.expansionPanel = index |
|
} |
|
|
|
this.$nextTick(() => { |
|
const accord = this.$el.querySelector(`#tn_${tn}`) |
|
accord.focus() |
|
accord.scrollIntoView() |
|
}) |
|
}, |
|
|
|
async saveTemplate() { |
|
this.loading = true |
|
try { |
|
if (this.id || this.localId) { |
|
await this.$axios.put( |
|
`${process.env.NC_API_URL}/api/v1/nc/templates/${ |
|
this.id || this.localId |
|
}`, |
|
this.projectTemplate, |
|
{ |
|
params: { |
|
token: this.$store.state.template |
|
} |
|
} |
|
) |
|
this.$toast.success('Template updated successfully').goAway(3000) |
|
} else if (!this.$store.state.template) { |
|
if (!this.copyJSON()) { |
|
return |
|
} |
|
|
|
this.$toast.info('Initiating Github for template').goAway(3000) |
|
const res = await this.$axios.post( |
|
`${process.env.NC_API_URL}/api/v1/projectTemplateCreate`, |
|
this.projectTemplate |
|
) |
|
this.$toast.success('Initiated Github successfully').goAway(3000) |
|
window.open(res.data.path, '_blank') |
|
} else { |
|
const res = await this.$axios.post( |
|
`${process.env.NC_API_URL}/api/v1/nc/templates`, |
|
this.projectTemplate, |
|
{ |
|
params: { |
|
token: this.$store.state.template |
|
} |
|
} |
|
) |
|
this.localId = res.data.id |
|
this.$toast.success('Template updated successfully').goAway(3000) |
|
} |
|
|
|
this.$emit('saved') |
|
} catch (e) { |
|
this.$toast.error(e.message).goAway(3000) |
|
} finally { |
|
this.loading = false |
|
} |
|
}, |
|
getRules(col, table) { |
|
return v => |
|
col.uidt !== UITypes.LinkToAnotherRecord || |
|
!table.columns.some( |
|
c => |
|
c !== col && |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.type === col.type && |
|
c.ref_table_name === col.ref_table_name |
|
) || |
|
'Duplicate relation is not allowed' |
|
}, |
|
onTableNameUpdate(oldTable, newVal) { |
|
const oldVal = oldTable.table_name |
|
this.$set(oldTable, 'table_name', newVal) |
|
|
|
for (const table of this.project.tables) { |
|
for (const col of table.columns) { |
|
if (col.uidt === UITypes.LinkToAnotherRecord) { |
|
if (col.ref_table_name === oldVal) { |
|
this.$set(col, 'ref_table_name', newVal) |
|
} |
|
} else if ( |
|
col.uidt === UITypes.Rollup || |
|
col.uidt === UITypes.Lookup |
|
) { |
|
if (col.ref_table_name && col.ref_table_name.table_name === oldVal) { |
|
this.$set(col.ref_table_name, 'table_name', newVal) |
|
} |
|
} |
|
} |
|
} |
|
}, |
|
onColumnNameUpdate(oldCol, newVal, tn) { |
|
const oldVal = oldCol.column_name |
|
this.$set(oldCol, 'column_name', newVal) |
|
|
|
for (const table of this.project.tables) { |
|
for (const col of table.columns) { |
|
if (col.uidt === UITypes.Rollup || col.uidt === UITypes.Lookup) { |
|
if (col.ref_table_name && col.ref_column_name === oldVal && col.ref_table_name.table_name === tn) { |
|
this.$set(col, 'ref_column_name', newVal) |
|
} |
|
} |
|
} |
|
} |
|
}, |
|
async onRtnChange(oldVal, newVal, col, table) { |
|
this.$set(col, 'ref_table_name', newVal) |
|
|
|
await this.$nextTick() |
|
|
|
if ( |
|
col.uidt !== UITypes.LinkToAnotherRecord && |
|
col.uidt !== UITypes.ForeignKey |
|
) { |
|
return |
|
} |
|
|
|
if (oldVal) { |
|
const rTable = this.project.tables.find(t => t.table_name === oldVal) |
|
// delete relation from other table if exist |
|
|
|
let index = -1 |
|
if (col.uidt === UITypes.LinkToAnotherRecord && col.type === 'mm') { |
|
index = rTable.columns.findIndex( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'mm' |
|
) |
|
} else if ( |
|
col.uidt === UITypes.LinkToAnotherRecord && |
|
col.type === 'hm' |
|
) { |
|
index = rTable.columns.findIndex( |
|
c => c.uidt === UITypes.ForeignKey && c.ref_table_name === table.table_name |
|
) |
|
} else if (col.uidt === UITypes.ForeignKey) { |
|
index = rTable.columns.findIndex( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'hm' |
|
) |
|
} |
|
|
|
if (index > -1) { |
|
rTable.columns.splice(index, 1) |
|
} |
|
} |
|
if (newVal) { |
|
const rTable = this.project.tables.find(t => t.table_name === newVal) |
|
|
|
// check relation relation exist in other table |
|
// if not create a relation |
|
if (col.uidt === UITypes.LinkToAnotherRecord && col.type === 'mm') { |
|
if ( |
|
!rTable.columns.find( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'mm' |
|
) |
|
) { |
|
rTable.columns.push({ |
|
column_name: `title${rTable.columns.length + 1}`, |
|
uidt: UITypes.LinkToAnotherRecord, |
|
type: 'mm', |
|
ref_table_name: table.table_name |
|
}) |
|
} |
|
} else if ( |
|
col.uidt === UITypes.LinkToAnotherRecord && |
|
col.type === 'hm' |
|
) { |
|
if ( |
|
!rTable.columns.find( |
|
c => c.uidt === UITypes.ForeignKey && c.ref_table_name === table.table_name |
|
) |
|
) { |
|
rTable.columns.push({ |
|
column_name: `title${rTable.columns.length + 1}`, |
|
uidt: UITypes.ForeignKey, |
|
ref_table_name: table.table_name |
|
}) |
|
} |
|
} else if (col.uidt === UITypes.ForeignKey) { |
|
if ( |
|
!rTable.columns.find( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'hm' |
|
) |
|
) { |
|
rTable.columns.push({ |
|
column_name: `title${rTable.columns.length + 1}`, |
|
uidt: UITypes.LinkToAnotherRecord, |
|
type: 'hm', |
|
ref_table_name: table.table_name |
|
}) |
|
} |
|
} |
|
} |
|
}, |
|
onRTypeChange(oldType, newType, col, table) { |
|
this.$set(col, 'type', newType) |
|
|
|
const rTable = this.project.tables.find(t => t.table_name === col.ref_table_name) |
|
|
|
let index = -1 |
|
|
|
// find column and update relation |
|
// or create a new column |
|
|
|
if (oldType === 'hm') { |
|
index = rTable.columns.findIndex( |
|
c => c.uidt === UITypes.ForeignKey && c.ref_table_name === table.table_name |
|
) |
|
} else if (oldType === 'mm') { |
|
index = rTable.columns.findIndex( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'mm' |
|
) |
|
} |
|
|
|
const rCol = |
|
index === -1 |
|
? { column_name: `title${rTable.columns.length + 1}` } |
|
: { ...rTable.columns[index] } |
|
index = index === -1 ? rTable.columns.length : index |
|
|
|
if (newType === 'mm') { |
|
rCol.type = 'mm' |
|
rCol.uidt = UITypes.LinkToAnotherRecord |
|
} else if (newType === 'hm') { |
|
rCol.type = 'bt' |
|
rCol.uidt = UITypes.ForeignKey |
|
} |
|
rCol.ref_table_name = table.table_name |
|
|
|
this.$set(rTable.columns, index, rCol) |
|
}, |
|
onUidtChange(oldVal, newVal, col, table) { |
|
this.$set(col, 'uidt', newVal) |
|
this.$set(col, 'dtxp', undefined) |
|
|
|
// delete relation column from other table |
|
// if previous type is relation |
|
|
|
let index = -1 |
|
let rTable |
|
|
|
if (oldVal === UITypes.LinkToAnotherRecord) { |
|
rTable = this.project.tables.find(t => t.table_name === col.ref_table_name) |
|
if (rTable) { |
|
if (col.type === 'hm') { |
|
index = rTable.columns.findIndex( |
|
c => c.uidt === UITypes.ForeignKey && c.ref_table_name === table.table_name |
|
) |
|
} else if (col.type === 'mm') { |
|
index = rTable.columns.findIndex( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'mm' |
|
) |
|
} |
|
} |
|
} else if (oldVal === UITypes.ForeignKey) { |
|
rTable = this.project.tables.find(t => t.table_name === col.ref_table_name) |
|
if (rTable) { |
|
index = rTable.columns.findIndex( |
|
c => |
|
c.uidt === UITypes.LinkToAnotherRecord && |
|
c.ref_table_name === table.table_name && |
|
c.type === 'hm' |
|
) |
|
} |
|
} |
|
if (rTable && index > -1) { |
|
rTable.columns.splice(index, 1) |
|
} |
|
|
|
col.ref_table_name = undefined |
|
col.type = undefined |
|
col.ref_column_name = undefined |
|
|
|
if (col.uidt === LinkToAnotherRecord) { |
|
col.type = col.type || 'mm' |
|
} |
|
} |
|
} |
|
} |
|
</script> |
|
|
|
<style scoped> |
|
/deep/ .v-select__selections { |
|
flex-wrap: nowrap; |
|
} |
|
</style>
|
|
|