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.
1712 lines
61 KiB
1712 lines
61 KiB
<template> |
|
<v-container fluid> |
|
|
|
<v-col class="col-md-8 offset-md-2 col-sm-10 offset-sm-1 col-12" style="position: relative"> |
|
<v-form |
|
class="mt-8 pt-8" |
|
ref="form" |
|
v-model="valid"> |
|
<v-card class="elevation-5" |
|
ref="mainCard"> |
|
|
|
|
|
<div |
|
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')" |
|
> |
|
</v-img> |
|
</div> |
|
<v-toolbar flat color="" class="mb-3" style="width: 100%; border-bottom: 1px solid grey"> |
|
|
|
<v-toolbar-title class="display-1 "> |
|
Create Project |
|
</v-toolbar-title> |
|
<v-spacer></v-spacer> |
|
<x-btn tooltip="Cancel and Return" |
|
to="/" |
|
v-ge="['project','cancel']" |
|
class="elevation-20">Cancel |
|
</x-btn> |
|
<x-btn |
|
:disabled="!valid || !envStatusValid" |
|
class="primary" |
|
v-ge="['project','save']" |
|
@click="createOrUpdateProject()"> |
|
Save Project |
|
</x-btn> |
|
<v-progress-linear |
|
v-if="projectReloading" |
|
top |
|
absolute |
|
color="success" |
|
indeterminate |
|
height="3" |
|
style="top:-3px" |
|
></v-progress-linear> |
|
|
|
</v-toolbar> |
|
|
|
<div ref="panelContainer" style=""> |
|
<v-overlay v-if="projectReloading" absolute color="grey" opacity="0.4"> |
|
<div class="d-flex flex-column justify-center align-center"> |
|
</div> |
|
</v-overlay> |
|
<v-container fluid> |
|
<v-row> |
|
<v-col cols="6" offset="3 " class="mb-0 pb-0"> |
|
<!-- <div class="ml-7 pb-5" v-if="edit">--> |
|
<!-- <x-btn--> |
|
<!-- :tooltip="getProjectEditTooltip()"--> |
|
<!-- :disabled="!this.edit"--> |
|
<!-- btn.class="primary"--> |
|
<!-- icon="mdi-circle-edit-outline"--> |
|
<!-- @click="openJsonInSystemEditor()">--> |
|
<!-- <p class="pa-0 ma-0"><b>Open Editor</b> <span--> |
|
<!-- class="caption">(to edit Project Json)</span>--> |
|
<!-- </p>--> |
|
<!-- </x-btn>--> |
|
|
|
<!-- </div>--> |
|
<v-text-field |
|
v-ge="['project','name']" |
|
:rules="form.titleRequiredRule" :height="20" v-model="project.title" label="Enter Project Name" |
|
autofocus> |
|
<v-icon color="info" class="blink_me" slot="prepend"> |
|
mdi-lightbulb-on |
|
</v-icon> |
|
</v-text-field> |
|
|
|
|
|
<v-select |
|
v-model="project.projectType" hint="Choose Project type" persistent-hint dense |
|
:items="projectTypes"> |
|
<template v-slot:prepend> |
|
<img v-if="typeIcon.type === 'img'" :src="typeIcon.icon" style="width: 32px"> |
|
<v-icon v-else :color="typeIcon.iconColor">{{ typeIcon.icon }}</v-icon> |
|
</template> |
|
<template v-slot:item="{item}"> |
|
<span class="caption d-flex align-center"> |
|
<img v-if="item.type === 'img'" :src="item.icon" style="width: 30px"> |
|
<v-icon v-else :color="item.iconColor">{{ item.icon }}</v-icon> {{ item.text }}</span> |
|
</template> |
|
|
|
</v-select> |
|
|
|
|
|
</v-col> |
|
|
|
<v-col cols="10" offset="1" v-show="project.title.trim().length" |
|
:class="{'mt-0 pt-0':!edit,'mt-3 pt-3':edit}"> |
|
<h2 :class="{'text-center mb-2':!edit,'text-center mb-2 grey--text':edit}"> |
|
{{ project.title.toUpperCase() }}'s |
|
Environments</h2> |
|
<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" |
|
@change="onPanelToggle(panelIndex,envKey)" |
|
:ref="`panel${envKey}`" |
|
> |
|
<v-expansion-panel-header disable-icon-rotate> |
|
<p class="pa-0 ma-0"> |
|
<v-icon>mdi-test-tube</v-icon> |
|
<span class="title"> <b>'{{ envKey }}'</b> environment : </span> |
|
<v-tooltip v-for="(db,tabIndex) in envData.db" |
|
:key="tabIndex" |
|
bottom |
|
> |
|
<template v-slot:activator="{ on }"> |
|
<v-icon small @click.native.stop="showDBTabInEnvPanel(panelIndex,tabIndex)" v-on="on" |
|
:color="getDbStatusColor(db)" |
|
>mdi-database |
|
</v-icon> |
|
</template> |
|
<span>{{ getDbStatusTooltip(db) }}</span> |
|
</v-tooltip> |
|
|
|
<span class="caption" v-if="project.ui[envKey]" :class="project.ui[envKey].color + '--text'"> |
|
<i>{{ project.ui[envKey].msg }}</i> |
|
</span> |
|
|
|
|
|
<x-btn small text v-if="panelIndex" |
|
btn.class="float-right" |
|
tooltip="Click here to remove environment" |
|
@click.native.stop="removeEnv(envKey)" |
|
v-ge="['project','env-delete']" |
|
> |
|
<v-hover v-slot:default="{ hover }"> |
|
<v-icon :color="hover ? 'error' : 'grey'" @click.native.stop="removeEnv(envKey)"> |
|
mdi-delete |
|
</v-icon> |
|
</v-hover> |
|
</x-btn> |
|
</p> |
|
<template v-slot:actions> |
|
<v-tooltip bottom v-if="getEnvironmentStatusAggregated(envData.db)"> |
|
<template v-slot:activator="{ on }"> |
|
<v-icon v-on="on" color="green">mdi-check-circle</v-icon> |
|
</template> |
|
<span>Environment setup complete</span> |
|
</v-tooltip> |
|
<v-tooltip bottom v-else-if="edit"> |
|
<template v-slot:activator="{ on }"> |
|
<v-icon v-on="on" color="orange">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]" background-color=""> |
|
<v-tab v-for="(db,dbIndex) in project.envs[envKey].db" :key="dbIndex"> |
|
<v-icon>mdi-database</v-icon> {{ db.connection.database }} |
|
</v-tab> |
|
<v-tooltip bottom> |
|
<template v-slot:activator="{ on }"> |
|
<x-btn tooltip="Add New Database to Environment" text small class="ma-2" v-on="on" |
|
@click.prevent.stop="addNewDB(envKey,panelIndex)" |
|
v-ge="['project','env-db-add']" |
|
> |
|
<v-hover v-slot:default="{ hover }"> |
|
<v-icon :color="hover ? 'primary' : 'grey'">mdi-database-plus |
|
</v-icon> |
|
</v-hover> |
|
</x-btn> |
|
</template> |
|
<span>Add new database to '{{ envKey }}' environment</span> |
|
</v-tooltip> |
|
|
|
<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> |
|
<v-col cols="4" class="py-0"> |
|
<v-select |
|
v-ge="['project','env-db-change']" |
|
class="body-2 db-select" |
|
:items="Object.keys(databaseNames)" |
|
v-model="client[dbIndex]" |
|
label="Database Type" |
|
@change="onDatabaseTypeChanged(client[dbIndex],db,dbIndex,envKey)" |
|
|
|
> |
|
<template slot="item" slot-scope="data"> |
|
{{ data.item }} |
|
<!-- <div class="d-flex flex-column mx-auto "--> |
|
<!-- style="width:100%;border-bottom: 1px solid #ddd">--> |
|
<!-- <img class="mx-auto py-3" width="80" :src="dbIcons[data.item]"/>--> |
|
<!-- <!– {{ data.item }}–>--> |
|
|
|
<!-- <p v-if="!databaseNames[data.item]" class="text-center grey--text">--> |
|
<!-- Coming soon</p>--> |
|
<!-- </div>--> |
|
</template> |
|
|
|
</v-select> |
|
</v-col> |
|
|
|
<v-col class="py-0" v-if="db.client === 'sqlite3'"> |
|
<v-text-field |
|
:rules="form.folderRequiredRule" |
|
v-model="db.connection.connection.filename" |
|
label="SQLite File" |
|
v-ge="['project','env-db-file']" |
|
@click="selectSqliteFile(db)"> |
|
<v-icon color="info" slot="prepend"> |
|
mdi-file-outline |
|
</v-icon> |
|
</v-text-field> |
|
|
|
</v-col> |
|
|
|
<v-col cols="4" v-if="db.client !== 'sqlite3'" class="py-0"> |
|
<v-text-field |
|
v-ge="['project','env-db-host']" |
|
class="body-2" |
|
:rules="form.requiredRule" |
|
v-model="db.connection.host" |
|
label="Host address" |
|
></v-text-field> |
|
</v-col> |
|
<v-col cols="4" class="py-0" v-if="db.client !== 'sqlite3'"> |
|
<v-text-field |
|
class="body-2" |
|
v-ge="['project','env-db-port']" |
|
v-model="db.connection.port" |
|
label="Port number" |
|
:rules="form.portValidationRule" |
|
></v-text-field> |
|
</v-col> |
|
<v-col cols="4" class="py-0" v-if="db.client !== 'sqlite3'"> |
|
<v-text-field |
|
class="body-2" |
|
v-ge="['project','env-db-user']" |
|
:rules="form.requiredRule" |
|
v-model="db.connection.user" |
|
label="Username" |
|
></v-text-field> |
|
</v-col> |
|
<v-col cols="4" class="py-0" v-if="db.client !== 'sqlite3'"> |
|
<v-text-field |
|
class="body-2 db-password" |
|
:type="showPass[`${panelIndex}_${dbIndex}`] ? 'text' : 'password'" |
|
:ref="`password${envKey}`" |
|
v-ge="['project','env-db-password']" |
|
v-model="db.connection.password" |
|
label="Password" |
|
> |
|
<template v-slot: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> |
|
<v-col cols="4" class="py-0" v-if="db.client !== 'sqlite3'"> |
|
<v-text-field |
|
class="body-2" |
|
:rules="form.requiredRule" |
|
v-model="db.connection.database" |
|
v-ge="['project','env-db-name']" |
|
label="Database : create if not exists" |
|
></v-text-field> |
|
</v-col> |
|
<v-col class="" v-if="db.client !== 'sqlite3'"> |
|
<v-expansion-panels> |
|
<v-expansion-panel |
|
style="border: 1px solid wheat"> |
|
<v-expansion-panel-header> |
|
<span class="grey--text">SSL / Advanced parameters</span> |
|
</v-expansion-panel-header> |
|
<v-expansion-panel-content> |
|
<v-card class="elevation-0"> |
|
<v-card-text> |
|
<v-select |
|
:items="Object.keys(sslUsage)" |
|
v-model="db.ui.sslUse" |
|
></v-select> |
|
|
|
<v-row class="pa-0 ma-0"> |
|
<x-btn tooltip="Select .cert file" |
|
small |
|
color="primary" |
|
outlined |
|
@click="selectFile(db,'ssl', 'certFilePath')" |
|
class="elevation-5" |
|
v-ge="['project','env-db-cert']" |
|
>{{ db.ui.ssl.cert }} |
|
</x-btn> |
|
<x-btn tooltip="Select .key file" |
|
small |
|
color="primary" |
|
outlined |
|
@click="selectFile(db,'ssl', 'keyFilePath')" |
|
v-ge="['project','env-db-key']" |
|
class="elevation-5" |
|
>{{ db.ui.ssl.key }} |
|
</x-btn> |
|
|
|
<x-btn tooltip="Select CA file" |
|
small |
|
color="primary" |
|
outlined |
|
@click="selectFile(db,'ssl', 'caFilePath')" |
|
v-ge="['project','env-db-ca']" |
|
>{{ db.ui.ssl.ca }} |
|
</x-btn> |
|
|
|
</v-row> |
|
|
|
<v-row> |
|
<v-col> |
|
<v-select |
|
label="Inflection - Table name" |
|
multiple |
|
:items="['camelize','pluralize']" |
|
v-model="db.meta.inflection.tn" |
|
></v-select> |
|
</v-col> |
|
<v-col> |
|
<v-select |
|
label="Inflection - Column name" |
|
multiple |
|
:items="['camelize']" |
|
v-model="db.meta.inflection.cn" |
|
></v-select> |
|
</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"> |
|
<x-btn tooltip="Test Database Connection" |
|
outlined |
|
small |
|
v-ge="['project','env-db-test-connection']" |
|
@click="testConnection(db,envKey,panelIndex)"> |
|
Test Database Connection |
|
</x-btn> |
|
<x-btn tooltip="Remove Database from environment" |
|
text |
|
small |
|
v-if="dbIndex" |
|
@click="removeDBFromEnv(db,envKey,panelIndex,dbIndex)" |
|
v-ge="['project','env-db-delete']" |
|
> |
|
<v-hover v-slot:default="{ 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-panel> |
|
<v-expansion-panel-header disable-icon-rotate> |
|
<v-tooltip bottom> |
|
<template v-slot:activator="{ on }"> |
|
<x-btn tooltip="Add New Environment to Project" color="grey" block v-on="on" outlined |
|
v-ge="['project','env-add']" |
|
@click.stop="addNewEnvironment"> |
|
<v-icon>mdi-plus</v-icon> |
|
Add Another Environment |
|
</x-btn> |
|
</template> |
|
<span>Add new environment to {{ project.title }} project</span> |
|
</v-tooltip> |
|
<template v-slot:actions> |
|
<i></i> |
|
</template> |
|
</v-expansion-panel-header> |
|
</v-expansion-panel> |
|
|
|
</v-expansion-panels> |
|
|
|
</v-col> |
|
|
|
|
|
<v-col cols="10" offset="1" v-show="project.title.trim().length" |
|
:class="{'mt-0 pt-0':!edit,'mt-3 pt-3':edit}"> |
|
<!-- <h2 :class="{'text-center mb-2':!edit,'text-center mb-2 grey--text':edit}">--> |
|
<!-- Advanced Configuration</h2>--> |
|
<v-expansion-panels focusable accordion="" class="elevation-20" |
|
style="border: 1px solid grey"> |
|
<v-expansion-panel |
|
> |
|
<v-expansion-panel-header disable-icon-rotate> |
|
|
|
<p class="pa-0 ma-0"> |
|
<v-icon class="mt-n2 " color="grey darken-1">mdi-cog</v-icon> |
|
<span class="grey--text text--darken-1"> Advanced Configuration </span> |
|
</p> |
|
|
|
</v-expansion-panel-header> |
|
<v-expansion-panel-content eager> |
|
|
|
<v-container class="justify-center"> |
|
<v-row> |
|
<v-col cols="12" class="py-0"> |
|
<v-select |
|
v-model="auth.authType" hint="Choose Authentication type" |
|
persistent-hint dense |
|
:items="authTypes"> |
|
|
|
<template v-slot:item="{item}"> |
|
<span class="caption"> |
|
{{ item.text }}</span> |
|
</template> |
|
|
|
</v-select> |
|
|
|
|
|
</v-col> |
|
<v-col cols="12" class="py-0" v-if="auth.authType && auth.authType !== 'none'"> |
|
<v-text-field |
|
|
|
v-if="auth.authType !== 'middleware'" |
|
v-model="auth.authSecret" |
|
label="Enter Auth Secret (Randomly generated)" |
|
:type="showSecret ? 'text' : 'password'" |
|
> |
|
<template v-slot:append> |
|
<v-icon small |
|
@click="showSecret = !showSecret" |
|
>{{ |
|
showSecret ? 'visibility_off' : |
|
'visibility' |
|
}} |
|
</v-icon> |
|
</template> |
|
</v-text-field> |
|
<v-text-field |
|
v-else |
|
|
|
v-model="auth.webhook" |
|
label="Webhook url" |
|
|
|
> |
|
</v-text-field> |
|
|
|
</v-col> |
|
|
|
</v-row> |
|
</v-container> |
|
|
|
</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" |
|
:dialogShow="dialog.show" |
|
:mtdOk="dialog.mtdOk" |
|
:heading="dialog.heading" |
|
:type="dialog.type" |
|
/> |
|
|
|
<textDlgSubmitCancel |
|
v-if="dialogGetEnvName.dialogShow" |
|
:dialogShow="dialogGetEnvName.dialogShow" |
|
:heading="dialogGetEnvName.heading" |
|
:mtdDialogSubmit="mtdDialogGetEnvNameSubmit" |
|
:mtdDialogCancel="mtdDialogGetEnvNameCancel" |
|
/> |
|
|
|
|
|
<div class="floating-button" v-if="project.title.trim().length"> |
|
<v-tooltip top> |
|
<template v-slot:activator="{ on }"> |
|
<v-btn v-on="on" fab dark large tooltip="Scroll to top" |
|
:disabled="!valid || !envStatusValid" |
|
class="primary" |
|
v-ge="['project','save']" |
|
@click="createOrUpdateProject()"> |
|
|
|
<v-icon>save</v-icon> |
|
</v-btn> |
|
</template> |
|
<span> |
|
Save Project |
|
</span> |
|
</v-tooltip> |
|
</div> |
|
|
|
</v-container> |
|
</template> |
|
<script> |
|
const {uniqueNamesGenerator, starWars, adjectives, animals} = require('unique-names-generator'); |
|
|
|
|
|
import {mapGetters, mapActions, mapState, mapMutations} from "vuex"; |
|
import Vue from 'vue'; |
|
import textDlgSubmitCancel from "../../components/utils/dlgTextSubmitCancel"; |
|
|
|
import {v4 as uuidv4} from 'uuid'; |
|
import dlgOk from "../../components/utils/dlgOk.vue"; |
|
import XBtn from "../../components/global/xBtn"; |
|
|
|
import axios from 'axios'; |
|
|
|
const homeDir = '' |
|
|
|
export default { |
|
layout: 'empty', |
|
|
|
components: { |
|
XBtn, |
|
dlgOk, |
|
textDlgSubmitCancel |
|
}, |
|
data() { |
|
|
|
return { |
|
showSecret: false, |
|
loaderMessages: [ |
|
'Setting up new database configs', |
|
'Inferring database schema', |
|
'Generating APIs.', |
|
'Generating APIs..', |
|
'Generating APIs...', |
|
'Generating APIs....', |
|
'Please wait...' |
|
], |
|
loaderMessage: '', |
|
projectReloading: false, |
|
authTypes: [ |
|
{text: "JWT", value: "jwt"}, |
|
{text: "Master Key", value: "masterKey"}, |
|
{text: "Middleware", value: "middleware"}, |
|
{text: "Disabled", value: "none"}, |
|
], |
|
projectTypes: [ |
|
{text: 'Automatic REST APIs on database', value: 'rest', icon: 'mdi-json', iconColor: 'green'}, |
|
{text: 'Automatic GRAPHQL APIs on database', value: 'graphql', icon: 'mdi-graphql', iconColor: 'pink'}, |
|
{text: 'Automatic gRPC APIs on database', value: 'grpc', icon: 'grpc-icon-color.png', type: 'img'}, |
|
// { |
|
// text: 'Automatic SQL Schema Migrations', |
|
// value: 'migrations', |
|
// icon: 'mdi-database-sync', |
|
// iconColor: 'indigo' |
|
// }, |
|
// {text: 'Simple Database Connection', value: 'dbConnection', icon: 'mdi-database', iconColor: 'primary'}, |
|
], |
|
|
|
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: null, |
|
client: ["Sqlite"], |
|
baseFolder: homeDir, |
|
|
|
tab: null, |
|
env: null, |
|
databases: [], |
|
/**************** END : form related ****************/ |
|
auth: { |
|
authSecret: uuidv4(), |
|
authType: 'jwt', |
|
webhook: null |
|
}, |
|
project: {}, |
|
defaultProject: { |
|
title: '', |
|
folder: homeDir, |
|
envs: { |
|
"dev": { |
|
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: { |
|
tn: [] |
|
} |
|
}, |
|
ui: { |
|
setup: -1, |
|
ssl: { |
|
key: "Client Key", |
|
cert: "Client Cert", |
|
ca: "Server CA" |
|
}, |
|
sslUse: 'Preferred' |
|
} |
|
} |
|
], |
|
apiClient: { |
|
data: [] |
|
} |
|
} |
|
}, |
|
"workingEnv": "dev", |
|
ui: { |
|
envs: { |
|
dev: {}, |
|
|
|
} |
|
}, |
|
meta: { |
|
version: '0.5', |
|
seedsFolder: 'seeds', |
|
queriesFolder: 'queries', |
|
apisFolder: 'apis', |
|
projectType: "rest", |
|
type: 'mvc', |
|
language: 'ts' |
|
}, |
|
version: '0.5', |
|
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: "" |
|
} |
|
}, |
|
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 |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
edit: false, |
|
dialog: { |
|
show: false, |
|
title: '', |
|
heading: '', |
|
mtdOk: this.testConnectionMethodSubmit, |
|
type: 'primary' |
|
}, |
|
sslUsage: { |
|
No: "No", |
|
Preferred: "Preferred", |
|
Required: "pg", |
|
"Required-CA": "Required-CA", |
|
"Required-IDENTITY": "Required-IDENTITY" |
|
}, |
|
sslUse: "Preferred", |
|
ssl: { |
|
key: "Client Key", |
|
cert: "Client Cert", |
|
ca: "Server CA" |
|
}, |
|
databaseNames: { |
|
MySQL: "mysql2", |
|
Postgres: "pg", |
|
Oracle: "oracledb", |
|
MsSQL: "mssql", |
|
Sqlite: "sqlite3", |
|
// 'Google Analytics': '', |
|
// Vitess: "mysql", |
|
// 'Salesforce': '', |
|
// 'SAP': '', |
|
// 'Stripe': '', |
|
}, |
|
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: [ |
|
'Invalid character in folder path.', |
|
'Invalid database credentials.', |
|
'Unable to connect to database, please check your database is up.', |
|
'User does not exist or have sufficient permission to create schema.', |
|
], |
|
compErrorMessage: '' |
|
} |
|
}, |
|
computed: { |
|
...mapGetters({sqlMgr: "sqlMgr/sqlMgr"}), |
|
envStatusValid() { |
|
return 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: { |
|
|
|
...mapActions({ |
|
loadProjects: "project/loadProjects", |
|
}), |
|
|
|
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')); |
|
}, |
|
|
|
selectFile(db, obj, key) { |
|
// console.log(obj, key); |
|
const file = dialog.showOpenDialog({ |
|
properties: ["openFile"] |
|
}); |
|
console.log(typeof file, file, typeof file[0]); |
|
if (file && file[0]) { |
|
let fileName = path.basename(file[0]); |
|
db.ui[obj][key] = fileName; |
|
Vue.set(db.ui[obj], key, fileName) |
|
//db.connection[obj][key] = file[0].toString(); |
|
Vue.set(db.connection[obj], key, file[0].toString()) |
|
} |
|
}, |
|
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() { |
|
|
|
console.log('Project json before creating', this.project); |
|
|
|
/** |
|
* remove UI keys within project |
|
*/ |
|
let xcConfig = JSON.parse(JSON.stringify(this.project)); |
|
console.log(JSON.stringify(this.project)); |
|
console.log('Project json after parsing', xcConfig); |
|
delete xcConfig.ui; |
|
|
|
|
|
for (let 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; |
|
console.log('getProjectJson:', env, i, xcConfig.envs[env].db[i]); |
|
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 (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.tn)) { |
|
inflectionObj.tn = inflectionObj.tn.join(',') |
|
} |
|
if (Array.isArray(inflectionObj.cn)) { |
|
inflectionObj.cn = inflectionObj.cn.join(',') |
|
} |
|
|
|
inflectionObj.tn = inflectionObj.tn || 'none'; |
|
inflectionObj.cn = inflectionObj.cn || 'none'; |
|
|
|
} |
|
|
|
|
|
} |
|
} |
|
|
|
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('admin-secret', 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'; |
|
|
|
console.log('Project json : after', xcConfig); |
|
|
|
return xcConfig; |
|
|
|
}, |
|
|
|
constructProjectJsonFromProject(project) { |
|
|
|
// const {projectJson: envs, ...rest} = project; |
|
|
|
// let p = {...rest, ...envs}; |
|
let p = JSON.parse(JSON.stringify(project.projectJson)); |
|
|
|
p.ui = { |
|
envs: { |
|
dev: {}, |
|
} |
|
}; |
|
for (let env in p.envs) { |
|
let i = 0; |
|
for (let db of p.envs[env].db) { |
|
|
|
Vue.set(this.client, i++, this.databaseNamesReverse[db.client]); |
|
|
|
Vue.set(db, 'ui', { |
|
setup: 0, |
|
ssl: { |
|
key: "Client Key", |
|
cert: "Client Cert", |
|
ca: "Server CA" |
|
}, |
|
sslUse: '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; |
|
|
|
|
|
}, |
|
|
|
|
|
async createOrUpdateProject() { |
|
// if (this.$store.state.windows.isComp) { |
|
// try { |
|
// ga('send', 'event', 'NewProject.', 'Action failed', this.$store.state.windows.isComp); |
|
// } catch (e) { |
|
// } |
|
// this.$toast.info(this.compErrorMessage).goAway(800); |
|
// return; |
|
// } |
|
|
|
const projectJson = this.getProjectJson(); |
|
//electron error from this.sqlMgr.projectCreate1 this fn |
|
// Attempting to call a function in a renderer window that has been closed or released. |
|
// const result = await this.sqlMgr.projectCreate1({ |
|
// project: { |
|
// title: this.project.title, |
|
// folder: this.project.folder, |
|
// type: 'mysql' |
|
// }, |
|
// projectJson |
|
// }); |
|
|
|
const folder = projectJson.folder; |
|
delete projectJson.folder; |
|
|
|
|
|
// let result = await this.$store.dispatch('sqlMgr/ActSqlOpPlus', [ |
|
let result = await this.$store.dispatch('sqlMgr/ActSqlOp', [ |
|
{ |
|
query: { |
|
skipProjectHasDb: 1 |
|
} |
|
}, |
|
this.edit ? 'projectUpdateByWeb' : "projectCreateByWeb", |
|
// "projectCreate1", |
|
{ |
|
project: { |
|
title: projectJson.title, |
|
folder: 'config.xc.json',//slash(path.join(folder, 'config.xc.json')), |
|
type: 'pg' |
|
}, |
|
projectJson |
|
}]); |
|
|
|
|
|
console.log( |
|
"project created redirect to project page", |
|
projectJson, |
|
result, |
|
// result.data.object.id |
|
); |
|
// await new Audio("/new-project.mp3").play(); |
|
|
|
this.projectReloading = true; |
|
|
|
let i = 0; |
|
const toast = this.$toast.info(this.loaderMessages[0]); |
|
await new Promise(resolve => { |
|
const interv = setInterval(() => { |
|
if (i < this.loaderMessages.length - 1) i++; |
|
if (toast) { |
|
toast.text(this.loaderMessages[i]) |
|
} |
|
|
|
axios.create({ |
|
baseURL: `${$axios.defaults.baseURL}/dashboard`, |
|
}).get('').then(() => { |
|
toast.goAway(100); |
|
this.projectReloading = false; |
|
clearInterval(interv); |
|
resolve(); |
|
}).catch(err => { |
|
}) |
|
}, 1000); |
|
}) |
|
|
|
|
|
await this.$store.dispatch('project/ActLoadProjectInfo'); |
|
|
|
if (this.$store.state.project.projectInfo.firstUser || this.$store.state.project.projectInfo.authType === 'masterKey') { |
|
return this.$router.push({ |
|
path: `/user/authentication/signup` |
|
}); |
|
} |
|
|
|
|
|
this.$router.push({ |
|
path: `/` |
|
}); |
|
}, |
|
|
|
mtdDialogGetEnvNameSubmit(envName, cookie) { |
|
console.log(envName); |
|
this.dialogGetEnvName.dialogShow = false |
|
if (envName in this.project.envs) { |
|
console.log('Environment exists'); |
|
} else { |
|
Vue.set(this.project.envs, envName, |
|
{ |
|
db: [ |
|
{ |
|
"client": "pg", |
|
"connection": { |
|
"host": "localhost", |
|
"port": "5432", |
|
"user": "postgres", |
|
"password": "password", |
|
"database": "new_database" |
|
}, |
|
"meta": { |
|
"tn": "xc_evolutions", |
|
"dbAlias": "db", |
|
inflection: { |
|
tn: [] |
|
} |
|
}, |
|
ui: { |
|
setup: 0, |
|
ssl: { |
|
key: "Client Key", |
|
cert: "Client Cert", |
|
ca: "Server CA" |
|
}, |
|
sslUse: 'Preferred' |
|
} |
|
}, |
|
], |
|
apiClient: {data: []} |
|
}); |
|
} |
|
|
|
}, |
|
mtdDialogGetEnvNameCancel() { |
|
console.log("mtdDialogGetTableNameCancel cancelled"); |
|
this.dialogGetEnvName.dialogShow = false; |
|
}, |
|
|
|
addNewEnvironment() { |
|
this.dialogGetEnvName.dialogShow = true; |
|
}, |
|
addNewDB(envKey, panelIndex) { |
|
let len = this.project.envs[envKey].db.length; |
|
let 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": "xc_evolutions", |
|
"dbAlias": dbAlias, |
|
inflection: { |
|
tn: [] |
|
}, |
|
api: { |
|
type: "", |
|
} |
|
}, |
|
ui: { |
|
setup: 0, |
|
sslUse: 'Preferred', |
|
ssl: { |
|
key: "Client Key", |
|
cert: "Client Cert", |
|
ca: "Server CA" |
|
}, |
|
} |
|
}) |
|
// set active tab as newly created |
|
this.databases[panelIndex] = newlyCreatedIndex; |
|
}, |
|
|
|
|
|
testConnectionMethodSubmit() { |
|
this.dialog.show = false; |
|
}, |
|
selectDir(ev) { |
|
// console.log(ev) |
|
const file = dialog.showOpenDialog({ |
|
properties: ["openDirectory"] |
|
}); |
|
if (file && file[0]) { |
|
this.baseFolder = file[0]; |
|
this.project.folder = file[0]; |
|
this.userSelectedDir = true; |
|
} |
|
}, |
|
selectSqliteFile(db) { |
|
// console.log(ev) |
|
const file = dialog.showOpenDialog({ |
|
properties: ["openFile"] |
|
}); |
|
if (file && file[0]) { |
|
db.connection.connection.filename = file[0]; |
|
} |
|
}, |
|
|
|
getDbStatusColor(db) { |
|
switch (db.ui.setup) { |
|
case -1: |
|
return "red" |
|
break; |
|
case 0: |
|
return "orange" |
|
break; |
|
case 1: |
|
return "green" |
|
break; |
|
default: |
|
break; |
|
} |
|
}, |
|
|
|
getDbStatusTooltip(db) { |
|
switch (db.ui.setup) { |
|
case -1: |
|
return "DB Connection NOT successful" |
|
break; |
|
case 0: |
|
return "MySql Database Detected - Test your connection" |
|
break; |
|
case 1: |
|
return "DB Connection successful" |
|
break; |
|
default: |
|
break; |
|
} |
|
}, |
|
async newTestConnection(db, env, panelIndex) { |
|
console.log(this.project.envs[env][0]); |
|
if (db.connection.host === 'localhost' |
|
&& !this.edit |
|
&& env === 'dev' |
|
&& 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, database: this.testDatabaseNames[db.client]}, |
|
client: db.client |
|
}; |
|
|
|
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{ |
|
query: { |
|
skipProjectHasDb: 1 |
|
} |
|
}, 'testConnection', c1]); |
|
console.log("test connection result", result); |
|
|
|
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 (let e in this.project.envs) { |
|
if (e === env) { |
|
|
|
} else { |
|
|
|
console.log(this.project.envs[e]); |
|
|
|
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 { |
|
this.dialog.heading = "Connection was successful" |
|
this.dialog.type = 'success'; |
|
this.dialog.show = true; |
|
} |
|
|
|
|
|
} else { |
|
db.ui.setup = -1; |
|
this.dialog.heading = "Connection Failure: \n\n" + 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); |
|
console.log('sslOptions:', sslOptions); |
|
if (sslOptions[0]) { |
|
sendAdvancedConfig = true; |
|
} else { |
|
console.log('no ssl options'); |
|
} |
|
return sendAdvancedConfig; |
|
}, |
|
|
|
handleSSL(db, creating = true) { |
|
console.log('handleSSL', db); |
|
const sendAdvancedConfig = this.sendAdvancedConfig(db.connection); |
|
if (!sendAdvancedConfig) { |
|
//args.ssl = undefined; |
|
db.connection.ssl = undefined; |
|
} |
|
|
|
|
|
if (db.connection.ssl) { |
|
// db.connection.ssl.caFilePath = db.connection.ssl.ca; |
|
// db.connection.ssl.keyFilePath = db.connection.ssl.key; |
|
// db.connection.ssl.certFilePath = db.connection.ssl.cert; |
|
// if(creating) { |
|
// delete db.connection.ssl.ca; |
|
// delete db.connection.ssl.key; |
|
// delete db.connection.ssl.cert; |
|
// } |
|
} |
|
}, |
|
getDatabaseForTestConnection(dbType) { |
|
|
|
}, |
|
async testConnection(db, env, panelIndex) { |
|
|
|
this.$store.commit('notification/MutToggleProgressBar', true) |
|
try { |
|
if (!await this.newTestConnection(db, env, panelIndex)) { |
|
// this.activeDbNode.testConnectionStatus = false; |
|
// |
|
|
|
this.handleSSL(db); |
|
|
|
console.log('testconnection params', db); |
|
if (db.client === 'sqlite3') { |
|
db.ui.setup = 1; |
|
} else { |
|
const c1 = { |
|
connection: {...db.connection, database: this.testDatabaseNames[db.client]}, |
|
client: db.client |
|
}; |
|
|
|
// const result = await this.sqlMgr.testConnection(c1); |
|
const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{ |
|
query: { |
|
skipProjectHasDb: 1 |
|
} |
|
}, 'testConnection', c1]); |
|
|
|
console.log("test connection result", result); |
|
|
|
if (result.code === 0) { |
|
db.ui.setup = 1; |
|
this.dialog.heading = "Connection was successful" |
|
this.dialog.type = 'success'; |
|
this.dialog.show = true; |
|
} else { |
|
db.ui.setup = -1; |
|
// this.activeDbNode.testConnectionStatus = false; |
|
this.dialog.heading = "Connection Failure: \n\n" + result.message; |
|
this.dialog.type = 'error'; |
|
this.dialog.show = true; |
|
} |
|
|
|
console.log('testconnection params : after', db); |
|
} |
|
} |
|
} 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 (let 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 (let 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('/'), |
|
// database: path.join(this.project.folder, `${this.project.title}_${env}_${index + 1}`), |
|
useNullAsDefault: true |
|
}) |
|
// Vue.set(db.connection, 'connection', {filename: `${this.project.folder}/${this.project.title}_${env}_${index + 1}`}) |
|
// Vue.set(db.connection, 'database', `${this.project.folder}/${this.project.title}_${env}_${index + 1}`) |
|
} |
|
|
|
} |
|
} |
|
}, |
|
selectDatabaseClient(database, index = 0) { |
|
if (this.client) this.client[index] = database; |
|
}, |
|
setDBStatus(db, status) { |
|
db.ui.setup = status; |
|
}, |
|
removeDBFromEnv(db, env, panelIndex, dbIndex) { |
|
|
|
console.log(db, env, panelIndex, dbIndex); |
|
|
|
for (let 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() { |
|
}, |
|
async created() { |
|
this.compErrorMessage = this.compErrorMessages[Math.floor(Math.random() * this.compErrorMessages.length)]; |
|
|
|
if (this.$route.query && this.$route.query.edit) { |
|
this.edit = true; |
|
// await this.$store.dispatch('sqlMgr/instantiateSqlMgr'); |
|
let data = await this.$store.dispatch('sqlMgr/ActSqlOp', [{id: this.$route.query.projectId}, 'PROJECT_READ_BY_WEB']); |
|
data = data.data.list[0]; |
|
console.log('created:', data); |
|
this.constructProjectJsonFromProject(data); |
|
this.$set(this.project, 'folder', data.folder); |
|
} 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 (let env in this.project.envs) { |
|
for (let 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} |
|
} |
|
// db.ui.setup = await PortScanner.isAlive(db.connection.host, parseInt(db.connection.port)) ? 0 : -1; |
|
} |
|
} |
|
} |
|
|
|
// for (let env in this.project.envs) { |
|
// for (let db of this.project.envs[env]) { |
|
// db.ui.setup = await PortScanner.isAlive(db.connection.host, parseInt(db.connection.port)) ? 0 : -1; |
|
// console.log('testing port', env, db.connection.database, db.ui.setup); |
|
// } |
|
// } |
|
} |
|
|
|
|
|
}, |
|
beforeMount() { |
|
}, |
|
mounted() { |
|
this.$set(this.project, 'title', uniqueNamesGenerator({ |
|
dictionaries: [[starWars], [adjectives, animals]][Math.floor(Math.random() * 2)] |
|
}).toLowerCase().replace(/[ -]/g, '_')) |
|
}, |
|
beforeDestroy() { |
|
}, |
|
destroy() { |
|
}, |
|
validate({params}) { |
|
return true |
|
}, |
|
head() { |
|
return { |
|
title: 'Create Project | XC', |
|
} |
|
}, |
|
props: {}, |
|
watch: { |
|
'project.title': function (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 (let env in this.project.envs) { |
|
for (let [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, 'connection', {filename: path.join(this.project.folder, `${this.project.title}_${env}_${index + 1}`)}) |
|
Vue.set(db.connection, 'database', `${this.project.title}_${env}_${index + 1}`) |
|
} |
|
} |
|
} |
|
} |
|
}, |
|
'project.envs': { |
|
deep: true, |
|
handler(envs) { |
|
Object.entries(envs).forEach(([key, env]) => { |
|
let res = 1, msg = {}; |
|
for (let 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 )'; |
|
break; |
|
case 0: |
|
msg.color = 'warning'; |
|
msg.msg = ' ( Click to validate database credentials )' |
|
break; |
|
case 1: |
|
msg.color = 'green'; |
|
msg.msg = ' ( Environment Validated )' |
|
break; |
|
} |
|
Vue.set(this.project.ui, key, msg); |
|
|
|
} |
|
}) |
|
} |
|
} |
|
}, |
|
directives: {} |
|
} |
|
</script> |
|
|
|
<style scoped> |
|
.floating-button { |
|
position: fixed; |
|
right: 7%; |
|
bottom: 100px |
|
} |
|
|
|
/deep/ .v-expansion-panel-header { |
|
padding: 0 6px; |
|
min-height: 50px !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/>. |
|
* |
|
*/ |
|
-->
|
|
|