Browse Source

feat: quick import (#2042)

* wip: basic add / import layout

* chore: move excel from create project options to project tabs

* chore: move drag attributes & rm unused methods

* chore: remove create project logic

* chore: rm project title text field

* fix: import excel into an existing project logic

* refactor: add / import menu ui

* feat: integrate with import-csv logic

* wip: new csv import logic

* feat: import csv basic ui

* refactor: use excel adapter for csv import

* chore: merge excel & csv together

* fix: accept csv for import

* i18n: add csv to excelSupport

* fix: empty map & extract error msg

* fix: duplicate columns with system fields during import

* chore: rename excel import -> quick import

* chore: separate csv & excel for better tele

* chore: pass quickImportType

* i18n: remove .csv from the message

* fix: wrong import type

* chore: hide gradient generator

* fix: file type validation

* i18n: add importCSV

* fix: import button text

* fix: set modal to false after importing

* fix: header text in quick import

* chore: show error message in parseAndExtractData

* i18n: add csvURL

* fix: import url label

* fix: wrong import type

* fix: failed to execute 'insertBefore' on 'Node'

* fix: delete logic & add pv to first column

* feat: set default primary value

* chore: disable virtual columns in dropdown

* fix: set pk & rqd to ID by default

* docs: remove creating project from excel

* docs: add quick import

* feat: add loadFirstCreatedTableTab

* feat: open the tab automatically after import

* test/cypress: UI corrections for quick-import

Signed-off-by: Raju Udava <86527202+dstala@users.noreply.github.com>

* fix: add UI permission to Add / Import

* fix: remove unnecessary drop handler

* fix: wrong class name in cypress test

* fix: use v-if instead of v-show

* fix: move _isUIAllowed to parent v-menu

Co-authored-by: Raju Udava <86527202+dstala@users.noreply.github.com>
pull/2050/head
աɨռɢӄաօռɢ 2 years ago committed by GitHub
parent
commit
19bbce998e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      packages/nc-gui/components/ProjectTreeView.vue
  2. 60
      packages/nc-gui/components/import/quickImport.vue
  3. 17
      packages/nc-gui/components/project/spreadsheet/components/importExport/columnMappingModal.vue
  4. 311
      packages/nc-gui/components/projectTabs.vue
  5. 139
      packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue
  6. 60
      packages/nc-gui/components/templates/editor.vue
  7. 2
      packages/nc-gui/lang/da.json
  8. 2
      packages/nc-gui/lang/de.json
  9. 2
      packages/nc-gui/lang/en.json
  10. 2
      packages/nc-gui/lang/es.json
  11. 2
      packages/nc-gui/lang/fa.json
  12. 2
      packages/nc-gui/lang/fi.json
  13. 4
      packages/nc-gui/lang/fr.json
  14. 2
      packages/nc-gui/lang/hr.json
  15. 2
      packages/nc-gui/lang/id.json
  16. 2
      packages/nc-gui/lang/it_IT.json
  17. 2
      packages/nc-gui/lang/iw.json
  18. 2
      packages/nc-gui/lang/ja.json
  19. 2
      packages/nc-gui/lang/ko.json
  20. 2
      packages/nc-gui/lang/lv.json
  21. 2
      packages/nc-gui/lang/nl.json
  22. 2
      packages/nc-gui/lang/no.json
  23. 2
      packages/nc-gui/lang/pl.json
  24. 2
      packages/nc-gui/lang/pt.json
  25. 2
      packages/nc-gui/lang/pt_BR.json
  26. 2
      packages/nc-gui/lang/ru.json
  27. 2
      packages/nc-gui/lang/sl.json
  28. 2
      packages/nc-gui/lang/sv.json
  29. 2
      packages/nc-gui/lang/th.json
  30. 2
      packages/nc-gui/lang/tr.json
  31. 2
      packages/nc-gui/lang/uk.json
  32. 2
      packages/nc-gui/lang/vi.json
  33. 2
      packages/nc-gui/lang/zh_CN.json
  34. 2
      packages/nc-gui/lang/zh_HK.json
  35. 2
      packages/nc-gui/lang/zh_TW.json
  36. 46
      packages/nc-gui/pages/projects/index.vue
  37. 17
      packages/nc-gui/store/tabs.js
  38. 29
      packages/noco-docs/content/en/setup-and-usages/dashboard.md
  39. 46
      packages/noco-docs/content/en/setup-and-usages/table-operations.md
  40. 2
      packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts
  41. 2
      scripts/cypress/integration/spec/roleValidation.spec.js
  42. 1
      scripts/cypress/support/commands.js

18
packages/nc-gui/components/ProjectTreeView.vue

@ -769,12 +769,12 @@
:heading="selectedNodeForDelete.heading"
type="error"
/>
<excel-import
ref="excelImport"
v-model="excelImportDialog"
<quick-import
ref="quickImport"
v-model="quickImportDialog"
hide-label
import-to-project
@success="onExcelImport"
@success="onQuickImport"
/>
</div>
</template>
@ -795,7 +795,7 @@ import DlgTableCreate from "@/components/utils/dlgTableCreate";
import DlgViewCreate from "@/components/utils/dlgViewCreate";
import SponsorMini from "@/components/sponsorMini";
import {validateTableName} from "~/helpers";
import ExcelImport from "~/components/import/excelImport";
import QuickImport from "~/components/import/quickImport";
import draggable from "vuedraggable";
import GithubStarBtn from "~/components/githubStarBtn";
@ -810,7 +810,7 @@ export default {
SettingsModal,
GithubStarBtn,
draggable,
ExcelImport,
QuickImport,
SponsorMini,
DlgViewCreate,
DlgTableCreate,
@ -864,7 +864,7 @@ export default {
open: [],
search: null,
menuVisible: false,
excelImportDialog: false,
quickImportDialog: false,
x: 0,
y: 0,
menuItem: null,
@ -1162,7 +1162,7 @@ export default {
this.miniExpanded = false;
}
},
onExcelImport() {
onQuickImport() {
if (!this.menuItem || this.menuItem.type !== "tableDir") {
this.menuItem = this.listViewArr.find((n) => n.type === "tableDir");
}
@ -1437,7 +1437,7 @@ export default {
await this.loadViews(this.menuItem);
this.$toast.success("Views refreshed").goAway(1000);
} else if (action === "IMPORT_EXCEL") {
this.excelImportDialog = true;
this.quickImportDialog = true;
} else if (action === "ENV_DB_FUNCTIONS_REFRESH") {
await this.loadFunctions(this.menuItem);
this.$toast.success("Functions refreshed").goAway(1000);

60
packages/nc-gui/components/import/excelImport.vue → packages/nc-gui/components/import/quickImport.vue

@ -43,8 +43,8 @@
{{ $t('msg.info.upload_sub') }}
</p>
<p class="caption grey--text">
<!-- Supported: .xls, .xlsx, .xlsm, .ods, .ots-->
<p v-if="quickImportType == 'excel'" class="caption grey--text">
<!-- Supported: .xls, .xlsx, .xlsm, .ods, .ots -->
{{ $t('msg.info.excelSupport') }}
</p>
</div>
@ -60,7 +60,7 @@
v-model="url"
hide-details="auto"
type="url"
:label="$t('msg.info.excelURL')"
:label="quickImportType == 'excel' ? $t('msg.info.excelURL') : $t('msg.info.csvURL') "
class="caption"
outlined
dense
@ -106,6 +106,7 @@
<v-tooltip bottom>
<template #activator="{on}">
<input
v-if="quickImportType == 'excel'"
ref="file"
class="nc-excel-import-input"
type="file"
@ -113,6 +114,15 @@
accept=".xlsx, .xls, .xlsm, .ods, .ots"
@change="_change($event)"
>
<input
v-if="quickImportType == 'csv'"
ref="file"
class="nc-excel-import-input"
type="file"
style="display: none"
accept=".csv"
@change="_change($event)"
>
<v-btn
v-if="!hideLabel"
@ -133,14 +143,19 @@
<v-dialog v-if="templateData" v-model="templateEditorModal" max-width="1000">
<v-card class="pa-6" min-width="500">
<template-editor :project-template.sync="templateData" excel-import>
<template-editor :project-template.sync="templateData" excel-import :quick-import-type="quickImportType">
<template #toolbar="{valid}">
<!--Importing-->
<h3 class="mt-2 grey--text">
{{ $t('activity.importExcel') }} : {{ filename }}
<!--Import Excel-->
<span v-if="quickImportType === 'excel'">
{{ $t('activity.importExcel') }}
</span>
<!--Import CSV-->
<span v-if="quickImportType === 'csv'">
{{ $t('activity.importCSV') }}
</span>
: {{ filename }}
</h3>
<!-- <span class="grey&#45;&#45;text">Importing 2 sheets</span>-->
<v-spacer />
<v-spacer />
<create-project-from-template-btn
@ -151,10 +166,16 @@
:valid="valid"
create-gql-text="Import as GQL Project"
create-rest-text="Import as REST Project"
@success="$emit('success'),templateEditorModal = false"
@closeModal="$emit('closeModal'),templateEditorModal = false"
>
<!--Import Excel-->
{{ $t('activity.importExcel') }}
<span v-if="quickImportType === 'excel'">
{{ $t('activity.importExcel') }}
</span>
<!--Import CSV-->
<span v-if="quickImportType === 'csv'">
{{ $t('activity.importCSV') }}
</span>
</create-project-from-template-btn>
</template>
</template-editor>
@ -172,12 +193,13 @@ import ExcelUrlTemplateAdapter from '~/components/import/templateParsers/ExcelUr
import ExcelTemplateAdapter from '~/components/import/templateParsers/ExcelTemplateAdapter'
export default {
name: 'ExcelImport',
name: 'QuickImport',
components: { CreateProjectFromTemplateBtn, TemplateEditor },
props: {
hideLabel: Boolean,
value: Boolean,
importToProject: Boolean
importToProject: Boolean,
quickImportType: String
},
data() {
return {
@ -276,7 +298,9 @@ export default {
this.templateEditorModal = true
} catch (e) {
console.log(e)
this.$toast.error(e.message).goAway(3000)
this.$toast
.error(await this._extractSdkResponseErrorMsg(e))
.goAway(3000)
}
},
@ -296,8 +320,14 @@ export default {
return
}
if ((!/\.xls[xm]?$/.test(file.name)) && (!/\.o[dt]s?$/.test(file.name))) {
return this.$toast.error('Dropped file is not an accepted file type. The accepted file types are .xlsx,.xls,.xlsm!').goAway(3000)
if (this.quickImportType === 'excel') {
if (!/.*\.(xls|xlsx|xlsm|ods|ots)/.test(file.name)) {
return this.$toast.error('Dropped file is not an accepted file type. The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots!').goAway(3000)
}
} else if (this.quickImportType === 'csv') {
if (!/.*\.(csv)/.test(file.name)) {
return this.$toast.error('Dropped file is not an accepted file type. The accepted file type is .csv!').goAway(3000)
}
}
this._file(file)
},

17
packages/nc-gui/components/project/spreadsheet/components/importExport/columnMappingModal.vue

@ -1,6 +1,7 @@
<template>
<v-dialog v-model="visible" max-width="800px">
<v-card>
<!-- Import CSV to existing Table -->
<v-card v-if="meta">
<v-card-actions>
<v-card-title>
Table : {{ meta.title }}
@ -99,12 +100,12 @@ export default {
meta: Object,
importDataColumns: Array,
value: Boolean,
parsedCsv: Object
parsedCsv: Object,
},
data() {
return {
mappings: [],
valid: false
valid: false,
}
},
computed: {
@ -194,9 +195,11 @@ export default {
this.mappings = []
for (const col of this.importDataColumns) {
const o = { sourceCn: col, enabled: true }
const tableColumn = this.meta.columns.find(c => c.title === col)
if (tableColumn) {
o.destCn = tableColumn.title
if (this.meta) {
const tableColumn = this.meta.columns.find(c => c.title === col)
if (tableColumn) {
o.destCn = tableColumn.title
}
}
this.mappings.push(o)
}
@ -204,7 +207,7 @@ export default {
},
getIcon(uidt) {
return getUIDTIcon(uidt) || 'mdi-alpha-v-circle-outline'
}
},
}
}
</script>

311
packages/nc-gui/components/projectTabs.vue

@ -42,14 +42,12 @@
max-width: 140px;
text-overflow: ellipsis;
"
>{{ tab.name }}</span
>
>{{ tab.name }}</span>
<v-icon icon :small="true" @click="removeTab(index)">
mdi-close
</v-icon>
</v-tab>
<!-- <v-tabs-items v-model="activeTab">-->
<v-tabs-items :value="activeTab">
<v-tab-item
v-for="(tab, index) in tabs"
@ -65,14 +63,13 @@
:reverse-transition="false"
>
<div v-if="tab._nodes.type === 'table'" style="height: 100%">
<!-- <sqlLogAndOutput :hide="hideLogWindows">-->
<TableView
:ref="'tabs' + index"
:is-active="
activeTab ===
`${(tab._nodes && tab._nodes).type || ''}||${
(tab._nodes && tab._nodes.dbAlias) || ''
}||${tab.name}`
`${(tab._nodes && tab._nodes).type || ''}||${
(tab._nodes && tab._nodes.dbAlias) || ''
}||${tab.name}`
"
:tab-id="`${pid}||${(tab._nodes && tab._nodes).type || ''}||${
(tab._nodes && tab._nodes.dbAlias) || ''
@ -80,18 +77,15 @@
:hide-log-windows.sync="hideLogWindows"
:nodes="tab._nodes"
/>
<!-- </sqlLogAndOutput>-->
</div>
<div v-else-if="tab._nodes.type === 'view'" style="height: 100%">
<!-- <sqlLogAndOutput>-->
<!-- <ViewTab :ref="'tabs'+index" :nodes="tab._nodes" />-->
<TableView
:ref="'tabs' + index"
:is-active="
activeTab ===
`${(tab._nodes && tab._nodes).type || ''}||${
(tab._nodes && tab._nodes.dbAlias) || ''
}||${tab.name}`
`${(tab._nodes && tab._nodes).type || ''}||${
(tab._nodes && tab._nodes.dbAlias) || ''
}||${tab.name}`
"
:tab-id="`${pid}||${(tab._nodes && tab._nodes).type || ''}||${
(tab._nodes && tab._nodes.dbAlias) || ''
@ -247,22 +241,83 @@
<h1>{{ tab._nodes }}</h1>
</div>
</v-tab-item>
<!-- </v-tabs-items>-->
</v-tabs-items>
<!-- tooltip: Add new table -->
<x-icon
v-if="_isUIAllowed('addTable')"
:tooltip="$t('tooltip.addTable')"
icon-class="add-btn"
:color="['white', 'grey lighten-2']"
@click="dialogCreateTableShowMethod"
>
mdi-plus-box
</x-icon>
<v-spacer />
<!-- Add / Import -->
<v-menu offset-y v-if="_isUIAllowed('addOrImport')">
<template #activator="{ on }">
<v-btn
color="primary"
style="height: 100%; padding: 5px;"
v-on="on"
>
<x-icon
icon-class="add-btn"
:color="['white', 'grey lighten-2']"
>
mdi-plus-box
</x-icon>
<span class="flex-grow-1 caption font-weight-bold text-capitalize mx-2">
<!-- TODO: i18n -->
Add / Import
</span>
<v-spacer />
</v-btn>
</template>
<v-list class="addOrImport">
<v-list-item
v-if="_isUIAllowed('addTable')"
v-t="['a:table:import-from-excel']"
@click="dialogCreateTableShowMethod"
>
<v-list-item-title>
<v-icon small>
mdi-table
</v-icon>
<span class="caption">
<!-- Add new table -->
{{ $t('tooltip.addTable') }}
</span>
</v-list-item-title>
</v-list-item>
<v-divider />
<v-subheader class="caption">
QUICK IMPORT FROM
</v-subheader>
<v-list-item
v-if="_isUIAllowed('csvQuickImport')"
v-t="['a:actions:import-csv']"
@click="onImportFromExcelOrCSV('csv')"
>
<v-list-item-title>
<v-icon small>
mdi-file-document-outline
</v-icon>
<span class="caption">
<!-- TODO: i18n -->
CSV file
</span>
</v-list-item-title>
</v-list-item>
<v-list-item
v-if="_isUIAllowed('excelQuickImport')"
v-t="['a:actions:import-excel']"
@click="onImportFromExcelOrCSV('excel')"
>
<v-list-item-title>
<v-icon small>
mdi-file-excel
</v-icon>
<span class="caption">
<!-- TODO: i18n -->
Microsoft Excel
</span>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-tabs>
<!-- Create Empty Table -->
<dlg-table-create
v-if="dialogCreateTableShow"
v-model="dialogCreateTableShow"
@ -271,39 +326,46 @@
dialogCreateTableShow = false;
"
/>
<!-- <screensaver v-if="showScreensaver && !($store.state.project.projectInfo && $store.state.project.projectInfo.ncMin)" class="screensaver" />-->
<!-- Import From Excel / CSV -->
<quick-import
ref="quickImport"
v-model="quickImportModal"
:quick-import-type="quickImportType"
hide-label
@closeModal="quickImportModal = false"
/>
</v-container>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
import treeViewIcons from "../helpers/treeViewIcons";
import TableView from "./project/table";
import FunctionTab from "./project/function";
import ProcedureTab from "./project/procedure";
import SequenceTab from "./project/sequence";
import SeedTab from "./project/seed";
import SqlClientTab from "./project/sqlClient";
import ApisTab from "./project/apis";
import ApiClientTab from "./project/apiClientOld";
import sqlLogAndOutput from "./project/sqlLogAndOutput";
import graphqlClient from "./project/graphqlClient";
import xTerm from "./xTerm";
import { mapGetters, mapMutations } from 'vuex'
import treeViewIcons from '../helpers/treeViewIcons'
import TableView from './project/table'
import FunctionTab from './project/function'
import ProcedureTab from './project/procedure'
import SequenceTab from './project/sequence'
import SeedTab from './project/seed'
import SqlClientTab from './project/sqlClient'
import ApisTab from './project/apis'
import ApiClientTab from './project/apiClientOld'
import sqlLogAndOutput from './project/sqlLogAndOutput'
import graphqlClient from './project/graphqlClient'
import xTerm from './xTerm'
import ApiClientSwaggerTab from "./project/apiClientSwagger";
import XcMeta from "./project/settings/xcMeta";
import XcInfo from "./project/xcInfo";
import SwaggerClient from "@/components/project/swaggerClient";
import DlgTableCreate from "@/components/utils/dlgTableCreate";
import AppStore from "@/components/project/appStore";
import AuthTab from "@/components/authTab";
import CronJobs from "@/components/project/cronJobs";
import DisableOrEnableModels from "@/components/project/projectMetadata/disableOrEnableModels";
import ProjectSettings from "@/components/project/projectSettings";
import GrpcClient from "@/components/project/grpcClient";
import GlobalAcl from "@/components/globalAcl";
import AuditTab from "~/components/project/auditTab";
import ApiClientSwaggerTab from './project/apiClientSwagger'
import XcMeta from './project/settings/xcMeta'
import XcInfo from './project/xcInfo'
import SwaggerClient from '@/components/project/swaggerClient'
import DlgTableCreate from '@/components/utils/dlgTableCreate'
import AppStore from '@/components/project/appStore'
import AuthTab from '@/components/authTab'
import CronJobs from '@/components/project/cronJobs'
import DisableOrEnableModels from '@/components/project/projectMetadata/disableOrEnableModels'
import ProjectSettings from '@/components/project/projectSettings'
import GrpcClient from '@/components/project/grpcClient'
import GlobalAcl from '@/components/globalAcl'
import AuditTab from '~/components/project/auditTab'
import QuickImport from '@/components/import/quickImport'
export default {
components: {
@ -334,147 +396,159 @@ export default {
sqlLogAndOutput,
xTerm,
graphqlClient,
QuickImport
},
data() {
return {
dragOver: false,
dialogCreateTableShow: false,
test: "",
test: '',
treeViewIcons,
hideLogWindows: false,
showScreensaver: false,
};
quickImportModal: false,
quickImportType: ''
}
},
methods: {
dialogCreateTableShowMethod() {
this.dialogCreateTableShow = true;
this.$e("c:table:create:navbar");
this.dialogCreateTableShow = true
this.$e('c:table:create:navbar')
},
checkInactiveState() {
let position = 0;
let idleTime = 0;
let position = 0
let idleTime = 0
// Increment the idle time counter every minute.
let idleInterval = setInterval(timerIncrement, 1000);
let idleInterval = setInterval(timerIncrement, 1000)
const self = this;
const self = this
// Zero the idle timer on mouse movement.
document.addEventListener("mousemove", (e) => {
self.showScreensaver = false;
idleTime = 0;
clearInterval(idleInterval);
idleInterval = setInterval(timerIncrement, 1000);
});
document.addEventListener("keypress", (e) => {
self.showScreensaver = false;
idleTime = 0;
clearInterval(idleInterval);
idleInterval = setInterval(timerIncrement, 1000);
});
document.addEventListener('mousemove', (e) => {
self.showScreensaver = false
idleTime = 0
clearInterval(idleInterval)
idleInterval = setInterval(timerIncrement, 1000)
})
document.addEventListener('keypress', (e) => {
self.showScreensaver = false
idleTime = 0
clearInterval(idleInterval)
idleInterval = setInterval(timerIncrement, 1000)
})
function timerIncrement() {
idleTime = idleTime + 1;
idleTime = idleTime + 1
if (idleTime > 120) {
const title = document.title;
const title = document.title
function scrolltitle() {
document.title = title + Array(position).fill(" .").join("");
position = ++position % 3;
document.title = title + Array(position).fill(' .').join('')
position = ++position % 3
if (self.showScreensaver) {
window.setTimeout(scrolltitle, 400);
window.setTimeout(scrolltitle, 400)
} else {
document.title = title;
document.title = title
}
}
self.showScreensaver = self.$store.state.windows.screensaver;
scrolltitle();
clearInterval(idleInterval);
self.showScreensaver = self.$store.state.windows.screensaver
scrolltitle()
clearInterval(idleInterval)
}
}
},
async handleKeyDown(event) {
const activeTabEleKey = `tabs${this.activeTab}`;
let isHandled = false;
const activeTabEleKey = `tabs${this.activeTab}`
let isHandled = false
if (
this.$refs[activeTabEleKey] &&
this.$refs[activeTabEleKey][0] &&
this.$refs[activeTabEleKey][0].handleKeyDown
) {
isHandled = await this.$refs[activeTabEleKey][0].handleKeyDown(event);
isHandled = await this.$refs[activeTabEleKey][0].handleKeyDown(event)
}
if (!isHandled) {
switch (
[this._isMac ? event.metaKey : event.ctrlKey, event.key].join("_")
[this._isMac ? event.metaKey : event.ctrlKey, event.key].join('_')
) {
case "true_w":
this.removeTab(this.activeTab);
event.preventDefault();
event.stopPropagation();
break;
case 'true_w':
this.removeTab(this.activeTab)
event.preventDefault()
event.stopPropagation()
break
}
}
},
...mapMutations({
setActiveTab: "tabs/active",
removeTab: "tabs/remove",
updateActiveTabx: "tabs/activeTabCtx",
setActiveTab: 'tabs/active',
removeTab: 'tabs/remove',
updateActiveTabx: 'tabs/activeTabCtx'
}),
tabActivated(tab) {},
onImportFromExcelOrCSV(quickImportType) {
this.quickImportModal = true
this.quickImportType = quickImportType
}
},
computed: {
...mapGetters({ tabs: "tabs/list", activeTabCtx: "tabs/activeTabCtx" }),
...mapGetters({ tabs: 'tabs/list', activeTabCtx: 'tabs/activeTabCtx' }),
pid() {
return this.$route.params.project_id;
return this.$route.params.project_id
},
activeTab: {
set(tab) {
if (!tab) {
return this.$router.push({
query: {},
});
query: {}
})
}
const [type, dbalias, name] = tab.split("||");
const [type, dbalias, name] = tab.split('||')
this.$router.push({
query: {
...this.$route.query,
type,
dbalias,
name,
},
});
name
}
})
},
get() {
return [
this.$route.query.type,
this.$route.query.dbalias,
this.$route.query.name,
].join("||");
},
},
this.$route.query.name
].join('||')
}
}
},
beforeCreated() {},
watch: {},
created() {
document.addEventListener("keydown", this.handleKeyDown);
document.addEventListener('keydown', this.handleKeyDown)
/**
* Listening for tab change so that we can hide/show projectlogs based on tab
*/
},
mounted() {},
mounted() {
if (this.$route && this.$route.query && this.$route.query.excelUrl) {
this.quickImportModal = true
}
},
beforeDestroy() {},
destroyed() {
document.removeEventListener("keydown", this.handleKeyDown);
document.removeEventListener('keydown', this.handleKeyDown)
},
directives: {},
validate({ params }) {
return true;
return true
},
head() {
return {};
return {}
},
props: {},
};
props: {}
}
</script>
<style scoped>
@ -544,6 +618,14 @@ export default {
font-weight: bold;
}
.addOrImport {
min-width: 200px;
}
.addOrImport .v-list-item {
min-height: 35px;
}
/deep/ .add-btn {
margin-left: 5px;
}
@ -562,6 +644,7 @@ export default {
*
* @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
*

139
packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue

@ -20,7 +20,7 @@ export default {
name: 'CreateProjectFromTemplateBtn',
mixins: [colors],
props: {
excelImport: Boolean,
quickImport: Boolean,
loading: Boolean,
importToProject: Boolean,
templateData: [Array, Object],
@ -99,7 +99,8 @@ export default {
this.$store.commit('loader/MutMessage', this.loaderMessages[this.loaderMessagesIndex])
}, 1000)
let project
const projectId = this.$store.state.project.project.id
let firstTable = null
// Not available now
if (this.importToProject) {
@ -122,45 +123,46 @@ export default {
// projectId = this.$route.params.project_id
// prefix = this.$store.getters['project/GtrProjectPrefix']
} else {
// Create an empty project
try {
this.$e("a:project:create:excel");
project = await this.$api.project.create({
title: this.templateData.title,
external: false
})
this.projectCreation = true
} catch (e) {
this.projectCreation = false
this.$toast
.error(await this._extractSdkResponseErrorMsg(e))
.goAway(3000)
} finally {
clearInterval(interv)
}
if (!this.projectCreation) {
// failed to create project
return
}
// Create tables
try {
for (const t of this.localTemplateData.tables) {
// enrich system fields if not provided
// e.g. id, created_at, updated_at
const systemColumns = SqlUiFactory
.create({ client: 'sqlite3' })
.create({ client: this.$store.state.project.project.bases[0].type })
.getNewTableColumns()
.filter(c => c.column_name != 'title')
.filter(c => c.column_name !== 'title')
const table = await this.$api.dbTable.create(project.id, {
for (const systemColumn of systemColumns) {
if (!t.columns.some(c => c.column_name.toLowerCase() === systemColumn.column_name.toLowerCase())) {
t.columns.push(systemColumn)
}
}
// set pk & rqd if ID is provided
for (const column of t.columns) {
if (column.column_name.toLowerCase() === 'id' && !('pk' in column)) {
column.pk = true
column.rqd = true
break
}
}
// create table
const table = await this.$api.dbTable.create(projectId, {
table_name: t.table_name,
title: '',
columns: [...t.columns, ...systemColumns]
columns: t.columns
})
t.table_title = table.title
// open the first table after import
if (firstTable === null) {
firstTable = table
}
// set primary value
await this.$api.dbTableColumn.primaryColumnSet(table.columns[0].id)
}
this.tableCreation = true
} catch (e) {
@ -181,30 +183,55 @@ export default {
// Bulk import data
if (this.importData) {
this.$store.commit('loader/MutMessage', 'Importing excel data to project')
await this.importDataToProject(this.templateData.title)
await this.importDataToProject()
}
this.$router.push({
path: `/nc/${project.id}`,
query: {
new: 1
// reload table list
this.$store.dispatch('project/_loadTables', {
dbKey: '0.projectJson.envs._noco.db.0',
key: '0.projectJson.envs._noco.db.0.tables',
_nodes: {
dbAlias: 'db',
env: '_noco',
type: 'tableDir'
}
}).then(() => {
// add tab - choose the first one if multiple tables are created
this.$store.dispatch('tabs/loadFirstCreatedTableTab', {
title: firstTable.title
}).then((item) => {
// set active tab - choose the first one if multiple tables are created
this.$nextTick(() => {
this.$router.push({
query: {
name: item.name || '',
dbalias: (item._nodes && item._nodes.dbAlias) || '',
type: (item._nodes && item._nodes.type) || 'table'
}
})
})
})
})
this.$emit('success')
// confetti effect
this.simpleAnim()
} catch (e) {
console.log(e)
this.$toast.error(e.message).goAway(3000)
this.$toast
.error(await this._extractSdkResponseErrorMsg(e))
.goAway(3000)
} finally {
clearInterval(interv)
this.$store.commit('loader/MutMessage', null)
this.projectCreation = false
this.tableCreation = false
this.$emit('closeModal')
}
},
async importDataToProject(projectName) {
async importDataToProject() {
let total = 0
let progress = 0
const projectName = this.$store.state.project.project.title
await Promise.all(this.localTemplateData.tables.map(v => (async(tableMeta) => {
const tableName = tableMeta.table_title
const data = this.importData[tableMeta.ref_table_name]
@ -227,12 +254,46 @@ export default {
remapColNames(batchData, columns) {
return batchData.map(data => (columns || []).reduce((aggObj, col) => ({
...aggObj,
[col.column_name]: data[col.ref_column_name]
[col.column_name]: data[col.ref_column_name || col.column_name]
}), {})
)
},
simpleAnim() {
const count = 200
const defaults = {
origin: { y: 0.7 }
}
function fire(particleRatio, opts) {
window.confetti(Object.assign({}, defaults, opts, {
particleCount: Math.floor(count * particleRatio)
}))
}
fire(0.25, {
spread: 26,
startVelocity: 55
})
fire(0.2, {
spread: 60
})
fire(0.35, {
spread: 100,
decay: 0.91,
scalar: 0.8
})
fire(0.1, {
spread: 120,
startVelocity: 25,
decay: 0.92,
scalar: 1.2
})
fire(0.1, {
spread: 120,
startVelocity: 45
})
}
}
}
</script>

60
packages/nc-gui/components/templates/editor.vue

@ -60,25 +60,7 @@
<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">
<p v-if="project.tables && quickImportType === 'excel'" class="caption grey--text mt-4">
{{ project.tables.length }} sheet{{
project.tables.length > 1 ? "s" : ""
}}
@ -127,7 +109,7 @@
<v-tooltip bottom>
<template #activator="{ on }">
<v-icon
v-if="!viewMode"
v-if="!viewMode && project.tables.length > 1"
class="flex-grow-0 mr-2"
small
color="grey"
@ -283,7 +265,7 @@
:ref="`uidt_${table.table_name}_${j}`"
style="max-width: 200px"
:value="col.uidt"
placeholder="Column Datatype"
placeholder="Column Data Type"
outlined
dense
class="caption"
@ -498,11 +480,26 @@
: 3
"
/>
<td style="max-width: 50px; width: 50px">
<v-tooltip bottom>
<td
style="max-width: 50px; width: 50px"
>
<v-tooltip v-if="!viewMode && j == 0" bottom>
<template #activator="{ on }">
<x-icon
small
class="mr-1"
color="primary"
v-on="on"
>
mdi-key-star
</x-icon>
</template>
<!-- TODO: i18n -->
<span>Primary Value</span>
</v-tooltip>
<v-tooltip v-else bottom>
<template #activator="{ on }">
<v-icon
v-if="!viewMode"
class="flex-grow-0"
small
color="grey"
@ -630,8 +627,9 @@
</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">
<!-- Disable Gradient Generator at time being -->
<!-- <div v-if="!viewMode" class="mx-auto" style="max-width: 600px">
<template v-if="!quickImport">
<gradient-generator
v-model="project.image_url"
class="d-100 mt-4"
@ -669,7 +667,7 @@
/>
</div>
</template>
</div>
</div> -->
</v-card-text>
</v-card>
</v-col>
@ -768,6 +766,9 @@ import {
} from '~/components/project/spreadsheet/helpers/uiTypes'
import GradientGenerator from '~/components/templates/gradientGenerator'
import Help from '~/components/templates/help'
import {
isVirtualCol,
} from "nocodb-sdk";
const LinkToAnotherRecord = 'LinkToAnotherRecord'
const Lookup = 'Lookup'
@ -781,7 +782,8 @@ export default {
id: [Number, String],
viewMode: Boolean,
projectTemplate: Object,
excelImport: Boolean
quickImport: Boolean,
quickImportType: String
},
data: () => ({
loading: false,
@ -802,7 +804,7 @@ export default {
createTableColumnsDialog: false,
selectedTable: null,
uiTypes: uiTypes.filter(
t => ![UITypes.Formula, UITypes.SpecificDBType].includes(t.name)
t => !isVirtualCol(t.name)
),
rollupFnList: [
{ text: 'count', value: 'count' },

2
packages/nc-gui/lang/da.json

@ -306,6 +306,7 @@
"deleteRow": "DELETE ROW.",
"deleteSelectedRow": "Slet de valgte rækker",
"importExcel": "Import Excel.",
"importCSV": "Import CSV.",
"downloadCSV": "Download som CSV.",
"uploadCSV": "Upload CSV.",
"import": "Importere",
@ -397,6 +398,7 @@
"upload_sub": "eller træk og slip filen",
"excelSupport": "Støttet: .xls, .xlsx, .xlsm, .ods, .Oer",
"excelURL": "Indtast Excel-fil-URL",
"csvURL": "Enter CSV file URL",
"footMsg": "# af rækker til at analysere for at udlede datatype",
"excelImport": "ark (r) er tilgængelige for import",
"exportMetadata": "Ønsker du at eksportere metadata fra metaborde?",

2
packages/nc-gui/lang/de.json

@ -306,6 +306,7 @@
"deleteRow": "Zeile löschen",
"deleteSelectedRow": "Ausgewählte Zeilen löschen",
"importExcel": "Import Excel",
"importCSV": "Import CSV",
"downloadCSV": "Download als CSV",
"uploadCSV": "Hochladen CSV",
"import": "Importieren",
@ -397,6 +398,7 @@
"upload_sub": "oder Drag & Drop Datei",
"excelSupport": "Unterstützt: .xls ,.xlsx ,.xlsm, .ods, .ots",
"excelURL": "Excel-Datei-URL eingeben",
"csvURL": "Enter CSV file URL",
"footMsg": "Anzahl der Zeilen, um den Datentyp analysieren zu können",
"excelImport": "Blatt/Blätter stehen für den Import zur Verfügung",
"exportMetadata": "Möchten Sie Metadaten von Meta-Tabellen exportieren?",

2
packages/nc-gui/lang/en.json

@ -306,6 +306,7 @@
"deleteRow": "Delete Row",
"deleteSelectedRow": "Delete Selected Rows",
"importExcel": "Import Excel",
"importCSV": "Import CSV",
"downloadCSV": "Download as CSV",
"uploadCSV": "Upload CSV",
"import": "Import",
@ -397,6 +398,7 @@
"upload_sub": "or drag and drop file",
"excelSupport": "Supported: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Enter excel file URL",
"csvURL": "Enter CSV file URL",
"footMsg": "# of rows to parse to infer datatype",
"excelImport": "sheet(s) are available for import",
"exportMetadata": "Do you want to export metadata from meta tables?",

2
packages/nc-gui/lang/es.json

@ -306,6 +306,7 @@
"deleteRow": "Borrar fila",
"deleteSelectedRow": "Eliminar filas seleccionadas",
"importExcel": "Importar Excel",
"importCSV": "Import CSV",
"downloadCSV": "Descargar como CSV",
"uploadCSV": "Subir CSV",
"import": "Importar",
@ -397,6 +398,7 @@
"upload_sub": "o arrastra y suelta el archivo",
"excelSupport": "Compatible: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Ingrese la URL del fichero Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# de filas para analizar para inferir el tipo de datos",
"excelImport": "hoja(s) están disponibles para importación",
"exportMetadata": "¿Quieres exportar metadatos de Meta Tables?",

2
packages/nc-gui/lang/fa.json

@ -306,6 +306,7 @@
"deleteRow": "حذف ردیف جدید",
"deleteSelectedRow": "حذف ردیفهای انتخاب شده",
"importExcel": "وارد کردن فایل Excel",
"importCSV": "Import CSV",
"downloadCSV": "دانلود بهعنوان CSV",
"uploadCSV": "بارگذاری CSV",
"import": "وارد کردن",
@ -397,6 +398,7 @@
"upload_sub": "یا فایل را بکشید و رها کنید",
"excelSupport": "فرمتهای پشتیبانی شده: xls - xlsx - xlsm - ods - ots",
"excelURL": "URL فایل Excel را انتخاب کنید",
"csvURL": "Enter CSV file URL",
"footMsg": "تعداد ردیفها برای parse جهت یافتن نوع داده",
"excelImport": "صفحه(های) آماده برای ورود",
"exportMetadata": "آیا میخواهید فراداده را از فراجدولها خارج کنید؟",

2
packages/nc-gui/lang/fi.json

@ -306,6 +306,7 @@
"deleteRow": "Poista rivi",
"deleteSelectedRow": "Poista valitut rivit",
"importExcel": "Tuonti excel",
"importCSV": "Import CSV",
"downloadCSV": "Lataa CSV",
"uploadCSV": "Lataa CSV",
"import": "Tuonti",
@ -397,6 +398,7 @@
"upload_sub": "tai vedä ja pudota tiedosto",
"excelSupport": "Tuetut: .xls, .xlsx, .xlsm, .odit,.",
"excelURL": "Anna Excel-tiedoston URL-osoite",
"csvURL": "Enter CSV file URL",
"footMsg": "# rivien jäsentää tietotekniikkaa",
"excelImport": "arkki (t) on saatavilla tuonti",
"exportMetadata": "Haluatko viedä metatietoja metapöydistä?",

4
packages/nc-gui/lang/fr.json

@ -306,6 +306,7 @@
"deleteRow": "Supprimer la ligne",
"deleteSelectedRow": "Supprimer les lignes sélectionnées",
"importExcel": "Importer depuis Excel",
"importCSV": "Import CSV",
"downloadCSV": "Télécharger comme CSV",
"uploadCSV": "Téléverser un CSV",
"import": "Importer",
@ -395,8 +396,9 @@
"footerInfo": "Lignes par page",
"upload": "Sélectionnez un fichier à téléverser",
"upload_sub": "ou glisser-déposer un fichier",
"excelSupport": "Pris en charge: .xls, .xlsx, .xlsm, .Ods, .ots",
"excelSupport": "Pris en charge: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Entrez l'URL du fichier Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "Nombre de lignes à analyser pour déduire le type de données",
"excelImport": "Les feuilles sont disponibles pour l'importation",
"exportMetadata": "Voulez-vous exporter des métadonnées des méta-tables?",

2
packages/nc-gui/lang/hr.json

@ -306,6 +306,7 @@
"deleteRow": "Brisanje retka",
"deleteSelectedRow": "Izbrišite odabrane retke",
"importExcel": "Uvoz Excel",
"importCSV": "Import CSV",
"downloadCSV": "Preuzmite kao CSV",
"uploadCSV": "Prenesite CSV",
"import": "Uvoz",
@ -397,6 +398,7 @@
"upload_sub": "ili povucite i ispustite datoteku",
"excelSupport": "Podržani: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Unesite URL Excel datoteka",
"csvURL": "Enter CSV file URL",
"footMsg": "# redaka za analizu da biste zaključili datatype",
"excelImport": "limovi (i) dostupni su za uvoz",
"exportMetadata": "Želite li izvesti metapodatke iz meta stolova?",

2
packages/nc-gui/lang/id.json

@ -306,6 +306,7 @@
"deleteRow": "Hapus Baris",
"deleteSelectedRow": "Hapus baris yang dipilih",
"importExcel": "Impor Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Unduh sebagai CSV.",
"uploadCSV": "Unggah CSV.",
"import": "Impor",
@ -397,6 +398,7 @@
"upload_sub": "atau seret dan jatuhkan file",
"excelSupport": "Didukung: .xls, .xlsx, .xlsm, .ots, .ots",
"excelURL": "Masukkan URL File Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# dari baris untuk menguraikan untuk menyimpulkan datatype",
"excelImport": "Lembar tersedia untuk impor",
"exportMetadata": "Apakah Anda ingin mengekspor metadata dari Meta Tables?",

2
packages/nc-gui/lang/it_IT.json

@ -306,6 +306,7 @@
"deleteRow": "Elimina riga.",
"deleteSelectedRow": "Elimina righe selezionate",
"importExcel": "Importa Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Scarica come csv.",
"uploadCSV": "Carica csv.",
"import": "Importa",
@ -397,6 +398,7 @@
"upload_sub": "o trascinare e rilasciare il file",
"excelSupport": "Supportato: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Inserisci l'URL del file Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# di righe per analizzare per dedurre il tipo di dati",
"excelImport": "foglio (i) sono disponibili per l'importazione",
"exportMetadata": "Vuoi esportare i metadati da Meta Tables?",

2
packages/nc-gui/lang/iw.json

@ -306,6 +306,7 @@
"deleteRow": "מחק שורה",
"deleteSelectedRow": "מחק את השורות שנבחרו",
"importExcel": "ייבוא Excel",
"importCSV": "Import CSV",
"downloadCSV": "הורד כמו CSV.",
"uploadCSV": "העלה CSV.",
"import": ְבוּא",
@ -397,6 +398,7 @@
"upload_sub": "או גרור ושחרר קובץ",
"excelSupport": "נתמך: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "הזן את כתובת האתר של קובץ Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# של שורות לנתח כדי להסיק datatype",
"excelImport": "גיליון (ים) זמינים לייבוא",
"exportMetadata": "האם אתה רוצה לייצא מטא נתונים מ מטא שולחנות?",

2
packages/nc-gui/lang/ja.json

@ -306,6 +306,7 @@
"deleteRow": "行を削除",
"deleteSelectedRow": "選択行を削除",
"importExcel": "エクセルファイルをインポート",
"importCSV": "Import CSV",
"downloadCSV": "CSVをダウンロード",
"uploadCSV": "CSVをアップロード",
"import": "インポート",
@ -397,6 +398,7 @@
"upload_sub": "またはファイルをドラッグ & ドロップ",
"excelSupport": "サポートしているファイル形式:.xls、.xlsx、.xlsm、.ods、.ots",
"excelURL": "ExcelファイルのURLを入力してください",
"csvURL": "Enter CSV file URL",
"footMsg": "# データ型を推測するために解析する行数",
"excelImport": "シートはインポート可能です",
"exportMetadata": "メタテーブルからメタデータをエクスポートしますか?",

2
packages/nc-gui/lang/ko.json

@ -306,6 +306,7 @@
"deleteRow": "행 삭제",
"deleteSelectedRow": "선택한 행을 삭제합니다",
"importExcel": "수입 Excel",
"importCSV": "Import CSV",
"downloadCSV": "CSV로 다운로드하십시오",
"uploadCSV": "CSV 업로드",
"import": "가져오기",
@ -397,6 +398,7 @@
"upload_sub": "또는 끌어서 놓기 파일",
"excelSupport": "지원 : .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Excel 파일 URL을 입력하십시오",
"csvURL": "Enter CSV file URL",
"footMsg": "파싱 할 행의 # DataType을 추론합니다",
"excelImport": "시트는 수입 가능합니다",
"exportMetadata": "메타 테이블에서 메타 데이터를 내보내려면 원하십니까?",

2
packages/nc-gui/lang/lv.json

@ -306,6 +306,7 @@
"deleteRow": "Dzēst ierakstu",
"deleteSelectedRow": "Dzēst izvēlētos ierakstus",
"importExcel": "Importēt Excel",
"importCSV": "Import CSV",
"downloadCSV": "Lejupielādēt kā CSV",
"uploadCSV": "Augšupielādēt CSV",
"import": "Importēt",
@ -397,6 +398,7 @@
"upload_sub": "vai vilkt un nomest datni",
"excelSupport": "Atbalsta: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Ievadīt Excel datnes saiti",
"csvURL": "Enter CSV file URL",
"footMsg": "# ierakstu analizēšanai lai secinātu datu tipus",
"excelImport": "lapa(s) ir pieejamas importēšanai",
"exportMetadata": "Vai tu vēlies eksportēt metadatus no tabulām?",

2
packages/nc-gui/lang/nl.json

@ -306,6 +306,7 @@
"deleteRow": "Verwijder rij",
"deleteSelectedRow": "Verwijder geselecteerde rijen",
"importExcel": "Excel importeren",
"importCSV": "Import CSV",
"downloadCSV": "Download als CSV",
"uploadCSV": "Upload CSV",
"import": "Importeren",
@ -397,6 +398,7 @@
"upload_sub": "of sleep het bestand naar hier",
"excelSupport": "Ondersteunt: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Voer Excel-bestandslink in",
"csvURL": "Enter CSV file URL",
"footMsg": "# rijen om te parseren om datatype af te leiden",
"excelImport": "blad(en) zijn beschikbaar om te importeren",
"exportMetadata": "Wilt u metadata uit metatabellen exporteren?",

2
packages/nc-gui/lang/no.json

@ -306,6 +306,7 @@
"deleteRow": "Slett rad",
"deleteSelectedRow": "Slett utvalgte rader",
"importExcel": "Importer Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Last ned som CSV.",
"uploadCSV": "Last opp CSV.",
"import": "Importer",
@ -397,6 +398,7 @@
"upload_sub": "eller dra og slipp filen",
"excelSupport": "Støttet: .xls, .xlsx, .xlsm ,.ods ,.ots",
"excelURL": "Skriv inn Excel File URL",
"csvURL": "Enter CSV file URL",
"footMsg": "# av rader for å analysere å utlede datatype",
"excelImport": "Ark (er) er tilgjengelige for import",
"exportMetadata": "Ønsker du å eksportere metadata fra Meta-bord?",

2
packages/nc-gui/lang/pl.json

@ -306,6 +306,7 @@
"deleteRow": "Usuń rząd",
"deleteSelectedRow": "Usuń wybrane wiersze",
"importExcel": "Importuj Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Pobierz jako CSV.",
"uploadCSV": "Prześlij CSV.",
"import": "Import",
@ -397,6 +398,7 @@
"upload_sub": "lub przeciągnij i upuść plik",
"excelSupport": "Obsługiwane: .xls, .xlsx, .xlsm, .ods, .oty",
"excelURL": "Wpisz adres URL pliku Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# wierszy do analizy do infera DataType",
"excelImport": "Arkusze są dostępne dla importu",
"exportMetadata": "Czy chcesz wyeksportować metadane z stołów meta?",

2
packages/nc-gui/lang/pt.json

@ -306,6 +306,7 @@
"deleteRow": "Excluir linha",
"deleteSelectedRow": "Excluir linhas selecionadas",
"importExcel": "Importar Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Baixe como CSV.",
"uploadCSV": "Carregar CSV.",
"import": "Importar",
@ -397,6 +398,7 @@
"upload_sub": "ou arrastar e soltar arquivo",
"excelSupport": "Suportado: .xls, .xlsx, .xlsm, .ods,.",
"excelURL": "Digite o URL do arquivo do Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# de linhas para analisar para inferir datatype",
"excelImport": "Sheet (s) estão disponíveis para importação",
"exportMetadata": "Você quer exportar metadados de meta tabelas?",

2
packages/nc-gui/lang/pt_BR.json

@ -306,6 +306,7 @@
"deleteRow": "Excluir linha",
"deleteSelectedRow": "Excluir linhas selecionadas",
"importExcel": "Importar Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Baixe como CSV.",
"uploadCSV": "Carregar CSV.",
"import": "Importar",
@ -397,6 +398,7 @@
"upload_sub": "ou arrastar e soltar arquivo",
"excelSupport": "Suportado: .xls, .xlsx, .xlsm, .ods,.",
"excelURL": "Digite o URL do arquivo do Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# de linhas para analisar para inferir datatype",
"excelImport": "Sheet (s) estão disponíveis para importação",
"exportMetadata": "Você quer exportar metadados de meta tabelas?",

2
packages/nc-gui/lang/ru.json

@ -305,6 +305,7 @@
"deleteRow": "Удалить строку",
"deleteSelectedRow": "Удалить выбранные строки",
"importExcel": "Импорт из Excel",
"importCSV": "Import CSV",
"downloadCSV": "Скачать как CSV.",
"uploadCSV": "Загрузить CSV.",
"import": "Импортировать",
@ -396,6 +397,7 @@
"upload_sub": "или перетащите файл",
"excelSupport": "Поддерживаются: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Введите URL-адрес файла Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "Количество рядов на анализ вывода данных",
"excelImport": "Листы доступны для импорта",
"exportMetadata": "Вы хотите экспортировать метаданные из металоги?",

2
packages/nc-gui/lang/sl.json

@ -306,6 +306,7 @@
"deleteRow": "Izbriši vrstico",
"deleteSelectedRow": "Izbrišite izbrane vrstice",
"importExcel": "Uvoz Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Prenesite kot CSV.",
"uploadCSV": "Upload CSV.",
"import": "Uvozi",
@ -397,6 +398,7 @@
"upload_sub": "ali datoteko povlecite in spustite",
"excelSupport": "Podprto: .xls, .xlsx, .xlsm, .ods, .h",
"excelURL": "Vnesite URL EXCEL datoteke",
"csvURL": "Enter CSV file URL",
"footMsg": "# vrstic za razčlenjevanje data podatkov",
"excelImport": "List (-e) so na voljo za uvoz",
"exportMetadata": "Želite izvoz metapodatkov iz meta tabele?",

2
packages/nc-gui/lang/sv.json

@ -306,6 +306,7 @@
"deleteRow": "Radera raden",
"deleteSelectedRow": "Ta bort valda rader",
"importExcel": "Import excel",
"importCSV": "Import CSV",
"downloadCSV": "Hämta som CSV",
"uploadCSV": "Ladda upp CSV",
"import": "Importera",
@ -397,6 +398,7 @@
"upload_sub": "eller dra och släpp filen",
"excelSupport": "Stöds: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Ange Excel-filadressen",
"csvURL": "Enter CSV file URL",
"footMsg": "# av rader att analysera att avleda datatyp",
"excelImport": "ark (er) är tillgängliga för import",
"exportMetadata": "Vill du exportera metadata från meta bord?",

2
packages/nc-gui/lang/th.json

@ -306,6 +306,7 @@
"deleteRow": "ลบแถว",
"deleteSelectedRow": "ลบแถวทเลอก",
"importExcel": "นำเขา Excel",
"importCSV": "Import CSV",
"downloadCSV": "ดาวนโหลดเปน CSV",
"uploadCSV": "อปโหลด CSV",
"import": "นำเขา",
@ -397,6 +398,7 @@
"upload_sub": "หรอลากและวางไฟล",
"excelSupport": "รองรบ:. xls, .xlsx,. xlsm, .ods, .ots",
"excelURL": "ปอน URL ไฟล Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# ของแถวทจะแยกวเคราะหบ DataType",
"excelImport": "มแผนงานสำหรบนำเขา",
"exportMetadata": "คณตองการสงออกขอมลเมตาจากตาราง Meta หรอไม?",

2
packages/nc-gui/lang/tr.json

@ -306,6 +306,7 @@
"deleteRow": "Satırı Sil",
"deleteSelectedRow": "Seçilen Satırları Sil",
"importExcel": "Excel'i içe aktar",
"importCSV": "Import CSV",
"downloadCSV": "CSV olarak indir",
"uploadCSV": "CSV yükle",
"import": "İçe aktar",
@ -397,6 +398,7 @@
"upload_sub": "veya dosyayı sürükleyip bırakın",
"excelSupport": "Desteklenen: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Excel dosyası linkini girin",
"csvURL": "Enter CSV file URL",
"footMsg": "Veri türünü bulmak için ayrıştırılacak satır sayısı #",
"excelImport": "sayfa(lar) içe aktarılabilir",
"exportMetadata": "Meta verileri meta tablolarından dışa aktarmak ister misiniz?",

2
packages/nc-gui/lang/uk.json

@ -306,6 +306,7 @@
"deleteRow": "Видалити рядок",
"deleteSelectedRow": "Видалити вибрані рядки",
"importExcel": "Імпорт Excel",
"importCSV": "Import CSV",
"downloadCSV": "Завантажити як CSV",
"uploadCSV": "Завантажити CSV",
"import": "Імпортувати",
@ -397,6 +398,7 @@
"upload_sub": "або перетягніть файл",
"excelSupport": "Підтримується: .xls, .xlsx, .xlsm, .ods, .ot",
"excelURL": "Введіть URL-адресу Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# рядків, щоб розібрати для виведення даних",
"excelImport": "Лист (и) доступні для імпорту",
"exportMetadata": "Ви хочете експортувати метадані з мета-таблиць?",

2
packages/nc-gui/lang/vi.json

@ -306,6 +306,7 @@
"deleteRow": "Xóa hàng",
"deleteSelectedRow": "Xóa các hàng đã chọn",
"importExcel": "Nhập Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Tải về dưới dạng CSV.",
"uploadCSV": "Tải lên CSV.",
"import": "Nhập khẩu",
@ -397,6 +398,7 @@
"upload_sub": "hoặc kéo và thả tập tin",
"excelSupport": "Được hỗ trợ: .xls, .xlsx, .xlsm, .ods,.",
"excelURL": "Nhập URL tệp Excel",
"csvURL": "Enter CSV file URL",
"footMsg": "# các hàng để phân tích để suy ra kiểu dữ liệu",
"excelImport": "(các) tấm có sẵn để nhập khẩu",
"exportMetadata": "Bạn có muốn xuất siêu dữ liệu từ bảng meta?",

2
packages/nc-gui/lang/zh_CN.json

@ -306,6 +306,7 @@
"deleteRow": "删除行",
"deleteSelectedRow": "删除所选行",
"importExcel": "导入Excel.",
"importCSV": "Import CSV",
"downloadCSV": "下载为CSV.",
"uploadCSV": "上传CSV.",
"import": "导入",
@ -397,6 +398,7 @@
"upload_sub": "或拖放文件",
"excelSupport": "支持:.xls,.xlsx,.xlsm,.ods,.ots",
"excelURL": "输入Excel文件URL",
"csvURL": "Enter CSV file URL",
"footMsg": "要解析为推断数据类型的行数",
"excelImport": "板材可用于进口",
"exportMetadata": "您想从元表导出元数据吗?",

2
packages/nc-gui/lang/zh_HK.json

@ -306,6 +306,7 @@
"deleteRow": "刪除行",
"deleteSelectedRow": "刪除所選行",
"importExcel": "導入Excel.",
"importCSV": "Import CSV",
"downloadCSV": "下載為CSV.",
"uploadCSV": "上傳CSV.",
"import": "導出去file",
@ -397,6 +398,7 @@
"upload_sub": "或拖放文件",
"excelSupport": "支持:.xls,.xlsx,.xlsm,.ods,.ots",
"excelURL": "輸入Excel文件URL",
"csvURL": "Enter CSV file URL",
"footMsg": "要解析為推斷數據類型的行數",
"excelImport": "板材可用於進口",
"exportMetadata": "您想從元表導出元數據嗎?",

2
packages/nc-gui/lang/zh_TW.json

@ -306,6 +306,7 @@
"deleteRow": "刪除行",
"deleteSelectedRow": "刪除所選行",
"importExcel": "導入Excel.",
"importCSV": "Import CSV",
"downloadCSV": "下載為CSV.",
"uploadCSV": "上傳CSV.",
"import": "匯入",
@ -397,6 +398,7 @@
"upload_sub": "或拖放文件",
"excelSupport": "支持:.xls,.xlsx,.xlsm,.ods,.ots",
"excelURL": "輸入Excel文件URL",
"csvURL": "Enter CSV file URL",
"footMsg": "要解析為推斷數據類型的行數",
"excelImport": "板材可用於進口",
"exportMetadata": "您想從元表導出元數據嗎?",

46
packages/nc-gui/pages/projects/index.vue

@ -2,12 +2,6 @@
<v-container
fluid
class="text-center px-10 pt-10 nc-container"
@dragover.prevent="dragOver = true"
@dragenter.prevent="dragOver = true"
@dragexit="dragOver = false"
@dragleave="dragOver = false"
@dragend="dragOver = false"
@drop.prevent.stop="onFileDrop"
>
<v-row>
<v-col v-if="loaded" class="col-lg-6 offset-lg-3 col-12 col-md-12">
@ -69,7 +63,7 @@
<template #activator="{ on }">
<div>
<x-btn
v-if="_isUIAllowed('projectCreate', true)"
v-if="_isUIAllowed('projectCreate')"
v-ge="['home', 'project-new']"
data-v-step="1"
outlined
@ -135,26 +129,6 @@
<span class="caption">{{ $t("tooltip.extDB") }}</span>
</v-tooltip>
</v-list-item>
<v-divider />
<v-list-item
title
class="pt-2 nc-create-project-from-excel"
@click="onCreateProjectFromExcel()"
>
<v-list-item-icon class="mr-2">
<v-icon small class="">
mdi-file-excel-outline
</v-icon>
</v-list-item-icon>
<v-list-item-title>
<span
class="caption font-weight-regular"
v-html="
$t('activity.createProjectExtended.excel')
"
/>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</template>
@ -560,7 +534,6 @@
:dialog-show="dialogShow"
:heading="confirmMessage"
/>
<excel-import ref="excelImport" v-model="excelImportModal" hide-label />
<templates-modal v-model="templatesModal" hide-label create-project />
</v-container>
</template>
@ -571,11 +544,9 @@ import ShareIcons from "../../components/share-icons";
import SponsorMini from "@/components/sponsorMini";
import colors from "~/mixins/colors";
import TemplatesModal from "~/components/templates/templatesModal";
import ExcelImport from "~/components/import/excelImport";
export default {
components: {
ExcelImport,
TemplatesModal,
ShareIcons,
SponsorMini,
@ -588,8 +559,6 @@ export default {
},
data() {
return {
dragOver: false,
excelImportModal: false,
templatesModal: false,
overlayVisible: true,
showCommunity: false,
@ -698,16 +667,8 @@ export default {
setTimeout(() => (this.showCommunity = true), 2000);
await this.projectsLoad();
if (this.$route && this.$route.query && this.$route.query.excelUrl) {
this.excelImportModal = true;
}
},
methods: {
async onFileDrop(e) {
this.excelImportModal = true;
this.$refs.excelImport.dropHandler(e);
},
async stopProject(project) {
this.dialogShow = true;
this.confirmMessage = "Do you want to stop the project?";
@ -841,11 +802,6 @@ export default {
this.templatesModal = true;
this.$e("c:project:create:template");
},
onCreateProjectFromExcel() {
// this.$refs.excelImport.selectFile()
this.excelImportModal = true;
this.$e("c:project:create:excel");
},
async importProjectFromJSON() {},
onTourCompletion() {
// this.$store.commit('windows/MutShowTour', {page: 'home'})

17
packages/nc-gui/store/tabs.js

@ -385,6 +385,22 @@ export const actions = {
// }
// })
// });
},
async loadFirstCreatedTableTab({ commit, state, rootGetters, dispatch, rootState }, data) {
const tabs = state.list || []
const item = rootState.project
.list[0] // project
.children[0] // environment
.children[0] // db
.children.find(n => n.type === 'tableDir') // parent node
.children.find(n => n.title === data.title) // look for the target table
if (item) {
tabs.push(item)
}
if (tabs.length) {
commit('list', tabs)
}
return item
}
}
/**
@ -392,6 +408,7 @@ export const actions = {
*
* @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
*

29
packages/noco-docs/content/en/setup-and-usages/dashboard.md

@ -98,31 +98,4 @@ Tip 3: You can click Edit Connection JSON and specify the schema you want to use
Click `Test Database Connection` to see if the connection can be established or not. NocoDB creates a new **empty database** with specified parameters if the database doesn't exist.
![image](https://user-images.githubusercontent.com/35857179/163136039-ad521d74-6996-4173-84ba-cfc55392c3b7.png)
### Creating Project from Excel
Click `Create Project from Excel`, you can either upload / drag and drop Excel file (OR) specify Excel file URL.
<alert type="success">
If your excel file contains multiple sheets, each sheet will be stored in a separate table. <br> Currently the data will be imported to NC_DB only. We'll support importing to existing projects with other database types in the future.
</alert>
<img src="https://user-images.githubusercontent.com/86527202/144373863-7ced9315-a70b-4746-9295-325e463dc110.png" width="60%"/>
You can change Project Name, Table Name, Column Name or even Column Type as you want.
![image](https://user-images.githubusercontent.com/35857179/167252703-3a9be428-8737-4683-bc29-d3f9dbbfb712.png)
Click Import Excel to start importing process. The project and the table(s) will be created and the data will be imported to the corresponding table(s).
![image](https://user-images.githubusercontent.com/35857179/167253045-2e9890ca-4451-4b59-8eba-cb90ea5abdf1.png)
Supported file formats
- Xls
- Xlsx
- Xlsm
- Ods
- Ots
![image](https://user-images.githubusercontent.com/35857179/163136039-ad521d74-6996-4173-84ba-cfc55392c3b7.png)

46
packages/noco-docs/content/en/setup-and-usages/table-operations.md

@ -14,19 +14,22 @@ Once you have created a new NocoDB project you can open it, In the browser, the
Now you can start creating new tables by simply clicking one of the following options.
![table_create](https://user-images.githubusercontent.com/61551451/126771744-063f22da-6def-43fe-b9ef-1744d104db9d.png)
- Click the plus button next to Table menu
- Click Add / Import, then click Add new table
On click, in modal popup, enter the table name, enable/disable default columns and click `Submit` button.
<img width="567" alt="image" src="https://user-images.githubusercontent.com/35857179/168411444-e39ecf95-2efd-4133-ac3e-5815a9983a3d.png">
A modal will be popped up. Input the corresponding info and enable or disable default columns and click `Submit` button.
![table_create_modal](https://user-images.githubusercontent.com/61551451/126772859-5a301c45-d830-4df2-a05a-43b15dd77728.png)
<alert>
You can't disable the `id` column since NocoDB needs a primary column for every table.
Note: You can't disable the `id` column since NocoDB needs a primary column for every table. You can rename it after the creation.
</alert>
After the successful submission, the table will be created and open as a new tab.
![TableCreated](https://user-images.githubusercontent.com/86527202/144402089-b5e35564-80d5-4105-9e00-7e3e1c4a5030.png)
![table_created](https://user-images.githubusercontent.com/35857179/168411541-b0233cf1-4683-490b-bdec-f2546a2d9015.png)
### Table Rename
@ -38,7 +41,38 @@ In modal popup, enter new table name and click `Submit` button
### Table Delete
The table can be deleted using the `delete` icon present in the toolbar within the table tab.
<img src="https://user-images.githubusercontent.com/86527202/144403591-5d3d36eb-64b7-4057-9244-56a95b47b97b.png" width="60%"/>
![image](https://user-images.githubusercontent.com/35857179/168411589-540f50d2-78e3-4d97-b17c-1b9fad9f90b7.png)
### Quick Import
You can use Quick Import when you have data from an existing CSV file or Microsoft Excel by clicking `Add / Import` and choosing the corresponding options.
![image](https://user-images.githubusercontent.com/35857179/168412001-54b86df4-5d34-427a-b741-81240f9a63a6.png)
#### Import CSV data into an existing project
- Click Add / Import and click CSV file
- Drag & drop or select file to upload or specify Excel file URL
![image](https://user-images.githubusercontent.com/35857179/168412051-ed988659-011d-455b-ba32-be0a2e1184b0.png)
- You can revise the table name, column name and column type. By default, the first column will be chosen as <a href="./primary-value" target="_blank">Primary Value</a> and cannot be deleted.
![image](https://user-images.githubusercontent.com/35857179/168412069-aea8a8fb-09ab-4412-95b7-963bdbe24cfc.png)
- Click `Import CSV` to start importing process. The table will be created and the data will be imported.
![image](https://user-images.githubusercontent.com/35857179/168412172-9bb24ab9-da15-45cf-9b12-3af362fc604a.png)
#### Import Microsoft Excel data into an existing project
- Click Add / Import and click Microsoft Excel
- Drag & drop or select file to upload or specify Excel file URL
![image](https://user-images.githubusercontent.com/35857179/168412483-a12f7d90-1b91-48bb-96a7-2a16dc8c7b81.png)
- You can revise the table name, column name and column type. By default, the first column will be chosen as <a href="./primary-value" target="_blank">Primary Value</a> and cannot be deleted.
<alert>
Note: If your Excel file contains multiple sheets, each sheet will be stored in a separate table.
</alert>
![image](https://user-images.githubusercontent.com/35857179/168412465-e46b4fcf-ec1c-4d32-bb56-eb62516829f5.png)
- Click `Import Excel` to start importing process. The table(s) will be created and the data will be imported to the corresponding table(s).
![image](https://user-images.githubusercontent.com/35857179/168413233-adfb85e2-8d52-46d8-a754-e2ec9f8d3234.png)
## Column

2
packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts

@ -1686,7 +1686,7 @@ export default class NcMetaMgr {
postListenerCb = async () => {
if (args?.args?.template) {
Tele.emit('evt', {
evt_type: args.args?.excelImport
evt_type: args.args?.quickImport
? 'project:created:fromExcel'
: 'project:created:fromTemplate',
xcdb: true

2
scripts/cypress/integration/spec/roleValidation.spec.js

@ -78,7 +78,7 @@ export function _editSchema(roleType, previewMode) {
cy.get(".add-btn").should(validationString);
cy.get(".v-tabs-bar")
.eq(0)
.find("button.mdi-plus-box")
.find(".add-btn.mdi-plus-box")
.should(validationString);
// delete table option

1
scripts/cypress/support/commands.js

@ -258,6 +258,7 @@ Cypress.Commands.add("getActiveContentModal", () => {
Cypress.Commands.add("createTable", (name) => {
cy.get(".add-btn").click();
cy.getActiveMenu().contains("Add new table").should('exist').click()
cy.get('.nc-create-table-card .nc-table-name input[type="text"]')
.first()
.click()

Loading…
Cancel
Save