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.
2146 lines
80 KiB
2146 lines
80 KiB
<template> |
|
<v-container fluid> |
|
<v-col |
|
:class="{ 'col-md-8 offset-md-2 col-sm-10 offset-sm-1 col-12': !edit }" |
|
style="position: relative" |
|
> |
|
<v-form ref="form" v-model="valid" :class="{ 'mt-8 pt-8': !edit }"> |
|
<v-card ref="mainCard" class="elevation-5"> |
|
<div |
|
v-if="!edit" |
|
style=" |
|
position: absolute; |
|
top: -30px; |
|
left: -moz-calc(50% - 30px); |
|
left: -webkit-calc(50% - 30px); |
|
left: calc(50% - 30px); |
|
z-index: 999; |
|
border-radius: 10px; |
|
" |
|
class="primary" |
|
> |
|
<v-img |
|
class="mx-auto" |
|
width="60" |
|
height="60" |
|
:src="require('@/assets/img/icons/512x512-trans.png')" |
|
@dblclick="enableAllSchemas()" |
|
/> |
|
</div> |
|
<v-toolbar |
|
flat |
|
color="" |
|
class="mb-3" |
|
style=" |
|
width: 100%; |
|
border-bottom: 1px solid var(--v-backgroundColor-base); |
|
" |
|
> |
|
<v-toolbar-title class="title"> |
|
<!-- Edit Project --> |
|
<span v-if="edit">{{ $t("activity.editProject") }}</span> |
|
<!-- Create Project --> |
|
<span v-else>{{ $t("activity.createProject") }}</span> |
|
</v-toolbar-title> |
|
<v-spacer /> |
|
<!-- Cancel and Return --> |
|
<x-btn |
|
v-ge="['project', 'cancel']" |
|
:tooltip="$t('tooltip.cancelReturn')" |
|
to="/" |
|
class="elevation-20" |
|
> |
|
<!-- Cancel --> |
|
{{ $t("general.cancel") }} |
|
</x-btn> |
|
<x-btn |
|
v-ge="['project', 'save']" |
|
:disabled="!valid || !envStatusValid" |
|
class="primary" |
|
@click="createOrUpdateProject()" |
|
> |
|
<!-- Update & Restart --> |
|
<span v-if="edit">{{ $t("tooltip.updateRestart") }}</span> |
|
<!-- Save Project --> |
|
<span v-else>{{ $t("activity.saveProject") }}</span> |
|
</x-btn> |
|
<v-progress-linear |
|
v-if="projectReloading" |
|
top |
|
absolute |
|
color="success" |
|
indeterminate |
|
height="3" |
|
style="top: -3px" |
|
/> |
|
</v-toolbar> |
|
|
|
<div ref="panelContainer" style=""> |
|
<api-overlay |
|
v-show="projectReloading" |
|
:project-created="projectCreated" |
|
/> |
|
<v-container fluid> |
|
<v-row> |
|
<v-col cols="12" class="mb-0 pb-0"> |
|
<div style="max-width: 360px" class="mx-auto mb-3"> |
|
<!-- Enter Project Name --> |
|
<v-text-field |
|
ref="name" |
|
v-model="project.title" |
|
v-ge="['project', 'name']" |
|
:rules="form.titleRequiredRule" |
|
:height="20" |
|
:label="$t('placeholder.projName')" |
|
autofocus |
|
/> |
|
</div> |
|
</v-col> |
|
|
|
<v-col |
|
v-show="isTitle" |
|
cols="10" |
|
offset="1" |
|
:class="{ 'mt-0 pt-0': !edit, 'mt-3 pt-3': edit }" |
|
> |
|
<p |
|
:class="{ |
|
'text-center mb-2 mt-3': !edit, |
|
'text-center mb-2 mt-3 grey--text': edit, |
|
}" |
|
> |
|
{{ $t("title.dbCredentials") }} |
|
</p> |
|
<v-expansion-panels |
|
v-model="panel" |
|
focusable |
|
accordion="" |
|
class="elevation-20" |
|
style="border: 1px solid white" |
|
> |
|
<v-expansion-panel |
|
v-for="(envData, envKey, panelIndex) in project.envs" |
|
:key="panelIndex" |
|
:ref="`panel${envKey}`" |
|
@change="onPanelToggle(panelIndex, envKey)" |
|
> |
|
<v-expansion-panel-header disable-icon-rotate> |
|
<p class="pa-0 ma-0"> |
|
<v-tooltip |
|
v-for="(db, tabIndex) in envData.db" |
|
:key="tabIndex" |
|
bottom |
|
> |
|
<template #activator="{ on }"> |
|
<v-icon |
|
small |
|
:color="getDbStatusColor(db)" |
|
@click.native.stop=" |
|
showDBTabInEnvPanel(panelIndex, tabIndex) |
|
" |
|
v-on="on" |
|
> |
|
mdi-database |
|
</v-icon> |
|
</template> |
|
{{ getDbStatusTooltip(db) }} |
|
</v-tooltip> |
|
|
|
<span |
|
v-if="project.ui[envKey]" |
|
class="caption" |
|
:class="project.ui[envKey].color + '--text'" |
|
> |
|
<i>{{ project.ui[envKey].msg }}</i> |
|
</span> |
|
|
|
<x-btn |
|
v-if="panelIndex" |
|
v-ge="['project', 'env-delete']" |
|
small |
|
text |
|
btn.class="float-right" |
|
tooltip="Click here to remove environment" |
|
@click.native.stop="removeEnv(envKey)" |
|
> |
|
<v-hover v-slot="{ hover }"> |
|
<v-icon |
|
:color="hover ? 'error' : 'grey'" |
|
@click.native.stop="removeEnv(envKey)" |
|
> |
|
mdi-delete |
|
</v-icon> |
|
</v-hover> |
|
</x-btn> |
|
</p> |
|
<template #actions> |
|
<v-tooltip |
|
v-if="getEnvironmentStatusAggregated(envData.db)" |
|
bottom |
|
> |
|
<template #activator="{ on }"> |
|
<v-icon color="green" v-on="on"> |
|
mdi-check-circle |
|
</v-icon> |
|
</template> |
|
<span>Environment setup complete</span> |
|
</v-tooltip> |
|
<v-tooltip v-else-if="edit" bottom> |
|
<template #activator="{ on }"> |
|
<v-icon color="orange" v-on="on"> |
|
mdi-alert-circle |
|
</v-icon> |
|
</template> |
|
<span>Environment setup pending</span> |
|
</v-tooltip> |
|
</template> |
|
</v-expansion-panel-header> |
|
<v-expansion-panel-content eager> |
|
<v-col> |
|
<v-card flat=""> |
|
<v-tabs |
|
v-model="databases[panelIndex]" |
|
height="34" |
|
background-color="" |
|
> |
|
<v-tab |
|
v-for="(db, dbIndex) in project.envs[envKey].db" |
|
:key="dbIndex" |
|
> |
|
<v-icon small> mdi-database </v-icon> |
|
<span class="text-capitalize caption">{{ |
|
db.connection.database |
|
}}</span> |
|
</v-tab> |
|
<v-tabs-items v-model="databases[panelIndex]"> |
|
<v-tab-item |
|
v-for="(db, dbIndex) in project.envs[envKey] |
|
.db" |
|
:key="dbIndex" |
|
> |
|
<v-card flat> |
|
<!-- <form ref="form" class="pa-3">--> |
|
<v-container class="justify-center"> |
|
<v-row style="position: relative"> |
|
<v-overlay |
|
v-if="showMonaco[dbIndex]" |
|
absolute |
|
class="monaco-overlay" |
|
> |
|
<v-container fluid class="h-100"> |
|
<v-card |
|
style="position: relative" |
|
class="h-100" |
|
> |
|
<v-icon |
|
class="monaco-overlay-close pointer" |
|
color="error" |
|
@click=" |
|
$set( |
|
showMonaco, |
|
dbIndex, |
|
false |
|
) |
|
" |
|
> |
|
mdi-close-circle |
|
</v-icon> |
|
|
|
<span |
|
class="ml-2 caption grey--text" |
|
>Refer knex documentation |
|
<a |
|
href="https://knexjs.org/#Installation-client" |
|
target="_blank" |
|
class="grey--text" |
|
>here</a |
|
> |
|
.</span |
|
> |
|
|
|
<monaco-json-object-editor |
|
v-model=" |
|
project.envs[envKey].db[ |
|
dbIndex |
|
] |
|
" |
|
style=" |
|
height: calc(100% - 20px); |
|
width: 100%; |
|
" |
|
/> |
|
</v-card> |
|
</v-container> |
|
</v-overlay> |
|
|
|
<v-col cols="4" class="py-0"> |
|
<!-- Database Type --> |
|
<v-select |
|
v-model="client[dbIndex]" |
|
v-ge="['project', 'env-db-change']" |
|
class="body-2 db-select" |
|
:items="Object.keys(databaseNames)" |
|
:label="$t('labels.dbType')" |
|
@change=" |
|
onDatabaseTypeChanged( |
|
client[dbIndex], |
|
db, |
|
dbIndex, |
|
envKey |
|
) |
|
" |
|
> |
|
<template #selection="{ item }"> |
|
<v-chip |
|
small |
|
:color=" |
|
colors[ |
|
Object.keys( |
|
databaseNames |
|
).indexOf(item) % |
|
colors.length |
|
] |
|
" |
|
class="" |
|
> |
|
{{ item }} |
|
</v-chip> |
|
</template> |
|
|
|
<template |
|
slot="item" |
|
slot-scope="data" |
|
> |
|
<v-chip |
|
:color=" |
|
colors[ |
|
Object.keys( |
|
databaseNames |
|
).indexOf(data.item) % |
|
colors.length |
|
] |
|
" |
|
class="caption" |
|
> |
|
{{ data.item }} |
|
</v-chip> |
|
</template> |
|
</v-select> |
|
</v-col> |
|
<!-- SQLite File --> |
|
<v-col |
|
v-if="db.client === 'sqlite3'" |
|
class="py-0" |
|
> |
|
<v-text-field |
|
v-model=" |
|
db.connection.connection.filename |
|
" |
|
v-ge="['project', 'env-db-file']" |
|
:rules="form.folderRequiredRule" |
|
:label="$t('labels.sqliteFile')" |
|
@click="selectSqliteFile(db)" |
|
> |
|
<v-icon slot="prepend" color="info"> |
|
mdi-file-outline |
|
</v-icon> |
|
</v-text-field> |
|
</v-col> |
|
<!-- Host Address --> |
|
<v-col |
|
v-if="db.client !== 'sqlite3'" |
|
cols="4" |
|
class="py-0" |
|
> |
|
<v-text-field |
|
v-model="db.connection.host" |
|
v-ge="['project', 'env-db-host']" |
|
class="body-2" |
|
:rules="form.requiredRule" |
|
:label="$t('labels.hostAddress')" |
|
/> |
|
</v-col> |
|
<!-- Port Number --> |
|
<v-col |
|
v-if="db.client !== 'sqlite3'" |
|
cols="4" |
|
class="py-0" |
|
> |
|
<v-text-field |
|
v-model="db.connection.port" |
|
v-ge="['project', 'env-db-port']" |
|
class="body-2" |
|
:label="$t('labels.port')" |
|
:rules="form.portValidationRule" |
|
/> |
|
</v-col> |
|
<!-- Username --> |
|
<v-col |
|
v-if="db.client !== 'sqlite3'" |
|
cols="4" |
|
class="py-0" |
|
> |
|
<v-text-field |
|
v-model="db.connection.user" |
|
v-ge="['project', 'env-db-user']" |
|
class="body-2" |
|
:rules="form.requiredRule" |
|
:label="$t('labels.username')" |
|
/> |
|
</v-col> |
|
<!-- Password --> |
|
<v-col |
|
v-if="db.client !== 'sqlite3'" |
|
cols="4" |
|
class="py-0" |
|
> |
|
<v-text-field |
|
:ref="`password${envKey}`" |
|
v-model="db.connection.password" |
|
v-ge="[ |
|
'project', |
|
'env-db-password', |
|
]" |
|
class="body-2 db-password" |
|
:type=" |
|
showPass[ |
|
`${panelIndex}_${dbIndex}` |
|
] |
|
? 'text' |
|
: 'password' |
|
" |
|
:label="$t('labels.password')" |
|
@dblclick="enableDbEdit++" |
|
> |
|
<template #append> |
|
<v-icon |
|
small |
|
@click=" |
|
$set( |
|
showPass, |
|
`${panelIndex}_${dbIndex}`, |
|
!showPass[ |
|
`${panelIndex}_${dbIndex}` |
|
] |
|
) |
|
" |
|
> |
|
{{ |
|
showPass[ |
|
`${panelIndex}_${dbIndex}` |
|
] |
|
? "visibility_off" |
|
: "visibility" |
|
}} |
|
</v-icon> |
|
</template> |
|
</v-text-field> |
|
</v-col> |
|
<!-- Database : create if not exists --> |
|
<v-col |
|
v-if="db.client !== 'sqlite3'" |
|
cols="4" |
|
class="py-0" |
|
> |
|
<v-text-field |
|
v-model="db.connection.database" |
|
v-ge="['project', 'env-db-name']" |
|
:disabled="edit && enableDbEdit < 2" |
|
class="body-2 database-field" |
|
:rules="form.requiredRule" |
|
:label=" |
|
$t('labels.dbCreateIfNotExists') |
|
" |
|
/> |
|
</v-col> |
|
<!-- todo : ssl & inflection --> |
|
<v-col |
|
v-if="db.client !== 'sqlite3'" |
|
class="" |
|
> |
|
<v-expansion-panels> |
|
<v-expansion-panel |
|
style="border: 1px solid wheat" |
|
> |
|
<v-expansion-panel-header> |
|
<!-- SSL & Advanced parameters --> |
|
<span |
|
class="grey--text caption" |
|
>{{ |
|
$t( |
|
"title.advancedParameters" |
|
) |
|
}}</span |
|
> |
|
</v-expansion-panel-header> |
|
<v-expansion-panel-content> |
|
<v-card class="elevation-0"> |
|
<v-card-text> |
|
<v-select |
|
v-model="db.ui.sslUse" |
|
class="caption" |
|
:items=" |
|
Object.keys(sslUsage) |
|
" |
|
> |
|
<template |
|
#item="{ item }" |
|
> |
|
<span class="caption">{{ |
|
item |
|
}}</span> |
|
</template> |
|
</v-select> |
|
|
|
<v-row class="pa-0 ma-0"> |
|
<input |
|
ref="certFilePath" |
|
type="file" |
|
class="d-none" |
|
@change=" |
|
readFileContent( |
|
db, |
|
'ssl', |
|
'cert', |
|
dbIndex |
|
) |
|
" |
|
/> |
|
<!-- Select .cert file --> |
|
<x-btn |
|
v-ge="[ |
|
'project', |
|
'env-db-cert', |
|
]" |
|
:tooltip=" |
|
$t( |
|
'tooltip.clientCert' |
|
) |
|
" |
|
small |
|
color="primary" |
|
outlined |
|
class="elevation-5" |
|
@click=" |
|
selectFile( |
|
db, |
|
'ssl', |
|
'certFilePath', |
|
dbIndex |
|
) |
|
" |
|
> |
|
{{ db.ui.ssl.cert }} |
|
</x-btn> |
|
<!-- Select .key file --> |
|
<input |
|
ref="keyFilePath" |
|
type="file" |
|
class="d-none" |
|
@change=" |
|
readFileContent( |
|
db, |
|
'ssl', |
|
'key', |
|
dbIndex |
|
) |
|
" |
|
/> |
|
<x-btn |
|
v-ge="[ |
|
'project', |
|
'env-db-key', |
|
]" |
|
:tooltip=" |
|
$t( |
|
'tooltip.clientKey' |
|
) |
|
" |
|
small |
|
color="primary" |
|
outlined |
|
class="elevation-5" |
|
@click=" |
|
selectFile( |
|
db, |
|
'ssl', |
|
'keyFilePath', |
|
dbIndex |
|
) |
|
" |
|
> |
|
{{ db.ui.ssl.key }} |
|
</x-btn> |
|
<!-- Select CA file --> |
|
<input |
|
ref="caFilePath" |
|
type="file" |
|
class="d-none" |
|
@change=" |
|
readFileContent( |
|
db, |
|
'ssl', |
|
'ca', |
|
dbIndex |
|
) |
|
" |
|
/> |
|
<x-btn |
|
v-ge="[ |
|
'project', |
|
'env-db-ca', |
|
]" |
|
:tooltip=" |
|
$t('tooltip.clientCA') |
|
" |
|
small |
|
color="primary" |
|
outlined |
|
@click=" |
|
selectFile( |
|
db, |
|
'ssl', |
|
'caFilePath', |
|
dbIndex |
|
) |
|
" |
|
> |
|
{{ db.ui.ssl.ca }} |
|
</x-btn> |
|
</v-row> |
|
|
|
<v-row> |
|
<v-col> |
|
<!-- Inflection - Table name --> |
|
<v-select |
|
v-model=" |
|
db.meta.inflection |
|
.table_name |
|
" |
|
:disabled="edit" |
|
class="caption" |
|
:label=" |
|
$t( |
|
'labels.inflection.tableName' |
|
) |
|
" |
|
:items=" |
|
project.projectType === |
|
'rest' |
|
? [ |
|
'camelize', |
|
'none', |
|
] |
|
: ['camelize'] |
|
" |
|
> |
|
<template |
|
#item="{ item }" |
|
> |
|
<span |
|
class="caption" |
|
>{{ item }}</span |
|
> |
|
</template> |
|
</v-select> |
|
</v-col> |
|
<v-col> |
|
<!-- Inflection - Column name --> |
|
<v-select |
|
v-model=" |
|
db.meta.inflection |
|
.column_name |
|
" |
|
:disabled="edit" |
|
class="caption" |
|
:label=" |
|
$t( |
|
'labels.inflection.columnName' |
|
) |
|
" |
|
:items=" |
|
project.projectType === |
|
'rest' |
|
? [ |
|
'camelize', |
|
'none', |
|
] |
|
: ['camelize'] |
|
" |
|
> |
|
<template |
|
#item="{ item }" |
|
> |
|
<span |
|
class="caption" |
|
>{{ item }}</span |
|
> |
|
</template> |
|
</v-select> |
|
</v-col> |
|
<v-col |
|
class="d-flex align-center flex-shrink-1 flex-grow-0" |
|
> |
|
<x-btn |
|
small |
|
btn.class="text-capitalize" |
|
:tooltip=" |
|
$t( |
|
'activity.editConnJson' |
|
) |
|
" |
|
outlined |
|
@click=" |
|
$set( |
|
showMonaco, |
|
dbIndex, |
|
!showMonaco[ |
|
dbIndex |
|
] |
|
) |
|
" |
|
> |
|
<v-icon |
|
small |
|
class="mr-1" |
|
> |
|
mdi-database-edit |
|
</v-icon> |
|
<!-- Edit connection JSON --> |
|
{{ |
|
$t( |
|
"activity.editConnJson" |
|
) |
|
}} |
|
</x-btn> |
|
</v-col> |
|
</v-row> |
|
</v-card-text> |
|
</v-card> |
|
</v-expansion-panel-content> |
|
</v-expansion-panel> |
|
</v-expansion-panels> |
|
</v-col> |
|
</v-row> |
|
|
|
<v-row class="text-right justify-end"> |
|
<!-- Test Database Connection --> |
|
<x-btn |
|
v-ge="[ |
|
'project', |
|
'env-db-test-connection', |
|
]" |
|
:tooltip="$t('activity.testDbConn')" |
|
outlined |
|
small |
|
@click=" |
|
testConnection( |
|
db, |
|
envKey, |
|
panelIndex |
|
) |
|
" |
|
> |
|
<!-- Test Database Connection --> |
|
{{ $t("activity.testDbConn") }} |
|
</x-btn> |
|
<!-- Remove Database from environment --> |
|
<x-btn |
|
v-if="dbIndex" |
|
v-ge="['project', 'env-db-delete']" |
|
:tooltip=" |
|
$t('activity.removeDbFromEnv') |
|
" |
|
text |
|
small |
|
@click=" |
|
removeDBFromEnv( |
|
db, |
|
envKey, |
|
panelIndex, |
|
dbIndex |
|
) |
|
" |
|
> |
|
<v-hover v-slot="{ hover }"> |
|
<v-icon |
|
:color="hover ? 'error' : 'grey'" |
|
> |
|
mdi-database-remove |
|
</v-icon> |
|
</v-hover> |
|
</x-btn> |
|
</v-row> |
|
</v-container> |
|
<!-- </form>--> |
|
</v-card> |
|
</v-tab-item> |
|
</v-tabs-items> |
|
</v-tabs> |
|
</v-card> |
|
</v-col> |
|
</v-expansion-panel-content> |
|
</v-expansion-panel> |
|
</v-expansion-panels> |
|
</v-col> |
|
</v-row> |
|
</v-container> |
|
</div> |
|
</v-card> |
|
</v-form> |
|
</v-col> |
|
<dlgOk |
|
v-if="dialog.show" |
|
:dialog-show="dialog.show" |
|
:mtd-ok="dialog.mtdOk" |
|
:heading="dialog.heading" |
|
:type="dialog.type" |
|
/> |
|
|
|
<!-- heading="Connection was successful" --> |
|
<!-- ok-label="Ok & Save Project" --> |
|
<dlg-ok-new |
|
v-model="testSuccess" |
|
:heading="$t('msg.info.dbConnected')" |
|
:ok-label="$t('activity.OkSaveProject')" |
|
type="success" |
|
:btn-attr="{ small: false }" |
|
@ok="createOrUpdateProject" |
|
/> |
|
|
|
<textDlgSubmitCancel |
|
v-if="dialogGetEnvName.dialogShow" |
|
:dialog-show="dialogGetEnvName.dialogShow" |
|
:heading="dialogGetEnvName.heading" |
|
:mtd-dialog-submit="mtdDialogGetEnvNameSubmit" |
|
:mtd-dialog-cancel="mtdDialogGetEnvNameCancel" |
|
/> |
|
|
|
<div v-if="isTitle && !edit" class="floating-button"> |
|
<v-tooltip top> |
|
<template #activator="{ on }"> |
|
<v-btn |
|
v-ge="['project', 'save']" |
|
fab |
|
dark |
|
large |
|
tooltip="Scroll to top" |
|
:disabled="!valid || !envStatusValid" |
|
class="primary" |
|
v-on="on" |
|
@click="createOrUpdateProject()" |
|
> |
|
<v-icon>save</v-icon> |
|
</v-btn> |
|
</template> |
|
<span> Save Project </span> |
|
</v-tooltip> |
|
</div> |
|
</v-container> |
|
</template> |
|
<script> |
|
import JSON5 from "json5"; |
|
|
|
import { mapGetters, mapActions } from "vuex"; |
|
import Vue from "vue"; |
|
|
|
import { v4 as uuidv4 } from "uuid"; |
|
|
|
import XBtn from "./global/xBtn"; |
|
import dlgOk from "./utils/dlgOk.vue"; |
|
import textDlgSubmitCancel from "./utils/dlgTextSubmitCancel"; |
|
import MonacoJsonObjectEditor from "@/components/monaco/MonacoJsonObjectEditor"; |
|
import ApiOverlay from "@/components/apiOverlay"; |
|
import colors from "@/mixins/colors"; |
|
import DlgOkNew from "@/components/utils/dlgOkNew"; |
|
import readFile from "@/helpers/fileReader"; |
|
|
|
const { |
|
uniqueNamesGenerator, |
|
starWars, |
|
adjectives, |
|
animals, |
|
} = require("unique-names-generator"); |
|
|
|
const homeDir = ""; |
|
|
|
export default { |
|
components: { |
|
DlgOkNew, |
|
ApiOverlay, |
|
MonacoJsonObjectEditor, |
|
XBtn, |
|
dlgOk, |
|
textDlgSubmitCancel, |
|
}, |
|
mixins: [colors], |
|
layout: "empty", |
|
data() { |
|
return { |
|
testSuccess: false, |
|
projectCreated: false, |
|
allSchemas: false, |
|
showMonaco: [], |
|
smtpConfiguration: { |
|
from: "", |
|
options: "", |
|
}, |
|
showSecret: false, |
|
loaderMessages: [ |
|
"Setting up new database configs", |
|
"Inferring database schema", |
|
"Generating APIs.", |
|
"Generating APIs..", |
|
"Generating APIs...", |
|
"Generating APIs....", |
|
"Please wait", |
|
"Please wait.", |
|
"Please wait..", |
|
"Please wait...", |
|
"Please wait..", |
|
"Please wait.", |
|
"Please wait", |
|
"Please wait.", |
|
"Please wait..", |
|
"Please wait...", |
|
"Please wait..", |
|
"Please wait.", |
|
"Please wait..", |
|
"Please wait...", |
|
], |
|
loaderMessage: "", |
|
projectReloading: false, |
|
enableDbEdit: 0, |
|
authTypes: [ |
|
{ |
|
text: "JWT", |
|
value: "jwt", |
|
}, |
|
{ |
|
text: "Master Key", |
|
value: "masterKey", |
|
}, |
|
{ |
|
text: "Middleware", |
|
value: "middleware", |
|
}, |
|
{ |
|
text: "Disabled", |
|
value: "none", |
|
}, |
|
], |
|
projectTypes: [ |
|
{ |
|
text: "REST APIs", |
|
value: "rest", |
|
icon: "mdi-code-json", |
|
iconColor: "green", |
|
}, |
|
{ |
|
text: "GRAPHQL APIs", |
|
value: "graphql", |
|
icon: "mdi-graphql", |
|
iconColor: "pink", |
|
}, |
|
], |
|
|
|
showPass: {}, |
|
/** ************** START : form related ****************/ |
|
form: { |
|
portValidationRule: [(v) => /^\d+$/.test(v) || "Not a valid port"], |
|
titleRequiredRule: [(v) => !!v || "Title is required"], |
|
requiredRule: [(v) => !!v || "Field is required"], |
|
folderRequiredRule: [(v) => !!v || "Folder path is required"], |
|
}, |
|
valid: null, |
|
panel: 0, |
|
client: ["Sqlite"], |
|
baseFolder: homeDir, |
|
|
|
tab: null, |
|
env: null, |
|
databases: [], |
|
/** ************** END : form related ****************/ |
|
auth: { |
|
authSecret: uuidv4(), |
|
authType: "jwt", |
|
webhook: null, |
|
}, |
|
project: {}, |
|
defaultProject: { |
|
title: "", |
|
version: "0.6", |
|
folder: homeDir, |
|
envs: { |
|
_noco: { |
|
db: [ |
|
{ |
|
client: "pg", |
|
connection: { |
|
host: "localhost", |
|
port: "5432", |
|
user: "postgres", |
|
password: "password", |
|
database: "_dev", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
meta: { |
|
tn: "nc_evolutions", |
|
dbAlias: "db", |
|
api: { |
|
type: "rest", |
|
prefix: "", |
|
graphqlDepthLimit: 10, |
|
}, |
|
inflection: { |
|
table_name: "camelize", |
|
column_name: "camelize", |
|
}, |
|
}, |
|
ui: { |
|
setup: -1, |
|
ssl: { |
|
key: this.$t("labels.clientKey"), // Client Key |
|
cert: this.$t("labels.clientCert"), // Client Cert |
|
ca: this.$t("labels.serverCA"), // Server CA |
|
}, |
|
sslUse: "Preferred", |
|
}, |
|
}, |
|
], |
|
apiClient: { |
|
data: [], |
|
}, |
|
}, |
|
}, |
|
workingEnv: "_noco", |
|
ui: { |
|
envs: { |
|
_noco: {}, |
|
}, |
|
}, |
|
meta: { |
|
version: "0.6", |
|
seedsFolder: "seeds", |
|
queriesFolder: "queries", |
|
apisFolder: "apis", |
|
projectType: "rest", |
|
type: "mvc", |
|
language: "ts", |
|
}, |
|
seedsFolder: "seeds", |
|
queriesFolder: "queries", |
|
apisFolder: "apis", |
|
projectType: "rest", |
|
type: "mvc", |
|
language: "ts", |
|
apiClient: { |
|
data: [], |
|
}, |
|
}, |
|
|
|
sampleConnectionData: { |
|
Postgres: { |
|
host: "localhost", |
|
port: "5432", |
|
user: "postgres", |
|
password: "password", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
MySQL: { |
|
host: "localhost", |
|
port: "3306", |
|
user: "root", |
|
password: "password", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
Vitess: { |
|
host: "localhost", |
|
port: "15306", |
|
user: "root", |
|
password: "password", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
TiDB: { |
|
host: "localhost", |
|
port: "4000", |
|
user: "root", |
|
password: "", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
Yugabyte: { |
|
host: "localhost", |
|
port: "5432", |
|
user: "postgres", |
|
password: "", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
CitusDB: { |
|
host: "localhost", |
|
port: "5432", |
|
user: "postgres", |
|
password: "", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
CockroachDB: { |
|
host: "localhost", |
|
port: "5432", |
|
user: "postgres", |
|
password: "", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
Greenplum: { |
|
host: "localhost", |
|
port: "5432", |
|
user: "postgres", |
|
password: "", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
MsSQL: { |
|
host: "localhost", |
|
port: 1433, |
|
user: "sa", |
|
password: "Password123.", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
Oracle: { |
|
host: "localhost", |
|
port: "1521", |
|
user: "system", |
|
password: "Oracle18", |
|
database: "_test", |
|
ssl: { |
|
ca: "", |
|
key: "", |
|
cert: "", |
|
}, |
|
}, |
|
Sqlite: { |
|
client: "sqlite3", |
|
database: homeDir, |
|
connection: { |
|
filename: homeDir, |
|
}, |
|
useNullAsDefault: true, |
|
}, |
|
}, |
|
dialog: { |
|
show: false, |
|
title: "", |
|
heading: "", |
|
mtdOk: this.testConnectionMethodSubmit, |
|
type: "primary", |
|
}, |
|
// TODO: apply i18n for sslUsage |
|
// See general.no - 5 in en.json |
|
sslUsage: { |
|
No: "No", |
|
Preferred: "Preferred", |
|
Required: "pg", |
|
"Required-CA": "Required-CA", |
|
"Required-IDENTITY": "Required-IDENTITY", |
|
}, |
|
sslUse: this.$t("general.preferred"), // Preferred |
|
ssl: { |
|
key: this.$t("labels.clientKey"), // Client Key |
|
cert: this.$t("labels.clientCert"), // Client Cert |
|
ca: this.$t("labels.serverCA"), // Server CA |
|
}, |
|
databaseNames: { |
|
MySQL: "mysql2", |
|
Postgres: "pg", |
|
// Oracle: "oracledb", |
|
MsSQL: "mssql", |
|
Sqlite: "sqlite3", |
|
// Vitess: "mysql2", |
|
// TiDB: "mysql2", |
|
// Yugabyte: "pg", |
|
// CitusDB: "pg", |
|
// CockroachDB: "pg", |
|
// Greenplum: "pg" |
|
}, |
|
testDatabaseNames: { |
|
mysql2: null, |
|
mysql: null, |
|
pg: "postgres", |
|
oracledb: "xe", |
|
mssql: undefined, |
|
sqlite3: "a.sqlite", |
|
}, |
|
dbIcons: { |
|
Oracle: "temp/db/oracle.png", |
|
Postgres: "temp/db/postgre.png", |
|
MySQL: "temp/db/mysql.png", |
|
MsSQL: "temp/db/mssql.png", |
|
Sqlite: "temp/db/sqlite.svg", |
|
Salesforce: "temp/salesforce-3-569548.webp", |
|
SAP: "temp/sap.png", |
|
Stripe: "temp/stripe.svg", |
|
}, |
|
dialogGetEnvName: { |
|
dialogShow: false, |
|
heading: "Enter New Environment Name", |
|
field: "Environment Name", |
|
}, |
|
|
|
compErrorMessages: [ |
|
this.$t("msg.error.invalidChar"), // Invalid character in folder path |
|
this.$t("msg.error.invalidDbCredentials"), // Invalid database credentials |
|
this.$t("msg.error.unableToConnectToDb"), // Unable to connect to database, please check your database is up |
|
this.$t("msg.error.userDoesntHaveSufficientPermission"), // User does not exist or have sufficient permission to create schema |
|
], |
|
compErrorMessage: "", |
|
}; |
|
}, |
|
computed: { |
|
...mapGetters({ sqlMgr: "sqlMgr/sqlMgr" }), |
|
isTitle() { |
|
return this.project.title && this.project.title.trim().length; |
|
}, |
|
envStatusValid() { |
|
return ( |
|
this.project.envs && |
|
Object.values(this.project.envs).every( |
|
this.getEnvironmentStatusAggregatedNew |
|
) |
|
); |
|
}, |
|
typeIcon() { |
|
if (this.project.projectType) { |
|
return this.projectTypes.find( |
|
({ value }) => value === this.project.projectType |
|
); |
|
} else { |
|
return { |
|
icon: "mdi-server", |
|
iconColor: "primary", |
|
}; |
|
} |
|
}, |
|
databaseNamesReverse() { |
|
return Object.entries(this.databaseNames).reduce( |
|
(newObj, [value, key]) => { |
|
newObj[key] = value; |
|
return newObj; |
|
}, |
|
{} |
|
); |
|
}, |
|
}, |
|
methods: { |
|
async enableAllSchemas() { |
|
this.$toast.info("Enabled all schemas").goAway(3000); |
|
this.allSchemas = true; |
|
await this.$axios({ |
|
url: "demo", |
|
baseURL: `${this.$axios.defaults.baseURL}/dashboard`, |
|
}); |
|
}, |
|
|
|
...mapActions({ |
|
loadProjects: "project/loadProjects", |
|
}), |
|
onAdvancePanelToggle() { |
|
if (this.$refs.monacoEditor) { |
|
setTimeout(() => this.$refs.monacoEditor.resizeLayout(), 400); |
|
} |
|
}, |
|
getProjectEditTooltip() { |
|
// return `Opens ${path.join(this.project.folder, 'config.xc.json')} and edit - its really simple`; |
|
}, |
|
openJsonInSystemEditor() { |
|
// shell.openItem(path.join(this.project.folder, 'config.xc.json')); |
|
}, |
|
readFileContent(db, obj, key, index) { |
|
readFile(this.$refs[`${key}FilePath`][index], (data) => { |
|
Vue.set(db.connection[obj], key, data); |
|
}); |
|
}, |
|
selectFile(db, obj, key, index) { |
|
this.$refs[key][index].click(); |
|
}, |
|
onPanelToggle(panelIndex, envKey) { |
|
this.$nextTick(() => { |
|
if (this.panel !== undefined) { |
|
const panelContainer = this.$refs.panelContainer; |
|
const panel = this.$refs[`panel${envKey}`][0].$el; |
|
setTimeout( |
|
() => |
|
(panelContainer.scrollTop = |
|
panel.getBoundingClientRect().top + |
|
panelContainer.scrollTop - |
|
panelContainer.getBoundingClientRect().top - |
|
50), |
|
500 |
|
); |
|
setTimeout(() => this.$refs[`password${envKey}`][0].focus()); |
|
} |
|
}); |
|
}, |
|
scrollToTop() { |
|
document.querySelector("html").scrollTop = 0; |
|
}, |
|
showDBTabInEnvPanel(panelIndex, tabIndex) { |
|
this.panel = panelIndex; |
|
Vue.set(this.databases, panelIndex, tabIndex); |
|
}, |
|
getProjectJson() { |
|
/** |
|
* remove UI keys within project |
|
*/ |
|
const xcConfig = JSON.parse(JSON.stringify(this.project)); |
|
delete xcConfig.ui; |
|
|
|
for (const env in xcConfig.envs) { |
|
for (let i = 0; i < xcConfig.envs[env].db.length; ++i) { |
|
xcConfig.envs[env].db[i].meta.api.type = this.project.projectType; |
|
if ( |
|
xcConfig.envs[env].db[i].client === "mysql" || |
|
xcConfig.envs[env].db[i].client === "mysql2" |
|
) { |
|
xcConfig.envs[env].db[i].connection.multipleStatements = true; |
|
} |
|
this.handleSSL(xcConfig.envs[env].db[i], false); |
|
delete xcConfig.envs[env].db[i].ui; |
|
if (this.client[i] === "Vitess") { |
|
xcConfig.envs[env].db[i].meta.dbtype = "vitess"; |
|
} |
|
if (this.client[i] === "TiDB") { |
|
xcConfig.envs[env].db[i].meta.dbtype = "tidb"; |
|
} |
|
if (xcConfig.envs[env].db[i].client === "oracledb") { |
|
xcConfig.envs[env].db[i].pool = { |
|
min: 0, |
|
max: 50, |
|
}; |
|
|
|
xcConfig.envs[env].db[i].acquireConnectionTimeout = 60000; |
|
} |
|
|
|
const inflectionObj = xcConfig.envs[env].db[i].meta.inflection; |
|
|
|
if (inflectionObj) { |
|
if (Array.isArray(inflectionObj.table_name)) { |
|
inflectionObj.table_name = inflectionObj.table_name.join(","); |
|
} |
|
if (Array.isArray(inflectionObj.column_name)) { |
|
inflectionObj.column_name = inflectionObj.column_name.join(","); |
|
} |
|
|
|
inflectionObj.table_name = inflectionObj.table_name || "none"; |
|
inflectionObj.column_name = inflectionObj.column_name || "none"; |
|
} |
|
|
|
if (this.allSchemas) { |
|
delete xcConfig.envs[env].db[i].connection.database; |
|
xcConfig.envs[env].db[i].meta.allSchemas = true; |
|
} |
|
} |
|
} |
|
|
|
xcConfig.auth = {}; |
|
switch (this.auth.authType) { |
|
case "jwt": |
|
xcConfig.auth.jwt = { |
|
secret: this.auth.authSecret, |
|
dbAlias: |
|
xcConfig.envs[Object.keys(xcConfig.envs)[0]].db[0].meta.dbAlias, |
|
}; |
|
break; |
|
case "masterKey": |
|
xcConfig.auth.masterKey = { |
|
secret: this.auth.authSecret, |
|
}; |
|
sessionStorage.setItem("masterKey", this.auth.authSecret); |
|
break; |
|
case "middleware": |
|
xcConfig.auth.masterKey = { |
|
url: this.auth.webhook, |
|
}; |
|
break; |
|
default: |
|
this.auth.disabled = true; |
|
break; |
|
} |
|
|
|
xcConfig.type = this.$store.state.project.projectInfo |
|
? this.$store.state.project.projectInfo.type |
|
: "docker"; |
|
|
|
if ( |
|
this.smtpConfiguration && |
|
this.smtpConfiguration.from && |
|
this.smtpConfiguration.options.trim() |
|
) { |
|
try { |
|
xcConfig.mailer = { |
|
options: JSON5.parse(this.smtpConfiguration.options), |
|
from: this.smtpConfiguration.from, |
|
}; |
|
} catch (e) {} |
|
} |
|
|
|
xcConfig.meta = xcConfig.meta || {}; |
|
xcConfig.meta.db = { |
|
client: "sqlite3", |
|
connection: { |
|
filename: "xc.db", |
|
}, |
|
}; |
|
|
|
return xcConfig; |
|
}, |
|
|
|
constructProjectJsonFromProject(project) { |
|
const p = project; // JSON.parse(JSON.stringify(project.projectJson)); |
|
|
|
p.ui = { |
|
envs: { |
|
_noco: {}, |
|
}, |
|
}; |
|
for (const env in p.envs) { |
|
let i = 0; |
|
for (const db of p.envs[env].db) { |
|
Vue.set(this.client, i++, this.databaseNamesReverse[db.client]); |
|
|
|
Vue.set(db, "ui", { |
|
setup: 0, |
|
ssl: { |
|
key: this.$t("labels.clientKey"), // Client Key |
|
cert: this.$t("labels.clientCert"), // Client Cert |
|
ca: this.$t("labels.serverCA"), // Server CA |
|
}, |
|
sslUse: this.$t("general.preferred"), // Preferred |
|
}); |
|
} |
|
} |
|
// delete p.projectJson; |
|
|
|
if (p.auth) { |
|
if (p.auth.jwt) { |
|
this.auth.authType = "jwt"; |
|
this.auth.authSecret = p.auth.jwt.secret; |
|
} else if (p.auth.masterKey) { |
|
if (p.auth.masterKey.secret) { |
|
this.auth.authSecret = p.auth.masterKey.secret; |
|
this.auth.authType = "masterKey"; |
|
} else if (p.auth.masterKey.url) { |
|
this.auth.webhook = p.auth.masterKey.url; |
|
this.auth.authType = "middleware"; |
|
} else { |
|
this.auth.authType = "none"; |
|
} |
|
} else { |
|
this.auth.authType = "none"; |
|
} |
|
} else { |
|
this.auth.authType = "none"; |
|
} |
|
|
|
this.project = p; |
|
if (p.mailer) { |
|
this.smtpConfiguration = { |
|
from: p.mailer.from, |
|
options: JSON.stringify(p.mailer.options, 0, 2), |
|
}; |
|
} |
|
delete p.mailer; |
|
}, |
|
|
|
async createOrUpdateProject() { |
|
const projectJson = this.getProjectJson(); |
|
delete projectJson.folder; |
|
|
|
let i = 0; |
|
const toast = this.$toast.info(this.loaderMessages[0]); |
|
const interv = setInterval(() => { |
|
if (this.edit) { |
|
return; |
|
} |
|
if (i < this.loaderMessages.length - 1) { |
|
i++; |
|
} |
|
if (toast) { |
|
if (!this.allSchemas) { |
|
toast.text(this.loaderMessages[i]); |
|
} else { |
|
toast.goAway(100); |
|
} |
|
} |
|
}, 1000); |
|
|
|
this.projectReloading = true; |
|
|
|
const con = projectJson.envs._noco.db[0]; |
|
const inflection = (con.meta && con.meta.inflection) || {}; |
|
try { |
|
const result = await this.$api.project.create({ |
|
title: projectJson.title, |
|
bases: [ |
|
{ |
|
type: con.client, |
|
config: con, |
|
inflection_column: inflection.column_name, |
|
inflection_table: inflection.table_name, |
|
}, |
|
], |
|
external: true, |
|
}); |
|
|
|
clearInterval(interv); |
|
toast.goAway(100); |
|
|
|
await this.$store.dispatch("project/ActLoadProjectInfo"); |
|
|
|
this.projectReloading = false; |
|
|
|
if (!this.edit && !this.allSchemas) { |
|
this.$router.push({ |
|
path: `/nc/${result.id}`, |
|
query: { |
|
new: 1, |
|
}, |
|
}); |
|
} |
|
|
|
this.projectCreated = true; |
|
} catch (e) { |
|
this.$toast |
|
.error(await this._extractSdkResponseErrorMsg(e)) |
|
.goAway(3000); |
|
toast.goAway(0); |
|
} |
|
|
|
this.projectReloading = false; |
|
this.$e("a:project:create:extdb"); |
|
}, |
|
|
|
mtdDialogGetEnvNameSubmit(envName, cookie) { |
|
this.dialogGetEnvName.dialogShow = false; |
|
if (envName in this.project.envs) { |
|
} else { |
|
Vue.set(this.project.envs, envName, { |
|
db: [ |
|
{ |
|
client: "pg", |
|
connection: { |
|
host: "localhost", |
|
port: "5432", |
|
user: "postgres", |
|
password: "password", |
|
database: "new_database", |
|
}, |
|
meta: { |
|
tn: "nc_evolutions", |
|
dbAlias: "db", |
|
inflection: { |
|
table_name: "camelize", |
|
column_name: "camelize", |
|
}, |
|
api: { |
|
type: "", |
|
}, |
|
}, |
|
ui: { |
|
setup: 0, |
|
ssl: { |
|
key: this.$t("labels.clientKey"), // Client Key |
|
cert: this.$t("labels.clientCert"), // Client Cert |
|
ca: this.$t("labels.serverCA"), // Server CA |
|
}, |
|
sslUse: this.$t("general.preferred"), // Preferred |
|
}, |
|
}, |
|
], |
|
apiClient: { data: [] }, |
|
}); |
|
} |
|
}, |
|
mtdDialogGetEnvNameCancel() { |
|
this.dialogGetEnvName.dialogShow = false; |
|
}, |
|
|
|
addNewEnvironment() { |
|
this.dialogGetEnvName.dialogShow = true; |
|
}, |
|
addNewDB(envKey, panelIndex) { |
|
const len = this.project.envs[envKey].db.length; |
|
// eslint-disable-next-line no-unused-vars |
|
const lastDbName = `${this.project.title}_${envKey}_${len}`; |
|
const dbType = (this.client[len] = |
|
this.client[len] || this.client[len - 1]); |
|
const newlyCreatedIndex = this.project.envs[envKey].db.length; |
|
const dbAlias = |
|
this.project.envs[envKey].db.length <= 0 |
|
? "db" |
|
: `db${this.project.envs[envKey].db.length + 1}`; |
|
this.project.envs[envKey].db.push({ |
|
client: this.databaseNames[dbType], |
|
connection: { |
|
...this.sampleConnectionData[dbType], |
|
database: `${this.project.title}_${envKey}_${newlyCreatedIndex + 1}`, |
|
}, |
|
meta: { |
|
tn: "nc_evolutions", |
|
dbAlias, |
|
inflection: { |
|
table_name: "camelize", |
|
column_name: "camelize", |
|
}, |
|
api: { |
|
type: "", |
|
}, |
|
}, |
|
ui: { |
|
setup: 0, |
|
sslUse: this.$t("general.preferred"), // Preferred |
|
ssl: { |
|
key: this.$t("labels.clientKey"), // Client Key |
|
cert: this.$t("labels.clientCert"), // Client Cert |
|
ca: this.$t("labels.serverCA"), // Server CA |
|
}, |
|
}, |
|
}); |
|
// set active tab as newly created |
|
this.databases[panelIndex] = newlyCreatedIndex; |
|
}, |
|
|
|
testConnectionMethodSubmit() { |
|
this.dialog.show = false; |
|
}, |
|
selectDir(ev) {}, |
|
selectSqliteFile(db) {}, |
|
|
|
getDbStatusColor(db) { |
|
switch (db.ui.setup) { |
|
case -1: |
|
return "red"; |
|
|
|
case 0: |
|
return "orange"; |
|
|
|
case 1: |
|
return "green"; |
|
|
|
default: |
|
break; |
|
} |
|
}, |
|
|
|
getDbStatusTooltip(db) { |
|
switch (db.ui.setup) { |
|
case -1: |
|
return "DB Connection NOT successful"; |
|
|
|
case 0: |
|
return "MySql Database Detected - Test your connection"; |
|
|
|
case 1: |
|
return "DB Connection successful"; |
|
|
|
default: |
|
break; |
|
} |
|
}, |
|
async newTestConnection(db, env, panelIndex) { |
|
if ( |
|
db.connection.host === "localhost" && |
|
!this.edit && |
|
env === "_noco" && |
|
this.project.envs[env].db.length === 1 && |
|
this.project.envs[env].db[0].connection.user === "postgres" && |
|
this.project.envs[env].db[0].connection.database === |
|
`${this.project.title}_${env}_${this.project.envs[env].length}` |
|
) { |
|
this.handleSSL(db); |
|
if (db.client === "sqlite3") { |
|
db.ui.setup = 1; |
|
} else { |
|
const c1 = { |
|
connection: { |
|
...db.connection, |
|
...(db.client !== "pg" |
|
? { database: this.testDatabaseNames[db.client] } |
|
: {}), |
|
}, |
|
client: db.client, |
|
}; |
|
|
|
const result = await this.$store.dispatch("sqlMgr/ActSqlOp", [ |
|
{ |
|
query: { |
|
skipProjectHasDb: 1, |
|
}, |
|
}, |
|
"testConnection", |
|
c1, |
|
]); |
|
|
|
if (result.code === 0) { |
|
db.ui.setup = 1; |
|
let passed = true; |
|
/** |
|
* get other environments |
|
* and if host is localhost - test and update connection status |
|
* UI panel close |
|
*/ |
|
|
|
for (const e in this.project.envs) { |
|
if (e === env) { |
|
// ignore |
|
} else { |
|
const c2 = { |
|
connection: { |
|
...this.project.envs[e].db[0].connection, |
|
database: undefined, |
|
}, |
|
client: this.project.envs[e].db[0].client, |
|
}; |
|
|
|
this.handleSSL(c2); |
|
|
|
const result = await this.sqlMgr.testConnection(c2); |
|
|
|
if (result.code === 0) { |
|
this.project.envs[e][0].ui.setup = 1; |
|
} else { |
|
this.project.envs[e][0].ui.setup = -1; |
|
passed = false; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (passed) { |
|
this.panel = null; |
|
} else { |
|
// Connection was successful |
|
this.dialog.heading = this.$t("msg.info.dbConnected"); |
|
this.dialog.type = "success"; |
|
this.dialog.show = true; |
|
} |
|
} else { |
|
db.ui.setup = -1; |
|
// Connection Failure: |
|
this.dialog.heading = |
|
this.$t("msg.error.dbConnectionFailed") + result.message; |
|
this.dialog.type = "error"; |
|
this.dialog.show = true; |
|
} |
|
} |
|
|
|
return true; |
|
} else { |
|
return false; |
|
} |
|
}, |
|
|
|
sendAdvancedConfig(connection) { |
|
if (!connection.ssl) { |
|
return false; |
|
} |
|
let sendAdvancedConfig = false; |
|
const sslOptions = Object.values(connection.ssl).filter((el) => !!el); |
|
if (sslOptions[0]) { |
|
sendAdvancedConfig = true; |
|
} else { |
|
} |
|
return sendAdvancedConfig; |
|
}, |
|
|
|
handleSSL(db, creating = true) { |
|
const sendAdvancedConfig = this.sendAdvancedConfig(db.connection); |
|
if (!sendAdvancedConfig) { |
|
db.connection.ssl = undefined; |
|
} |
|
|
|
if (db.connection.ssl) { |
|
} |
|
}, |
|
getDatabaseForTestConnection(dbType) {}, |
|
async testConnection(db, env, panelIndex) { |
|
this.$e("a:project:create:extdb:test-connection"); |
|
this.$store.commit("notification/MutToggleProgressBar", true); |
|
try { |
|
if (!(await this.newTestConnection(db, env, panelIndex))) { |
|
this.handleSSL(db); |
|
|
|
if (db.client === "sqlite3") { |
|
db.ui.setup = 1; |
|
} else { |
|
const c1 = { |
|
connection: { |
|
...db.connection, |
|
...(db.client !== "pg" |
|
? { database: this.testDatabaseNames[db.client] } |
|
: {}), |
|
}, |
|
client: db.client, |
|
}; |
|
|
|
const result = await this.$api.utils.testConnection(c1); |
|
|
|
if (result.code === 0) { |
|
db.ui.setup = 1; |
|
// this.dialog.heading = "Connection was successful" |
|
// this.dialog.type = 'success'; |
|
// this.dialog.show = true; |
|
this.testSuccess = true; |
|
} else { |
|
db.ui.setup = -1; |
|
// this.activeDbNode.testConnectionStatus = false; |
|
this.dialog.heading = |
|
this.$t("msg.error.dbConnectionFailed") + result.message; |
|
this.dialog.type = "error"; |
|
this.dialog.show = true; |
|
} |
|
} |
|
} |
|
} catch (e) { |
|
console.log(e); |
|
} finally { |
|
this.$store.commit("notification/MutToggleProgressBar", false); |
|
} |
|
}, |
|
getEnvironmentStatusAggregated(dbs) { |
|
return dbs.every((db) => db.ui.setup === 1); |
|
}, |
|
|
|
getEnvironmentStatusAggregatedNew(dbs) { |
|
return dbs.db.every((db) => db.ui.setup === 1); |
|
}, |
|
openFirstPanel() { |
|
if (!this.edit) { |
|
this.panel = 0; |
|
} |
|
}, |
|
onDatabaseTypeChanged(client, db1, index, env) { |
|
for (const env in this.project.envs) { |
|
if (this.project.envs[env].db.length > index) { |
|
const db = this.project.envs[env].db[index]; |
|
Vue.set(db, "client", this.databaseNames[client]); |
|
if (client !== "Sqlite") { |
|
const { ssl, ...connectionDet } = this.sampleConnectionData[client]; |
|
|
|
Vue.set(db, "connection", { |
|
...connectionDet, |
|
database: `${this.project.title}_${env}_${index + 1}`, |
|
ssl: { ...ssl }, |
|
}); |
|
|
|
for (const env in this.project.envs) { |
|
if (this.project.envs[env].length > index) { |
|
this.setDBStatus(this.project.envs[env][index], 0); |
|
} |
|
} |
|
} else { |
|
db.connection = {}; |
|
Vue.set(db, "connection", { |
|
client: "sqlite3", |
|
// connection: {filename: path.join(this.project.folder, `${this.project.title}_${env}_${index + 1}`)}, |
|
connection: { |
|
filename: [ |
|
this.project.folder, |
|
`${this.project.title}_${env}_${index + 1}`, |
|
].join("/"), |
|
}, |
|
database: [ |
|
this.project.folder, |
|
`${this.project.title}_${env}_${index + 1}`, |
|
].join("/"), |
|
useNullAsDefault: true, |
|
}); |
|
} |
|
} |
|
} |
|
}, |
|
selectDatabaseClient(database, index = 0) { |
|
if (this.client) { |
|
this.client[index] = database; |
|
} |
|
}, |
|
setDBStatus(db, status) { |
|
db.ui.setup = status; |
|
}, |
|
removeDBFromEnv(db, env, panelIndex, dbIndex) { |
|
for (const env in this.project.envs) { |
|
if (this.project.envs[env].db.length > dbIndex) { |
|
this.project.envs[env].db.splice(dbIndex, 1); |
|
} |
|
} |
|
}, |
|
removeEnv(envKey) { |
|
delete this.project.envs[envKey]; |
|
Vue.set(this.project, "envs", { ...this.project.envs }); |
|
}, |
|
}, |
|
fetch({ store, params }) {}, |
|
beforeCreated() {}, |
|
watch: { |
|
"project.title"(newValue, oldValue) { |
|
if (!newValue) { |
|
return; |
|
} |
|
if (!this.edit) { |
|
// Vue.set(this.project, 'folder', slash(path.join(this.baseFolder, newValue))) |
|
Vue.set(this.project, "folder", [this.baseFolder, newValue].join("/")); |
|
// }//this.project.folder = `${this.baseFolder}/${newValue}`; |
|
|
|
for (const env in this.project.envs) { |
|
for (const [index, db] of this.project.envs[env].db.entries()) { |
|
// db.connection.database = `${this.project.title}_${env}_${index}` |
|
if (db.client !== "sqlite3") { |
|
Vue.set( |
|
db.connection, |
|
"database", |
|
`${this.project.title}_${env}_${index + 1}` |
|
); |
|
} else { |
|
Vue.set( |
|
db.connection, |
|
"database", |
|
`${this.project.title}_${env}_${index + 1}` |
|
); |
|
} |
|
} |
|
} |
|
} |
|
}, |
|
"project.envs": { |
|
deep: true, |
|
handler(envs) { |
|
if (typeof envs === "object" && envs) { |
|
Object.entries(envs).forEach(([key, env]) => { |
|
let res = 1; |
|
const msg = {}; |
|
for (const db of env.db) { |
|
res = db.ui.setup < res ? db.ui.setup : res; |
|
} |
|
if (this.edit) { |
|
Vue.set(this.project.ui, key, ""); |
|
} else { |
|
switch (res) { |
|
case -1: |
|
msg.color = "red"; |
|
// msg.msg = ' ( Invalid database parameters )' |
|
msg.msg = `( ${this.$t("msg.error.dbConnectionStatus")} )`; |
|
break; |
|
case 0: |
|
msg.color = "warning"; |
|
msg.msg = " ( Click to validate database credentials )"; |
|
break; |
|
case 1: |
|
msg.color = "green"; |
|
// msg.msg = ' ( Environment Validated )' |
|
msg.msg = `( ${this.$t("msg.info.dbConnectionStatus")} )`; |
|
break; |
|
} |
|
Vue.set(this.project.ui, key, msg); |
|
} |
|
}); |
|
} |
|
}, |
|
}, |
|
}, |
|
async created() { |
|
this.compErrorMessage = |
|
this.compErrorMessages[ |
|
Math.floor(Math.random() * this.compErrorMessages.length) |
|
]; |
|
|
|
if (this.edit) { |
|
try { |
|
let data = await this.$store.dispatch("sqlMgr/ActSqlOp", [ |
|
null, |
|
"xcProjectGetConfig", |
|
]); |
|
data = JSON.parse(data.config); |
|
this.constructProjectJsonFromProject(data); |
|
this.$set(this.project, "folder", data.folder); |
|
} catch (e) { |
|
this.$toast.error(e.message).goAway(3000); |
|
} |
|
} else { |
|
this.project = JSON.parse(JSON.stringify(this.defaultProject)); |
|
// this.edit = false; |
|
|
|
/** |
|
* Figure out which databases users has by scanning port numbers |
|
* preference can be - pg | mysql | mssql | oracledb | sqlite |
|
* create this.project based on the database |
|
* |
|
* |
|
*/ |
|
let dbsAvailable = []; // await PortScanner.getOpenDbPortsAsList(); |
|
// // setting MySQL as default value if no databases are available |
|
// if (!dbsAvailable || !dbsAvailable.length) { |
|
dbsAvailable = ["MySQL"]; |
|
// } |
|
|
|
this.selectDatabaseClient(dbsAvailable[0], 0); |
|
|
|
// iterating over environment and setting default connection details based |
|
// on first available database |
|
for (const env in this.project.envs) { |
|
for (const db of this.project.envs[env].db) { |
|
db.client = this.databaseNames[dbsAvailable[0]]; |
|
|
|
if (db.client === "sqlite3") { |
|
db.connection = { |
|
...this.sampleConnectionData[dbsAvailable[0]], |
|
}; |
|
|
|
db.ui.setup = 0; |
|
} else { |
|
db.connection = { |
|
...this.sampleConnectionData[dbsAvailable[0]], |
|
ssl: { ...this.sampleConnectionData[dbsAvailable[0]].ssl }, |
|
}; |
|
} |
|
} |
|
} |
|
} |
|
}, |
|
beforeMount() {}, |
|
mounted() { |
|
this.$set( |
|
this.project, |
|
"title", |
|
uniqueNamesGenerator({ |
|
dictionaries: [[starWars], [adjectives, animals]][ |
|
Math.floor(Math.random() * 2) |
|
], |
|
}) |
|
.toLowerCase() |
|
.replace(/[ -]/g, "_") |
|
); |
|
|
|
this.$nextTick(() => { |
|
const input = this.$refs.name.$el.querySelector("input"); |
|
input.setSelectionRange(0, this.project.title.length); |
|
input.focus(); |
|
}); |
|
}, |
|
beforeDestroy() {}, |
|
destroy() {}, |
|
validate({ params }) { |
|
return true; |
|
}, |
|
head() { |
|
return { |
|
title: this.$t("title.headCreateProject"), |
|
}; |
|
}, |
|
props: { |
|
edit: { |
|
type: Boolean, |
|
default: false, |
|
}, |
|
}, |
|
directives: {}, |
|
}; |
|
</script> |
|
|
|
<style scoped> |
|
.floating-button { |
|
position: fixed; |
|
right: 7%; |
|
bottom: 100px; |
|
} |
|
|
|
/deep/ .v-expansion-panel-header { |
|
padding: 0 6px; |
|
min-height: 50px !important; |
|
} |
|
|
|
/deep/ .monaco-overlay { |
|
align-items: stretch; |
|
} |
|
|
|
/deep/ .monaco-overlay .v-overlay__content { |
|
flex-grow: 1; |
|
} |
|
|
|
.monaco-overlay-close { |
|
position: absolute; |
|
right: 10px; |
|
top: 10px; |
|
z-index: 999; |
|
cursor: pointer !important; |
|
} |
|
</style> |
|
<!-- |
|
/** |
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
|
* |
|
* @author Naveen MR <oof1lab@gmail.com> |
|
* @author Pranav C Balan <pranavxc@gmail.com> |
|
* @author Wing-Kam Wong <wingkwong.code@gmail.com> |
|
* |
|
* @license GNU AGPL version 3 or any later version |
|
* |
|
* This program is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU Affero General Public License as |
|
* published by the Free Software Foundation, either version 3 of the |
|
* License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU Affero General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU Affero General Public License |
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
* |
|
*/ |
|
-->
|
|
|