Browse Source

Merge branch 'develop' into feat/kanban-view

pull/3818/head
Wing-Kam Wong 2 years ago
parent
commit
e7f4b26f5c
  1. 1
      .github/workflows/ci-cd.yml
  2. 4
      .github/workflows/release-draft.yml
  3. 7
      packages/nc-gui/assets/style.scss
  4. 3
      packages/nc-gui/components.d.ts
  5. 5
      packages/nc-gui/components/dashboard/settings/Erd.vue
  6. 2
      packages/nc-gui/components/dashboard/settings/Misc.vue
  7. 10
      packages/nc-gui/components/dashboard/settings/Modal.vue
  8. 4
      packages/nc-gui/components/dlg/AirtableImport.vue
  9. 4
      packages/nc-gui/components/dlg/QuickImport.vue
  10. 227
      packages/nc-gui/components/erd/Flow.vue
  11. 161
      packages/nc-gui/components/erd/RelationEdge.vue
  12. 121
      packages/nc-gui/components/erd/TableNode.vue
  13. 162
      packages/nc-gui/components/erd/View.vue
  14. 2
      packages/nc-gui/components/smartsheet-header/VirtualCell.vue
  15. 42
      packages/nc-gui/components/smartsheet-toolbar/Erd.vue
  16. 4
      packages/nc-gui/components/smartsheet-toolbar/FieldsMenu.vue
  17. 32
      packages/nc-gui/components/smartsheet-toolbar/ViewActions.vue
  18. 91
      packages/nc-gui/components/smartsheet/Gallery.vue
  19. 48
      packages/nc-gui/components/smartsheet/Grid.vue
  20. 39
      packages/nc-gui/components/smartsheet/expanded-form/Header.vue
  21. 22
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  22. 1
      packages/nc-gui/components/smartsheet/sidebar/index.vue
  23. 4
      packages/nc-gui/components/tabs/Smartsheet.vue
  24. 8
      packages/nc-gui/components/template/Editor.vue
  25. 3
      packages/nc-gui/components/virtual-cell/components/ListChildItems.vue
  26. 24
      packages/nc-gui/components/webhook/Editor.vue
  27. 10
      packages/nc-gui/composables/useExpandedFormStore.ts
  28. 8
      packages/nc-gui/composables/useMetas.ts
  29. 3
      packages/nc-gui/composables/useViewData.ts
  30. 3
      packages/nc-gui/composables/useViewFilters.ts
  31. 6
      packages/nc-gui/composables/useViewSorts.ts
  32. 1
      packages/nc-gui/context/index.ts
  33. 28
      packages/nc-gui/lang/ar.json
  34. 28
      packages/nc-gui/lang/bn_IN.json
  35. 28
      packages/nc-gui/lang/da.json
  36. 28
      packages/nc-gui/lang/de.json
  37. 28
      packages/nc-gui/lang/en.json
  38. 28
      packages/nc-gui/lang/es.json
  39. 28
      packages/nc-gui/lang/fa.json
  40. 28
      packages/nc-gui/lang/fi.json
  41. 28
      packages/nc-gui/lang/fr.json
  42. 28
      packages/nc-gui/lang/he.json
  43. 28
      packages/nc-gui/lang/hi.json
  44. 28
      packages/nc-gui/lang/hr.json
  45. 28
      packages/nc-gui/lang/id.json
  46. 28
      packages/nc-gui/lang/it.json
  47. 28
      packages/nc-gui/lang/ja.json
  48. 28
      packages/nc-gui/lang/ko.json
  49. 28
      packages/nc-gui/lang/lv.json
  50. 28
      packages/nc-gui/lang/nl.json
  51. 28
      packages/nc-gui/lang/no.json
  52. 28
      packages/nc-gui/lang/pl.json
  53. 28
      packages/nc-gui/lang/pt.json
  54. 28
      packages/nc-gui/lang/pt_BR.json
  55. 28
      packages/nc-gui/lang/ru.json
  56. 28
      packages/nc-gui/lang/sl.json
  57. 28
      packages/nc-gui/lang/sv.json
  58. 28
      packages/nc-gui/lang/th.json
  59. 28
      packages/nc-gui/lang/tr.json
  60. 28
      packages/nc-gui/lang/uk.json
  61. 28
      packages/nc-gui/lang/vi.json
  62. 28
      packages/nc-gui/lang/zh-Hans.json
  63. 28
      packages/nc-gui/lang/zh-Hant.json
  64. 2
      packages/nc-gui/middleware/auth.global.ts
  65. 13
      packages/nc-gui/nuxt.config.ts
  66. 361
      packages/nc-gui/package-lock.json
  67. 3
      packages/nc-gui/package.json
  68. 2
      packages/nc-gui/pages/[projectType]/[projectId]/index.vue
  69. 16
      packages/nc-gui/pages/index/index/create-external.vue
  70. 72
      packages/nc-gui/utils/validation.ts
  71. 13
      packages/noco-docs/content/en/setup-and-usages/meta-management.md
  72. 664
      packages/nocodb-sdk/package-lock.json
  73. 1
      packages/nocodb-sdk/src/lib/Api.ts
  74. 11
      packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts
  75. 60
      scripts/cypress/integration/common/1b_table_column_operations.js
  76. 54
      scripts/cypress/integration/common/2b_table_with_m2m_column.js
  77. 49
      scripts/cypress/integration/common/3a_filter_sort_fields_operations.js
  78. 30
      scripts/cypress/integration/common/3c_lookup_column.js
  79. 38
      scripts/cypress/integration/common/3d_rollup_column.js
  80. 85
      scripts/cypress/integration/common/3e_duration_column.js
  81. 151
      scripts/cypress/integration/common/3f_link_to_another_record.js
  82. 51
      scripts/cypress/integration/common/4f_grid_view_share.js
  83. 201
      scripts/cypress/integration/common/4g_table_view_expanded_form.js
  84. 33
      scripts/cypress/integration/common/6g_base_share.js
  85. 114
      scripts/cypress/integration/common/8a_webhook.js
  86. 373
      scripts/cypress/integration/common/9b_ERD.js
  87. 176
      scripts/cypress/integration/spec/roleValidation.spec.js
  88. 2
      scripts/cypress/integration/test/pg-restViews.js
  89. 6
      scripts/cypress/integration/test/restMisc.js
  90. 1
      scripts/cypress/integration/test/restTableOps.js
  91. 18
      scripts/cypress/integration/test/restViews.js
  92. 115
      scripts/cypress/support/commands.js
  93. 40
      scripts/cypress/support/page_objects/mainPage.js
  94. 10
      scripts/cypress/support/page_objects/projectConstants.js
  95. 6
      scripts/sdk/swagger.json

1
.github/workflows/ci-cd.yml

@ -11,6 +11,7 @@ on:
- "packages/nocodb/**" - "packages/nocodb/**"
- ".github/workflows/ci-cd.yml" - ".github/workflows/ci-cd.yml"
pull_request: pull_request:
types: [ready_for_review]
branches: [develop] branches: [develop]
paths: paths:
- "packages/nc-gui/**" - "packages/nc-gui/**"

4
.github/workflows/release-draft.yml

@ -49,9 +49,9 @@ jobs:
# the SHA from the third commit (i.e. Auto PR from master to develop) will be taken # the SHA from the third commit (i.e. Auto PR from master to develop) will be taken
# else HEAD will be taken # else HEAD will be taken
run: | run: |
TARGET_SHA=$(git rev-parse HEAD~2) TARGET_SHA=$(git rev-list -n 3 HEAD | tail -1)
if [[ ${{ github.event.inputs.tagHeadSHA || inputs.tagHeadSHA }} == "Y" ]]; then if [[ ${{ github.event.inputs.tagHeadSHA || inputs.tagHeadSHA }} == "Y" ]]; then
TARGET_SHA=$(git rev-parse HEAD) TARGET_SHA=$(git rev-list -n 1 HEAD | tail -1)
fi fi
echo "::set-output name=TARGET_SHA::${TARGET_SHA}" echo "::set-output name=TARGET_SHA::${TARGET_SHA}"
echo "Setting TARGET_SHA: ${TARGET_SHA}" echo "Setting TARGET_SHA: ${TARGET_SHA}"

7
packages/nc-gui/assets/style.scss

@ -1,4 +1,6 @@
@import 'ant-design-vue/dist/antd.variable.min.css'; @import 'ant-design-vue/dist/antd.variable.min.css';
@import '@braks/vue-flow/dist/style.css';
@import '@braks/vue-flow/dist/theme-default.css';
:root { :root {
--header-height: 42px; --header-height: 42px;
@ -248,3 +250,8 @@ a {
.ant-dropdown-menu-submenu-title{ .ant-dropdown-menu-submenu-title{
@apply !pr-2; @apply !pr-2;
} }
.vue-flow__minimap {
transform: scale(75%);
transform-origin: bottom right;
}

3
packages/nc-gui/components.d.ts vendored

@ -143,6 +143,7 @@ declare module '@vue/runtime-core' {
MdiEmailArrowRightOutline: typeof import('~icons/mdi/email-arrow-right-outline')['default'] MdiEmailArrowRightOutline: typeof import('~icons/mdi/email-arrow-right-outline')['default']
MdiExitToApp: typeof import('~icons/mdi/exit-to-app')['default'] MdiExitToApp: typeof import('~icons/mdi/exit-to-app')['default']
MdiExport: typeof import('~icons/mdi/export')['default'] MdiExport: typeof import('~icons/mdi/export')['default']
MdiEyeCircleOutline: typeof import('~icons/mdi/eye-circle-outline')['default']
MdiEyeOffOutline: typeof import('~icons/mdi/eye-off-outline')['default'] MdiEyeOffOutline: typeof import('~icons/mdi/eye-off-outline')['default']
MdiFileDocumentOutline: typeof import('~icons/mdi/file-document-outline')['default'] MdiFileDocumentOutline: typeof import('~icons/mdi/file-document-outline')['default']
MdiFileExcel: typeof import('~icons/mdi/file-excel')['default'] MdiFileExcel: typeof import('~icons/mdi/file-excel')['default']
@ -175,6 +176,7 @@ declare module '@vue/runtime-core' {
MdiMoonFull: typeof import('~icons/mdi/moon-full')['default'] MdiMoonFull: typeof import('~icons/mdi/moon-full')['default']
MdiNumeric: typeof import('~icons/mdi/numeric')['default'] MdiNumeric: typeof import('~icons/mdi/numeric')['default']
MdiOpenInNew: typeof import('~icons/mdi/open-in-new')['default'] MdiOpenInNew: typeof import('~icons/mdi/open-in-new')['default']
MdiOpenInNewIcon: typeof import('~icons/mdi/open-in-new-icon')['default']
MdiPencil: typeof import('~icons/mdi/pencil')['default'] MdiPencil: typeof import('~icons/mdi/pencil')['default']
MdiPlus: typeof import('~icons/mdi/plus')['default'] MdiPlus: typeof import('~icons/mdi/plus')['default']
MdiPlusCircleOutline: typeof import('~icons/mdi/plus-circle-outline')['default'] MdiPlusCircleOutline: typeof import('~icons/mdi/plus-circle-outline')['default']
@ -190,6 +192,7 @@ declare module '@vue/runtime-core' {
MdiStarOutline: typeof import('~icons/mdi/star-outline')['default'] MdiStarOutline: typeof import('~icons/mdi/star-outline')['default']
MdiTable: typeof import('~icons/mdi/table')['default'] MdiTable: typeof import('~icons/mdi/table')['default']
MdiTableArrowRight: typeof import('~icons/mdi/table-arrow-right')['default'] MdiTableArrowRight: typeof import('~icons/mdi/table-arrow-right')['default']
MdiTableLarge: typeof import('~icons/mdi/table-large')['default']
MdiText: typeof import('~icons/mdi/text')['default'] MdiText: typeof import('~icons/mdi/text')['default']
MdiThumbUp: typeof import('~icons/mdi/thumb-up')['default'] MdiThumbUp: typeof import('~icons/mdi/thumb-up')['default']
MdiTrashCan: typeof import('~icons/mdi/trash-can')['default'] MdiTrashCan: typeof import('~icons/mdi/trash-can')['default']

5
packages/nc-gui/components/dashboard/settings/Erd.vue

@ -0,0 +1,5 @@
<template>
<div class="w-full h-full !py-0 !px-2" style="height: 70vh">
<ErdView />
</div>
</template>

2
packages/nc-gui/components/dashboard/settings/Misc.vue

@ -10,7 +10,7 @@ watch(includeM2M, async () => await loadTables())
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class="flex flex-row items-center w-full mb-4 gap-2"> <div class="flex flex-row items-center w-full mb-4 gap-2">
<!-- Show M2M Tables --> <!-- Show M2M Tables -->
<a-checkbox v-model:checked="includeM2M" v-e="['c:themes:show-m2m-tables']">{{ <a-checkbox v-model:checked="includeM2M" v-e="['c:themes:show-m2m-tables']" class="nc-settings-meta-misc">{{
$t('msg.info.showM2mTables') $t('msg.info.showM2mTables')
}}</a-checkbox> }}</a-checkbox>
</div> </div>

10
packages/nc-gui/components/dashboard/settings/Modal.vue

@ -5,6 +5,7 @@ import AppStore from './AppStore.vue'
import Metadata from './Metadata.vue' import Metadata from './Metadata.vue'
import UIAcl from './UIAcl.vue' import UIAcl from './UIAcl.vue'
import Misc from './Misc.vue' import Misc from './Misc.vue'
import Erd from './Erd.vue'
import { useNuxtApp } from '#app' import { useNuxtApp } from '#app'
import { useI18n, useUIPermission, useVModel, watch } from '#imports' import { useI18n, useUIPermission, useVModel, watch } from '#imports'
import ApiTokenManagement from '~/components/tabs/auth/ApiTokenManagement.vue' import ApiTokenManagement from '~/components/tabs/auth/ApiTokenManagement.vue'
@ -90,7 +91,7 @@ const tabsInfo: TabGroup = {
$e('c:settings:appstore') $e('c:settings:appstore')
}, },
}, },
metaData: { projMetaData: {
// Project Metadata // Project Metadata
title: t('title.projMeta'), title: t('title.projMeta'),
icon: MultipleTableIcon, icon: MultipleTableIcon,
@ -108,6 +109,13 @@ const tabsInfo: TabGroup = {
$e('c:table:ui-acl') $e('c:table:ui-acl')
}, },
}, },
erd: {
title: t('title.erdView'),
body: Erd,
onClick: () => {
$e('c:settings:erd')
},
},
misc: { misc: {
title: t('general.misc'), title: t('general.misc'),
body: Misc, body: Misc,

4
packages/nc-gui/components/dlg/AirtableImport.vue

@ -65,8 +65,8 @@ const syncSource = ref({
}) })
const validators = computed(() => ({ const validators = computed(() => ({
'details.apiKey': [fieldRequiredValidator], 'details.apiKey': [fieldRequiredValidator()],
'details.syncSourceUrlOrId': [fieldRequiredValidator], 'details.syncSourceUrlOrId': [fieldRequiredValidator()],
})) }))
const dialogShow = computed({ const dialogShow = computed({

4
packages/nc-gui/components/dlg/QuickImport.vue

@ -70,8 +70,8 @@ const isImportTypeCsv = computed(() => importType === 'csv')
const IsImportTypeExcel = computed(() => importType === 'excel') const IsImportTypeExcel = computed(() => importType === 'excel')
const validators = computed(() => ({ const validators = computed(() => ({
url: [fieldRequiredValidator, importUrlValidator, isImportTypeCsv.value ? importCsvUrlValidator : importExcelUrlValidator], url: [fieldRequiredValidator(), importUrlValidator, isImportTypeCsv.value ? importCsvUrlValidator : importExcelUrlValidator],
maxRowsToParse: [fieldRequiredValidator], maxRowsToParse: [fieldRequiredValidator()],
})) }))
const { validate, validateInfos } = useForm(importState, validators) const { validate, validateInfos } = useForm(importState, validators)

227
packages/nc-gui/components/erd/Flow.vue

@ -0,0 +1,227 @@
<script setup lang="ts">
import type { Edge, Node } from '@braks/vue-flow'
import { Background, Controls, VueFlow, useVueFlow } from '@braks/vue-flow'
import type { ColumnType, FormulaType, LinkToAnotherRecordType, LookupType, RollupType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import dagre from 'dagre'
import TableNode from './TableNode.vue'
import RelationEdge from './RelationEdge.vue'
interface Props {
tables: any[]
config: {
showPkAndFk: boolean
showViews: boolean
showAllColumns: boolean
singleTableMode: boolean
showJunctionTableNames: boolean
}
}
const { tables, config } = defineProps<Props>()
const { metasWithIdAsKey } = useMetas()
const { $destroy, fitView } = useVueFlow()
const nodes = ref<Node[]>([])
const edges = ref<Edge[]>([])
let dagreGraph: dagre.graphlib.Graph
const initDagre = () => {
dagreGraph = new dagre.graphlib.Graph()
dagreGraph.setDefaultEdgeLabel(() => ({}))
dagreGraph.setGraph({ rankdir: 'LR' })
}
const populateInitialNodes = () => {
nodes.value = tables.flatMap((table) => {
if (!table.id) return []
const columns =
metasWithIdAsKey.value[table.id].columns?.filter(
(col) => config.showAllColumns || (!config.showAllColumns && col.uidt === UITypes.LinkToAnotherRecord),
) || []
dagreGraph.setNode(table.id, { width: 250, height: 50 * columns.length })
return [
{
id: table.id,
data: { ...metasWithIdAsKey.value[table.id], showPkAndFk: config.showPkAndFk, showAllColumns: config.showAllColumns },
type: 'custom',
position: { x: 0, y: 0 },
},
]
})
}
const populateEdges = () => {
const ltarColumns = tables.reduce<ColumnType[]>((acc, table) => {
const meta = metasWithIdAsKey.value[table.id!]
const columns = meta.columns?.filter(
(column: ColumnType) => column.uidt === UITypes.LinkToAnotherRecord && column.system !== 1,
)
columns?.forEach((column: ColumnType) => {
if ((column.colOptions as LinkToAnotherRecordType)?.type === 'hm') {
acc.push(column)
}
if ((column.colOptions as LinkToAnotherRecordType).type === 'mm') {
// Avoid duplicate mm connections
const correspondingColumn = acc.find(
(c) =>
(c.colOptions as LinkToAnotherRecordType | FormulaType | RollupType | LookupType).type === 'mm' &&
(c.colOptions as LinkToAnotherRecordType).fk_parent_column_id ===
(column.colOptions as LinkToAnotherRecordType).fk_child_column_id &&
(c.colOptions as LinkToAnotherRecordType).fk_child_column_id ===
(column.colOptions as LinkToAnotherRecordType).fk_parent_column_id,
)
if (!correspondingColumn) {
acc.push(column)
}
}
})
return acc
}, [] as ColumnType[])
const edgeMMTableLabel = (modelId: string) => {
const mmModel = metasWithIdAsKey.value[modelId]
if (mmModel.title !== mmModel.table_name) {
return `${mmModel.title} (${mmModel.table_name})`
}
return mmModel.title
}
edges.value = ltarColumns.map((column) => {
const source = column.fk_model_id!
const target = (column.colOptions as LinkToAnotherRecordType).fk_related_model_id!
let sourceColumnId, targetColumnId
let edgeLabel = ''
if ((column.colOptions as LinkToAnotherRecordType).type === 'hm') {
sourceColumnId = (column.colOptions as LinkToAnotherRecordType).fk_child_column_id
targetColumnId = (column.colOptions as LinkToAnotherRecordType).fk_child_column_id
}
if ((column.colOptions as LinkToAnotherRecordType).type === 'mm') {
sourceColumnId = (column.colOptions as LinkToAnotherRecordType).fk_parent_column_id
targetColumnId = (column.colOptions as LinkToAnotherRecordType).fk_child_column_id
edgeLabel = config.showJunctionTableNames
? edgeMMTableLabel((column.colOptions as LinkToAnotherRecordType).fk_mm_model_id!)
: ''
}
if (source !== target) dagreGraph.setEdge(source, target)
return {
id: `e-${sourceColumnId}-${source}-${targetColumnId}-${target}-#${edgeLabel}`,
source: `${source}`,
target: `${target}`,
sourceHandle: `s-${sourceColumnId}-${source}`,
targetHandle: `d-${targetColumnId}-${target}`,
type: 'custom',
data: {
column,
isSelfRelation: source === target && sourceColumnId === targetColumnId,
label: edgeLabel,
},
}
})
}
const connectNonConnectedNodes = () => {
const connectedNodes = new Set<string>()
edges.value.forEach((edge) => {
connectedNodes.add(edge.source)
connectedNodes.add(edge.target)
})
const nonConnectedNodes = tables.filter((table) => !connectedNodes.has(table.id!))
if (nonConnectedNodes.length === 0) return
if (nonConnectedNodes.length === 1) {
const firstTable = tables.find((table) => table.type === 'table' && table.id !== nonConnectedNodes[0].id)
if (!firstTable) return
dagreGraph.setEdge(nonConnectedNodes[0].id, firstTable.id)
return
}
const firstNode = nonConnectedNodes[0]
nonConnectedNodes.forEach((node, index) => {
if (index === 0) return
const source = firstNode.id
const target = node.id
dagreGraph.setEdge(source, target)
})
}
const layoutNodes = () => {
if (!config.singleTableMode) connectNonConnectedNodes()
dagre.layout(dagreGraph)
nodes.value = nodes.value.flatMap((node) => {
const nodeWithPosition = dagreGraph.node(node.id)
if (!nodeWithPosition) return []
return [{ ...node, position: { x: nodeWithPosition.x, y: nodeWithPosition.y } } as Node]
})
}
const init = () => {
initDagre()
populateInitialNodes()
populateEdges()
layoutNodes()
setTimeout(() => fitView({ duration: 300 }))
}
init()
onScopeDispose($destroy)
watch([() => tables, () => config], init, { deep: true, flush: 'pre' })
</script>
<template>
<VueFlow :nodes="nodes" :edges="edges" elevate-edges-on-select>
<Controls class="!left-auto right-2 !top-3.5 !bottom-auto" :show-fit-view="false" :show-interactive="false" />
<template #node-custom="props">
<TableNode :data="props.data" />
</template>
<template #edge-custom="props">
<RelationEdge v-bind="props" />
</template>
<Background />
<div
v-if="!config.singleTableMode"
class="absolute bottom-0 right-0 flex flex-col text-xs bg-white px-2 py-1 border-1 rounded-md border-gray-200 z-50 nc-erd-histogram"
style="font-size: 0.6rem"
>
<div class="flex flex-row items-center space-x-1 border-b-1 pb-1 border-gray-100">
<MdiTableLarge class="text-primary" />
<div>{{ $t('objects.table') }}</div>
</div>
<div class="flex flex-row items-center space-x-1 pt-1">
<MdiEyeCircleOutline class="text-primary" />
<div>{{ $t('objects.sqlVIew') }}</div>
</div>
</div>
</VueFlow>
</template>

161
packages/nc-gui/components/erd/RelationEdge.vue

@ -0,0 +1,161 @@
<script setup>
import { EdgeText, getBezierPath, getEdgeCenter } from '@braks/vue-flow'
import { computed } from 'vue'
const props = defineProps({
id: {
type: String,
required: true,
},
sourceX: {
type: Number,
required: true,
},
sourceY: {
type: Number,
required: true,
},
targetX: {
type: Number,
required: true,
},
targetY: {
type: Number,
required: true,
},
sourcePosition: {
type: String,
required: true,
},
targetPosition: {
type: String,
required: true,
},
data: {
type: Object,
required: false,
},
markerEnd: {
type: String,
required: false,
},
style: {
type: Object,
required: false,
},
sourceHandleId: {
type: String,
required: false,
},
targetHandleId: {
type: String,
required: false,
},
})
const data = toRef(props, 'data')
const isManyToMany = computed(() => data.value.column?.colOptions?.type === 'mm')
const edgePath = computed(() => {
if (data.value.isSelfRelation) {
const { sourceX, sourceY, targetX, targetY } = props
const radiusX = (sourceX - targetX) * 0.6
const radiusY = 50
return `M ${sourceX} ${sourceY} A ${radiusX} ${radiusY} 0 1 0 ${targetX} ${targetY}`
}
return getBezierPath({
sourceX: props.sourceX,
sourceY: props.sourceY,
sourcePosition: props.sourcePosition,
targetX: props.targetX,
targetY: props.targetY,
targetPosition: props.targetPosition,
})
})
const center = computed(() =>
getEdgeCenter({
sourceX: props.sourceX,
sourceY: props.sourceY,
targetX: props.targetX,
targetY: props.targetY,
}),
)
</script>
<script>
export default {
inheritAttrs: false,
}
</script>
<template>
<path
:id="id"
:style="style"
class="path-wrapper p-4 hover:cursor-pointer"
:stroke-width="8"
fill="none"
:d="edgePath"
:marker-end="markerEnd"
/>
<path
:id="id"
:style="style"
class="path stroke-gray-500 hover:stroke-green-500 hover:cursor-pointer"
:stroke-width="1.5"
fill="none"
:d="edgePath"
:marker-end="markerEnd"
/>
<EdgeText
v-if="data.label?.length > 0"
:class="`nc-erd-table-label-${data.label.toLowerCase().replace(' ', '-').replace('\(', '').replace(')', '')}`"
:x="center[0]"
:y="center[1]"
:label="data.label"
:label-style="{ fill: 'white' }"
:label-show-bg="true"
:label-bg-style="{ fill: '#10b981' }"
:label-bg-padding="[2, 4]"
:label-bg-border-radius="2"
/>
<rect
class="nc-erd-edge-rect"
:x="sourceX"
:y="sourceY - 4"
width="8"
height="8"
fill="#fff"
stroke="#6F3381"
:stroke-width="1.5"
:transform="`rotate(45,${sourceX + 2},${sourceY - 4})`"
/>
<rect
v-if="isManyToMany"
class="nc-erd-edge-rect"
:x="targetX"
:y="targetY - 4"
width="8"
height="8"
fill="#fff"
stroke="#6F3381"
:stroke-width="1.5"
:transform="`rotate(45,${targetX + 2},${targetY - 4})`"
/>
<circle v-else class="nc-erd-edge-circle" :cx="targetX" :cy="targetY" fill="#fff" :r="5" stroke="#6F3381" :stroke-width="1.5" />
</template>
<style scoped lang="scss">
.path-wrapper:hover + .path {
@apply stroke-green-500;
stroke-width: 2;
}
.path:hover {
stroke-width: 2;
}
</style>

121
packages/nc-gui/components/erd/TableNode.vue

@ -0,0 +1,121 @@
<script lang="ts" setup>
import type { NodeProps } from '@braks/vue-flow'
import { Handle, Position } from '@braks/vue-flow'
import type { ColumnType, TableType } from 'nocodb-sdk'
import { UITypes, isVirtualCol } from 'nocodb-sdk'
import type { Ref } from 'vue'
interface Props extends NodeProps {
data: TableType & { showPkAndFk: boolean; showAllColumns: boolean }
}
const props = defineProps<Props>()
const { data } = toRefs(props)
provide(MetaInj, data as Ref<TableType>)
const { $e } = useNuxtApp()
const columns = computed(() => {
// Hide hm ltar created for `mm` relations
return data.value.columns?.filter((col) => !(col.uidt === UITypes.LinkToAnotherRecord && col.system === 1))
})
const pkAndFkColumns = computed(() => {
return columns.value
?.filter(() => data.value.showPkAndFk && data.value.showAllColumns)
.filter((col) => col.pk || col.uidt === UITypes.ForeignKey)
})
const nonPkColumns = computed(() => {
return columns.value
?.filter(
(col: ColumnType) => data.value.showAllColumns || (!data.value.showAllColumns && col.uidt === UITypes.LinkToAnotherRecord),
)
.filter((col: ColumnType) => !col.pk && col.uidt !== UITypes.ForeignKey)
})
const relatedColumnId = (col: Record<string, any>) =>
col.colOptions.type === 'mm' ? col.colOptions.fk_parent_column_id : col.colOptions.fk_child_column_id
</script>
<template>
<div
class="h-full flex flex-col min-w-16 bg-gray-50 rounded-lg border-1 nc-erd-table-node"
:class="`nc-erd-table-node-${data.table_name}`"
@click="$e('c:erd:node-click')"
>
<GeneralTooltip modifier-key="Alt">
<template #title> {{ data.table_name }} </template>
<div
class="text-gray-600 text-md py-2 border-b-1 border-gray-200 rounded-t-lg w-full pr-3 pl-2 bg-gray-100 font-semibold flex flex-row items-center"
>
<MdiTableLarge v-if="data.type === 'table'" class="text-primary" />
<MdiEyeCircleOutline v-else class="text-primary" />
<div class="flex pl-1.5">
{{ data.title }}
</div>
</div>
</GeneralTooltip>
<div>
<div
v-for="col in pkAndFkColumns"
:key="col.title"
class="w-full border-b-1 py-2 border-gray-100 keys"
:class="`nc-erd-table-node-${data.table_name}-column-${col.column_name}`"
>
<SmartsheetHeaderCell v-if="col" :column="col" :hide-menu="true" />
</div>
<div class="w-full mb-1"></div>
<div v-for="(col, index) in nonPkColumns" :key="col.title">
<div
class="w-full h-full flex items-center min-w-32 border-gray-100 py-2 px-1"
:class="index + 1 === nonPkColumns.length ? 'rounded-b-lg' : 'border-b-1'"
>
<div
v-if="col.uidt === UITypes.LinkToAnotherRecord"
class="flex relative w-full"
:class="`nc-erd-table-node-${data.table_name}-column-${col.title?.toLowerCase().replace(' ', '_')}`"
>
<Handle
:id="`s-${relatedColumnId(col)}-${data.id}`"
class="-right-4 opacity-0"
type="source"
:position="Position.Right"
/>
<Handle
:id="`d-${relatedColumnId(col)}-${data.id}`"
class="-left-1 opacity-0"
type="target"
:position="Position.Left"
/>
<SmartsheetHeaderVirtualCell :column="col" :hide-menu="true" />
</div>
<SmartsheetHeaderVirtualCell
v-else-if="isVirtualCol(col)"
:column="col"
:hide-menu="true"
:class="`nc-erd-table-node-${data.table_name}-column-${col.column_name}`"
/>
<SmartsheetHeaderCell
v-else
:column="col"
:hide-menu="true"
:class="`nc-erd-table-node-${data.table_name}-column-${col.column_name}`"
/>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.keys {
background-color: #f6f6f6;
}
</style>

162
packages/nc-gui/components/erd/View.vue

@ -0,0 +1,162 @@
<script setup lang="ts">
import type { LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
const { table } = defineProps<{ table?: TableType }>()
const { includeM2M } = useGlobal()
const { tables: projectTables } = useProject()
const tables = ref<TableType[]>([])
const { metas, getMeta } = useMetas()
let isLoading = $ref(true)
const showAdvancedOptions = ref(false)
const config = ref({
showPkAndFk: true,
showViews: false,
showAllColumns: true,
singleTableMode: !!table,
showMMTables: false,
showJunctionTableNames: false,
})
const loadMetaOfTablesNotInMetas = async (localTables: TableType[]) => {
await Promise.all(
localTables
.filter((table) => !metas.value[table.id!])
.map(async (table) => {
await getMeta(table.id!)
}),
)
}
const populateTables = async () => {
let localTables: TableType[] = []
if (table) {
// if table is provided only get the table and its related tables
localTables = projectTables.value.filter(
(t) =>
t.id === table.id ||
table.columns?.find(
(column) =>
column.uidt === UITypes.LinkToAnotherRecord &&
(column.colOptions as LinkToAnotherRecordType)?.fk_related_model_id === t.id,
),
)
} else {
localTables = projectTables.value
}
await loadMetaOfTablesNotInMetas(localTables)
tables.value = localTables
.filter(
(t) =>
// todo: table type is missing mm property in type definition
config.value.showMMTables ||
(!config.value.showMMTables && !t.mm) ||
// Show mm table if it's the selected table
t.id === table?.id,
)
.filter((t) => (!config.value.showViews && t.type !== 'view') || config.value.showViews)
isLoading = false
}
watch(
[config, metas],
async () => {
await populateTables()
},
{
deep: true,
},
)
watch(
[projectTables],
async () => {
await populateTables()
},
{ immediate: true },
)
watch(
() => config.value.showAllColumns,
() => {
config.value.showPkAndFk = config.value.showAllColumns
},
)
</script>
<template>
<div
class="w-full"
style="height: inherit"
:class="{
'nc-erd-vue-flow': !config.singleTableMode,
'nc-erd-vue-flow-single-table': config.singleTableMode,
}"
>
<div v-if="isLoading" class="h-full w-full flex flex-col justify-center items-center">
<div class="flex flex-row justify-center">
<a-spin size="large" />
</div>
</div>
<div v-else class="relative h-full">
<ErdFlow :tables="tables" :config="config" />
<div
class="absolute top-2 right-10 flex-col bg-white py-2 px-4 border-1 border-gray-100 rounded-md z-50 space-y-1 nc-erd-context-menu z-50"
>
<div class="flex flex-row items-center">
<a-checkbox
v-model:checked="config.showAllColumns"
v-e="['c:erd:showAllColumns']"
class="nc-erd-showColumns-checkbox"
/>
<span
class="ml-2 select-none nc-erd-showColumns-label"
style="font-size: 0.65rem"
@dblclick="showAdvancedOptions = true"
>
{{ $t('activity.erd.showColumns') }}
</span>
</div>
<div class="flex flex-row items-center">
<a-checkbox
v-model:checked="config.showPkAndFk"
v-e="['c:erd:showPkAndFk']"
class="nc-erd-showPkAndFk-checkbox"
:class="{
'nc-erd-showPkAndFk-checkbox-enabled': config.showAllColumns,
'nc-erd-showPkAndFk-checkbox-disabled': !config.showAllColumns,
'nc-erd-showPkAndFk-checkbox-checked': config.showPkAndFk,
'nc-erd-showPkAndFk-checkbox-unchecked': !config.showPkAndFk,
}"
:disabled="!config.showAllColumns"
/>
<span class="ml-2 select-none text-[0.65rem]">{{ $t('activity.erd.showPkAndFk') }}</span>
</div>
<div v-if="!table" class="flex flex-row items-center">
<a-checkbox v-model:checked="config.showViews" v-e="['c:erd:showViews']" class="nc-erd-showViews-checkbox" />
<span class="ml-2 select-none text-[0.65rem]">{{ $t('activity.erd.showSqlViews') }}</span>
</div>
<div v-if="!table && showAdvancedOptions && includeM2M" class="flex flex-row items-center">
<a-checkbox v-model:checked="config.showMMTables" v-e="['c:erd:showMMTables']" class="nc-erd-showMMTables-checkbox" />
<span class="ml-2 select-none text-[0.65rem]">{{ $t('activity.erd.showMMTables') }}</span>
</div>
<div v-if="showAdvancedOptions && includeM2M" class="flex flex-row items-center">
<a-checkbox
v-model:checked="config.showJunctionTableNames"
v-e="['c:erd:showJunctionTableNames']"
class="nc-erd-showJunctionTableNames-checkbox"
/>
<span class="ml-2 select-none text-[0.65rem]">{{ $t('activity.erd.showJunctionTableNames') }}</span>
</div>
</div>
</div>
</div>
</template>

2
packages/nc-gui/components/smartsheet-header/VirtualCell.vue

@ -16,7 +16,7 @@ import {
useVirtualCell, useVirtualCell,
} from '#imports' } from '#imports'
const props = defineProps<{ column: ColumnType & { meta: any }; hideMenu?: boolean; required?: boolean | number }>() const props = defineProps<{ column: ColumnType; hideMenu?: boolean; required?: boolean | number }>()
const { t } = useI18n() const { t } = useI18n()

42
packages/nc-gui/components/smartsheet-toolbar/Erd.vue

@ -0,0 +1,42 @@
<script lang="ts" setup>
const props = defineProps<Props>()
const emits = defineEmits(['update:modelValue'])
const meta = inject(MetaInj)
interface Props {
modelValue: boolean
}
const vModel = useVModel(props, 'modelValue', emits)
const selectedView = inject(ActiveViewInj)
</script>
<template>
<a-modal
v-model:visible="vModel"
size="small"
:footer="null"
width="max(900px,60vw)"
:closable="false"
wrap-class-name="erd-single-table-modal"
transition-name="fade"
>
<div class="flex flex-row justify-between w-full items-center mb-1">
<a-typography-title class="ml-4 select-none" type="secondary" :level="5">
{{ `${$t('title.erdView')}: ${selectedView?.title}` }}
</a-typography-title>
<a-button type="text" class="!rounded-md border-none -mt-1.5 -mr-1" @click="vModel = false">
<template #icon>
<MdiClose class="cursor-pointer mt-1 nc-modal-close" />
</template>
</a-button>
</div>
<div class="w-full h-full !py-0 !px-2" style="height: 70vh">
<ErdView :table="meta" />
</div>
</a-modal>
</template>

4
packages/nc-gui/components/smartsheet-toolbar/FieldsMenu.vue

@ -26,6 +26,8 @@ const activeView = inject(ActiveViewInj, ref())
const reloadDataHook = inject(ReloadViewDataHookInj)! const reloadDataHook = inject(ReloadViewDataHookInj)!
const reloadViewMetaHook = inject(ReloadViewMetaHookInj)!
const rootFields = inject(FieldsInj) const rootFields = inject(FieldsInj)
const isLocked = inject(IsLockedInj, ref(false)) const isLocked = inject(IsLockedInj, ref(false))
@ -93,7 +95,7 @@ const coverImageColumnId = computed({
fk_cover_image_col_id: val, fk_cover_image_col_id: val,
}) })
;(activeView.value?.view as GalleryType).fk_cover_image_col_id = val ;(activeView.value?.view as GalleryType).fk_cover_image_col_id = val
reloadDataHook.trigger() reloadViewMetaHook.trigger()
} }
}, },
}) })

32
packages/nc-gui/components/smartsheet-toolbar/ViewActions.vue

@ -18,6 +18,7 @@ import { LockType } from '~/lib'
import MdiLockOutlineIcon from '~icons/mdi/lock-outline' import MdiLockOutlineIcon from '~icons/mdi/lock-outline'
import MdiAccountIcon from '~icons/mdi/account' import MdiAccountIcon from '~icons/mdi/account'
import MdiAccountGroupIcon from '~icons/mdi/account-group' import MdiAccountGroupIcon from '~icons/mdi/account-group'
import AcountTreeRoundedIcon from '~icons/material-symbols/account-tree-rounded'
const { t } = useI18n() const { t } = useI18n()
@ -37,6 +38,8 @@ const showWebhookDrawer = ref(false)
const showApiSnippetDrawer = ref(false) const showApiSnippetDrawer = ref(false)
const showErd = ref(false)
const quickImportDialog = ref(false) const quickImportDialog = ref(false)
const { isUIAllowed } = useUIPermission() const { isUIAllowed } = useUIPermission()
@ -160,9 +163,8 @@ const { isSqlView } = useSmartsheetStoreOrThrow()
</template> </template>
<template #expandIcon></template> <template #expandIcon></template>
<a-menu-item> <a-menu-item v-if="isUIAllowed('csvImport') && !isView && !isPublicView">
<div <div
v-if="isUIAllowed('csvImport') && !isView && !isPublicView"
v-e="['a:actions:upload-csv']" v-e="['a:actions:upload-csv']"
class="nc-project-menu-item" class="nc-project-menu-item"
:class="{ disabled: isLocked }" :class="{ disabled: isLocked }"
@ -177,13 +179,8 @@ const { isSqlView } = useSmartsheetStoreOrThrow()
</a-sub-menu> </a-sub-menu>
</template> </template>
<a-menu-divider /> <a-menu-divider />
<a-menu-item> <a-menu-item v-if="isUIAllowed('SharedViewList') && !isView && !isPublicView">
<div <div v-e="['a:actions:shared-view-list']" class="py-2 flex gap-2 items-center" @click="sharedViewListDlg = true">
v-if="isUIAllowed('SharedViewList') && !isView && !isPublicView"
v-e="['a:actions:shared-view-list']"
class="py-2 flex gap-2 items-center"
@click="sharedViewListDlg = true"
>
<MdiViewListOutline class="text-gray-500" /> <MdiViewListOutline class="text-gray-500" />
<!-- Shared View List --> <!-- Shared View List -->
{{ $t('activity.listSharedView') }} {{ $t('activity.listSharedView') }}
@ -200,18 +197,19 @@ const { isSqlView } = useSmartsheetStoreOrThrow()
{{ $t('objects.webhooks') }} {{ $t('objects.webhooks') }}
</div> </div>
</a-menu-item> </a-menu-item>
<a-menu-item> <a-menu-item v-if="!isSharedBase && !isPublicView">
<div <div v-e="['c:snippet:open']" class="py-2 flex gap-2 items-center" @click="showApiSnippetDrawer = true">
v-if="!isSharedBase && !isPublicView"
v-e="['c:snippet:open']"
class="py-2 flex gap-2 items-center"
@click="showApiSnippetDrawer = true"
>
<MdiXml class="text-gray-500" /> <MdiXml class="text-gray-500" />
<!-- Get API Snippet --> <!-- Get API Snippet -->
{{ $t('activity.getApiSnippet') }} {{ $t('activity.getApiSnippet') }}
</div> </div>
</a-menu-item> </a-menu-item>
<a-menu-item>
<div v-e="['c:erd:open']" class="py-2 flex gap-2 items-center nc-view-action-erd" @click="showErd = true">
<AcountTreeRoundedIcon class="text-gray-500" />
{{ $t('title.erdView') }}
</div>
</a-menu-item>
</a-menu-item-group> </a-menu-item-group>
</a-menu> </a-menu>
</template> </template>
@ -221,6 +219,8 @@ const { isSqlView } = useSmartsheetStoreOrThrow()
<WebhookDrawer v-if="showWebhookDrawer" v-model="showWebhookDrawer" /> <WebhookDrawer v-if="showWebhookDrawer" v-model="showWebhookDrawer" />
<SmartsheetToolbarErd v-model="showErd" />
<a-modal <a-modal
v-model:visible="sharedViewListDlg" v-model:visible="sharedViewListDlg"
:title="$t('activity.listSharedView')" :title="$t('activity.listSharedView')"

91
packages/nc-gui/components/smartsheet/Gallery.vue

@ -1,4 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted } from '@vue/runtime-core'
import { isVirtualCol } from 'nocodb-sdk' import { isVirtualCol } from 'nocodb-sdk'
import { import {
ActiveViewInj, ActiveViewInj,
@ -11,7 +12,8 @@ import {
OpenNewRecordFormHookInj, OpenNewRecordFormHookInj,
PaginationDataInj, PaginationDataInj,
ReadonlyInj, ReadonlyInj,
ReloadViewDataHookInj, ReloadViewMetaHookInj,
extractPkFromRow,
inject, inject,
provide, provide,
useViewData, useViewData,
@ -26,7 +28,7 @@ interface Attachment {
const meta = inject(MetaInj, ref()) const meta = inject(MetaInj, ref())
const view = inject(ActiveViewInj, ref()) const view = inject(ActiveViewInj, ref())
const reloadViewDataHook = inject(ReloadViewDataHookInj) const reloadViewMetaHook = inject(ReloadViewMetaHookInj)
const openNewRecordFormHook = inject(OpenNewRecordFormHookInj, createEventHook()) const openNewRecordFormHook = inject(OpenNewRecordFormHookInj, createEventHook())
const expandedFormDlg = ref(false) const expandedFormDlg = ref(false)
@ -54,6 +56,10 @@ provide(ReadonlyInj, !isUIAllowed('xcDatatableEditable'))
const fields = inject(FieldsInj, ref([])) const fields = inject(FieldsInj, ref([]))
const route = useRoute()
const router = useRouter()
const fieldsWithoutCover = computed(() => fields.value.filter((f) => f.id !== galleryData.value?.fk_cover_image_col_id)) const fieldsWithoutCover = computed(() => fields.value.filter((f) => f.id !== galleryData.value?.fk_cover_image_col_id))
const coverImageColumn: any = $( const coverImageColumn: any = $(
@ -64,17 +70,6 @@ const coverImageColumn: any = $(
), ),
) )
watch(
[meta, view],
async () => {
if (meta?.value && view?.value) {
await loadData()
await loadGalleryData()
}
},
{ immediate: true },
)
const isRowEmpty = (record: any, col: any) => { const isRowEmpty = (record: any, col: any) => {
const val = record.row[col.title] const val = record.row[col.title]
if (!val) return true if (!val) return true
@ -90,23 +85,24 @@ const attachments = (record: any): Array<Attachment> => {
} }
} }
const reloadAttachments = ref(false) const expandForm = (row: RowType, _state?: Record<string, any>) => {
if (!isUIAllowed('xcDatatableEditable')) return
reloadViewDataHook?.on(async () => { const rowId = extractPkFromRow(row.row, meta.value.columns)
await loadData()
await loadGalleryData()
reloadAttachments.value = true
nextTick(() => {
reloadAttachments.value = false
})
})
const expandForm = (row: RowType, state?: Record<string, any>) => { if (rowId) {
if (!isUIAllowed('xcDatatableEditable')) return router.push({
query: {
...route.query,
rowId,
},
})
} else {
expandedFormRow.value = row expandedFormRow.value = row
expandedFormRowState.value = state expandedFormRowState.value = state
expandedFormDlg.value = true expandedFormDlg.value = true
} }
}
const expandFormClick = async (e: MouseEvent, row: RowType) => { const expandFormClick = async (e: MouseEvent, row: RowType) => {
const target = e.target as HTMLElement const target = e.target as HTMLElement
@ -119,10 +115,40 @@ openNewRecordFormHook?.on(async () => {
const newRow = await addEmptyRow() const newRow = await addEmptyRow()
expandForm(newRow) expandForm(newRow)
}) })
const expandedFormOnRowIdDlg = computed({
get() {
return !!route.query.rowId
},
set(val) {
if (!val)
router.push({
query: {
...route.query,
rowId: undefined,
},
})
},
})
const reloadAttachments = ref(false)
reloadViewMetaHook?.on(async () => {
await loadGalleryData()
reloadAttachments.value = true
nextTick(() => {
reloadAttachments.value = false
})
})
onMounted(async () => {
await loadData()
await loadGalleryData()
})
</script> </script>
<template> <template>
<div class="flex flex-col h-full w-full overflow-auto"> <div class="flex flex-col h-full w-full overflow-auto nc-gallery">
<div class="nc-gallery-container grid gap-2 my-4 px-3"> <div class="nc-gallery-container grid gap-2 my-4 px-3">
<div v-for="record in data" :key="`record-${record.row.id}`"> <div v-for="record in data" :key="`record-${record.row.id}`">
<Row :row="record"> <Row :row="record">
@ -135,7 +161,9 @@ openNewRecordFormHook?.on(async () => {
<a-carousel v-if="!reloadAttachments && attachments(record).length" autoplay class="gallery-carousel" arrows> <a-carousel v-if="!reloadAttachments && attachments(record).length" autoplay class="gallery-carousel" arrows>
<template #customPaging> <template #customPaging>
<a> <a>
<div class="pt-[12px]"><div></div></div> <div class="pt-[12px]">
<div></div>
</div>
</a> </a>
</template> </template>
<template #prevArrow> <template #prevArrow>
@ -186,6 +214,17 @@ openNewRecordFormHook?.on(async () => {
:row="expandedFormRow" :row="expandedFormRow"
:state="expandedFormRowState" :state="expandedFormRowState"
:meta="meta" :meta="meta"
:view="view"
/>
<SmartsheetExpandedForm
v-if="expandedFormOnRowIdDlg"
:key="route.query.rowId"
v-model="expandedFormOnRowIdDlg"
:row="{ row: {}, oldRow: {}, rowMeta: {} }"
:meta="meta"
:row-id="route.query.rowId"
:view="view"
/> />
</div> </div>
</template> </template>

48
packages/nc-gui/components/smartsheet/Grid.vue

@ -17,6 +17,7 @@ import {
ReadonlyInj, ReadonlyInj,
ReloadViewDataHookInj, ReloadViewDataHookInj,
createEventHook, createEventHook,
extractPkFromRow,
inject, inject,
onClickOutside, onClickOutside,
onMounted, onMounted,
@ -27,6 +28,7 @@ import {
useEventListener, useEventListener,
useGridViewColumnWidth, useGridViewColumnWidth,
useI18n, useI18n,
useRoute,
useSmartsheetStoreOrThrow, useSmartsheetStoreOrThrow,
useUIPermission, useUIPermission,
useViewData, useViewData,
@ -53,6 +55,9 @@ const openNewRecordFormHook = inject(OpenNewRecordFormHookInj, createEventHook()
const { isUIAllowed } = useUIPermission() const { isUIAllowed } = useUIPermission()
const hasEditPermission = isUIAllowed('xcDatatableEditable') const hasEditPermission = isUIAllowed('xcDatatableEditable')
const route = useRoute()
const router = useRouter()
// todo: get from parent ( inject or use prop ) // todo: get from parent ( inject or use prop )
const isView = false const isView = false
@ -130,11 +135,22 @@ reloadViewDataHook?.on(async (shouldShowLoading) => {
const skipRowRemovalOnCancel = ref(false) const skipRowRemovalOnCancel = ref(false)
const expandForm = (row: Row, state?: Record<string, any>, fromToolbar = false) => { const expandForm = (row: Row, state?: Record<string, any>, fromToolbar = false) => {
const rowId = extractPkFromRow(row.row, meta.value.columns)
if (rowId) {
router.push({
query: {
...route.query,
rowId,
},
})
} else {
expandedFormRow.value = row expandedFormRow.value = row
expandedFormRowState.value = state expandedFormRowState.value = state
expandedFormDlg.value = true expandedFormDlg.value = true
skipRowRemovalOnCancel.value = !fromToolbar skipRowRemovalOnCancel.value = !fromToolbar
} }
}
openNewRecordFormHook?.on(async () => { openNewRecordFormHook?.on(async () => {
const newRow = await addEmptyRow() const newRow = await addEmptyRow()
@ -377,6 +393,27 @@ onBeforeUnmount(async () => {
} }
} }
}) })
const expandedFormOnRowIdDlg = computed({
get() {
return !!route.query.rowId
},
set(val) {
if (!val)
router.push({
query: {
...route.query,
rowId: undefined,
},
})
},
})
// reload table data reload hook as fallback to rowdatareload
provide(ReloadRowDataHookInj, reloadViewDataHook)
// trigger initial data load in grid
reloadViewDataHook.trigger()
</script> </script>
<template> <template>
@ -611,12 +648,23 @@ onBeforeUnmount(async () => {
:row="expandedFormRow" :row="expandedFormRow"
:state="expandedFormRowState" :state="expandedFormRowState"
:meta="meta" :meta="meta"
:view="view"
@update:model-value=" @update:model-value="
() => { () => {
if (!skipRowRemovalOnCancel) removeRowIfNew(expandedFormRow) if (!skipRowRemovalOnCancel) removeRowIfNew(expandedFormRow)
} }
" "
/> />
<SmartsheetExpandedForm
v-if="expandedFormOnRowIdDlg"
:key="route.query.rowId"
v-model="expandedFormOnRowIdDlg"
:row="{ row: {}, oldRow: {}, rowMeta: {} }"
:meta="meta"
:row-id="route.query.rowId"
:view="view"
/>
</div> </div>
</template> </template>

39
packages/nc-gui/components/smartsheet/expanded-form/Header.vue

@ -1,4 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { message } from 'ant-design-vue'
import type { ViewType } from 'nocodb-sdk'
import { import {
ReloadRowDataHookInj, ReloadRowDataHookInj,
useExpandedFormStoreOrThrow, useExpandedFormStoreOrThrow,
@ -7,11 +9,15 @@ import {
useUIPermission, useUIPermission,
} from '#imports' } from '#imports'
const props = defineProps<{ view?: ViewType }>()
const emit = defineEmits(['cancel']) const emit = defineEmits(['cancel'])
const route = useRoute()
const { meta, isSqlView } = useSmartsheetStoreOrThrow() const { meta, isSqlView } = useSmartsheetStoreOrThrow()
const { commentsDrawer, primaryValue, save: _save, loadRow } = useExpandedFormStoreOrThrow() const { commentsDrawer, primaryValue, primaryKey, save: _save, loadRow } = useExpandedFormStoreOrThrow()
const { isNew, syncLTARRefs } = useSmartsheetRowStoreOrThrow() const { isNew, syncLTARRefs } = useSmartsheetRowStoreOrThrow()
@ -26,15 +32,29 @@ const save = async () => {
reloadTrigger?.trigger() reloadTrigger?.trigger()
} else { } else {
await _save() await _save()
reloadTrigger?.trigger()
} }
} }
// todo: accept as a prop / inject // todo: accept as a prop / inject
const iconColor = '#1890ff' const iconColor = '#1890ff'
const { dashboardUrl } = useDashboard()
const { copy } = useClipboard()
const copyRecordUrl = () => {
copy(
`${dashboardUrl?.value}#/${route.params.projectType}/${route.params.projectId}/${route.params.type}/${meta.value?.title}${
props.view ? `/${props.view.title}` : ''
}?rowId=${primaryKey.value}`,
)
message.success('Copied to clipboard')
}
</script> </script>
<template> <template>
<div class="flex p-2 items-center gap-2 p-4"> <div class="flex p-2 items-center gap-2 p-4 nc-expanded-form-header">
<h5 class="text-lg font-weight-medium flex items-center gap-1 mb-0 min-w-0 overflow-x-hidden truncate"> <h5 class="text-lg font-weight-medium flex items-center gap-1 mb-0 min-w-0 overflow-x-hidden truncate">
<mdi-table-arrow-right :style="{ color: iconColor }" /> <mdi-table-arrow-right :style="{ color: iconColor }" />
@ -55,7 +75,14 @@ const iconColor = '#1890ff'
<template #title> <template #title>
<div class="text-center w-full">{{ $t('general.reload') }}</div> <div class="text-center w-full">{{ $t('general.reload') }}</div>
</template> </template>
<mdi-reload v-if="!isNew" class="cursor-pointer select-none text-gray-500" @click="loadRow" /> <mdi-reload v-if="!isNew" class="cursor-pointer select-none text-gray-500 mx-1" @click="loadRow" />
</a-tooltip>
<a-tooltip placement="bottom">
<template #title>
<!-- todo: i18n -->
<div class="text-center w-full">Copy record URL</div>
</template>
<mdi-link v-if="!isNew" class="cursor-pointer select-none text-gray-500 mx-1 nc-copy-row-url" @click="copyRecordUrl" />
</a-tooltip> </a-tooltip>
<a-tooltip v-if="!isSqlView" placement="bottom"> <a-tooltip v-if="!isSqlView" placement="bottom">
<!-- Toggle comments draw --> <!-- Toggle comments draw -->
@ -65,17 +92,17 @@ const iconColor = '#1890ff'
<MdiCommentTextOutline <MdiCommentTextOutline
v-if="isUIAllowed('rowComments') && !isNew" v-if="isUIAllowed('rowComments') && !isNew"
v-e="['c:row-expand:comment-toggle']" v-e="['c:row-expand:comment-toggle']"
class="cursor-pointer select-none nc-toggle-comments text-gray-500" class="cursor-pointer select-none nc-toggle-comments text-gray-500 mx-1"
@click="commentsDrawer = !commentsDrawer" @click="commentsDrawer = !commentsDrawer"
/> />
</a-tooltip> </a-tooltip>
<a-button class="!text" @click="emit('cancel')"> <a-button class="!text mx-1 nc-expand-form-close-btn" @click="emit('cancel')">
<!-- Cancel --> <!-- Cancel -->
{{ $t('general.cancel') }} {{ $t('general.cancel') }}
</a-button> </a-button>
<a-button :disabled="!isUIAllowed('tableRowUpdate')" type="primary" @click="save"> <a-button :disabled="!isUIAllowed('tableRowUpdate')" type="primary" class="mx-1" @click="save">
<!-- Save Row --> <!-- Save Row -->
{{ $t('activity.saveRow') }} {{ $t('activity.saveRow') }}
</a-button> </a-button>

22
packages/nc-gui/components/smartsheet/expanded-form/index.vue

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { message } from 'ant-design-vue'
import type { TableType, ViewType } from 'nocodb-sdk' import type { TableType, ViewType } from 'nocodb-sdk'
import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk' import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import type { Ref } from 'vue' import type { Ref } from 'vue'
@ -17,6 +18,7 @@ import {
toRef, toRef,
useProvideExpandedFormStore, useProvideExpandedFormStore,
useProvideSmartsheetStore, useProvideSmartsheetStore,
useRouter,
useVModel, useVModel,
watch, watch,
} from '#imports' } from '#imports'
@ -29,6 +31,8 @@ interface Props {
meta: TableType meta: TableType
loadRow?: boolean loadRow?: boolean
useMetaFields?: boolean useMetaFields?: boolean
rowId?: string
view?: ViewType
} }
const props = defineProps<Props>() const props = defineProps<Props>()
@ -41,6 +45,8 @@ const state = toRef(props, 'state')
const meta = toRef(props, 'meta') const meta = toRef(props, 'meta')
const router = useRouter()
const fields = computedInject(FieldsInj, (_fields) => { const fields = computedInject(FieldsInj, (_fields) => {
if (props.useMetaFields) { if (props.useMetaFields) {
return (meta.value.columns ?? []).filter((col) => !isSystemColumn(col)) return (meta.value.columns ?? []).filter((col) => !isSystemColumn(col))
@ -56,6 +62,18 @@ if (props.loadRow) {
await loadRow() await loadRow()
} }
if (props.rowId) {
try {
await loadRow(props.rowId)
} catch (e) {
if (e.response?.status === 404) {
// todo: i18n
message.error('Record not found')
router.replace({ query: {} })
} else throw e
}
}
useProvideSmartsheetStore(ref({}) as Ref<ViewType>, meta) useProvideSmartsheetStore(ref({}) as Ref<ViewType>, meta)
provide(IsFormInj, ref(true)) provide(IsFormInj, ref(true))
@ -117,10 +135,10 @@ export default {
:closable="false" :closable="false"
class="nc-drawer-expanded-form" class="nc-drawer-expanded-form"
> >
<Header @cancel="onClose" /> <Header :view="view" @cancel="onClose" />
<div class="!bg-gray-100 rounded flex-1"> <div class="!bg-gray-100 rounded flex-1">
<div class="flex h-full nc-form-wrapper items-stretch min-h-[max(70vh,100%)]"> <div class="flex h-full nc-form-wrapper items-stretch min-h-[max(70vh,100%)]">
<div class="flex-1 overflow-auto scrollbar-thin-dull"> <div class="flex-1 overflow-auto scrollbar-thin-dull nc-form-fields-container">
<div class="w-[500px] mx-auto"> <div class="w-[500px] mx-auto">
<div <div
v-for="col of fields" v-for="col of fields"

1
packages/nc-gui/components/smartsheet/sidebar/index.vue

@ -93,7 +93,6 @@ function openModal({ type, title = '', copyViewId }: { type: ViewTypes; title: s
/** Handle view creation */ /** Handle view creation */
function onCreate(view: ViewType) { function onCreate(view: ViewType) {
views.value.push(view) views.value.push(view)
activeView.value = view
router.push({ params: { viewTitle: view.title || '' } }) router.push({ params: { viewTitle: view.title || '' } })
modalOpen = false modalOpen = false
$e('a:view:create', { view: view.type }) $e('a:view:create', { view: view.type })

4
packages/nc-gui/components/tabs/Smartsheet.vue

@ -36,6 +36,7 @@ provide(TabMetaInj, ref(activeTab))
const meta = computed<TableType>(() => metas.value?.[activeTab?.id as string]) const meta = computed<TableType>(() => metas.value?.[activeTab?.id as string])
const reloadEventHook = createEventHook<void>() const reloadEventHook = createEventHook<void>()
const reloadViewMetaEventHook = createEventHook<void>()
const openNewRecordFormHook = createEventHook<void>() const openNewRecordFormHook = createEventHook<void>()
const reloadKanbanMetaHook = createEventHook<void>() const reloadKanbanMetaHook = createEventHook<void>()
@ -50,6 +51,7 @@ provide(ActiveViewInj, activeView)
provide(IsLockedInj, isLocked) provide(IsLockedInj, isLocked)
provide(ReloadViewDataHookInj, reloadEventHook) provide(ReloadViewDataHookInj, reloadEventHook)
provide(ReloadKanbanMetaHookInj, reloadKanbanMetaHook) provide(ReloadKanbanMetaHookInj, reloadKanbanMetaHook)
provide(ReloadViewMetaHookInj, reloadViewMetaEventHook)
provide(OpenNewRecordFormHookInj, openNewRecordFormHook) provide(OpenNewRecordFormHookInj, openNewRecordFormHook)
provide(FieldsInj, fields) provide(FieldsInj, fields)
provide(IsFormInj, isForm) provide(IsFormInj, isForm)
@ -71,7 +73,7 @@ watch(isLocked, (nextValue) => (treeViewIsLockedInj.value = nextValue), { immedi
<SmartsheetGallery v-else-if="isGallery" /> <SmartsheetGallery v-else-if="isGallery" />
<SmartsheetForm v-else-if="isForm" /> <SmartsheetForm v-else-if="isForm && !$route.query.reload" />
<SmartsheetKanban v-else-if="isKanban" /> <SmartsheetKanban v-else-if="isKanban" />
</div> </div>

8
packages/nc-gui/components/template/Editor.vue

@ -94,13 +94,13 @@ const data = reactive<{ title: string | null; name: string; tables: (TableType &
}) })
const validators = computed(() => const validators = computed(() =>
data.tables.reduce<Record<string, [typeof fieldRequiredValidator]>>((acc, table, tableIdx) => { data.tables.reduce<Record<string, [ReturnType<typeof fieldRequiredValidator>]>>((acc, table, tableIdx) => {
acc[`tables.${tableIdx}.ref_table_name`] = [fieldRequiredValidator] acc[`tables.${tableIdx}.ref_table_name`] = [fieldRequiredValidator()]
hasSelectColumn.value[tableIdx] = false hasSelectColumn.value[tableIdx] = false
table.columns?.forEach((column, columnIdx) => { table.columns?.forEach((column, columnIdx) => {
acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [fieldRequiredValidator] acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [fieldRequiredValidator()]
acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator] acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator()]
if (isSelect(column)) { if (isSelect(column)) {
hasSelectColumn.value[tableIdx] = true hasSelectColumn.value[tableIdx] = true
} }

3
packages/nc-gui/components/virtual-cell/components/ListChildItems.vue

@ -78,10 +78,11 @@ const container = computed(() =>
const expandedFormDlg = ref(false) const expandedFormDlg = ref(false)
const expandedFormRow = ref() const expandedFormRow = ref()
/** reload children list whenever cell value changes and list is visible */
watch( watch(
() => props.cellValue, () => props.cellValue,
() => { () => {
if (!isNew.value) loadChildrenList() if (!isNew.value && vModel.value) loadChildrenList()
}, },
) )
</script> </script>

24
packages/nc-gui/components/webhook/Editor.vue

@ -184,28 +184,28 @@ const methodList = ref([
const validators = computed(() => { const validators = computed(() => {
return { return {
'title': [fieldRequiredValidator], 'title': [fieldRequiredValidator()],
'eventOperation': [fieldRequiredValidator], 'eventOperation': [fieldRequiredValidator()],
'notification.type': [fieldRequiredValidator], 'notification.type': [fieldRequiredValidator()],
...(hook.notification.type === 'URL' && { ...(hook.notification.type === 'URL' && {
'notification.payload.method': [fieldRequiredValidator], 'notification.payload.method': [fieldRequiredValidator()],
'notification.payload.path': [fieldRequiredValidator], 'notification.payload.path': [fieldRequiredValidator()],
}), }),
...(hook.notification.type === 'Email' && { ...(hook.notification.type === 'Email' && {
'notification.payload.to': [fieldRequiredValidator], 'notification.payload.to': [fieldRequiredValidator()],
'notification.payload.subject': [fieldRequiredValidator], 'notification.payload.subject': [fieldRequiredValidator()],
'notification.payload.body': [fieldRequiredValidator], 'notification.payload.body': [fieldRequiredValidator()],
}), }),
...((hook.notification.type === 'Slack' || ...((hook.notification.type === 'Slack' ||
hook.notification.type === 'Microsoft Teams' || hook.notification.type === 'Microsoft Teams' ||
hook.notification.type === 'Discord' || hook.notification.type === 'Discord' ||
hook.notification.type === 'Mattermost') && { hook.notification.type === 'Mattermost') && {
'notification.payload.channels': [fieldRequiredValidator], 'notification.payload.channels': [fieldRequiredValidator()],
'notification.payload.body': [fieldRequiredValidator], 'notification.payload.body': [fieldRequiredValidator()],
}), }),
...((hook.notification.type === 'Twilio' || hook.notification.type === 'Whatsapp Twilio') && { ...((hook.notification.type === 'Twilio' || hook.notification.type === 'Whatsapp Twilio') && {
'notification.payload.body': [fieldRequiredValidator], 'notification.payload.body': [fieldRequiredValidator()],
'notification.payload.to': [fieldRequiredValidator], 'notification.payload.to': [fieldRequiredValidator()],
}), }),
} }
}) })

10
packages/nc-gui/composables/useExpandedFormStore.ts

@ -66,6 +66,10 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
} }
}) })
const primaryKey = computed(() => {
return extractPkFromRow(row.value.row, meta.value.columns as ColumnType[])
})
// actions // actions
const loadCommentsAndLogs = async () => { const loadCommentsAndLogs = async () => {
if (!row.value) return if (!row.value) return
@ -179,13 +183,14 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
return data return data
} }
const loadRow = async () => { const loadRow = async (rowId?: string) => {
const record = await $api.dbTableRow.read( const record = await $api.dbTableRow.read(
NOCO, NOCO,
(project?.value?.id || sharedView.value.view.project_id) as string, (project?.value?.id || sharedView.value.view.project_id) as string,
meta.value.title, meta.value.title,
extractPkFromRow(row.value.row, meta.value.columns as ColumnType[]), rowId ?? extractPkFromRow(row.value.row, meta.value.columns as ColumnType[]),
) )
Object.assign(row.value, { Object.assign(row.value, {
row: record, row: record,
oldRow: { ...record }, oldRow: { ...record },
@ -209,6 +214,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
save, save,
changedColumns, changedColumns,
loadRow, loadRow,
primaryKey,
} }
}, 'expanded-form-store') }, 'expanded-form-store')

8
packages/nc-gui/composables/useMetas.ts

@ -10,6 +10,12 @@ export function useMetas() {
const { tables } = useProject() const { tables } = useProject()
const metas = useState<{ [idOrTitle: string]: TableType | any }>('metas', () => ({})) const metas = useState<{ [idOrTitle: string]: TableType | any }>('metas', () => ({}))
const metasWithIdAsKey = computed<Record<string, TableType>>(() => {
const idEntries = Object.entries(metas.value).filter(([k, v]) => k === v.id)
return Object.fromEntries(idEntries)
})
const loadingState = useState<Record<string, boolean>>('metas-loading-state', () => ({})) const loadingState = useState<Record<string, boolean>>('metas-loading-state', () => ({}))
const setMeta = async (model: any) => { const setMeta = async (model: any) => {
@ -91,5 +97,5 @@ export function useMetas() {
} }
} }
return { getMeta, clearAllMeta, metas, removeMeta, setMeta } return { getMeta, clearAllMeta, metas, metasWithIdAsKey, removeMeta, setMeta }
} }

3
packages/nc-gui/composables/useViewData.ts

@ -1,3 +1,4 @@
import { ViewTypes } from 'nocodb-sdk'
import type { Api, ColumnType, FormType, GalleryType, PaginatedType, TableType, ViewType } from 'nocodb-sdk' import type { Api, ColumnType, FormType, GalleryType, PaginatedType, TableType, ViewType } from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
@ -174,8 +175,10 @@ export function useViewData(
: await fetchSharedViewData() : await fetchSharedViewData()
formattedData.value = formatData(response.list) formattedData.value = formatData(response.list)
paginationData.value = response.pageInfo paginationData.value = response.pageInfo
if (viewMeta.value?.type === ViewTypes.GRID) {
await loadAggCommentsCount() await loadAggCommentsCount()
} }
}
async function loadGalleryData() { async function loadGalleryData() {
if (!viewMeta?.value?.id) return if (!viewMeta?.value?.id) return

3
packages/nc-gui/composables/useViewFilters.ts

@ -46,7 +46,6 @@ export function useViewFilters(
if (isNestedRoot) nestedFilters.value = value if (isNestedRoot) nestedFilters.value = value
nestedFilters.value = [...nestedFilters.value] nestedFilters.value = [...nestedFilters.value]
reloadHook?.trigger()
return return
} }
@ -174,6 +173,8 @@ export function useViewFilters(
fk_parent_id: parentId, fk_parent_id: parentId,
}) })
} }
reloadHook?.trigger()
} catch (e: any) { } catch (e: any) {
console.log(e) console.log(e)
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))

6
packages/nc-gui/composables/useViewSorts.ts

@ -37,6 +37,7 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
if (isPublic.value || isSharedBase.value) { if (isPublic.value || isSharedBase.value) {
sorts.value[i] = sort sorts.value[i] = sort
sorts.value = [...sorts.value] sorts.value = [...sorts.value]
reloadHook?.trigger()
return return
} }
@ -75,6 +76,7 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
sorts.value.splice(i, 1) sorts.value.splice(i, 1)
sorts.value = [...sorts.value] sorts.value = [...sorts.value]
reloadHook?.trigger()
$e('a:sort:delete') $e('a:sort:delete')
} catch (e: any) { } catch (e: any) {
console.error(e) console.error(e)
@ -82,9 +84,5 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
} }
} }
watch(sorts, () => {
reloadHook?.trigger()
})
return { sorts, loadSorts, addSort, deleteSort, saveOrUpdate } return { sorts, loadSorts, addSort, deleteSort, saveOrUpdate }
} }

1
packages/nc-gui/context/index.ts

@ -25,6 +25,7 @@ export const ReadonlyInj: InjectionKey<boolean> = Symbol('readonly-injection')
export const ReloadKanbanMetaHookInj: InjectionKey<EventHook<void>> = Symbol('reload-kanban-meta-injection') export const ReloadKanbanMetaHookInj: InjectionKey<EventHook<void>> = Symbol('reload-kanban-meta-injection')
/** when bool is passed, it indicates if a loading spinner should be visible while reloading */ /** when bool is passed, it indicates if a loading spinner should be visible while reloading */
export const ReloadViewDataHookInj: InjectionKey<EventHook<boolean | void>> = Symbol('reload-view-data-injection') export const ReloadViewDataHookInj: InjectionKey<EventHook<boolean | void>> = Symbol('reload-view-data-injection')
export const ReloadViewMetaHookInj: InjectionKey<EventHook<boolean | void>> = Symbol('reload-view-meta-injection')
export const ReloadRowDataHookInj: InjectionKey<EventHook<void>> = Symbol('reload-row-data-injection') export const ReloadRowDataHookInj: InjectionKey<EventHook<void>> = Symbol('reload-row-data-injection')
export const OpenNewRecordFormHookInj: InjectionKey<EventHook<void>> = Symbol('open-new-record-form-injection') export const OpenNewRecordFormHookInj: InjectionKey<EventHook<void>> = Symbol('open-new-record-form-injection')
export const FieldsInj: InjectionKey<Ref<any[]>> = Symbol('fields-injection') export const FieldsInj: InjectionKey<Ref<any[]>> = Symbol('fields-injection')

28
packages/nc-gui/lang/ar.json

@ -103,7 +103,8 @@
"editor": "محرر", "editor": "محرر",
"commenter": "معلق", "commenter": "معلق",
"viewer": "مشاهد" "viewer": "مشاهد"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "هوية", "ID": "هوية",
@ -157,6 +158,7 @@
"isNotNull": "ليس فارغاً" "isNotNull": "ليس فارغاً"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "مشروع جديد", "newProj": "مشروع جديد",
"myProject": "مشاريعي", "myProject": "مشاريعي",
"formTitle": "عنوان النموذج", "formTitle": "عنوان النموذج",
@ -406,7 +408,14 @@
"linkRecord": "اربط سجل", "linkRecord": "اربط سجل",
"addNewRecord": "إضافة سجل جديد", "addNewRecord": "إضافة سجل جديد",
"useConnectionUrl": "استخدام رابط الاتصال", "useConnectionUrl": "استخدام رابط الاتصال",
"toggleCommentsDraw": "تبديل سحب التعليقات" "toggleCommentsDraw": "تبديل سحب التعليقات",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "حفظ التغييرات", "saveChanges": "حفظ التغييرات",
@ -616,7 +625,20 @@
"rowUpdateFailed": "فشل تحديث الصف", "rowUpdateFailed": "فشل تحديث الصف",
"deleteRowFailed": "فشل في حذف الصف", "deleteRowFailed": "فشل في حذف الصف",
"setFormDataFailed": "فشل في تعيين بيانات النموذج", "setFormDataFailed": "فشل في تعيين بيانات النموذج",
"formViewUpdateFailed": "فشل تحديث عرض النموذج" "formViewUpdateFailed": "فشل تحديث عرض النموذج",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "تصدير البيانات الوصفية للمشروع بنجاح", "exportMetadata": "تصدير البيانات الوصفية للمشروع بنجاح",

28
packages/nc-gui/lang/bn_IN.json

@ -103,7 +103,8 @@
"editor": "সমদক", "editor": "সমদক",
"commenter": "মনতবযক", "commenter": "মনতবযক",
"viewer": "দরশক" "viewer": "দরশক"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "আইডি", "ID": "আইডি",
@ -157,6 +158,7 @@
"isNotNull": "নল নয" "isNotNull": "নল নয"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "নতন পরকলপ", "newProj": "নতন পরকলপ",
"myProject": "আমর পরকলপ", "myProject": "আমর পরকলপ",
"formTitle": "ফরম শিম", "formTitle": "ফরম শিম",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "परिवरतनरकित कर", "saveChanges": "परिवरतनरकित कर",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "পরকলপ ম সফলভ রফতি কর", "exportMetadata": "পরকলপ ম সফলভ রফতি কর",

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

@ -103,7 +103,8 @@
"editor": "Editor.", "editor": "Editor.",
"commenter": "Kommenter.", "commenter": "Kommenter.",
"viewer": "Viewer." "viewer": "Viewer."
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID.", "ID": "ID.",
@ -157,6 +158,7 @@
"isNotNull": "er ikke null." "isNotNull": "er ikke null."
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Nyt projekt", "newProj": "Nyt projekt",
"myProject": "Mine projekter", "myProject": "Mine projekter",
"formTitle": "Form titel", "formTitle": "Form titel",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Gem ændringer", "saveChanges": "Gem ændringer",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Project Metadata eksporteres med succes", "exportMetadata": "Project Metadata eksporteres med succes",

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

@ -103,7 +103,8 @@
"editor": "Bearbeiter", "editor": "Bearbeiter",
"commenter": "Kommentator", "commenter": "Kommentator",
"viewer": "Zuschauer" "viewer": "Zuschauer"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "ist nicht Null" "isNotNull": "ist nicht Null"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Neues Projekt", "newProj": "Neues Projekt",
"myProject": "Meine Projekte", "myProject": "Meine Projekte",
"formTitle": "Formular Titel", "formTitle": "Formular Titel",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Änderungen speichern", "saveChanges": "Änderungen speichern",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Projektmetadaten erfolgreich exportiert", "exportMetadata": "Projektmetadaten erfolgreich exportiert",

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

@ -103,7 +103,8 @@
"editor": "Editor", "editor": "Editor",
"commenter": "Commenter", "commenter": "Commenter",
"viewer": "Viewer" "viewer": "Viewer"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "is not null" "isNotNull": "is not null"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "New Project", "newProj": "New Project",
"myProject": "My Projects", "myProject": "My Projects",
"formTitle": "Form Title", "formTitle": "Form Title",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Save changes", "saveChanges": "Save changes",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Project metadata exported successfully", "exportMetadata": "Project metadata exported successfully",

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

@ -103,7 +103,8 @@
"editor": "Editor", "editor": "Editor",
"commenter": "Comentarista", "commenter": "Comentarista",
"viewer": "Visor" "viewer": "Visor"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "no es nulo" "isNotNull": "no es nulo"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Nuevo proyecto", "newProj": "Nuevo proyecto",
"myProject": "Mis proyectos", "myProject": "Mis proyectos",
"formTitle": "Título del formulario", "formTitle": "Título del formulario",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Guardar cambios", "saveChanges": "Guardar cambios",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Metadatos del proyecto exportados con éxito.", "exportMetadata": "Metadatos del proyecto exportados con éxito.",

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

@ -103,7 +103,8 @@
"editor": "ویرایشگر", "editor": "ویرایشگر",
"commenter": "نظردهنده", "commenter": "نظردهنده",
"viewer": "بیننده" "viewer": "بیننده"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "شناسه (ID)", "ID": "شناسه (ID)",
@ -157,6 +158,7 @@
"isNotNull": "تهی نیست" "isNotNull": "تهی نیست"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "پروژه جدید", "newProj": "پروژه جدید",
"myProject": "پروژههای من", "myProject": "پروژههای من",
"formTitle": "عنوان فرم", "formTitle": "عنوان فرم",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "ذخیره تغییرات", "saveChanges": "ذخیره تغییرات",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "فراداده پروژه با موفقیت خارج شد", "exportMetadata": "فراداده پروژه با موفقیت خارج شد",

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

@ -103,7 +103,8 @@
"editor": "Toimittaja", "editor": "Toimittaja",
"commenter": "Kommentti", "commenter": "Kommentti",
"viewer": "Katselija" "viewer": "Katselija"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "Id", "ID": "Id",
@ -157,6 +158,7 @@
"isNotNull": "ei ole nolla" "isNotNull": "ei ole nolla"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Uusi projekti", "newProj": "Uusi projekti",
"myProject": "Omat hankkeet", "myProject": "Omat hankkeet",
"formTitle": "Muodosta otsikko", "formTitle": "Muodosta otsikko",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Tallenna muutokset", "saveChanges": "Tallenna muutokset",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Project Metadata viedään onnistuneesti", "exportMetadata": "Project Metadata viedään onnistuneesti",

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

@ -103,7 +103,8 @@
"editor": "Éditeur", "editor": "Éditeur",
"commenter": "Commentateur", "commenter": "Commentateur",
"viewer": "Lecture seule" "viewer": "Lecture seule"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "Identifiant", "ID": "Identifiant",
@ -157,6 +158,7 @@
"isNotNull": "est non null" "isNotNull": "est non null"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Nouveau projet", "newProj": "Nouveau projet",
"myProject": "Mes projets", "myProject": "Mes projets",
"formTitle": "Intitulé du formulaire", "formTitle": "Intitulé du formulaire",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Sauvegarder les modifications", "saveChanges": "Sauvegarder les modifications",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Les métadonnées de projet sont exportées avec succès", "exportMetadata": "Les métadonnées de projet sont exportées avec succès",

28
packages/nc-gui/lang/he.json

@ -103,7 +103,8 @@
"editor": "עוֹרֵך", "editor": "עוֹרֵך",
"commenter": "פרשן", "commenter": "פרשן",
"viewer": "צוֹפֶה" "viewer": "צוֹפֶה"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": ְעוּדַת זֶהוּת", "ID": ְעוּדַת זֶהוּת",
@ -157,6 +158,7 @@
"isNotNull": "is not null" "isNotNull": "is not null"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "פרוייקט חדש", "newProj": "פרוייקט חדש",
"myProject": "הפרויקטים שלי", "myProject": "הפרויקטים שלי",
"formTitle": "טופס כותרת", "formTitle": "טופס כותרת",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "שמור שינויים", "saveChanges": "שמור שינויים",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "פרויקט Metadata מיוצא בהצלחה", "exportMetadata": "פרויקט Metadata מיוצא בהצלחה",

28
packages/nc-gui/lang/hi.json

@ -103,7 +103,8 @@
"editor": "सदक", "editor": "सदक",
"commenter": "टिपणर", "commenter": "टिपणर",
"viewer": "दरशक" "viewer": "दरशक"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "पहचन", "ID": "पहचन",
@ -157,6 +158,7 @@
"isNotNull": "निररथक नह" "isNotNull": "निररथक नह"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "नयम", "newProj": "नयम",
"myProject": "म परिजन", "myProject": "म परिजन",
"formTitle": "परपतर शषक", "formTitle": "परपतर शषक",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "परिवरतनरकित कर", "saveChanges": "परिवरतनरकित कर",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "परिजन सफलतवक नित क गई", "exportMetadata": "परिजन सफलतवक नित क गई",

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

@ -103,7 +103,8 @@
"editor": "Urednik", "editor": "Urednik",
"commenter": "Komentator", "commenter": "Komentator",
"viewer": "Preglednika" "viewer": "Preglednika"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "iskaznica", "ID": "iskaznica",
@ -157,6 +158,7 @@
"isNotNull": "nije ništavan" "isNotNull": "nije ništavan"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Novi projekt", "newProj": "Novi projekt",
"myProject": "Moji projekti", "myProject": "Moji projekti",
"formTitle": "Naslov oblika", "formTitle": "Naslov oblika",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Spremi promjene", "saveChanges": "Spremi promjene",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Projektni metapodaci su uspješno izvozili", "exportMetadata": "Projektni metapodaci su uspješno izvozili",

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

@ -103,7 +103,8 @@
"editor": "Editor", "editor": "Editor",
"commenter": "Komentator", "commenter": "Komentator",
"viewer": "Penonton" "viewer": "Penonton"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "Indo", "ID": "Indo",
@ -157,6 +158,7 @@
"isNotNull": "bukan null." "isNotNull": "bukan null."
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Proyek baru", "newProj": "Proyek baru",
"myProject": "Proyek saya", "myProject": "Proyek saya",
"formTitle": "Bentuk judul", "formTitle": "Bentuk judul",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Simpan perubahan", "saveChanges": "Simpan perubahan",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Metadata proyek berhasil diekspor", "exportMetadata": "Metadata proyek berhasil diekspor",

28
packages/nc-gui/lang/it.json

@ -103,7 +103,8 @@
"editor": "Editor", "editor": "Editor",
"commenter": "Commentatore", "commenter": "Commentatore",
"viewer": "Spettatore" "viewer": "Spettatore"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "non è nullo" "isNotNull": "non è nullo"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Nuovo progetto", "newProj": "Nuovo progetto",
"myProject": "I miei progetti", "myProject": "I miei progetti",
"formTitle": "Titolo del modulo", "formTitle": "Titolo del modulo",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Salva le modifiche", "saveChanges": "Salva le modifiche",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Metadati del progetto esportati con successo", "exportMetadata": "Metadati del progetto esportati con successo",

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

@ -103,7 +103,8 @@
"editor": "編集者", "editor": "編集者",
"commenter": "コメンター", "commenter": "コメンター",
"viewer": "閲覧者" "viewer": "閲覧者"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "がnullでない" "isNotNull": "がnullでない"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "新規プロジェクト", "newProj": "新規プロジェクト",
"myProject": "マイプロジェクト", "myProject": "マイプロジェクト",
"formTitle": "フォームタイトル", "formTitle": "フォームタイトル",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "変更を保存", "saveChanges": "変更を保存",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "プロジェクトメタデータは正常にエクスポートされました", "exportMetadata": "プロジェクトメタデータは正常にエクスポートされました",

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

@ -103,7 +103,8 @@
"editor": "편집자", "editor": "편집자",
"commenter": "해설자", "commenter": "해설자",
"viewer": "뷰어" "viewer": "뷰어"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "is not null" "isNotNull": "is not null"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "새 프로젝트", "newProj": "새 프로젝트",
"myProject": "내 프로젝트", "myProject": "내 프로젝트",
"formTitle": "양식 제목", "formTitle": "양식 제목",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "변경 사항 저장", "saveChanges": "변경 사항 저장",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "프로젝트 메타 데이터를 성공적으로 내보냈습니다.", "exportMetadata": "프로젝트 메타 데이터를 성공적으로 내보냈습니다.",

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

@ -103,7 +103,8 @@
"editor": "Redaktors", "editor": "Redaktors",
"commenter": "Komentētājs", "commenter": "Komentētājs",
"viewer": "Skatītājs" "viewer": "Skatītājs"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "nav null" "isNotNull": "nav null"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Jauns projekts", "newProj": "Jauns projekts",
"myProject": "Mani projekti", "myProject": "Mani projekti",
"formTitle": "Formas nosaukums", "formTitle": "Formas nosaukums",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Saglabāt izmaiņas", "saveChanges": "Saglabāt izmaiņas",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Projekta metadati eksportēti veiksmīgi", "exportMetadata": "Projekta metadati eksportēti veiksmīgi",

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

@ -103,7 +103,8 @@
"editor": "Bewerker", "editor": "Bewerker",
"commenter": "Reviewer", "commenter": "Reviewer",
"viewer": "Kijker" "viewer": "Kijker"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "is niet NULL" "isNotNull": "is niet NULL"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Nieuw Project", "newProj": "Nieuw Project",
"myProject": "Mijn Projecten", "myProject": "Mijn Projecten",
"formTitle": "Formuliertitel", "formTitle": "Formuliertitel",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Wijzigingen opslaan", "saveChanges": "Wijzigingen opslaan",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Project metadata met succes geëxporteerd", "exportMetadata": "Project metadata met succes geëxporteerd",

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

@ -103,7 +103,8 @@
"editor": "Redaktør", "editor": "Redaktør",
"commenter": "Kommenterer", "commenter": "Kommenterer",
"viewer": "Seer." "viewer": "Seer."
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "Id.", "ID": "Id.",
@ -157,6 +158,7 @@
"isNotNull": "er ikke null" "isNotNull": "er ikke null"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Nytt prosjekt", "newProj": "Nytt prosjekt",
"myProject": "Mine prosjekter", "myProject": "Mine prosjekter",
"formTitle": "Skjema tittel", "formTitle": "Skjema tittel",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Lagre endringer", "saveChanges": "Lagre endringer",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Prosjektmetadata eksporteres vellykket", "exportMetadata": "Prosjektmetadata eksporteres vellykket",

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

@ -103,7 +103,8 @@
"editor": "Redaktor", "editor": "Redaktor",
"commenter": "Komentator", "commenter": "Komentator",
"viewer": "Widz" "viewer": "Widz"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "nie jest null." "isNotNull": "nie jest null."
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Nowy projekt", "newProj": "Nowy projekt",
"myProject": "Moje projekty", "myProject": "Moje projekty",
"formTitle": "Tytuł formy", "formTitle": "Tytuł formy",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Zapisz zmiany", "saveChanges": "Zapisz zmiany",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Pomyślnie wyeksportowano metadane projektu", "exportMetadata": "Pomyślnie wyeksportowano metadane projektu",

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

@ -103,7 +103,8 @@
"editor": "editor", "editor": "editor",
"commenter": "Comentarista", "commenter": "Comentarista",
"viewer": "Viewer." "viewer": "Viewer."
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "identificação", "ID": "identificação",
@ -157,6 +158,7 @@
"isNotNull": "não é nulo" "isNotNull": "não é nulo"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Novo Projecto", "newProj": "Novo Projecto",
"myProject": "Os meus Projectos", "myProject": "Os meus Projectos",
"formTitle": "Título de forma", "formTitle": "Título de forma",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Salvar alterações", "saveChanges": "Salvar alterações",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Metadados do projeto exportado com sucesso", "exportMetadata": "Metadados do projeto exportado com sucesso",

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

@ -103,7 +103,8 @@
"editor": "editor", "editor": "editor",
"commenter": "Comentarista", "commenter": "Comentarista",
"viewer": "Viewer." "viewer": "Viewer."
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "identificação", "ID": "identificação",
@ -157,6 +158,7 @@
"isNotNull": "não é nulo" "isNotNull": "não é nulo"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Novo Projeto", "newProj": "Novo Projeto",
"myProject": "Os meus Projetos", "myProject": "Os meus Projetos",
"formTitle": "Título de forma", "formTitle": "Título de forma",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Salvar alterações", "saveChanges": "Salvar alterações",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Metadados do projeto exportado com sucesso", "exportMetadata": "Metadados do projeto exportado com sucesso",

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

@ -103,7 +103,8 @@
"editor": "Редактор", "editor": "Редактор",
"commenter": "Комментатор", "commenter": "Комментатор",
"viewer": "Просмотр" "viewer": "Просмотр"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "Идентификатор", "ID": "Идентификатор",
@ -157,6 +158,7 @@
"isNotNull": "не ноль" "isNotNull": "не ноль"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Новый проект", "newProj": "Новый проект",
"myProject": "Мои проекты", "myProject": "Мои проекты",
"formTitle": "Заголовк формы", "formTitle": "Заголовк формы",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Сохранить изменения", "saveChanges": "Сохранить изменения",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Метаданные проекта успешно экспортированы", "exportMetadata": "Метаданные проекта успешно экспортированы",

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

@ -103,7 +103,8 @@
"editor": "Urednik", "editor": "Urednik",
"commenter": "Komentar", "commenter": "Komentar",
"viewer": "Gledalca." "viewer": "Gledalca."
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "Id", "ID": "Id",
@ -157,6 +158,7 @@
"isNotNull": "ni null" "isNotNull": "ni null"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Novi projekt", "newProj": "Novi projekt",
"myProject": "Moji projekti", "myProject": "Moji projekti",
"formTitle": "Naslov obrazca", "formTitle": "Naslov obrazca",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Shrani spremembe", "saveChanges": "Shrani spremembe",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Projekt Metapodatki se je uspešno izvozil", "exportMetadata": "Projekt Metapodatki se je uspešno izvozil",

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

@ -103,7 +103,8 @@
"editor": "Redaktör", "editor": "Redaktör",
"commenter": "Kommentare", "commenter": "Kommentare",
"viewer": "Visare" "viewer": "Visare"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "Id", "ID": "Id",
@ -157,6 +158,7 @@
"isNotNull": "är inte noll" "isNotNull": "är inte noll"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Nytt projekt", "newProj": "Nytt projekt",
"myProject": "Mina projekt", "myProject": "Mina projekt",
"formTitle": "Formtitel", "formTitle": "Formtitel",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Spara ändringar", "saveChanges": "Spara ändringar",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Projektmetadata exporterades framgångsrikt", "exportMetadata": "Projektmetadata exporterades framgångsrikt",

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

@ -103,7 +103,8 @@
"editor": "บรรณาธการ", "editor": "บรรณาธการ",
"commenter": "ผจารณ", "commenter": "ผจารณ",
"viewer": "ผ" "viewer": "ผ"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "id", "ID": "id",
@ -157,6 +158,7 @@
"isNotNull": "ไมเปนโมฆะ" "isNotNull": "ไมเปนโมฆะ"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "โครงการใหม", "newProj": "โครงการใหม",
"myProject": "โครงการของฉน", "myProject": "โครงการของฉน",
"formTitle": "ชอรปแบบ", "formTitle": "ชอรปแบบ",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "บนทกการเปลยนแปลง", "saveChanges": "บนทกการเปลยนแปลง",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "ขอมลเมตาของโครงการสงออกเรยบรอยแลว", "exportMetadata": "ขอมลเมตาของโครงการสงออกเรยบรอยแลว",

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

@ -103,7 +103,8 @@
"editor": "Editör", "editor": "Editör",
"commenter": "Yorumcu", "commenter": "Yorumcu",
"viewer": "İzleyici" "viewer": "İzleyici"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "null değil" "isNotNull": "null değil"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Yeni proje", "newProj": "Yeni proje",
"myProject": "Benim projelerim", "myProject": "Benim projelerim",
"formTitle": "Form başlığı", "formTitle": "Form başlığı",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Değişiklikleri Kaydet", "saveChanges": "Değişiklikleri Kaydet",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Proje metaverileri başarıyla dışa aktarıldı", "exportMetadata": "Proje metaverileri başarıyla dışa aktarıldı",

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

@ -103,7 +103,8 @@
"editor": "Редактор", "editor": "Редактор",
"commenter": "Коментатор", "commenter": "Коментатор",
"viewer": "Глядач" "viewer": "Глядач"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "Ідентифікатор", "ID": "Ідентифікатор",
@ -157,6 +158,7 @@
"isNotNull": "не є нульовим" "isNotNull": "не є нульовим"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Новий проект", "newProj": "Новий проект",
"myProject": "Мої проекти", "myProject": "Мої проекти",
"formTitle": "Назва форми", "formTitle": "Назва форми",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Зберегти зміни", "saveChanges": "Зберегти зміни",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Метадані проекту успішно експортується", "exportMetadata": "Метадані проекту успішно експортується",

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

@ -103,7 +103,8 @@
"editor": "Biên tập viên", "editor": "Biên tập viên",
"commenter": "Bình luận", "commenter": "Bình luận",
"viewer": "Người xem" "viewer": "Người xem"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "TÔI", "ID": "TÔI",
@ -157,6 +158,7 @@
"isNotNull": "không phải là null." "isNotNull": "không phải là null."
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "Dự án mới", "newProj": "Dự án mới",
"myProject": "Những dự án của tôi", "myProject": "Những dự án của tôi",
"formTitle": "Tiêu đề mẫu", "formTitle": "Tiêu đề mẫu",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "Lưu thay đổi", "saveChanges": "Lưu thay đổi",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "Metadata dự án xuất khẩu thành công", "exportMetadata": "Metadata dự án xuất khẩu thành công",

28
packages/nc-gui/lang/zh-Hans.json

@ -103,7 +103,8 @@
"editor": "编辑", "editor": "编辑",
"commenter": "评论者", "commenter": "评论者",
"viewer": "观众" "viewer": "观众"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "不是空虚" "isNotNull": "不是空虚"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "创建新项目", "newProj": "创建新项目",
"myProject": "我的项目", "myProject": "我的项目",
"formTitle": "表格标题", "formTitle": "表格标题",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "保存更改", "saveChanges": "保存更改",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "项目元数据成功导出", "exportMetadata": "项目元数据成功导出",

28
packages/nc-gui/lang/zh-Hant.json

@ -103,7 +103,8 @@
"editor": "編輯", "editor": "編輯",
"commenter": "評論者", "commenter": "評論者",
"viewer": "檢視者" "viewer": "檢視者"
} },
"sqlVIew": "SQL View"
}, },
"datatype": { "datatype": {
"ID": "ID", "ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "不是空虛" "isNotNull": "不是空虛"
}, },
"title": { "title": {
"erdView": "ERD View",
"newProj": "建立新專案", "newProj": "建立新專案",
"myProject": "我的專案", "myProject": "我的專案",
"formTitle": "表格標題", "formTitle": "表格標題",
@ -406,7 +408,14 @@
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw" "toggleCommentsDraw": "Toggle comments draw",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
}
}, },
"tooltip": { "tooltip": {
"saveChanges": "儲存更動", "saveChanges": "儲存更動",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed", "rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view" "formViewUpdateFailed": "Failed to update form view",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed"
}, },
"toast": { "toast": {
"exportMetadata": "專案中繼資料已成功匯出", "exportMetadata": "專案中繼資料已成功匯出",

2
packages/nc-gui/middleware/auth.global.ts

@ -69,7 +69,7 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
} }
} else { } else {
/** if users are accessing the projects without having enough permissions, redirect to My Projects page */ /** if users are accessing the projects without having enough permissions, redirect to My Projects page */
if (to.params.projectId) { if (to.params.projectId && from.params.projectId !== to.params.projectId) {
const user = await api.auth.me({ project_id: to?.params?.projectId as string }) const user = await api.auth.me({ project_id: to?.params?.projectId as string })
if (user?.roles?.user) { if (user?.roles?.user) {
message.error("You don't have enough permission to access the project.") message.error("You don't have enough permission to access the project.")

13
packages/nc-gui/nuxt.config.ts

@ -14,6 +14,11 @@ export default defineNuxtConfig({
ssr: false, ssr: false,
app: {
/** In production build we need to load assets using relative path, to achieve the result we are using cdnURL */
cdnURL: process.env.NODE_ENV === 'production' ? '.' : undefined,
},
css: [ css: [
'virtual:windi.css', 'virtual:windi.css',
'virtual:windi-devtools', 'virtual:windi-devtools',
@ -46,9 +51,10 @@ export default defineNuxtConfig({
}, },
vite: { vite: {
// todo: minifiy again
build: { build: {
minify: false, commonjsOptions: {
ignoreTryCatch: false,
},
}, },
plugins: [ plugins: [
vueI18n({ vueI18n({
@ -77,7 +83,8 @@ export default defineNuxtConfig({
], ],
define: { define: {
'process.env.DEBUG': 'false', 'process.env.DEBUG': 'false',
'process.nextTick': () => {}, 'process.nextTick': () => {
},
}, },
server: { server: {
watch: { watch: {

361
packages/nc-gui/package-lock.json generated

@ -6,12 +6,14 @@
"": { "": {
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@braks/vue-flow": "^0.4.39",
"@ckpack/vue-color": "^1.2.0", "@ckpack/vue-color": "^1.2.0",
"@vuelidate/core": "^2.0.0-alpha.44", "@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31", "@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2", "@vueuse/core": "^9.0.2",
"@vueuse/integrations": "^9.0.2", "@vueuse/integrations": "^9.0.2",
"ant-design-vue": "^3.2.11", "ant-design-vue": "^3.2.11",
"dagre": "^0.8.5",
"dayjs": "^1.11.3", "dayjs": "^1.11.3",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"httpsnippet": "^2.0.0", "httpsnippet": "^2.0.0",
@ -53,6 +55,7 @@
"@intlify/vite-plugin-vue-i18n": "^6.0.1", "@intlify/vite-plugin-vue-i18n": "^6.0.1",
"@nuxt/image-edge": "^1.0.0-27657146.da85542", "@nuxt/image-edge": "^1.0.0-27657146.da85542",
"@types/axios": "^0.14.0", "@types/axios": "^0.14.0",
"@types/dagre": "^0.7.48",
"@types/file-saver": "^2.0.5", "@types/file-saver": "^2.0.5",
"@types/papaparse": "^5.3.2", "@types/papaparse": "^5.3.2",
"@types/sortablejs": "^1.13.0", "@types/sortablejs": "^1.13.0",
@ -878,6 +881,103 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@braks/vue-flow": {
"version": "0.4.39",
"resolved": "https://registry.npmjs.org/@braks/vue-flow/-/vue-flow-0.4.39.tgz",
"integrity": "sha512-ZWKEwvEDKZe0Yw2sS8RxmxLs1k3O9DGFF0rk5xj+zWlExm15uBBhHAf8rWIRVULEbkjOmDwJEJ4bQrqwHn4pdA==",
"dependencies": {
"@vueuse/core": "^9.1.0",
"d3-drag": "^3.0.0",
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0"
},
"peerDependencies": {
"vue": "^3.2.25"
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/core": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.2.0.tgz",
"integrity": "sha512-/MZ6qpz6uSyaXrtoeBWQzAKRG3N7CvfVWvQxiM3ei3Xe5ydOjjtVbo7lGl9p8dECV93j7W8s63A8H0kFLpLyxg==",
"dependencies": {
"@types/web-bluetooth": "^0.0.15",
"@vueuse/metadata": "9.2.0",
"@vueuse/shared": "9.2.0",
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/metadata": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.2.0.tgz",
"integrity": "sha512-exN4KE6iquxDCdt72BgEhb3tlOpECtD61AUdXnUqBTIUCl70x1Ar/QXo3bYcvxmdMS2/peQyfeTzBjRTpvL5xw==",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/shared": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.2.0.tgz",
"integrity": "sha512-NnRp/noSWuXW0dKhZK5D0YLrDi0nmZ18UeEgwXQq7Ul5TTP93lcNnKjrHtd68j2xFB/l59yPGFlCryL692bnrA==",
"dependencies": {
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@braks/vue-flow/node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@ckpack/vue-color": { "node_modules/@ckpack/vue-color": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz",
@ -2347,6 +2447,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/dagre": {
"version": "0.7.48",
"resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.48.tgz",
"integrity": "sha512-rF3yXSwHIrDxEkN6edCE4TXknb5YSEpiXfLaspw1I08grC49ZFuAVGOQCmZGIuLUGoFgcqGlUFBL/XrpgYpQgw==",
"dev": true
},
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "8.4.3", "version": "8.4.3",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.3.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.3.tgz",
@ -5144,6 +5250,111 @@
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==", "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
"dev": true "dev": true
}, },
"node_modules/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-dispatch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-drag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"dependencies": {
"d3-color": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-selection": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-transition": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
"dependencies": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
"d3-ease": "1 - 3",
"d3-interpolate": "1 - 3",
"d3-timer": "1 - 3"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"d3-selection": "2 - 3"
}
},
"node_modules/d3-zoom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
"d3-interpolate": "1 - 3",
"d3-selection": "2 - 3",
"d3-transition": "2 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/dagre": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
"integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
"dependencies": {
"graphlib": "^2.1.8",
"lodash": "^4.17.15"
}
},
"node_modules/data-uri-to-buffer": { "node_modules/data-uri-to-buffer": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
@ -7882,6 +8093,14 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true "dev": true
}, },
"node_modules/graphlib": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
"integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
"dependencies": {
"lodash": "^4.17.15"
}
},
"node_modules/gzip-size": { "node_modules/gzip-size": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz",
@ -15831,6 +16050,59 @@
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
} }
}, },
"@braks/vue-flow": {
"version": "0.4.39",
"resolved": "https://registry.npmjs.org/@braks/vue-flow/-/vue-flow-0.4.39.tgz",
"integrity": "sha512-ZWKEwvEDKZe0Yw2sS8RxmxLs1k3O9DGFF0rk5xj+zWlExm15uBBhHAf8rWIRVULEbkjOmDwJEJ4bQrqwHn4pdA==",
"requires": {
"@vueuse/core": "^9.1.0",
"d3-drag": "^3.0.0",
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0"
},
"dependencies": {
"@vueuse/core": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.2.0.tgz",
"integrity": "sha512-/MZ6qpz6uSyaXrtoeBWQzAKRG3N7CvfVWvQxiM3ei3Xe5ydOjjtVbo7lGl9p8dECV93j7W8s63A8H0kFLpLyxg==",
"requires": {
"@types/web-bluetooth": "^0.0.15",
"@vueuse/metadata": "9.2.0",
"@vueuse/shared": "9.2.0",
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"requires": {}
}
}
},
"@vueuse/metadata": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.2.0.tgz",
"integrity": "sha512-exN4KE6iquxDCdt72BgEhb3tlOpECtD61AUdXnUqBTIUCl70x1Ar/QXo3bYcvxmdMS2/peQyfeTzBjRTpvL5xw=="
},
"@vueuse/shared": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.2.0.tgz",
"integrity": "sha512-NnRp/noSWuXW0dKhZK5D0YLrDi0nmZ18UeEgwXQq7Ul5TTP93lcNnKjrHtd68j2xFB/l59yPGFlCryL692bnrA==",
"requires": {
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"requires": {}
}
}
}
}
},
"@ckpack/vue-color": { "@ckpack/vue-color": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz",
@ -16999,6 +17271,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/dagre": {
"version": "0.7.48",
"resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.48.tgz",
"integrity": "sha512-rF3yXSwHIrDxEkN6edCE4TXknb5YSEpiXfLaspw1I08grC49ZFuAVGOQCmZGIuLUGoFgcqGlUFBL/XrpgYpQgw==",
"dev": true
},
"@types/eslint": { "@types/eslint": {
"version": "8.4.3", "version": "8.4.3",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.3.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.3.tgz",
@ -19096,6 +19374,81 @@
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==", "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
"dev": true "dev": true
}, },
"d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="
},
"d3-dispatch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="
},
"d3-drag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
"requires": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
}
},
"d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="
},
"d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"requires": {
"d3-color": "1 - 3"
}
},
"d3-selection": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
},
"d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="
},
"d3-transition": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
"requires": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
"d3-ease": "1 - 3",
"d3-interpolate": "1 - 3",
"d3-timer": "1 - 3"
}
},
"d3-zoom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
"requires": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
"d3-interpolate": "1 - 3",
"d3-selection": "2 - 3",
"d3-transition": "2 - 3"
}
},
"dagre": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
"integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
"requires": {
"graphlib": "^2.1.8",
"lodash": "^4.17.15"
}
},
"data-uri-to-buffer": { "data-uri-to-buffer": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
@ -21041,6 +21394,14 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true "dev": true
}, },
"graphlib": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
"integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
"requires": {
"lodash": "^4.17.15"
}
},
"gzip-size": { "gzip-size": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz",

3
packages/nc-gui/package.json

@ -15,12 +15,14 @@
"postinstall": "node scripts/updateNuxtRouting.js" "postinstall": "node scripts/updateNuxtRouting.js"
}, },
"dependencies": { "dependencies": {
"@braks/vue-flow": "^0.4.39",
"@ckpack/vue-color": "^1.2.0", "@ckpack/vue-color": "^1.2.0",
"@vuelidate/core": "^2.0.0-alpha.44", "@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31", "@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2", "@vueuse/core": "^9.0.2",
"@vueuse/integrations": "^9.0.2", "@vueuse/integrations": "^9.0.2",
"ant-design-vue": "^3.2.11", "ant-design-vue": "^3.2.11",
"dagre": "^0.8.5",
"dayjs": "^1.11.3", "dayjs": "^1.11.3",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"httpsnippet": "^2.0.0", "httpsnippet": "^2.0.0",
@ -62,6 +64,7 @@
"@intlify/vite-plugin-vue-i18n": "^6.0.1", "@intlify/vite-plugin-vue-i18n": "^6.0.1",
"@nuxt/image-edge": "^1.0.0-27657146.da85542", "@nuxt/image-edge": "^1.0.0-27657146.da85542",
"@types/axios": "^0.14.0", "@types/axios": "^0.14.0",
"@types/dagre": "^0.7.48",
"@types/file-saver": "^2.0.5", "@types/file-saver": "^2.0.5",
"@types/papaparse": "^5.3.2", "@types/papaparse": "^5.3.2",
"@types/sortablejs": "^1.13.0", "@types/sortablejs": "^1.13.0",

2
packages/nc-gui/pages/[projectType]/[projectId]/index.vue

@ -465,7 +465,7 @@ onBeforeUnmount(reset)
</a-layout-sider> </a-layout-sider>
</template> </template>
<div :key="$route.fullPath"> <div :key="$route.fullPath.split('?')[0]">
<dashboard-settings-modal v-model="dialogOpen" :open-key="openDialogKey" /> <dashboard-settings-modal v-model="dialogOpen" :open-key="openDialogKey" />
<NuxtPage /> <NuxtPage />

16
packages/nc-gui/pages/index/index/create-external.vue

@ -73,20 +73,20 @@ const validators = computed(() => {
projectTitleValidator, projectTitleValidator,
], ],
'extraParameters': [extraParameterValidator], 'extraParameters': [extraParameterValidator],
'dataSource.client': [fieldRequiredValidator], 'dataSource.client': [fieldRequiredValidator()],
...(formState.dataSource.client === ClientType.SQLITE ...(formState.dataSource.client === ClientType.SQLITE
? { ? {
'dataSource.connection.connection.filename': [fieldRequiredValidator], 'dataSource.connection.connection.filename': [fieldRequiredValidator()],
} }
: { : {
'dataSource.connection.host': [fieldRequiredValidator], 'dataSource.connection.host': [fieldRequiredValidator()],
'dataSource.connection.port': [fieldRequiredValidator], 'dataSource.connection.port': [fieldRequiredValidator()],
'dataSource.connection.user': [fieldRequiredValidator], 'dataSource.connection.user': [fieldRequiredValidator()],
'dataSource.connection.password': [fieldRequiredValidator], 'dataSource.connection.password': [fieldRequiredValidator()],
'dataSource.connection.database': [fieldRequiredValidator], 'dataSource.connection.database': [fieldRequiredValidator()],
...([ClientType.PG, ClientType.MSSQL].includes(formState.dataSource.client) ...([ClientType.PG, ClientType.MSSQL].includes(formState.dataSource.client)
? { ? {
'dataSource.searchPath.0': [fieldRequiredValidator], 'dataSource.searchPath.0': [fieldRequiredValidator()],
} }
: {}), : {}),
}), }),

72
packages/nc-gui/utils/validation.ts

@ -1,9 +1,14 @@
import { getI18n } from '~/plugins/a.i18n'
export const isEmail = (v: string) => export const isEmail = (v: string) =>
/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i.test(v) /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i.test(v)
export function validateTableName(v: string, isGQL = false) { export function validateTableName(v: string, isGQL = false) {
const { t } = getI18n().global
if (!v) { if (!v) {
return 'Table name required' // return 'Table name required'
return t('msg.error.tableNameRequired')
} }
// GraphQL naming convention // GraphQL naming convention
@ -15,11 +20,13 @@ export function validateTableName(v: string, isGQL = false) {
} }
if (/^[^_A-Za-z]/.test(v)) { if (/^[^_A-Za-z]/.test(v)) {
return 'Name should start with an alphabet or _' // return 'Name should start with an alphabet or _'
return t('msg.error.nameShouldStartWithAnAlphabetOr_')
} }
const m = v.match(/[^_A-Za-z\d]/g) const m = v.match(/[^_A-Za-z\d]/g)
if (m) { if (m) {
return `Following characters are not allowed ${m.map((c) => JSON.stringify(c)).join(', ')}` // return `Following characters are not allowed ${m.map((c) => JSON.stringify(c)).join(', ')}`
return `${t('msg.error.followingCharactersAreNotAllowed')} ${m.map((c) => JSON.stringify(c)).join(', ')}`
} }
} else { } else {
// exclude . / \ // exclude . / \
@ -27,7 +34,8 @@ export function validateTableName(v: string, isGQL = false) {
// https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/acreldb/n0rfg6x1shw0ppn1cwhco6yn09f7.htm#:~:text=By%20default%2C%20MySQL%20encloses%20column,not%20truncate%20a%20longer%20name. // https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/acreldb/n0rfg6x1shw0ppn1cwhco6yn09f7.htm#:~:text=By%20default%2C%20MySQL%20encloses%20column,not%20truncate%20a%20longer%20name.
const m = v.match(/[./\\]/g) const m = v.match(/[./\\]/g)
if (m) { if (m) {
return `Following characters are not allowed ${m.map((c) => JSON.stringify(c)).join(', ')}` // return `Following characters are not allowed ${m.map((c) => JSON.stringify(c)).join(', ')}`
return `${t('msg.error.followingCharactersAreNotAllowed')} ${m.map((c) => JSON.stringify(c)).join(', ')}`
} }
return true return true
@ -35,8 +43,10 @@ export function validateTableName(v: string, isGQL = false) {
} }
export function validateColumnName(v: string, isGQL = false) { export function validateColumnName(v: string, isGQL = false) {
const { t } = getI18n().global
if (!v) { if (!v) {
return 'Column name required' // return 'Column name required'
return t('msg.error.columnNameRequired')
} }
// GraphQL naming convention // GraphQL naming convention
@ -47,11 +57,13 @@ export function validateColumnName(v: string, isGQL = false) {
} }
if (/^[^_A-Za-z]/.test(v)) { if (/^[^_A-Za-z]/.test(v)) {
return 'Name should start with an alphabet or _' // return 'Name should start with an alphabet or _'
return t('msg.error.nameShouldStartWithAnAlphabetOr_')
} }
const m = v.match(/[^_A-Za-z\d]/g) const m = v.match(/[^_A-Za-z\d]/g)
if (m) { if (m) {
return `Following characters are not allowed ${m.map((c) => JSON.stringify(c)).join(', ')}` // return `Following characters are not allowed ${m.map((c) => JSON.stringify(c)).join(', ')}`
return `${t('msg.error.followingCharactersAreNotAllowed')} ${m.map((c) => JSON.stringify(c)).join(', ')}`
} }
} else { } else {
// exclude . / \ // exclude . / \
@ -59,7 +71,8 @@ export function validateColumnName(v: string, isGQL = false) {
// https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/acreldb/n0rfg6x1shw0ppn1cwhco6yn09f7.htm#:~:text=By%20default%2C%20MySQL%20encloses%20column,not%20truncate%20a%20longer%20name. // https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/acreldb/n0rfg6x1shw0ppn1cwhco6yn09f7.htm#:~:text=By%20default%2C%20MySQL%20encloses%20column,not%20truncate%20a%20longer%20name.
const m = v.match(/[./\\]/g) const m = v.match(/[./\\]/g)
if (m) { if (m) {
return `Following characters are not allowed ${m.map((c) => JSON.stringify(c)).join(', ')}` // return `Following characters are not allowed ${m.map((c) => JSON.stringify(c)).join(', ')}`
return `${t('msg.error.followingCharactersAreNotAllowed')} ${m.map((c) => JSON.stringify(c)).join(', ')}`
} }
return true return true
@ -68,36 +81,40 @@ export function validateColumnName(v: string, isGQL = false) {
export const projectTitleValidator = { export const projectTitleValidator = {
validator: (rule: any, value: any, callback: (errMsg?: string) => void) => { validator: (rule: any, value: any, callback: (errMsg?: string) => void) => {
const { t } = getI18n().global
if (value?.length > 50) { if (value?.length > 50) {
callback('Project name exceeds 50 characters') // callback('Project name exceeds 50 characters')
callback(t('msg.error.projectNameExceeds50Characters'))
} }
if (value[0] === ' ') { if (value[0] === ' ') {
callback('Project name cannot start with space') // callback('Project name cannot start with space')
callback(t('msg.error.projectNameCannotStartWithSpace'))
} }
callback() callback()
}, },
} }
export const fieldRequiredValidator = { export const fieldRequiredValidator = () => {
const { t } = getI18n().global
return {
required: true, required: true,
message: 'Field is required', // message: `Required field`,
message: t('msg.error.requiredField'),
}
} }
export const getRequiredValidator = (field = 'Field') => ({
required: true,
message: `${field} is required`,
})
export const importUrlValidator = { export const importUrlValidator = {
validator: (rule: any, value: any) => { validator: (rule: any, value: any) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const { t } = getI18n().global
if ( if (
/(10)(\.([2]([0-5][0-5]|[01234][6-9])|[1][0-9][0-9]|[1-9][0-9]|[0-9])){3}|(172)\.(1[6-9]|2[0-9]|3[0-1])(\.(2[0-4][0-9]|25[0-5]|[1][0-9][0-9]|[1-9][0-9]|[0-9])){2}|(192)\.(168)(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){2}|(0.0.0.0)|localhost?/g.test( /(10)(\.([2]([0-5][0-5]|[01234][6-9])|[1][0-9][0-9]|[1-9][0-9]|[0-9])){3}|(172)\.(1[6-9]|2[0-9]|3[0-1])(\.(2[0-4][0-9]|25[0-5]|[1][0-9][0-9]|[1-9][0-9]|[0-9])){2}|(192)\.(168)(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){2}|(0.0.0.0)|localhost?/g.test(
value, value,
) )
) { ) {
return reject(new Error('IP Not allowed!')) // return reject(new Error('IP Not allowed!'))
return reject(new Error(t('msg.error.ipNotAllowed')))
} }
return resolve(true) return resolve(true)
}) })
@ -107,8 +124,12 @@ export const importUrlValidator = {
export const importCsvUrlValidator = { export const importCsvUrlValidator = {
validator: (rule: any, value: any) => { validator: (rule: any, value: any) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const { t } = getI18n().global
if (value && !/.*\.(csv)/.test(value)) { if (value && !/.*\.(csv)/.test(value)) {
return reject(new Error('Target file is not an accepted file type. The accepted file type is .csv!')) // return reject(new Error('Target file is not an accepted file type. The accepted file type is .csv!'))
return reject(
new Error(`${t('msg.error.targetFileIsNotAnAcceptedFileType')}. ${t('msg.error.theAcceptedFileTypeIsCsv')}`),
)
} }
return resolve(true) return resolve(true)
}) })
@ -118,9 +139,13 @@ export const importCsvUrlValidator = {
export const importExcelUrlValidator = { export const importExcelUrlValidator = {
validator: (rule: any, value: any) => { validator: (rule: any, value: any) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const { t } = getI18n().global
if (value && !/.*\.(xls|xlsx|xlsm|ods|ots)/.test(value)) { if (value && !/.*\.(xls|xlsx|xlsm|ods|ots)/.test(value)) {
return reject( return reject(
new Error('Target file is not an accepted file type. The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots!'), // new Error('Target file is not an accepted file type. The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots!'),
new Error(
`${t('msg.error.targetFileIsNotAnAcceptedFileType')}. ${t('msg.error.theAcceptedFileTypesAreXlsXlsxXlsmOdsOts')}`,
),
) )
} }
return resolve(true) return resolve(true)
@ -131,12 +156,15 @@ export const importExcelUrlValidator = {
export const extraParameterValidator = { export const extraParameterValidator = {
validator: (_: unknown, value: { key: string; value: string }[]) => { validator: (_: unknown, value: { key: string; value: string }[]) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const { t } = getI18n().global
for (const param of value) { for (const param of value) {
if (param.key === '') { if (param.key === '') {
return reject(new Error('Parameter key cannot be empty')) // return reject(new Error('Parameter key cannot be empty'))
return reject(new Error(t('msg.error.parameterKeyCannotBeEmpty')))
} }
if (value.filter((el: any) => el.key === param.key).length !== 1) { if (value.filter((el: any) => el.key === param.key).length !== 1) {
return reject(new Error('Duplicate parameter keys are not allowed')) // return reject(new Error('Duplicate parameter keys are not allowed'))
return reject(new Error(t('msg.error.duplicateParameterKeysAreNotAllowed')))
} }
} }
return resolve(true) return resolve(true)

13
packages/noco-docs/content/en/setup-and-usages/meta-management.md

@ -55,16 +55,23 @@ From the destination project, go to `Project Metadata`. Under ``Export / Import
Go to `Project Metadata`, under ``Metadata``, you can see your metadata sync status. If it is out of sync, you can sync the schema. See <a href="./sync-schema">Sync Schema</a> for more. Go to `Project Metadata`, under ``Metadata``, you can see your metadata sync status. If it is out of sync, you can sync the schema. See <a href="./sync-schema">Sync Schema</a> for more.
<img width="1480" alt="image" src="https://user-images.githubusercontent.com/35857179/189116339-22b202ef-7674-4682-bab7-2b8625e13ea2.png"> <img width="1418" alt="image" src="https://user-images.githubusercontent.com/35809690/191258001-a4385df0-e796-4fa1-8ea4-a25361cd2d91.png">
## UI Access Control ## UI Access Control
Go to `Project Metadata`, under ``UI Access Control``, you can control the access to each table by roles. Go to `Project Metadata`, under ``UI Access Control``, you can control the access to each table by roles.
<img width="1480" alt="image" src="https://user-images.githubusercontent.com/35857179/189116502-78a0dc75-70cb-4bbe-a676-93af53ecca22.png"> <img width="1417" alt="image" src="https://user-images.githubusercontent.com/35809690/191258150-3abe8de9-bab9-46fe-9095-01b8815b57f2.png">
## ERD
Go to `Project Metadata`, under ``ERD View``, you can see the ERD of your database.
<img width="1419" alt="image" src="https://user-images.githubusercontent.com/35809690/191258324-18bd4ed0-521b-4480-a3f6-fe4660b8ddd5.png">
## Miscellaneous ## Miscellaneous
Currently only `Show M2M Tables` can be configurated under Miscellaneous. Currently only `Show M2M Tables` can be configurated under Miscellaneous.
<img width="1495" alt="image" src="https://user-images.githubusercontent.com/35857179/189116547-3c5ce944-82c0-4068-b91c-60f45b862d32.png"> <img width="1409" alt="image" src="https://user-images.githubusercontent.com/35809690/191258441-72a12941-2d2b-4a0d-84b8-f7f8783aa4e8.png">

664
packages/nocodb-sdk/package-lock.json generated

File diff suppressed because it is too large Load Diff

1
packages/nocodb-sdk/src/lib/Api.ts

@ -122,6 +122,7 @@ export interface TableType {
columnsById?: object; columnsById?: object;
slug?: string; slug?: string;
project_id?: string; project_id?: string;
mm?: boolean | number;
} }
export interface ViewType { export interface ViewType {

11
packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts

@ -3,6 +3,7 @@ import Model from '../../../models/Model';
import { nocoExecute } from 'nc-help'; import { nocoExecute } from 'nc-help';
import Base from '../../../models/Base'; import Base from '../../../models/Base';
import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2';
import { NcError } from '../../helpers/catchError';
import { PagedResponseImpl } from '../../helpers/PagedResponse'; import { PagedResponseImpl } from '../../helpers/PagedResponse';
import View from '../../../models/View'; import View from '../../../models/View';
import ncMetaAclMw from '../../helpers/ncMetaAclMw'; import ncMetaAclMw from '../../helpers/ncMetaAclMw';
@ -92,6 +93,7 @@ async function dataDelete(req: Request, res: Response) {
} }
res.json(await baseModel.delByPk(req.params.rowId, null, req)); res.json(await baseModel.delByPk(req.params.rowId, null, req));
} }
async function getDataList(model, view: View, req) { async function getDataList(model, view: View, req) {
const base = await Base.get(model.base_id); const base = await Base.get(model.base_id);
@ -190,10 +192,16 @@ async function dataRead(req: Request, res: Response) {
dbDriver: NcConnectionMgrv2.get(base), dbDriver: NcConnectionMgrv2.get(base),
}); });
const row = await baseModel.readByPk(req.params.rowId);
if (!row) {
NcError.notFound();
}
res.json( res.json(
await nocoExecute( await nocoExecute(
await getAst({ model, query: req.query, view }), await getAst({ model, query: req.query, view }),
await baseModel.readByPk(req.params.rowId), row,
{}, {},
{} {}
) )
@ -213,6 +221,7 @@ async function dataExist(req: Request, res: Response) {
res.json(await baseModel.exist(req.params.rowId)); res.json(await baseModel.exist(req.params.rowId));
} }
const router = Router({ mergeParams: true }); const router = Router({ mergeParams: true });
// table data crud apis // table data crud apis

60
scripts/cypress/integration/common/1b_table_column_operations.js

@ -11,16 +11,18 @@ export const genTest = (apiType, dbType) => {
cy.get(".nc-add-new-row-btn:visible").should("exist"); cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click(); cy.get(".nc-add-new-row-btn").click();
// cy.get("#data-table-form-Title > input").first().type(cellValue); // cy.get("#data-table-form-Title > input").first().type(cellValue);
cy.get(".nc-expand-col-Title").find(".nc-cell > input") cy.get(".nc-expand-col-Title")
.find(".nc-cell > input")
.should("exist") .should("exist")
.first() .first()
.clear() .clear()
.type(cellValue); .type(cellValue);
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Save row") .contains("Save row")
.click({ force: true }); .should("exist")
.click();
cy.toastWait("updated successfully"); cy.toastWait("updated successfully");
cy.get("body").type("{esc}"); cy.get("body").type("{esc}");
@ -41,11 +43,11 @@ export const genTest = (apiType, dbType) => {
beforeEach(() => { beforeEach(() => {
cy.restoreLocalStorage(); cy.restoreLocalStorage();
}) });
afterEach(() => { afterEach(() => {
cy.saveLocalStorage(); cy.saveLocalStorage();
}) });
// // delete table // // delete table
// after(() => { // after(() => {
@ -59,7 +61,6 @@ export const genTest = (apiType, dbType) => {
// edit the newly created column // edit the newly created column
it("Edit table column - change datatype", () => { it("Edit table column - change datatype", () => {
if (!isXcdb()) { if (!isXcdb()) {
cy.get(`th:contains(${colName}) .nc-icon.ant-dropdown-trigger`) cy.get(`th:contains(${colName}) .nc-icon.ant-dropdown-trigger`)
.trigger("mouseover", { force: true }) .trigger("mouseover", { force: true })
@ -71,17 +72,20 @@ export const genTest = (apiType, dbType) => {
.find(".nc-column-edit") .find(".nc-column-edit")
.click(); .click();
// fix me! wait till the modal rendering (input highlight) is completed
cy.wait(500);
// change column type and verify // change column type and verify
// cy.get(".nc-column-type-input").last().click(); // cy.get(".nc-column-type-input").last().click();
cy.getActiveMenu('.nc-dropdown-edit-column') cy.getActiveMenu(".nc-dropdown-edit-column")
.find(".nc-column-type-input") .find(".nc-column-type-input")
.last() .last()
.click(); .click();
cy.getActiveSelection('.nc-dropdown-column-type') cy.getActiveSelection(".nc-dropdown-column-type")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains("LongText") .contains("LongText")
.click(); .click();
cy.getActiveMenu('.nc-dropdown-edit-column') cy.getActiveMenu(".nc-dropdown-edit-column")
.find(".ant-btn-primary:visible") .find(".ant-btn-primary:visible")
.contains("Save") .contains("Save")
.click(); .click();
@ -103,12 +107,13 @@ export const genTest = (apiType, dbType) => {
.click(); .click();
// rename column and verify // rename column and verify
cy.getActiveMenu(".nc-dropdown-edit-column").find('input.nc-column-name-input', { timeout: 3000 }) cy.getActiveMenu(".nc-dropdown-edit-column")
.should('exist') .find("input.nc-column-name-input", { timeout: 3000 })
.should("exist")
.clear() .clear()
.type(updatedColName); .type(updatedColName);
// cy.get(".ant-btn-primary:visible").contains("Save").click(); // cy.get(".ant-btn-primary:visible").contains("Save").click();
cy.getActiveMenu('.nc-dropdown-edit-column') cy.getActiveMenu(".nc-dropdown-edit-column")
.find(".ant-btn-primary:visible") .find(".ant-btn-primary:visible")
.contains("Save") .contains("Save")
.click(); .click();
@ -131,30 +136,31 @@ export const genTest = (apiType, dbType) => {
it("Update row", () => { it("Update row", () => {
mainPage mainPage
.getRow(1) .getRow(1)
.find('.nc-row-no').should('exist').eq(0).trigger('mouseover', { force: true }) .find(".nc-row-no")
cy.get(".nc-row-expand") .should("exist")
.click({ force: true }); .eq(0)
.trigger("mouseover", { force: true });
cy.get(".nc-row-expand").click({ force: true });
cy.get(".nc-expand-col-Title").find(".nc-cell > input") cy.get(".nc-expand-col-Title")
.find(".nc-cell > input")
.should("exist") .should("exist")
.first() .first()
.clear() .clear()
.type(updatedRandVal); .type(updatedRandVal);
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Save row") .contains("Save row")
.click({ force: true }); .should("exist")
.click();
// partial toast message // partial toast message
cy.toastWait("updated successfully"); cy.toastWait("updated successfully");
cy.get("body").type("{esc}"); cy.get("body").type("{esc}");
mainPage.getCell("Title", 1).contains(randVal).should("not.exist"); mainPage.getCell("Title", 1).contains(randVal).should("not.exist");
mainPage mainPage.getCell("Title", 1).contains(updatedRandVal).should("exist");
.getCell("Title", 1)
.contains(updatedRandVal)
.should("exist");
}); });
it("Delete Row", () => { it("Delete Row", () => {
@ -179,9 +185,11 @@ export const genTest = (apiType, dbType) => {
addNewRow(4, "a4"); addNewRow(4, "a4");
addNewRow(5, "a5"); addNewRow(5, "a5");
cy.get('.nc-no-label').should('exist').eq(0).trigger('mouseover', { force: true }) cy.get(".nc-no-label")
cy.get(".ant-checkbox").should('exist') .should("exist")
.eq(0).click({ force: true }); .eq(0)
.trigger("mouseover", { force: true });
cy.get(".ant-checkbox").should("exist").eq(0).click({ force: true });
// delete selected rows // delete selected rows
mainPage.getCell("Title", 3).rightclick({ force: true }); mainPage.getCell("Title", 3).rightclick({ force: true });

54
scripts/cypress/integration/common/2b_table_with_m2m_column.js

@ -11,11 +11,11 @@ export const genTest = (apiType, dbType) => {
beforeEach(() => { beforeEach(() => {
cy.restoreLocalStorage(); cy.restoreLocalStorage();
}) });
afterEach(() => { afterEach(() => {
cy.saveLocalStorage(); cy.saveLocalStorage();
}) });
// after(() => { // after(() => {
// cy.closeTableTab("Actor"); // cy.closeTableTab("Actor");
@ -31,20 +31,26 @@ export const genTest = (apiType, dbType) => {
it("M2m chip content validation on grid", () => { it("M2m chip content validation on grid", () => {
// grid m2m content validation // grid m2m content validation
mainPage.getCell("Film List", 1) mainPage
.find('.nc-virtual-cell > .chips-wrapper > .chips > .group > .name') .getCell("Film List", 1)
.find(".nc-virtual-cell > .chips-wrapper > .chips > .group > .name")
.contains("ACADEMY DINOSAUR") .contains("ACADEMY DINOSAUR")
.should('exist'); .should("exist");
mainPage.getCell("Film List", 1) mainPage
.find('.nc-virtual-cell > .chips-wrapper > .chips > .group > .name') .getCell("Film List", 1)
.find(".nc-virtual-cell > .chips-wrapper > .chips > .group > .name")
.contains("ANACONDA CONFESSIONS") .contains("ANACONDA CONFESSIONS")
.should('exist'); .should("exist");
}); });
it("Expand m2m column", () => { it("Expand m2m column", () => {
// expand first row // expand first row
mainPage.getCell("Film List", 1).should("exist").trigger("mouseover").click(); mainPage
cy.get('.nc-action-icon').eq(0).should('exist').click({ force: true }); .getCell("Film List", 1)
.should("exist")
.trigger("mouseover")
.click();
cy.get(".nc-action-icon").eq(0).should("exist").click({ force: true });
// GUI-v2 Kludge: // GUI-v2 Kludge:
// validations // validations
@ -66,7 +72,9 @@ export const genTest = (apiType, dbType) => {
.click() .click()
.then(() => { .then(() => {
// Link record form validation // Link record form validation
cy.getActiveModal(".nc-modal-link-record").contains("Link record").should("exist"); cy.getActiveModal(".nc-modal-link-record")
.contains("Link record")
.should("exist");
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find(".nc-reload") .find(".nc-reload")
.should("exist"); .should("exist");
@ -78,15 +86,20 @@ export const genTest = (apiType, dbType) => {
.eq(0) .eq(0)
.contains("ACE GOLDFINGER") .contains("ACE GOLDFINGER")
.should("exist"); .should("exist");
cy.getActiveModal(".nc-modal-link-record").find("button.ant-modal-close").click(); cy.getActiveModal(".nc-modal-link-record")
.find("button.ant-modal-close")
.click();
}); });
}); });
it("Expand first linked card, validate", () => { it("Expand first linked card, validate", () => {
// expand first row // expand first row
mainPage.getCell("Film List", 1).should("exist").trigger("mouseover").click(); mainPage
cy.get('.nc-action-icon').eq(0).should('exist').click({ force: true }); .getCell("Film List", 1)
.should("exist")
.trigger("mouseover")
.click();
cy.get(".nc-action-icon").eq(0).should("exist").click({ force: true });
cy.getActiveModal(".nc-modal-child-list") cy.getActiveModal(".nc-modal-child-list")
.find(".ant-card") .find(".ant-card")
@ -95,21 +108,22 @@ export const genTest = (apiType, dbType) => {
.click() .click()
.then(() => { .then(() => {
// wait to ensure pop up appears before we proceed further // wait to ensure pop up appears before we proceed further
cy.wait(1000) cy.wait(1000);
// Link card validation // Link card validation
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".text-lg") .find(".text-lg")
.contains("ACADEMY DINOSAUR") .contains("ACADEMY DINOSAUR")
.should("exist"); .should("exist");
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find('button:contains("Save row")') .find('button:contains("Save row")')
.should("exist"); .should("exist");
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find('button:contains("Cancel")') .find('button:contains("Cancel")')
.should("exist"); .should("exist");
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find('button:contains("Cancel")') .find('button:contains("Cancel")')
.should("exist")
.click(); .click();
cy.getActiveModal().find("button.ant-modal-close").click(); cy.getActiveModal().find("button.ant-modal-close").click();
}); });

49
scripts/cypress/integration/common/3a_filter_sort_fields_operations.js

@ -19,11 +19,11 @@ export const genTest = (apiType, dbType) => {
beforeEach(() => { beforeEach(() => {
cy.restoreLocalStorage(); cy.restoreLocalStorage();
}) });
afterEach(() => { afterEach(() => {
cy.saveLocalStorage(); cy.saveLocalStorage();
}) });
it("Check country table - Pagination", () => { it("Check country table - Pagination", () => {
cy.openTableTab("Country", 25); cy.openTableTab("Country", 25);
@ -49,10 +49,14 @@ export const genTest = (apiType, dbType) => {
// add a row to end of Country table // add a row to end of Country table
cy.get(".nc-add-new-row-btn").click(); cy.get(".nc-add-new-row-btn").click();
cy.wait(1000); cy.wait(1000);
cy.get(".nc-expand-col-Country").find(".nc-cell > input").first().type("Test Country"); cy.get(".nc-expand-col-Country")
cy.getActiveDrawer() .find(".nc-cell > input")
.first()
.type("Test Country");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".ant-btn-primary") .find(".ant-btn-primary")
.contains("Save row") .contains("Save row")
.should("exist")
.click(); .click();
// cy.get("#data-table-form-Country > input") // cy.get("#data-table-form-Country > input")
@ -61,19 +65,17 @@ export const genTest = (apiType, dbType) => {
// cy.contains("Save row").filter("button").click(); // cy.contains("Save row").filter("button").click();
cy.toastWait("updated successfully"); cy.toastWait("updated successfully");
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".ant-btn") .find(".ant-btn")
.contains("Cancel") .contains("Cancel")
.should("exist")
.click(); .click();
// verify // verify
mainPage.getPagination(5).click(); mainPage.getPagination(5).click();
// kludge: flicker on load // kludge: flicker on load
cy.wait(3000) cy.wait(3000);
mainPage mainPage.getCell("Country", 10).contains("Test Country").should("exist");
.getCell("Country", 10)
.contains("Test Country")
.should("exist");
}); });
// delete single row // delete single row
@ -81,7 +83,9 @@ export const genTest = (apiType, dbType) => {
it("Delete Row", () => { it("Delete Row", () => {
// delete row added in previous step // delete row added in previous step
mainPage.getCell("Country", 10).rightclick(); mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu(".nc-dropdown-grid-context-menu").contains("Delete Row").click(); cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Row")
.click();
// cy.toastWait('Deleted row successfully') // cy.toastWait('Deleted row successfully')
@ -135,10 +139,8 @@ export const genTest = (apiType, dbType) => {
// delete selected rows (multiple) // delete selected rows (multiple)
// //
it.skip("Delete Selected", () => { it.skip("Delete Selected", () => {
cy.get(".ant-checkbox").should('exist') cy.get(".ant-checkbox").should("exist").eq(10).click({ force: true });
.eq(10).click({ force: true }); cy.get(".ant-checkbox").should("exist").eq(11).click({ force: true });
cy.get(".ant-checkbox").should('exist')
.eq(11).click({ force: true });
mainPage.getCell("Country", 10).rightclick({ force: true }); mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu") cy.getActiveMenu(".nc-dropdown-grid-context-menu")
@ -148,17 +150,12 @@ export const genTest = (apiType, dbType) => {
// verify // verify
// mainPage.getCell("Country", 10).should("not.exist"); // mainPage.getCell("Country", 10).should("not.exist");
// mainPage.getCell("Country", 11).should("not.exist"); // mainPage.getCell("Country", 11).should("not.exist");
cy.get( cy.get(`:nth-child(10) > [data-title="Country"]`).should("not.exist");
`:nth-child(10) > [data-title="Country"]` cy.get(`:nth-child(11) > [data-title="Country"]`).should("not.exist");
).should("not.exist");
cy.get(
`:nth-child(11) > [data-title="Country"]`
).should("not.exist");
mainPage.getPagination(1).click(); mainPage.getPagination(1).click();
}); });
it("Enable sort", () => { it("Enable sort", () => {
mainPage.sortField("Country", "Z → A"); mainPage.sortField("Country", "Z → A");
cy.contains("Zambia").should("exist"); cy.contains("Zambia").should("exist");
@ -180,17 +177,13 @@ export const genTest = (apiType, dbType) => {
it("Create Filter", () => { it("Create Filter", () => {
mainPage.filterField("Country", "is equal", "India"); mainPage.filterField("Country", "is equal", "India");
// cy.get("td:contains(India)").should("exist"); // cy.get("td:contains(India)").should("exist");
mainPage.getCell("Country", 1) mainPage.getCell("Country", 1).contains("India").should("exist");
.contains("India")
.should("exist");
}); });
it("Delete Filter", () => { it("Delete Filter", () => {
// remove sort and check // remove sort and check
mainPage.filterReset(); mainPage.filterReset();
mainPage.getCell("Country", 1) mainPage.getCell("Country", 1).contains("India").should("not.exist");
.contains("India")
.should("not.exist");
// cy.contains("td:contains(India)").should("not.exist"); // cy.contains("td:contains(India)").should("not.exist");
cy.closeTableTab("Country"); cy.closeTableTab("Country");

30
scripts/cypress/integration/common/3c_lookup_column.js

@ -34,7 +34,7 @@ export const genTest = (apiType, dbType) => {
afterEach(() => { afterEach(() => {
cy.saveLocalStorage(); cy.saveLocalStorage();
}) });
// after(() => { // after(() => {
// cy.closeTableTab("City"); // cy.closeTableTab("City");
@ -43,42 +43,44 @@ export const genTest = (apiType, dbType) => {
// Routine to create a new look up column // Routine to create a new look up column
// //
const addLookUpColumn = (childTable, childCol) => { const addLookUpColumn = (childTable, childCol) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({ cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true, force: true,
}); });
cy.getActiveMenu(".nc-dropdown-grid-add-column") cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find('input.nc-column-name-input') .find("input.nc-column-name-input")
.should('exist') .should("exist")
.clear() .clear()
.type(childCol); .type(childCol);
// cy.get(".nc-column-type-input").last().click().type("Lookup"); // cy.get(".nc-column-type-input").last().click().type("Lookup");
cy.getActiveMenu('.nc-dropdown-grid-add-column') cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".nc-column-type-input") .find(".nc-column-type-input")
.last() .last()
.click() .click()
.type("Lookup"); .type("Lookup");
cy.getActiveSelection('.nc-dropdown-column-type') cy.getActiveSelection(".nc-dropdown-column-type")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains("Lookup") .contains("Lookup")
.click(); .click();
// wait for re-rendering & title selection to re-appear
cy.wait(500);
// Configure Child table & column names // Configure Child table & column names
fetchParentFromLabel("Child table"); fetchParentFromLabel("Child table");
cy.getActiveSelection('.nc-dropdown-relation-table') cy.getActiveSelection(".nc-dropdown-relation-table")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains(childTable) .contains(childTable)
.click(); .click();
fetchParentFromLabel("Child column"); fetchParentFromLabel("Child column");
cy.getActiveSelection('.nc-dropdown-relation-column') cy.getActiveSelection(".nc-dropdown-relation-column")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains(childCol) .contains(childCol)
.click(); .click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click(); // cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu('.nc-dropdown-grid-add-column') cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".ant-btn-primary:visible") .find(".ant-btn-primary:visible")
.contains("Save") .contains("Save")
.click(); .click();
@ -102,9 +104,7 @@ export const genTest = (apiType, dbType) => {
addLookUpColumn("Address", "PostalCode"); addLookUpColumn("Address", "PostalCode");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)' // Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
mainPage.getCell("PostalCode", 1) mainPage.getCell("PostalCode", 1).contains("4166").should("exist");
.contains("4166")
.should("exist");
deleteColumnByName("PostalCode"); deleteColumnByName("PostalCode");

38
scripts/cypress/integration/common/3d_rollup_column.js

@ -31,11 +31,11 @@ export const genTest = (apiType, dbType) => {
beforeEach(() => { beforeEach(() => {
cy.restoreLocalStorage(); cy.restoreLocalStorage();
}) });
afterEach(() => { afterEach(() => {
cy.saveLocalStorage(); cy.saveLocalStorage();
}) });
// after(() => { // after(() => {
// cy.closeTableTab("Country"); // cy.closeTableTab("Country");
@ -49,48 +49,50 @@ export const genTest = (apiType, dbType) => {
childCol, childCol,
aggregateFunc aggregateFunc
) => { ) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({ cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true, force: true,
}); });
cy.getActiveMenu(".nc-dropdown-grid-add-column") cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find('input.nc-column-name-input') .find("input.nc-column-name-input")
.should('exist') .should("exist")
.clear() .clear()
.type(columnName); .type(columnName);
// cy.get(".nc-column-type-input").last().click().type("RollUp"); // cy.get(".nc-column-type-input").last().click().type("RollUp");
cy.getActiveMenu('.nc-dropdown-grid-add-column') cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".nc-column-type-input") .find(".nc-column-type-input")
.last() .last()
.click() .click()
.type("RollUp") .type("RollUp");
cy.getActiveSelection('.nc-dropdown-column-type') cy.getActiveSelection(".nc-dropdown-column-type")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains("Rollup") .contains("Rollup")
.click(); .click();
// wait for re-rendering & title selection to re-appear
cy.wait(500);
// Configure Child table & column names // Configure Child table & column names
fetchParentFromLabel("Child table"); fetchParentFromLabel("Child table");
cy.getActiveSelection('.nc-dropdown-relation-table') cy.getActiveSelection(".nc-dropdown-relation-table")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains(childTable) .contains(childTable)
.click(); .click();
fetchParentFromLabel("Child column"); fetchParentFromLabel("Child column");
cy.getActiveSelection('.nc-dropdown-relation-column') cy.getActiveSelection(".nc-dropdown-relation-column")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains(childCol) .contains(childCol)
.click(); .click();
fetchParentFromLabel("Aggregate function"); fetchParentFromLabel("Aggregate function");
cy.getActiveSelection('.nc-dropdown-rollup-function') cy.getActiveSelection(".nc-dropdown-rollup-function")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains(aggregateFunc) .contains(aggregateFunc)
.click(); .click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click(); // cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu('.nc-dropdown-grid-add-column') cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".ant-btn-primary:visible") .find(".ant-btn-primary:visible")
.contains("Save") .contains("Save")
.click(); .click();
@ -138,9 +140,7 @@ export const genTest = (apiType, dbType) => {
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)' // Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
// intentionally verifying 4th item, as initial items are being masked out by list scroll down // intentionally verifying 4th item, as initial items are being masked out by list scroll down
mainPage.getCell("RollUpCol", 4) mainPage.getCell("RollUpCol", 4).contains("2").should("exist");
.contains("2")
.should("exist");
// editColumnByName("RollUpCol_2", "RollUpCol_New"); // editColumnByName("RollUpCol_2", "RollUpCol_New");
deleteColumnByName("RollUpCol"); deleteColumnByName("RollUpCol");

85
scripts/cypress/integration/common/3e_duration_column.js

@ -1,7 +1,5 @@
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
import { import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
isTestSuiteActive,
} from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return; if (!isTestSuiteActive(apiType, dbType)) return;
@ -29,8 +27,7 @@ export const genTest = (apiType, dbType) => {
cy.createTable(tableName); cy.createTable(tableName);
}); });
beforeEach(() => { beforeEach(() => {});
});
after(() => { after(() => {
cy.deleteTable(tableName); cy.deleteTable(tableName);
@ -39,36 +36,35 @@ export const genTest = (apiType, dbType) => {
// Routine to create a new look up column // Routine to create a new look up column
// //
const addDurationColumn = (columnName, durationFormat) => { const addDurationColumn = (columnName, durationFormat) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({ cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true, force: true,
}); });
cy.getActiveMenu(".nc-dropdown-grid-add-column") cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find('input.nc-column-name-input', { timeout: 3000 }) .find("input.nc-column-name-input", { timeout: 3000 })
.should('exist') .should("exist")
.clear() .clear()
.type(columnName); .type(columnName);
// cy.get(".nc-column-type-input").last().click().type("Duration"); // cy.get(".nc-column-type-input").last().click().type("Duration");
cy.getActiveMenu('.nc-dropdown-grid-add-column') cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".nc-column-type-input") .find(".nc-column-type-input")
.last() .last()
.click() .click()
.type("Duration") .type("Duration");
cy.getActiveSelection('.nc-dropdown-column-type') cy.getActiveSelection(".nc-dropdown-column-type")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains("Duration") .contains("Duration")
.click(); .click();
// Configure Duration format // Configure Duration format
fetchParentFromLabel("Duration Format"); fetchParentFromLabel("Duration Format");
cy.getActiveSelection('.nc-dropdown-duration-option') cy.getActiveSelection(".nc-dropdown-duration-option")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains(durationFormat) .contains(durationFormat)
.click(); .click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click(); // cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu('.nc-dropdown-grid-add-column') cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".ant-btn-primary:visible") .find(".ant-btn-primary:visible")
.contains("Save") .contains("Save")
.click(); .click();
@ -86,7 +82,6 @@ export const genTest = (apiType, dbType) => {
// routine to edit column // routine to edit column
// //
const editColumnByName = (oldName, newName, newDurationFormat) => { const editColumnByName = (oldName, newName, newDurationFormat) => {
cy.get(`th:contains(${oldName}) .nc-icon.ant-dropdown-trigger`) cy.get(`th:contains(${oldName}) .nc-icon.ant-dropdown-trigger`)
.trigger("mouseover", { force: true }) .trigger("mouseover", { force: true })
.click({ force: true }); .click({ force: true });
@ -99,19 +94,19 @@ export const genTest = (apiType, dbType) => {
// rename column and verify // rename column and verify
cy.getActiveMenu(".nc-dropdown-edit-column") cy.getActiveMenu(".nc-dropdown-edit-column")
.find('input.nc-column-name-input', { timeout: 3000 }) .find("input.nc-column-name-input", { timeout: 3000 })
.should('exist') .should("exist")
.clear() .clear()
.type(newName); .type(newName);
// Configure Duration format // Configure Duration format
fetchParentFromLabel("Duration Format"); fetchParentFromLabel("Duration Format");
cy.getActiveSelection('.nc-dropdown-duration-option') cy.getActiveSelection(".nc-dropdown-duration-option")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains(newDurationFormat) .contains(newDurationFormat)
.click(); .click();
// cy.get(".ant-btn-primary:visible").contains("Save").click(); // cy.get(".ant-btn-primary:visible").contains("Save").click();
cy.getActiveMenu('.nc-dropdown-edit-column') cy.getActiveMenu(".nc-dropdown-edit-column")
.find(".ant-btn-primary:visible") .find(".ant-btn-primary:visible")
.contains("Save") .contains("Save")
.click(); .click();
@ -122,10 +117,16 @@ export const genTest = (apiType, dbType) => {
cy.get(`th:contains(${newName})`).should("exist"); cy.get(`th:contains(${newName})`).should("exist");
}; };
const addDurationData = (colName, index, cellValue, expectedValue, isNewRow = false) => { const addDurationData = (
colName,
index,
cellValue,
expectedValue,
isNewRow = false
) => {
if (isNewRow) { if (isNewRow) {
cy.get(".nc-add-new-row-btn:visible").should("exist"); cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.wait(500) cy.wait(500);
cy.get(".nc-add-new-row-btn").click(); cy.get(".nc-add-new-row-btn").click();
} else { } else {
// mainPage.getRow(index).find(".nc-row-expand-icon").click({ force: true }); // mainPage.getRow(index).find(".nc-row-expand-icon").click({ force: true });
@ -133,17 +134,26 @@ export const genTest = (apiType, dbType) => {
.eq(index - 1) .eq(index - 1)
.click({ force: true }); .click({ force: true });
} }
cy.get(".duration-cell-wrapper > input").first().should('exist').type(cellValue); cy.get(".duration-cell-wrapper > input")
cy.getActiveDrawer().find("button").contains("Save row").click({ force: true }); .first()
.should("exist")
.type(cellValue);
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Save row")
.should("exist")
.click();
cy.toastWait("Row updated successfully"); cy.toastWait("Row updated successfully");
cy.getActiveDrawer().find("button").contains("Cancel").click({ force: true }); cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Cancel")
.should("exist")
.click();
// mainPage.getCell(colName, index).find('input').then(($e) => { // mainPage.getCell(colName, index).find('input').then(($e) => {
// expect($e[0].value).to.equal(expectedValue) // expect($e[0].value).to.equal(expectedValue)
// }) // })
mainPage.getCell(colName, index) mainPage.getCell(colName, index).contains(expectedValue).should("exist");
.contains(expectedValue) };
.should("exist");
}
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// Test case // Test case
@ -202,7 +212,10 @@ export const genTest = (apiType, dbType) => {
{ {
// h:mm:ss.s // h:mm:ss.s
it("Duration: h:mm:ss.s", () => { it("Duration: h:mm:ss.s", () => {
addDurationColumn("NC_DURATION_2", "h:mm:ss.s (e.g. 3:34.6, 1:23:40.0)"); addDurationColumn(
"NC_DURATION_2",
"h:mm:ss.s (e.g. 3:34.6, 1:23:40.0)"
);
addDurationData("NC_DURATION_2", 1, "1234", "00:20:34.0"); addDurationData("NC_DURATION_2", 1, "1234", "00:20:34.0");
addDurationData("NC_DURATION_2", 2, "12:34", "00:12:34.0"); addDurationData("NC_DURATION_2", 2, "12:34", "00:12:34.0");
addDurationData("NC_DURATION_2", 3, "12:34:56", "12:34:56.0"); addDurationData("NC_DURATION_2", 3, "12:34:56", "12:34:56.0");
@ -228,7 +241,10 @@ export const genTest = (apiType, dbType) => {
{ {
// h:mm:ss.ss // h:mm:ss.ss
it("Duration: h:mm:ss.ss", () => { it("Duration: h:mm:ss.ss", () => {
addDurationColumn("NC_DURATION_3", "h:mm:ss.ss (e.g. 3.45.67, 1:23:40.00)"); addDurationColumn(
"NC_DURATION_3",
"h:mm:ss.ss (e.g. 3.45.67, 1:23:40.00)"
);
addDurationData("NC_DURATION_3", 1, "1234", "00:20:34.00"); addDurationData("NC_DURATION_3", 1, "1234", "00:20:34.00");
addDurationData("NC_DURATION_3", 2, "12:34", "00:12:34.00"); addDurationData("NC_DURATION_3", 2, "12:34", "00:12:34.00");
addDurationData("NC_DURATION_3", 3, "12:34:56", "12:34:56.00"); addDurationData("NC_DURATION_3", 3, "12:34:56", "12:34:56.00");
@ -254,7 +270,10 @@ export const genTest = (apiType, dbType) => {
{ {
// h:mm:ss.sss // h:mm:ss.sss
it("Duration: h:mm:ss.sss", () => { it("Duration: h:mm:ss.sss", () => {
addDurationColumn("NC_DURATION_4", "h:mm:ss.sss (e.g. 3.45.678, 1:23:40.000)"); addDurationColumn(
"NC_DURATION_4",
"h:mm:ss.sss (e.g. 3.45.678, 1:23:40.000)"
);
addDurationData("NC_DURATION_4", 1, "1234", "00:20:34.000"); addDurationData("NC_DURATION_4", 1, "1234", "00:20:34.000");
addDurationData("NC_DURATION_4", 2, "12:34", "00:12:34.000"); addDurationData("NC_DURATION_4", 2, "12:34", "00:12:34.000");
addDurationData("NC_DURATION_4", 3, "12:34:56", "12:34:56.000"); addDurationData("NC_DURATION_4", 3, "12:34:56", "12:34:56.000");

151
scripts/cypress/integration/common/3f_link_to_another_record.js

@ -6,22 +6,20 @@ export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - Link to another record`, () => { describe(`${apiType.toUpperCase()} api - Link to another record`, () => {
function fetchParentFromLabel(label) { function fetchParentFromLabel(label) {
cy.get("label").contains(label).parents(".ant-row").click(); cy.get("label").contains(label).parents(".ant-row").click();
} }
// Insert new row // Insert new row
function addRow(index, cellValue) { function addRow(index, cellValue) {
cy.get('.nc-grid-add-new-cell').should('exist').click(); cy.get(".nc-grid-add-new-cell").should("exist").click();
mainPage.getCell('Title', index) mainPage
.dblclick().then(($el) => { .getCell("Title", index)
cy.wrap($el).find('input') .dblclick()
.clear() .then(($el) => {
.type(`${cellValue}{enter}`); cy.wrap($el).find("input").clear().type(`${cellValue}{enter}`);
}); });
mainPage.getCell('Title', index) mainPage.getCell("Title", index).contains(cellValue).should("exist");
.contains(cellValue).should('exist');
} }
// Insert LTAR column // Insert LTAR column
@ -31,8 +29,9 @@ export const genTest = (apiType, dbType) => {
cy.get(".nc-grid tr > th:last .nc-icon").click(); cy.get(".nc-grid tr > th:last .nc-icon").click();
// Column name // Column name
cy.getActiveMenu(".nc-dropdown-grid-add-column").find('input.nc-column-name-input', { timeout: 3000 }) cy.getActiveMenu(".nc-dropdown-grid-add-column")
.should('exist') .find("input.nc-column-name-input", { timeout: 3000 })
.should("exist")
.clear() .clear()
.type(columnName); .type(columnName);
@ -40,30 +39,27 @@ export const genTest = (apiType, dbType) => {
// cy.get(".nc-column-type-input").last() // cy.get(".nc-column-type-input").last()
// .click() // .click()
// .type("Link"); // .type("Link");
cy.getActiveMenu('.nc-dropdown-grid-add-column') cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".nc-column-type-input") .find(".nc-column-type-input")
.last() .last()
.click() .click()
.type("Link") .type("Link");
cy.getActiveSelection('.nc-dropdown-column-type') cy.getActiveSelection(".nc-dropdown-column-type")
.find('.ant-select-item-option') .find(".ant-select-item-option")
.contains("LinkToAnotherRecord") .contains("LinkToAnotherRecord")
.click(); .click();
// relation type (hm/ mm) // relation type (hm/ mm)
cy.get('.nc-ltar-relation-type') cy.get(".nc-ltar-relation-type")
.find('.ant-radio') .find(".ant-radio")
.eq(relationType==='hm'?0:1) .eq(relationType === "hm" ? 0 : 1)
.click(); .click();
// Foreign table // Foreign table
fetchParentFromLabel("Child table"); fetchParentFromLabel("Child table");
cy.get(".nc-ltar-child-table") cy.get(".nc-ltar-child-table").last().click().type(foreignTable);
.last() cy.getActiveSelection(".nc-dropdown-ltar-child-table")
.click() .find(".ant-select-item-option")
.type(foreignTable);
cy.getActiveSelection('.nc-dropdown-ltar-child-table')
.find('.ant-select-item-option')
.contains(foreignTable) .contains(foreignTable)
.click(); .click();
@ -72,7 +68,7 @@ export const genTest = (apiType, dbType) => {
// .contains("Save") // .contains("Save")
// .should('exist') // .should('exist')
// .click(); // .click();
cy.getActiveMenu('.nc-dropdown-grid-add-column') cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".ant-btn-primary:visible") .find(".ant-btn-primary:visible")
.contains("Save") .contains("Save")
.click(); .click();
@ -81,16 +77,15 @@ export const genTest = (apiType, dbType) => {
cy.toastWait(`Column created`); cy.toastWait(`Column created`);
// Verify // Verify
cy.get(`th[data-title="${columnName}"]`) cy.get(`th[data-title="${columnName}"]`).should("exist");
.should("exist"); }
};
// Content verification for LTAR cell // Content verification for LTAR cell
// Validates only 1st chip contents // Validates only 1st chip contents
// //
function verifyLtarCell(columnName, index, cellValue) { function verifyLtarCell(columnName, index, cellValue) {
cy.get(`:nth-child(${index}) > [data-title="${columnName}"]`) cy.get(`:nth-child(${index}) > [data-title="${columnName}"]`)
.find('.chip') .find(".chip")
.eq(0) .eq(0)
.contains(cellValue) .contains(cellValue)
.should("exist"); .should("exist");
@ -100,12 +95,14 @@ export const genTest = (apiType, dbType) => {
// //
function ltarUnlink(columnName, index) { function ltarUnlink(columnName, index) {
// Click on cell to enable unlink icon // Click on cell to enable unlink icon
cy.get(`:nth-child(${index}) > [data-title="${columnName}"]`).last() cy.get(`:nth-child(${index}) > [data-title="${columnName}"]`)
.click() .last()
.click();
// Click on unlink icon // Click on unlink icon
cy.get(`:nth-child(${index}) > [data-title="${columnName}"]`).last() cy.get(`:nth-child(${index}) > [data-title="${columnName}"]`)
.find('.unlink-icon') .last()
.find(".unlink-icon")
.should("exist") .should("exist")
.click(); .click();
@ -120,7 +117,7 @@ export const genTest = (apiType, dbType) => {
afterEach(() => { afterEach(() => {
cy.saveLocalStorage(); cy.saveLocalStorage();
}) });
beforeEach(() => { beforeEach(() => {
cy.restoreLocalStorage(); cy.restoreLocalStorage();
@ -174,7 +171,8 @@ export const genTest = (apiType, dbType) => {
cy.get(".nc-add-new-row-btn").click(); cy.get(".nc-add-new-row-btn").click();
// Title // Title
cy.get(".nc-expand-col-Title").find(".nc-cell > input") cy.get(".nc-expand-col-Title")
.find(".nc-cell > input")
.should("exist") .should("exist")
.first() .first()
.clear() .clear()
@ -186,80 +184,84 @@ export const genTest = (apiType, dbType) => {
// //
// BT // BT
cy.get(".nc-expand-col-Sheet1").find(".nc-action-icon") cy.get(".nc-expand-col-Sheet1")
.find(".nc-action-icon")
.should("exist") .should("exist")
.click({ force: true }); .click({ force: true });
cy.wait(1000); cy.wait(1000);
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find('.ant-card').should('exist') .find(".ant-card")
.eq(0).click(); .should("exist")
.eq(0)
.click();
// MM // MM
cy.get(".nc-expand-col-Sheet1.List").find(".ant-btn-primary").click(); cy.get(".nc-expand-col-Sheet1.List").find(".ant-btn-primary").click();
cy.wait(1000); cy.wait(1000);
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find('.ant-card').should('exist') .find(".ant-card")
.eq(0).click(); .should("exist")
.eq(0)
.click();
// HM // HM
cy.get(".nc-expand-col-Link2-1hm") cy.get(".nc-expand-col-Link2-1hm").find(".ant-btn-primary").click();
.find(".ant-btn-primary")
.click();
cy.wait(1000); cy.wait(1000);
cy.getActiveModal() cy.getActiveModal().find(".ant-card").should("exist").eq(0).click();
.find('.ant-card').should('exist')
.eq(0).click();
// Save row // Save row
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Save row") .contains("Save row")
.click({ force: true }); .should("exist")
.click();
// Toast // Toast
cy.toastWait("updated successfully"); cy.toastWait("updated successfully");
// Close modal // Close modal
cy.get("body").type("{esc}"); cy.get("body").type("{esc}");
}) });
// In cell insert // In cell insert
it("Add HM, BT, MM Link, In cell form", () => { it("Add HM, BT, MM Link, In cell form", () => {
// Insert row with `Title` field, rest of links are empty // Insert row with `Title` field, rest of links are empty
addRow(2, "2b"); addRow(2, "2b");
// BT // BT
mainPage.getCell("Sheet1", 2) mainPage
.getCell("Sheet1", 2)
.find(".nc-action-icon") .find(".nc-action-icon")
.click({ force: true }); .click({ force: true });
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find('.ant-card') .find(".ant-card")
.should('exist') .should("exist")
.eq(1) .eq(1)
.click(); .click();
cy.wait(1000); cy.wait(1000);
// MM // MM
mainPage.getCell("Sheet1 List", 2) mainPage
.getCell("Sheet1 List", 2)
.find(".nc-action-icon") .find(".nc-action-icon")
.last() .last()
.click({ force: true }); .click({ force: true });
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find('.ant-card') .find(".ant-card")
.should('exist') .should("exist")
.eq(1) .eq(1)
.click(); .click();
cy.wait(1000); cy.wait(1000);
// HM // HM
mainPage.getCell("Link2-1hm", 2) mainPage
.getCell("Link2-1hm", 2)
.find(".nc-action-icon") .find(".nc-action-icon")
.last() .last()
.click({ force: true }); .click({ force: true });
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find('.ant-card') .find(".ant-card")
.should('exist') .should("exist")
.eq(1) .eq(1)
.click(); .click();
}); });
@ -277,31 +279,36 @@ export const genTest = (apiType, dbType) => {
.click({ force: true }); .click({ force: true });
cy.wait(1000); cy.wait(1000);
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find('.ant-card').should('exist') .find(".ant-card")
.eq(2).click(); .should("exist")
.eq(2)
.click();
// MM // MM
cy.get(".nc-expand-col-Sheet1.List") cy.get(".nc-expand-col-Sheet1.List").find(".ant-btn-primary").click();
.find(".ant-btn-primary").click();
cy.wait(1000); cy.wait(1000);
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find('.ant-card').should('exist') .find(".ant-card")
.eq(2).click(); .should("exist")
.eq(2)
.click();
cy.wait(1000); cy.wait(1000);
// HM // HM
cy.get(".nc-expand-col-Link2-1hm") cy.get(".nc-expand-col-Link2-1hm").find(".ant-btn-primary").click();
.find(".ant-btn-primary").click();
cy.wait(1000); cy.wait(1000);
cy.getActiveModal(".nc-modal-link-record") cy.getActiveModal(".nc-modal-link-record")
.find('.ant-card').should('exist') .find(".ant-card")
.eq(2).click(); .should("exist")
.eq(2)
.click();
cy.wait(1000); cy.wait(1000);
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Save row") .contains("Save row")
.click({ force: true }); .should("exist")
.click();
// cy.toastWait("updated successfully"); // cy.toastWait("updated successfully");
cy.toastWait("No columns to update"); cy.toastWait("No columns to update");
@ -332,7 +339,7 @@ export const genTest = (apiType, dbType) => {
verifyLtarCell("Sheet2", 2, "2b"); verifyLtarCell("Sheet2", 2, "2b");
verifyLtarCell("Sheet2", 3, "2c"); verifyLtarCell("Sheet2", 3, "2c");
cy.closeTableTab("Sheet1"); cy.closeTableTab("Sheet1");
}) });
it("Unlink", () => { it("Unlink", () => {
cy.openTableTab("Sheet1", 3); cy.openTableTab("Sheet1", 3);

51
scripts/cypress/integration/common/4f_grid_view_share.js

@ -35,6 +35,8 @@ export const genTest = (apiType, dbType) => {
// viewURL.push($obj.text()) // viewURL.push($obj.text())
viewURL[viewName] = $obj.text().trim(); viewURL[viewName] = $obj.text().trim();
}); });
cy.getActiveModal(".nc-modal-share-view").should("not.be.visible");
}; };
describe(`${apiType.toUpperCase()} api - GRID view (Share)`, () => { describe(`${apiType.toUpperCase()} api - GRID view (Share)`, () => {
@ -66,10 +68,11 @@ export const genTest = (apiType, dbType) => {
// //
const viewTest = (viewType) => { const viewTest = (viewType) => {
it(`Create ${viewType.toUpperCase()} view`, () => { it(`Create ${viewType.toUpperCase()} view`, () => {
// create a normal public view // create a normal public view
cy.get(`.nc-create-${viewType}-view`).click(); cy.get(`.nc-create-${viewType}-view`).click();
cy.getActiveModal(".nc-modal-view-create").find("button:contains(Submit)").click(); cy.getActiveModal(".nc-modal-view-create")
.find("button:contains(Submit)")
.click();
cy.toastWait("View created successfully"); cy.toastWait("View created successfully");
// store base URL- to re-visit and delete form view later // store base URL- to re-visit and delete form view later
@ -79,6 +82,7 @@ export const genTest = (apiType, dbType) => {
}); });
it(`Share ${viewType.toUpperCase()} hide, sort, filter & verify`, () => { it(`Share ${viewType.toUpperCase()} hide, sort, filter & verify`, () => {
cy.intercept("/api/v1/db/meta/audits/comments/*").as("waitForPageLoad");
cy.get(`.nc-view-item.nc-${viewType}-view-item`) cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("Grid-1") .contains("Grid-1")
@ -88,10 +92,13 @@ export const genTest = (apiType, dbType) => {
mainPage.filterField("Address", "is like", "Ab"); mainPage.filterField("Address", "is like", "Ab");
generateViewLink("combined"); generateViewLink("combined");
cy.log(viewURL["combined"]); cy.log(viewURL["combined"]);
cy.wait(["@waitForPageLoad"]);
// kludge: additional wait to ensure page load is completed
cy.wait(2000);
}); });
it(`Share GRID view : ensure we have only one link even if shared multiple times`, () => { it(`Share GRID view : ensure we have only one link even if shared multiple times`, () => {
// generate view link multiple times // generate view link multiple times
generateViewLink("combined"); generateViewLink("combined");
generateViewLink("combined"); generateViewLink("combined");
@ -109,7 +116,7 @@ export const genTest = (apiType, dbType) => {
.its("length") .its("length")
.should("eq", 1) .should("eq", 1)
.then(() => { .then(() => {
cy.get('button.ant-modal-close:visible').click(); cy.get("button.ant-modal-close:visible").click();
}); });
cy.signOut(); cy.signOut();
@ -142,14 +149,8 @@ export const genTest = (apiType, dbType) => {
.getCell("District", 1) .getCell("District", 1)
.contains("West Bengali") .contains("West Bengali")
.should("exist"); .should("exist");
mainPage mainPage.getCell("District", 2).contains("Tutuila").should("exist");
.getCell("District", 2) mainPage.getCell("District", 3).contains("Tamil Nadu").should("exist");
.contains("Tutuila")
.should("exist");
mainPage
.getCell("District", 3)
.contains("Tamil Nadu")
.should("exist");
}); });
it(`Share ${viewType.toUpperCase()} view : verify download CSV`, () => { it(`Share ${viewType.toUpperCase()} view : verify download CSV`, () => {
@ -204,10 +205,7 @@ export const genTest = (apiType, dbType) => {
mainPage.filterField("District", "is like", "Tamil"); mainPage.filterField("District", "is like", "Tamil");
// wait for page rendering to complete // wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 2); cy.get(".nc-grid-row").should("have.length", 2);
mainPage mainPage.getCell("District", 1).contains("Tamil").should("exist");
.getCell("District", 1)
.contains("Tamil")
.should("exist");
}); });
it(`Share ${viewType.toUpperCase()} view : verify download CSV after local filter`, () => { it(`Share ${viewType.toUpperCase()} view : verify download CSV after local filter`, () => {
@ -349,7 +347,9 @@ export const genTest = (apiType, dbType) => {
cy.get(".nc-view-item").its("length").should("eq", 2); cy.get(".nc-view-item").its("length").should("eq", 2);
cy.get(".nc-view-delete-icon").eq(0).click({ force: true }); cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.getActiveModal(".nc-modal-view-delete").find(".ant-btn-dangerous").click(); cy.getActiveModal(".nc-modal-view-delete")
.find(".ant-btn-dangerous")
.click();
cy.toastWait("View deleted successfully"); cy.toastWait("View deleted successfully");
// confirm if the number of veiw entries is reduced by 1 // confirm if the number of veiw entries is reduced by 1
@ -392,19 +392,22 @@ export const genTest = (apiType, dbType) => {
it(`Generate default Shared GRID view URL`, () => { it(`Generate default Shared GRID view URL`, () => {
// add row // add row
cy.get(".nc-add-new-row-btn").click(); cy.get(".nc-add-new-row-btn").click();
cy.get(".nc-expand-col-Country").find(".nc-cell > input") cy.get(".nc-expand-col-Country")
.find(".nc-cell > input")
.should("exist") .should("exist")
.first() .first()
.clear({ force: true }) .clear({ force: true })
.type("a"); .type("a");
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Save row") .contains("Save row")
.should("exist")
.click(); .click();
cy.toastWait("updated successfully"); cy.toastWait("updated successfully");
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Cancel") .contains("Cancel")
.should("exist")
.click(); .click();
// add column // add column
mainPage.addColumn("dummy", "Country"); mainPage.addColumn("dummy", "Country");
@ -426,7 +429,9 @@ export const genTest = (apiType, dbType) => {
it(`Share GRID view : new row visible`, () => { it(`Share GRID view : new row visible`, () => {
// verify row // verify row
// cy.get(`.v-pagination > li:contains('5') button`).click(); // cy.get(`.v-pagination > li:contains('5') button`).click();
cy.get(`.nc-pagination > .ant-pagination-item.ant-pagination-item-5`).click(); cy.get(
`.nc-pagination > .ant-pagination-item.ant-pagination-item-5`
).click();
// wait for page rendering to complete // wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10); cy.get(".nc-grid-row").should("have.length", 10);
mainPage.getCell("Country", 10).contains("a").should("exist"); mainPage.getCell("Country", 10).contains("a").should("exist");
@ -439,12 +444,12 @@ export const genTest = (apiType, dbType) => {
it(`Clean up`, () => { it(`Clean up`, () => {
loginPage.loginAndOpenProject(apiType, dbType); loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Country", 25) cy.openTableTab("Country", 25);
// delete row // delete row
mainPage.getPagination(5).click(); mainPage.getPagination(5).click();
// kludge: flicker on load // kludge: flicker on load
cy.wait(3000) cy.wait(3000);
// wait for page rendering to complete // wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10); cy.get(".nc-grid-row").should("have.length", 10);

201
scripts/cypress/integration/common/4g_table_view_expanded_form.js

@ -0,0 +1,201 @@
import { isTestSuiteActive } from '../../support/page_objects/projectConstants';
import { loginPage } from '../../support/page_objects/navigation';
import { mainPage } from '../../support/page_objects/mainPage';
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// function verifyExpandFormHeader(title) {
// cy.getActiveDrawer(".nc-drawer-expanded-form")
// .should("exist")
// .find(".nc-expanded-form-header")
// .contains(title)
// .should("exist");
// }
function verifyExpandFormHeader(title) {
cy.get(
`.nc-drawer-expanded-form .nc-expanded-form-header :contains("${title}")`
).should('exist');
}
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - Table views: Expanded form`, () => {
before(() => {
cy.restoreLocalStorage();
// open a table to work on views
//
cy.openTableTab('Country', 25);
});
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
after(() => {
cy.restoreLocalStorage();
cy.closeTableTab('Country');
cy.saveLocalStorage();
});
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType} view`, () => {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal('.nc-modal-view-create')
.find('.ant-btn-primary')
.click();
cy.toastWait('View created successfully');
// validate if view was created && contains default name 'Country1'
cy.get(`.nc-${viewType}-view-item`)
.contains(`${capitalizeFirstLetter(viewType)}-1`)
.should('exist');
if (viewType === 'gallery') {
// cy.intercept('/api/v1/db/meta/galleries/*').as('getGalleryView');
// mainPage.unhideField("City List");
cy.get('.nc-fields-menu-btn').click();
cy.getActiveMenu('.nc-dropdown-fields-menu')
.find(`.nc-fields-list label:contains("City List"):visible`)
.click();
cy.get('.nc-fields-menu-btn').click();
cy.get('.ant-card-body [title="City List"]').should('exist');
cy.wait(1000);
// cy.wait(['@getGalleryView'])
}
});
it(`Expand a row in ${viewType} and verify url`, () => {
// click on first row-expand if grid & first card if its gallery
if (viewType === 'grid') {
cy.get('.nc-row-expand').first().click({ force: true });
} else if (viewType === 'gallery') {
cy.get('.nc-gallery-container .ant-card').first().click();
}
// ensure expand draw is open
verifyExpandFormHeader('Afghanistan');
cy.url().should('include', 'rowId=1');
// spy on clipboard to verify copied text
// creating alias for clipboard
cy.window().then((win) => {
cy.spy(win.navigator.clipboard, 'writeText').as('copy');
});
// copy url
cy.getActiveDrawer('.nc-drawer-expanded-form')
.should('exist')
.find('.nc-copy-row-url')
.click();
// use alias; verify if clipboard was called with correct text
cy.get('@copy').should('be.calledWithMatch', `?rowId=1`);
// close expanded form
cy.getActiveDrawer('.nc-drawer-expanded-form')
.find('.nc-expand-form-close-btn')
.click();
});
it(`Visit a ${viewType} row url and verify expanded form`, () => {
cy.url().then((url) => {
cy.visit(
'/' + url.split('/').slice(3).join('/').split('?')[0] + '?rowId=2'
);
verifyExpandFormHeader('Algeria');
});
});
it(`Visit an invalid ${viewType} row url and verify expanded form`, () => {
cy.url().then((url) => {
cy.visit(
'/' +
url.split('/').slice(3).join('/').split('?')[0] +
'?rowId=99999999'
);
cy.toastWait('Record not found');
cy.get(`.nc-drawer-expanded-form .ant-drawer-content:visible`).should(
'not.exist'
);
// defaults to corresponding grid / gallery view
cy.get(viewType === 'grid' ? '.nc-grid' : '.nc-gallery').should(
'exist'
);
});
});
it(`Visit a ${viewType} row url and verify nested expanded form`, () => {
cy.url().then((url) => {
cy.visit(
'/' + url.split('/').slice(3).join('/').split('?')[0] + '?rowId=1'
);
verifyExpandFormHeader('Afghanistan');
cy.get('.nc-drawer-expanded-form .ant-drawer-content').should(
'exist'
);
cy.getActiveDrawer('.nc-drawer-expanded-form')
.find('.ant-card-body')
.first()
.click();
cy.get('.nc-drawer-expanded-form .ant-drawer-content').should(
'have.length',
2
);
cy.wait(1000);
verifyExpandFormHeader('Kabul');
// close expanded forms
cy.getActiveDrawer('.nc-drawer-expanded-form')
.find('.ant-btn')
.contains('Cancel')
.click();
verifyExpandFormHeader('Afghanistan');
cy.getActiveDrawer('.nc-drawer-expanded-form')
.find('.ant-btn')
.contains('Cancel')
.click();
});
});
it('Delete view', () => {
cy.get('.nc-view-delete-icon').click({ force: true });
cy.getActiveModal('.nc-modal-view-delete')
.find('.ant-btn-dangerous')
.click();
cy.toastWait('View deleted successfully');
});
};
// viewTest("grid"); // grid view
viewTest('gallery'); // gallery view
});
};

33
scripts/cypress/integration/common/6g_base_share.js

@ -65,15 +65,15 @@ export const genTest = (apiType, dbType) => {
beforeEach(() => { beforeEach(() => {
cy.restoreLocalStorage(); cy.restoreLocalStorage();
}) });
afterEach(() => { afterEach(() => {
cy.saveLocalStorage(); cy.saveLocalStorage();
}) });
it(`Generate base share URL`, () => { it(`Generate base share URL`, () => {
// click SHARE // click SHARE
cy.get(".nc-share-base:visible").should('exist').click(); cy.get(".nc-share-base:visible").should("exist").click();
// Click on readonly base text // Click on readonly base text
cy.getActiveModal().find(".nc-disable-shared-base").click(); cy.getActiveModal().find(".nc-disable-shared-base").click();
@ -85,8 +85,8 @@ export const genTest = (apiType, dbType) => {
cy.getActiveModal().find(".nc-shared-base-role").click(); cy.getActiveModal().find(".nc-shared-base-role").click();
cy.getActiveSelection('.nc-dropdown-share-base-role') cy.getActiveSelection(".nc-dropdown-share-base-role")
.find('.ant-select-item') .find(".ant-select-item")
.eq(1) .eq(1)
.click(); .click();
@ -130,12 +130,12 @@ style="background: transparent; "></iframe>
loginPage.loginAndOpenProject(apiType, dbType); loginPage.loginAndOpenProject(apiType, dbType);
// click SHARE // click SHARE
cy.get(".nc-share-base:visible").should('exist').click(); cy.get(".nc-share-base:visible").should("exist").click();
cy.getActiveModal().find(".nc-shared-base-role").click(); cy.getActiveModal().find(".nc-shared-base-role").click();
cy.getActiveSelection('.nc-dropdown-share-base-role') cy.getActiveSelection(".nc-dropdown-share-base-role")
.find('.ant-select-item') .find(".ant-select-item")
.eq(0) .eq(0)
.click(); .click();
@ -148,7 +148,6 @@ style="background: transparent; "></iframe>
describe(`${apiType.toUpperCase()} iFrame Test`, () => { describe(`${apiType.toUpperCase()} iFrame Test`, () => {
// https://docs.cypress.io/api/commands/visit#Prefixes // https://docs.cypress.io/api/commands/visit#Prefixes
it("Generate & verify embed HTML IFrame", { baseUrl: null }, () => { it("Generate & verify embed HTML IFrame", { baseUrl: null }, () => {
let filePath = "scripts/cypress/fixtures/sampleFiles/iFrame.html"; let filePath = "scripts/cypress/fixtures/sampleFiles/iFrame.html";
cy.log(filePath); cy.log(filePath);
cy.visit(filePath, { baseUrl: null }); cy.visit(filePath, { baseUrl: null });
@ -157,7 +156,9 @@ style="background: transparent; "></iframe>
cy.frameLoaded(".nc-embed"); cy.frameLoaded(".nc-embed");
// cy.openTableTab("Country", 25); // cy.openTableTab("Country", 25);
cy.iframe().find(`.nc-project-tree-tbl-Actor`, {timeout: 10000}).should("exist") cy.iframe()
.find(`.nc-project-tree-tbl-Actor`, { timeout: 10000 })
.should("exist")
.first() .first()
.click({ force: true }); .click({ force: true });
@ -169,11 +170,15 @@ style="background: transparent; "></iframe>
cy.iframe().find(".nc-actions-menu-btn").should("exist"); cy.iframe().find(".nc-actions-menu-btn").should("exist");
// validate data (row-1) // validate data (row-1)
cy.iframe().find(`.nc-grid-cell`).eq(1).contains("PENELOPE").should("exist"); cy.iframe()
cy.iframe().find(`.nc-grid-cell`).eq(2).contains("GUINESS").should("exist"); .find(`.nc-grid-cell:eq(1):contains("PENELOPE")`)
.should("exist");
cy.iframe()
.find(`.nc-grid-cell:eq(2):contains("GUINESS")`)
.should("exist");
}); });
}) });
} };
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

114
scripts/cypress/integration/common/8a_webhook.js

@ -6,8 +6,11 @@ import { loginPage } from "../../support/page_objects/navigation";
let hookPath = "http://localhost:9090/hook"; let hookPath = "http://localhost:9090/hook";
function createWebhook(hook, test) { function createWebhook(hook, test) {
cy.get('.nc-actions-menu-btn').should('exist').click(); cy.get(".nc-actions-menu-btn").should("exist").click();
cy.getActiveMenu(".nc-dropdown-actions-menu").find('.ant-dropdown-menu-title-content').contains('Webhooks').click() cy.getActiveMenu(".nc-dropdown-actions-menu")
.find(".ant-dropdown-menu-title-content")
.contains("Webhooks")
.click();
// cy.get(".nc-btn-webhook").should("exist").click(); // cy.get(".nc-btn-webhook").should("exist").click();
cy.get(".nc-btn-create-webhook").should("exist").click(); cy.get(".nc-btn-create-webhook").should("exist").click();
@ -23,35 +26,45 @@ function createWebhook(hook, test) {
cy.get(".nc-input-hook-header-key") cy.get(".nc-input-hook-header-key")
.should("exist") .should("exist")
.click() .click()
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}")
.type('{downarrow}') .type("{downarrow}");
cy.getActiveSelection('.nc-dropdown-webhook-header').find('.ant-select-item-option-content').contains('Content-Type').should('exist').click(); cy.getActiveSelection(".nc-dropdown-webhook-header")
.find(".ant-select-item-option-content")
.contains("Content-Type")
.should("exist")
.click();
cy.get("input.nc-input-hook-header-value") cy.get("input.nc-input-hook-header-value")
.should("exist") .should("exist")
.clear({ force: true }) .clear({ force: true })
.type("application/json", { force: true }); .type("application/json", { force: true });
cy.get('.nc-hook-header-tab-checkbox').find('input.ant-checkbox-input').should('exist').click(); cy.get(".nc-hook-header-tab-checkbox")
.find("input.ant-checkbox-input")
.should("exist")
.click();
// common routine for both create & modify to configure hook // common routine for both create & modify to configure hook
configureWebhook(hook, test); configureWebhook(hook, test);
} }
function deleteWebhook(index) { function deleteWebhook(index) {
cy.get('.nc-actions-menu-btn').should('exist').click(); cy.get(".nc-actions-menu-btn").should("exist").click();
cy.getActiveMenu(".nc-dropdown-actions-menu").find('.ant-dropdown-menu-title-content').contains('Webhooks').click() cy.getActiveMenu(".nc-dropdown-actions-menu")
.find(".ant-dropdown-menu-title-content")
.contains("Webhooks")
.click();
cy.get(".nc-hook-delete-icon").eq(index).click({ force: true }); cy.get(".nc-hook-delete-icon").eq(index).click({ force: true });
cy.toastWait("Hook deleted successfully"); cy.toastWait("Hook deleted successfully");
@ -59,8 +72,11 @@ function deleteWebhook(index) {
} }
function openWebhook(index) { function openWebhook(index) {
cy.get('.nc-actions-menu-btn').should('exist').click(); cy.get(".nc-actions-menu-btn").should("exist").click();
cy.getActiveMenu(".nc-dropdown-actions-menu").find('.ant-dropdown-menu-title-content').contains('Webhooks').click() cy.getActiveMenu(".nc-dropdown-actions-menu")
.find(".ant-dropdown-menu-title-content")
.contains("Webhooks")
.click();
cy.get(".nc-hook").eq(index).click({ force: true }); cy.get(".nc-hook").eq(index).click({ force: true });
} }
@ -78,7 +94,7 @@ function configureWebhook(hook, test) {
if (hook?.event) { if (hook?.event) {
cy.get(".nc-text-field-hook-event").should("exist").click(); cy.get(".nc-text-field-hook-event").should("exist").click();
cy.getActiveSelection('.nc-dropdown-webhook-event') cy.getActiveSelection(".nc-dropdown-webhook-event")
.find(`.ant-select-item`) .find(`.ant-select-item`)
.contains(hook.event) .contains(hook.event)
.should("exist") .should("exist")
@ -93,9 +109,7 @@ function configureWebhook(hook, test) {
} }
if (hook?.deleteCondition === true) { if (hook?.deleteCondition === true) {
cy.get(".nc-filter-item-remove-btn") cy.get(".nc-filter-item-remove-btn").should("exist").click({ force: true });
.should("exist")
.click({ force: true });
} }
if (hook?.condition) { if (hook?.condition) {
@ -106,26 +120,26 @@ function configureWebhook(hook, test) {
.contains("Add Filter") .contains("Add Filter")
.click(); .click();
cy.get(".nc-filter-field-select") cy.get(".nc-filter-field-select").should("exist").last().click();
cy.get(".ant-select-dropdown:visible")
.should("exist") .should("exist")
.last()
.click()
cy.get('.ant-select-dropdown:visible')
.should('exist')
.find(`.ant-select-item`) .find(`.ant-select-item`)
.contains(new RegExp("^" + hook.condition.column + "$", "g")) .contains(new RegExp("^" + hook.condition.column + "$", "g"))
.should('exist') .should("exist")
.click(); .click();
cy.wait(1000); cy.wait(1000);
cy.get(".nc-filter-operation-select").should("exist").last().click(); cy.get(".nc-filter-operation-select").should("exist").last().click();
cy.get('.ant-select-dropdown:visible') cy.get(".ant-select-dropdown:visible")
.should('exist') .should("exist")
.find(`.ant-select-item`) .find(`.ant-select-item`)
.contains(hook.condition.operator) .contains(hook.condition.operator)
.should('exist') .should("exist")
.click(); .click();
if (hook.condition.operator != "is null" && hook.condition.operator != "is not null") { if (
hook.condition.operator != "is null" &&
hook.condition.operator != "is not null"
) {
cy.get(".nc-filter-value-select") cy.get(".nc-filter-value-select")
.should("exist") .should("exist")
.last() .last()
@ -160,13 +174,16 @@ function addNewRow(index, cellValue) {
cy.get(".nc-add-new-row-btn:visible").should("exist"); cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click(); cy.get(".nc-add-new-row-btn").click();
cy.wait(1000); cy.wait(1000);
cy.get(".nc-expand-col-Title").find(".nc-cell > input").first().type(cellValue); cy.get(".nc-expand-col-Title")
cy.getActiveDrawer('.nc-drawer-expanded-form') .find(".nc-cell > input")
.first()
.type(cellValue);
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".ant-btn-primary") .find(".ant-btn-primary")
.click(); .click();
cy.toastWait("updated successfully"); cy.toastWait("updated successfully");
cy.getActiveDrawer('.nc-drawer-expanded-form') cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".ant-btn") .find(".ant-btn")
.contains("Cancel") .contains("Cancel")
.click(); .click();
@ -178,26 +195,31 @@ function updateRow(index, cellValue) {
.eq(index - 1) .eq(index - 1)
.click({ force: true }); .click({ force: true });
cy.get(".nc-expand-col-Title").find(".nc-cell > input") cy.get(".nc-expand-col-Title")
.find(".nc-cell > input")
.should("exist") .should("exist")
.first() .first()
.clear() .clear()
.type(cellValue); .type(cellValue);
cy.getActiveDrawer('.nc-drawer-expanded-form') cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Save row") .contains("Save row")
.click({ force: true }); .should("exist")
.click();
// partial toast message // partial toast message
cy.toastWait("updated successfully"); cy.toastWait("updated successfully");
cy.getActiveDrawer('.nc-drawer-expanded-form') cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Cancel") .contains("Cancel")
.click({ force: true }); .click({ force: true });
} }
function verifyHookTrigger(count, lastValue) { function verifyHookTrigger(count, lastValue) {
// allow message to be received
cy.wait(500);
cy.request("http://localhost:9090/hook/count").then((msg) => { cy.request("http://localhost:9090/hook/count").then((msg) => {
cy.log(msg.body); cy.log(msg.body);
expect(msg.body).to.equal(count); expect(msg.body).to.equal(count);
@ -211,15 +233,13 @@ function verifyHookTrigger(count, lastValue) {
} }
function deleteRow(index) { function deleteRow(index) {
mainPage mainPage.getCell("Title", index).rightclick();
.getCell("Title", index)
.rightclick();
// delete row // delete row
cy.getActiveMenu(".nc-dropdown-grid-context-menu") cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.find('.ant-dropdown-menu-item:contains("Delete Row")') .find('.ant-dropdown-menu-item:contains("Delete Row")')
.first() .first()
.click({ force: true }); .click();
} }
export const genTest = (apiType, dbType) => { export const genTest = (apiType, dbType) => {
@ -237,7 +257,7 @@ export const genTest = (apiType, dbType) => {
afterEach(() => { afterEach(() => {
cy.saveLocalStorage(); cy.saveLocalStorage();
}) });
after(() => { after(() => {
cy.restoreLocalStorage(); cy.restoreLocalStorage();

373
scripts/cypress/integration/common/9b_ERD.js

@ -0,0 +1,373 @@
import { mainPage, settingsPage } from "../../support/page_objects/mainPage";
import {loginPage, projectsPage} from "../../support/page_objects/navigation";
import { isTestSuiteActive, sakilaSqlViews, sakilaTables } from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} ERD`, () => {
// before(() => {
// loginPage.loginAndOpenProject(apiType, dbType);
// cy.openTableTab("Country", 25);
// cy.saveLocalStorage();
// });
beforeEach(() => {
cy.restoreLocalStorage();
})
afterEach(() => {
cy.saveLocalStorage();
})
after(() => {
cy.restoreLocalStorage();
cy.closeTableTab("Country");
cy.saveLocalStorage();
});
// Test cases
it(`Enable MM setting Open Table ERD`, () => {
cy.openTableTab("Country", 25);
mainPage.toggleShowMMSetting();
mainPage.openErdTab();
mainPage.closeMetaTab();
});
it(`Verify ERD Context menu in all table view`, () => {
mainPage.openErdTab();
cy.get('.nc-erd-context-menu').should('be.visible');
cy.get('.nc-erd-context-menu').get('.nc-erd-histogram').should('be.visible');
cy.get('.nc-erd-context-menu').find('.ant-checkbox').should('have.length', 3);
cy.get('.nc-erd-context-menu').find('.ant-checkbox').eq(0).should('have.class', 'ant-checkbox-checked');
cy.get('.nc-erd-context-menu').find('.ant-checkbox').eq(1).should('have.class', 'ant-checkbox-checked');
cy.get('.nc-erd-context-menu').find('.ant-checkbox').eq(2).should('not.have.class', 'ant-checkbox-checked');
cy.get('.nc-erd-context-menu').find('.nc-erd-showColumns-label').dblclick();
cy.get('.nc-erd-context-menu').find('.ant-checkbox').should('have.length', 5);
});
it("Verify ERD of all tables view and verify columns of actor and payment with default config", () => {
cy.get('.nc-erd-vue-flow').find('.nc-erd-table-node').should('have.length', 12)
cy.get('.nc-erd-vue-flow').find('.vue-flow__edge').should('have.length', 14)
cy.get('.nc-erd-vue-flow').find('.nc-erd-edge-circle').should('have.length', 11)
cy.get('.nc-erd-vue-flow').find('.nc-erd-edge-rect').should('have.length', 17)
for(const tableName of sakilaTables) {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-${tableName}`).should('exist');
}
// Actor table
[
'actor_id',
'first_name',
'last_name',
'last_update',
'film_list'
].forEach((colTitle) => {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-actor`).find(`.nc-erd-table-node-actor-column-${colTitle}`).should('exist');
});
// Payment table
[
'payment_id',
'customer_id',
'staff_id',
'rental_id',
'amount',
'payment_date',
'last_update',
'customer',
'rental',
'staff'
].forEach((colTitle) => {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-payment`).find(`.nc-erd-table-node-payment-column-${colTitle}`).should('exist');
});
});
it("Verify ERD of all tables view and verify columns of actor and payment with default config with showAllColumn disabled", () => {
cy.get('.nc-erd-context-menu').get('.nc-erd-showColumns-checkbox').click();
cy.get('.nc-erd-showPkAndFk-checkbox-disabled').should('exist');
cy.get('.nc-erd-showPkAndFk-checkbox-unchecked').should('exist');
// Actor table
[
'film_list'
].forEach((colTitle) => {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-actor`).find(`.nc-erd-table-node-actor-column-${colTitle}`).should('exist');
});
// Payment table
[
'customer',
'rental',
'staff'
].forEach((colTitle) => {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-payment`).find(`.nc-erd-table-node-payment-column-${colTitle}`).should('exist');
});
});
it("Verify ERD of all tables view and verify columns of actor and payment with default config with showPkAndFk disabled", () => {
// enable showAllColumn
cy.get('.nc-erd-context-menu').get('.nc-erd-showColumns-checkbox').click();
cy.get('.nc-erd-context-menu').get('.nc-erd-showPkAndFk-checkbox').click();
// Actor table
[
'last_name',
'last_update',
'film_list'
].forEach((colTitle) => {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-actor`).find(`.nc-erd-table-node-actor-column-${colTitle}`).should('exist');
});
// Payment table
[
'amount',
'payment_date',
'last_update',
'customer',
'rental',
'staff'
].forEach((colTitle) => {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-payment`).find(`.nc-erd-table-node-payment-column-${colTitle}`).should('exist');
});
});
it("Verify ERD of all tables view with sql grid on and verify columns of ActorInfo", () => {
cy.get('.nc-erd-context-menu').get('.nc-erd-showViews-checkbox').click();
cy.get('.nc-erd-vue-flow').find('.nc-erd-table-node').should('have.length', 19)
cy.get('.nc-erd-vue-flow').find('.vue-flow__edge').should('have.length', 14)
cy.get('.nc-erd-vue-flow').find('.nc-erd-edge-circle').should('have.length', 11)
cy.get('.nc-erd-vue-flow').find('.nc-erd-edge-rect').should('have.length', 17)
for(const tableName of sakilaTables) {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-${tableName}`).should('exist');
}
for(const tableName of sakilaSqlViews) {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-${tableName}`).should('exist');
}
// ActorInfo SQL View
[
'actor_id',
'first_name',
'last_name',
'film_info'
].forEach((colTitle) => {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-actor_info`).find(`.nc-erd-table-node-actor_info-column-${colTitle}`).should('exist');
})
});
it("Verify show MM tables", () => {
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-store`).should('not.exist');
// disable showViews
cy.get('.nc-erd-context-menu').get('.nc-erd-showViews-checkbox').click();
cy.get('.nc-erd-context-menu').get('.nc-erd-showMMTables-checkbox').click();
cy.get('.nc-erd-vue-flow').find('.nc-erd-table-node').should('have.length', 16)
cy.get('.nc-erd-vue-flow').find('.vue-flow__edge').should('have.length', 26)
cy.get('.nc-erd-vue-flow').find('.nc-erd-edge-circle').should('have.length', 22)
cy.get('.nc-erd-vue-flow').find('.nc-erd-edge-rect').should('have.length', 30)
// Check if store table is present
cy.get('.nc-erd-vue-flow').find(`.nc-erd-table-node-store`).should('exist');
})
it("Verify show junction table names", () => {
// disable showViews
cy.get('.nc-erd-context-menu').get('.nc-erd-showJunctionTableNames-checkbox').click();
cy.get('.nc-erd-vue-flow').get('.nc-erd-table-label-filmactor-film_actor').should('exist');
mainPage.closeMetaTab();
})
it('Verify table ERD view of country', () => {
mainPage.openTableErdView();
cy.get('.nc-erd-vue-flow-single-table').find('.nc-erd-table-node').should('have.length', 2)
cy.get('.nc-erd-vue-flow-single-table').find('.vue-flow__edge').should('have.length', 1)
cy.get('.nc-erd-vue-flow-single-table').find('.nc-erd-edge-circle').should('have.length', 1)
cy.get('.nc-erd-vue-flow-single-table').find('.nc-erd-edge-rect').should('have.length', 1)
const countryColumns = [
'country_id',
'country',
'last_update',
'city_list'
]
// Country table
countryColumns.forEach((colTitle) => {
cy.get('.nc-erd-vue-flow-single-table').find(`.nc-erd-table-node-country`).find(`.nc-erd-table-node-country-column-${colTitle}`).should('exist');
});
const cityColumns = [
'city_id',
'city',
'last_update',
'country',
'address_list'
]
// City table
cityColumns.forEach((colTitle) => {
cy.get('.nc-erd-vue-flow-single-table').find(`.nc-erd-table-node-city`).find(`.nc-erd-table-node-city-column-${colTitle}`).should('exist');
});
})
it('Verify table ERD view of country showAllColumn disabled', () => {
cy.get('.nc-erd-vue-flow-single-table').within(() => {
cy.get('.nc-erd-context-menu').get('.nc-erd-showColumns-checkbox').click();
cy.get('.nc-erd-showPkAndFk-checkbox-disabled').should('exist');
cy.get('.nc-erd-showPkAndFk-checkbox-unchecked').should('exist');
const countryColumns = [
'city_list'
]
// Country table
countryColumns.forEach((colTitle) => {
cy.get(`.nc-erd-table-node-country`).find(`.nc-erd-table-node-country-column-${colTitle}`).should('exist');
});
const cityColumns = [
'country',
'address_list'
]
// City table
cityColumns.forEach((colTitle) => {
cy.get(`.nc-erd-table-node-city`).find(`.nc-erd-table-node-city-column-${colTitle}`).should('exist');
});
cy.get('.nc-erd-context-menu').get('.nc-erd-showColumns-checkbox').click();
})
})
it('Verify table ERD view of country show PK AND FK disabled', () => {
cy.get('.nc-erd-vue-flow-single-table').within(() => {
cy.get('.nc-erd-context-menu').get('.nc-erd-showPkAndFk-checkbox').click();
const countryColumns = [
'country',
'last_update',
'city_list'
]
// Country table
countryColumns.forEach((colTitle) => {
cy.get(`.nc-erd-table-node-country`).find(`.nc-erd-table-node-country-column-${colTitle}`).should('exist');
});
const cityColumns = [
'city',
'last_update',
'country',
'address_list'
]
// City table
cityColumns.forEach((colTitle) => {
cy.get(`.nc-erd-table-node-city`).find(`.nc-erd-table-node-city-column-${colTitle}`).should('exist');
});
cy.get('.nc-erd-context-menu').get('.nc-erd-showPkAndFk-checkbox').click();
})
cy.getActiveModal().find('.nc-modal-close').click({ force: true });
})
it('create column and check if the change is in the schema', () => {
mainPage.addColumn('test_column', 'country')
// table view
mainPage.openTableErdView();
cy.get('.nc-erd-vue-flow-single-table').within(() => {
cy.get('.nc-erd-table-node-country').find('.nc-erd-table-node-country-column-test_column').should('exist');
})
cy.getActiveModal().find('.nc-modal-close').click({ force: true });
// All table view
mainPage.openErdTab();
cy.get('.nc-erd-vue-flow').within(() => {
cy.get('.nc-erd-table-node-country').find('.nc-erd-table-node-country-column-test_column').should('exist');
})
mainPage.closeMetaTab();
mainPage.deleteColumn('test_column')
// table view
mainPage.openTableErdView();
cy.get('.nc-erd-vue-flow-single-table').within(() => {
cy.get('.nc-erd-table-node-country').find('.nc-erd-table-node-country-column-test_column').should('not.exist');
})
cy.getActiveModal().find('.nc-modal-close').click({ force: true });
// All table view
mainPage.openErdTab();
cy.get('.nc-erd-vue-flow').within(() => {
cy.get('.nc-erd-table-node-country').find('.nc-erd-table-node-country-column-test_column').should('not.exist');
})
mainPage.closeMetaTab();
})
it('Create table should reflected in ERD', () => {
cy.createTable('new')
mainPage.openErdTab();
cy.get('.nc-erd-vue-flow').within(() => {
cy.get('.nc-erd-table-node-new').should('exist');
})
mainPage.closeMetaTab();
cy.deleteTable('new')
mainPage.openErdTab();
cy.get('.nc-erd-vue-flow').within(() => {
cy.get('.nc-erd-table-node-new').should('not.exist');
})
mainPage.closeMetaTab();
})
it(`Disable MM setting Open Table ERD and check easter egg should not work`, () => {
mainPage.toggleShowMMSetting();
mainPage.openErdTab();
cy.get('.nc-erd-vue-flow').within(() => {
cy.get('.nc-erd-context-menu').find('.nc-erd-showColumns-label').dblclick();
cy.get('.nc-erd-context-menu').find('.ant-checkbox').should('have.length', 3);
})
mainPage.closeMetaTab();
});
});
};
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Raju Udava <sivadstala@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/>.
*
*/

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

@ -9,14 +9,15 @@ import { roles } from "../../support/page_objects/projectConstants";
export function _advSettings(roleType, mode) { export function _advSettings(roleType, mode) {
cy.log(roleType, mode); cy.log(roleType, mode);
if(mode === 'baseShare') { if (mode === "baseShare") {
// open modal // open modal
cy.get('.nc-project-menu').should('exist').click() cy.get(".nc-project-menu").should("exist").click();
cy.getActiveMenu(".nc-dropdown-project-menu").find(`[data-menu-id="language"]`).should('exist') cy.getActiveMenu(".nc-dropdown-project-menu")
.find(`[data-menu-id="language"]`)
.should("exist");
// click again to close modal // click again to close modal
cy.get('.nc-project-menu').should('exist').click() cy.get(".nc-project-menu").should("exist").click();
return; return;
} }
@ -24,27 +25,34 @@ export function _advSettings(roleType, mode) {
true == roles[roleType].validations.advSettings ? "exist" : "not.exist"; true == roles[roleType].validations.advSettings ? "exist" : "not.exist";
// cy.get(".nc-team-settings").should(validationString); // cy.get(".nc-team-settings").should(validationString);
cy.get('.nc-project-menu').should('exist').click() cy.get(".nc-project-menu").should("exist").click();
cy.getActiveMenu(".nc-dropdown-project-menu").find(`[data-menu-id="preview-as"]`).should(validationString) cy.getActiveMenu(".nc-dropdown-project-menu")
cy.getActiveMenu(".nc-dropdown-project-menu").find(`[data-menu-id="teamAndSettings"]:visible`).should(validationString) .find(`[data-menu-id="preview-as"]`)
.should(validationString);
cy.getActiveMenu(".nc-dropdown-project-menu")
.find(`[data-menu-id="teamAndSettings"]:visible`)
.should(validationString);
if (true === roles[roleType].validations.advSettings) { if (true === roles[roleType].validations.advSettings) {
cy.getActiveMenu(".nc-dropdown-project-menu").find(`[data-menu-id="teamAndSettings"]:visible`).should(validationString).click() cy.getActiveMenu(".nc-dropdown-project-menu")
.find(`[data-menu-id="teamAndSettings"]:visible`)
.should(validationString)
.click();
cy.get(`[data-menu-id="teamAndAuth"]`).should('exist') cy.get(`[data-menu-id="teamAndAuth"]`).should("exist");
cy.get(`[data-menu-id="appStore"]`).should('exist') cy.get(`[data-menu-id="appStore"]`).should("exist");
cy.get(`[data-menu-id="metaData"]`).should('exist') cy.get(`[data-menu-id="projMetaData"]`).should("exist");
cy.get(`[data-menu-id="audit"]`).should('exist') cy.get(`[data-menu-id="audit"]`).should("exist");
settingsPage.closeMenu() settingsPage.closeMenu();
} else { } else {
cy.get('.nc-project-menu').should('exist').click() cy.get(".nc-project-menu").should("exist").click();
} }
// float menu in preview mode // float menu in preview mode
if ("preview" === mode) { if ("preview" === mode) {
cy.get(".nc-floating-preview-btn").should("exist"); cy.get(".nc-floating-preview-btn").should("exist");
cy.get('.nc-floating-preview-btn') cy.get(".nc-floating-preview-btn")
.find(`[type="radio"][value="${roles[roleType].name}"]`) .find(`[type="radio"][value="${roles[roleType].name}"]`)
.should("be.checked"); .should("be.checked");
} }
@ -67,8 +75,14 @@ export function _editSchema(roleType, mode) {
cy.get(".ant-dropdown-content:visible").should(validationString); cy.get(".ant-dropdown-content:visible").should(validationString);
if (validationString === "exist") { if (validationString === "exist") {
cy.getActiveMenu(".nc-dropdown-tree-view-context-menu").find('[role="menuitem"]').contains("Delete").should("exist"); cy.getActiveMenu(".nc-dropdown-tree-view-context-menu")
cy.getActiveMenu(".nc-dropdown-tree-view-context-menu").find('[role="menuitem"]').contains("Rename").should("exist"); .find('[role="menuitem"]')
.contains("Delete")
.should("exist");
cy.getActiveMenu(".nc-dropdown-tree-view-context-menu")
.find('[role="menuitem"]')
.contains("Rename")
.should("exist");
// click on a cell to close table context menu // click on a cell to close table context menu
mainPage.getCell(columnName, 3).click(); mainPage.getCell(columnName, 3).click();
@ -79,15 +93,23 @@ export function _editSchema(roleType, mode) {
cy.get(".nc-column-add").should(validationString); cy.get(".nc-column-add").should(validationString);
// update column (edit/ delete menu) // update column (edit/ delete menu)
cy.get('.nc-ui-dt-dropdown').should(validationString) cy.get(".nc-ui-dt-dropdown").should(validationString);
if (validationString === "exist") { if (validationString === "exist") {
cy.get('.nc-import-menu').should('exist').click(); cy.get(".nc-import-menu").should("exist").click();
cy.getActiveMenu(".nc-dropdown-import-menu").should('exist') cy.getActiveMenu(".nc-dropdown-import-menu").should("exist");
cy.getActiveMenu(".nc-dropdown-import-menu").find('.ant-dropdown-menu-item').contains('Airtable') cy.getActiveMenu(".nc-dropdown-import-menu")
cy.getActiveMenu(".nc-dropdown-import-menu").find('.ant-dropdown-menu-item').contains('CSV file') .find(".ant-dropdown-menu-item")
cy.getActiveMenu(".nc-dropdown-import-menu").find('.ant-dropdown-menu-item').contains('JSON file') .contains("Airtable");
cy.getActiveMenu(".nc-dropdown-import-menu").find('.ant-dropdown-menu-item').contains('Microsoft Excel') cy.getActiveMenu(".nc-dropdown-import-menu")
.find(".ant-dropdown-menu-item")
.contains("CSV file");
cy.getActiveMenu(".nc-dropdown-import-menu")
.find(".ant-dropdown-menu-item")
.contains("JSON file");
cy.getActiveMenu(".nc-dropdown-import-menu")
.find(".ant-dropdown-menu-item")
.contains("Microsoft Excel");
} }
} }
@ -99,11 +121,11 @@ export function _editData(roleType, mode) {
cy.openTableTab(columnName, 25); cy.openTableTab(columnName, 25);
// add row button // add row button
cy.get('.nc-add-new-row-btn:visible').should(validationString); cy.get(".nc-add-new-row-btn:visible").should(validationString);
// add button at bottom of page // add button at bottom of page
mainPage.getCell(columnName, 25).scrollIntoView(); mainPage.getCell(columnName, 25).scrollIntoView();
cy.get('.nc-grid-add-new-cell:visible').should(validationString); cy.get(".nc-grid-add-new-cell:visible").should(validationString);
// update row option (right click) // update row option (right click)
// //
@ -114,10 +136,18 @@ export function _editData(roleType, mode) {
if (validationString === "exist") { if (validationString === "exist") {
// right click options will exist (only for 'exist' case) // right click options will exist (only for 'exist' case)
// //
cy.getActiveMenu(".nc-dropdown-grid-context-menu").contains("Insert New Row").should(validationString); cy.getActiveMenu(".nc-dropdown-grid-context-menu")
cy.getActiveMenu(".nc-dropdown-grid-context-menu").contains("Clear cell").should(validationString); .contains("Insert New Row")
cy.getActiveMenu(".nc-dropdown-grid-context-menu").contains("Delete Row").should(validationString); .should(validationString);
cy.getActiveMenu(".nc-dropdown-grid-context-menu").contains("Delete Selected Rows").should(validationString); cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Clear cell")
.should(validationString);
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Row")
.should(validationString);
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Selected Rows")
.should(validationString);
// cy.get("body").type("{esc}"); // cy.get("body").type("{esc}");
mainPage.getCell("City", 13).click(); mainPage.getCell("City", 13).click();
@ -126,32 +156,38 @@ export function _editData(roleType, mode) {
// //
mainPage mainPage
.getRow(1) .getRow(1)
.find('.nc-row-no').should('exist') .find(".nc-row-no")
.should("exist")
.eq(0) .eq(0)
.trigger('mouseover', { force: true }) .trigger("mouseover", { force: true });
cy.get(".nc-row-expand") cy.get(".nc-row-expand").should("exist").eq(10).click({ force: true });
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Save row")
.should("exist");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Cancel")
.should("exist") .should("exist")
.eq(10) .click();
.click({ force: true });
cy.getActiveDrawer().find("button").contains("Save row").should("exist");
cy.getActiveDrawer().find("button").contains("Cancel").should("exist").click();
} else { } else {
// update cell contents option using row expander should be disabled // update cell contents option using row expander should be disabled
// //
cy.get(".nc-row-expand") cy.get(".nc-row-expand").should("exist").eq(10).click({ force: true });
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button:disabled")
.contains("Save row")
.should("exist");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Cancel")
.should("exist") .should("exist")
.eq(10) .click();
.click({ force: true });
cy.getActiveDrawer().find("button:disabled").contains("Save row").should("exist");
cy.getActiveDrawer().find("button").contains("Cancel").should("exist").click();
} }
// double click cell entries to edit // double click cell entries to edit
// //
mainPage.getCell("City", 5) mainPage.getCell("City", 5).dblclick().find("input").should(validationString);
.dblclick()
.find("input")
.should(validationString);
} }
// read &/ update comment // read &/ update comment
@ -171,10 +207,7 @@ export function _editComment(roleType, mode) {
// click on comment icon & type comment // click on comment icon & type comment
// //
cy.get(".nc-row-expand") cy.get(".nc-row-expand").should("exist").eq(10).click({ force: true });
.should("exist")
.eq(10)
.click({force:true});
// Expected response: // Expected response:
// Viewer: Not able to see comment option // Viewer: Not able to see comment option
@ -184,23 +217,28 @@ export function _editComment(roleType, mode) {
cy.wait(3000); cy.wait(3000);
if ("viewer" === roleType) { if ("viewer" === roleType) {
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.should('exist') .should("exist")
.find(".nc-toggle-comments") .find(".nc-toggle-comments")
.should("not.exist"); .should("not.exist");
} else { } else {
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.should('exist') .should("exist")
.find(".nc-toggle-comments") .find(".nc-toggle-comments")
.should("exist") .should("exist")
.click(); .click();
cy.getActiveDrawer().find(".nc-comment-box").should('exist').type("Comment-1{enter}"); cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".nc-comment-box")
.should("exist")
.type("Comment-1{enter}");
// cy.toastWait('Comment added successfully') // cy.toastWait('Comment added successfully')
cy.getActiveDrawer().find(".nc-toggle-comments").click(); cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".nc-toggle-comments")
.click();
} }
cy.getActiveDrawer() cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button") .find("button")
.contains("Cancel") .contains("Cancel")
.should("exist") .should("exist")
@ -216,8 +254,8 @@ export function _viewMenu(roleType, mode) {
// Lock, Download, Upload // Lock, Download, Upload
let menuWithSubmenuCount = 3; let menuWithSubmenuCount = 3;
// share view list, webhook // share view list, webhook, api snippet, erd
let menuWithoutSubmenuCount = 3; let menuWithoutSubmenuCount = 4;
cy.openTableTab(columnName, 25); cy.openTableTab(columnName, 25);
@ -227,13 +265,15 @@ export function _viewMenu(roleType, mode) {
if (roleType === "editor") { if (roleType === "editor") {
// Download / Upload CSV // Download / Upload CSV
menuWithSubmenuCount = 2; menuWithSubmenuCount = 2;
// Get API Snippet // Get API Snippet and ERD
menuWithoutSubmenuCount = 1 menuWithoutSubmenuCount = 2;
if(mode === 'baseShare') menuWithoutSubmenuCount = 0 // ERD
if (mode === "baseShare") menuWithoutSubmenuCount = 1;
} else if (roleType === "commenter" || roleType === "viewer") { } else if (roleType === "commenter" || roleType === "viewer") {
// Download CSV & Download excel // Download CSV & Download excel
menuWithSubmenuCount = 0; menuWithSubmenuCount = 0;
menuWithoutSubmenuCount = 2 // Get API Snippet and ERD
menuWithoutSubmenuCount = 2;
} }
// view list field (default GRID view) // view list field (default GRID view)
@ -249,10 +289,10 @@ export function _viewMenu(roleType, mode) {
// actions menu (more), only download csv should be visible for non-previlaged users // actions menu (more), only download csv should be visible for non-previlaged users
cy.get(".nc-actions-menu-btn").click(); cy.get(".nc-actions-menu-btn").click();
cy.getActiveMenu(".nc-dropdown-actions-menu") cy.getActiveMenu(".nc-dropdown-actions-menu")
.find('.ant-dropdown-menu-submenu:visible') .find(".ant-dropdown-menu-submenu:visible")
.should("have.length", menuWithSubmenuCount); .should("have.length", menuWithSubmenuCount);
cy.getActiveMenu(".nc-dropdown-actions-menu") cy.getActiveMenu(".nc-dropdown-actions-menu")
.find('.ant-dropdown-menu-item:visible') .find(".ant-dropdown-menu-item:visible")
.should("have.length", menuWithoutSubmenuCount); .should("have.length", menuWithoutSubmenuCount);
// click again to close menu // click again to close menu
cy.get(".nc-actions-menu-btn").click(); cy.get(".nc-actions-menu-btn").click();
@ -289,6 +329,6 @@ export function enableTableAccess(tbl, role) {
export function _accessControl(roleType, previewMode) { export function _accessControl(roleType, previewMode) {
let validationString = roleType === "creator" ? "exist" : "not.exist"; let validationString = roleType === "creator" ? "exist" : "not.exist";
cy.get(`.nc-project-tree-tbl-Language`).should(validationString) cy.get(`.nc-project-tree-tbl-Language`).should(validationString);
cy.get(`.nc-project-tree-tbl-CustomerList`).should(validationString) cy.get(`.nc-project-tree-tbl-CustomerList`).should(validationString);
} }

2
scripts/cypress/integration/test/pg-restViews.js

@ -6,6 +6,7 @@ let t4c = require("../common/4c_form_view_detailed");
let t4d = require("../common/4d_table_view_grid_locked"); let t4d = require("../common/4d_table_view_grid_locked");
let t4e = require("../common/4e_form_view_share"); let t4e = require("../common/4e_form_view_share");
let t4f = require("../common/4f_pg_grid_view_share"); let t4f = require("../common/4f_pg_grid_view_share");
let t4g = require("../common/4g_table_view_expanded_form");
const { const {
setCurrentMode, setCurrentMode,
} = require("../../support/page_objects/projectConstants"); } = require("../../support/page_objects/projectConstants");
@ -20,6 +21,7 @@ const nocoTestSuite = (apiType, dbType) => {
t4b.genTest(apiType, dbType); t4b.genTest(apiType, dbType);
t4d.genTest(apiType, dbType); t4d.genTest(apiType, dbType);
t4e.genTest(apiType, dbType); t4e.genTest(apiType, dbType);
t4g.genTest(apiType, dbType);
// tbd t4f.genTest(apiType, dbType); // tbd t4f.genTest(apiType, dbType);
}; };

6
scripts/cypress/integration/test/restMisc.js

@ -7,7 +7,8 @@ let t6e = require("../common/6e_project_operations");
let t6f = require("../common/6f_attachments"); let t6f = require("../common/6f_attachments");
let t6g = require("../common/6g_base_share"); let t6g = require("../common/6g_base_share");
let t7a = require("../common/7a_create_project_from_excel"); let t7a = require("../common/7a_create_project_from_excel");
let t8a = require("../common/8a_webhook") let t8a = require("../common/8a_webhook");
let t9b = require("../common/9b_ERD");
const { const {
setCurrentMode, setCurrentMode,
} = require("../../support/page_objects/projectConstants"); } = require("../../support/page_objects/projectConstants");
@ -20,6 +21,9 @@ const nocoTestSuite = (apiType, dbType) => {
t6d.genTest(apiType, dbType); t6d.genTest(apiType, dbType);
// exclude@ncv2 t6c.genTest(apiType, dbType); // exclude@ncv2 t6c.genTest(apiType, dbType);
t6f.genTest(apiType, dbType); t6f.genTest(apiType, dbType);
t9b.genTest(apiType, dbType);
t6g.genTest(apiType, dbType); t6g.genTest(apiType, dbType);
// webhook tests // webhook tests

1
scripts/cypress/integration/test/restTableOps.js

@ -1,4 +1,3 @@
let t01 = require("../common/00_pre_configurations"); let t01 = require("../common/00_pre_configurations");
let t1a = require("../common/1a_table_operations"); let t1a = require("../common/1a_table_operations");
let t1b = require("../common/1b_table_column_operations"); let t1b = require("../common/1b_table_column_operations");

18
scripts/cypress/integration/test/restViews.js

@ -6,8 +6,8 @@ let t4c = require("../common/4c_form_view_detailed");
let t4d = require("../common/4d_table_view_grid_locked"); let t4d = require("../common/4d_table_view_grid_locked");
let t4e = require("../common/4e_form_view_share"); let t4e = require("../common/4e_form_view_share");
let t4f = require("../common/4f_grid_view_share"); let t4f = require("../common/4f_grid_view_share");
let t4g = require("../common/4g_kanban"); let t4g = require("../common/4g_table_view_expanded_form");
let t4h = require("../common/4g_kanban");
const { const {
setCurrentMode, setCurrentMode,
} = require("../../support/page_objects/projectConstants"); } = require("../../support/page_objects/projectConstants");
@ -15,15 +15,15 @@ const {
const nocoTestSuite = (apiType, dbType) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType); setCurrentMode(apiType, dbType);
t01.genTest(apiType, dbType); t01.genTest(apiType, dbType);
//
// // place plugin related activities at top // // place plugin related activities at top
// t4c.genTest(apiType, dbType); t4c.genTest(apiType, dbType);
// t4a.genTest(apiType, dbType); t4a.genTest(apiType, dbType);
// t4b.genTest(apiType, dbType); t4b.genTest(apiType, dbType);
// t4d.genTest(apiType, dbType); t4d.genTest(apiType, dbType);
// t4e.genTest(apiType, dbType); t4e.genTest(apiType, dbType);
// t4f.genTest(apiType, dbType); t4f.genTest(apiType, dbType);
t4g.genTest(apiType, dbType); t4g.genTest(apiType, dbType);
t4h.genTest(apiType, dbType);
}; };
nocoTestSuite("rest", "mysql"); nocoTestSuite("rest", "mysql");

115
scripts/cypress/support/commands.js

@ -222,13 +222,16 @@ Cypress.Commands.add("saveLocalStorage", (name) => {
cy.printLocalStorage(); cy.printLocalStorage();
}); });
Cypress.Commands.add("restoreLocalStorage", (name) => { const restoreLocalStorage = () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => { Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => {
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]); localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
}); });
cy.printLocalStorage(); cy.printLocalStorage();
}); };
Cypress.Commands.add("restoreLocalStorage", restoreLocalStorage);
// Cypress.on("window:before:load", restoreLocalStorage);
Cypress.Commands.add("deleteLocalStorage", () => { Cypress.Commands.add("deleteLocalStorage", () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => { Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => {
@ -236,33 +239,10 @@ Cypress.Commands.add("deleteLocalStorage", () => {
}); });
}); });
// saveLocalStorageToFile
Cypress.Commands.add("saveLocalStorageToFile", (name) => {
LOCAL_STORAGE_MEMORY_v2 = {};
Object.keys(localStorage).forEach((key) => {
LOCAL_STORAGE_MEMORY_v2[key] = localStorage[key];
});
cy.writeFile(
`scripts/cypress/fixtures/${name}.json`,
LOCAL_STORAGE_MEMORY_v2
);
});
// restoreLocalStorageFromFile
Cypress.Commands.add("restoreLocalStorageFromFile", (name) => {
cy.readFile(`scripts/cypress/fixtures/${name}.json`).then((data) => {
Object.keys(data).forEach((key) => {
localStorage.setItem(key, data[key]);
});
});
cy.saveLocalStorage();
});
Cypress.Commands.add("printLocalStorage", () => { Cypress.Commands.add("printLocalStorage", () => {
cy.task("log", `[printLocalStorage]`); // cy.task('log', `[printLocalStorage]`);
cy.task("log", JSON.stringify(localStorage, null, 2)); // cy.task('log', JSON.stringify(localStorage, null, 2));
cy.task("log", JSON.stringify(LOCAL_STORAGE_MEMORY, null, 2)); // cy.task('log', JSON.stringify(LOCAL_STORAGE_MEMORY, null, 2));
}); });
Cypress.Commands.add("getActiveModal", (wrapperSelector) => { Cypress.Commands.add("getActiveModal", (wrapperSelector) => {
@ -387,9 +367,10 @@ Cypress.Commands.add("renameTable", (oldName, newName) => {
// }); // });
Cypress.Commands.add("toastWait", (msg) => { Cypress.Commands.add("toastWait", (msg) => {
cy.get(".ant-message-notice-content:visible", { timeout: 60000 }) // cy.get('.ant-message-notice-content:visible', { timout: 30000 }).should('exist')
.contains(msg) cy.get(`.ant-message-notice-content:visible:contains("${msg}")`, {
.should("exist"); timeout: 30000,
}).should("exist");
cy.get(".ant-message-notice-content:visible", { timeout: 12000 }).should( cy.get(".ant-message-notice-content:visible", { timeout: 12000 }).should(
"not.exist" "not.exist"
); );
@ -503,78 +484,6 @@ Cypress.Commands.add("signOut", () => {
cy.get('button:contains("SIGN")').should("exist"); cy.get('button:contains("SIGN")').should("exist");
}); });
// View basic routines
//
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// viewCreate
// : viewType: grid, gallery, kanban, form
// : creates view with default name
//
Cypress.Commands.add("viewCreate", (viewType) => {
// click on 'Grid/Gallery/Form/Kanban' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal(".nc-modal-view-create").find(".ant-btn-primary").click();
cy.toastWait("View created successfully");
// validate if view was created && contains default name 'Country1'
cy.get(`.nc-${viewType}-view-item`)
.contains(`${capitalizeFirstLetter(viewType)}-1`)
.should("exist");
});
// viewDelete
// : delete view by index (0-based, exclude default view)
//
Cypress.Commands.add("viewDelete", (viewIndex) => {
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").eq(viewIndex).click({ force: true });
cy.wait(300);
// click on 'Delete' button on confirmation modal
cy.getActiveModal(".nc-modal-view-delete").find(".ant-btn-dangerous").click();
cy.toastWait("View deleted successfully");
});
// viewDuplicate
// : duplicate view by index (0-based, *include* default view)
//
Cypress.Commands.add("viewCopy", (viewIndex) => {
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-copy-icon").eq(viewIndex).click({ force: true });
cy.wait(300);
// click on 'Delete' button on confirmation modal
cy.getActiveModal(".nc-modal-view-create").find(".ant-btn-primary").click();
cy.toastWait("View created successfully");
});
// viewRename
// : rename view by index (0-based, exclude default view)
//
Cypress.Commands.add("viewRename", (viewType, viewIndex, newName) => {
// click on edit-icon (becomes visible on hovering mouse)
cy.get(`.nc-${viewType}-view-item`).eq(viewIndex).dblclick();
// feed new name
cy.get(`.nc-${viewType}-view-item input`).clear().type(`${newName}{enter}`);
cy.toastWait("View renamed successfully");
// validate
cy.get(`.nc-${viewType}-view-item`).contains(`${newName}`).should("exist");
});
// openTableView
// : open view by type & name
//
Cypress.Commands.add("openTableView", (viewType, viewName) => {
cy.get(`.nc-${viewType}-view-item`).contains(`${viewName}`).click();
});
// Drag n Drop // Drag n Drop
// refer: https://stackoverflow.com/a/55409853 // refer: https://stackoverflow.com/a/55409853
/* /*

40
scripts/cypress/support/page_objects/mainPage.js

@ -16,7 +16,7 @@ export class _settingsPage {
// menu // menu
this.TEAM_N_AUTH = "teamAndAuth"; this.TEAM_N_AUTH = "teamAndAuth";
this.APPSTORE = "appStore"; this.APPSTORE = "appStore";
this.PROJ_METADATA = "metaData"; this.PROJ_METADATA = "projMetaData";
this.AUDIT = "audit"; this.AUDIT = "audit";
// submenu // submenu
@ -26,6 +26,8 @@ export class _settingsPage {
this.METADATA = "metaData"; this.METADATA = "metaData";
this.UI_ACCESS_CONTROL = "acl"; this.UI_ACCESS_CONTROL = "acl";
this.AUDIT_LOG = "audit"; this.AUDIT_LOG = "audit";
this.ERD = "erd";
this.MISC = "misc";
} }
openMenu(menuId) { openMenu(menuId) {
@ -119,6 +121,13 @@ export class _mainPage {
// click on New User button, feed details // click on New User button, feed details
cy.get("button.nc-invite-team").click(); cy.get("button.nc-invite-team").click();
// additional wait to ensure the modal is fully loaded
cy.getActiveModal(".nc-modal-invite-user-and-share-base").should("exist");
cy.getActiveModal(".nc-modal-invite-user-and-share-base")
.find('input[placeholder="E-mail"]')
.should("exist");
cy.wait(1000);
cy.get('input[placeholder="E-mail"]').type(userCred.username); cy.get('input[placeholder="E-mail"]').type(userCred.username);
cy.get(".ant-select.nc-user-roles").click(); cy.get(".ant-select.nc-user-roles").click();
@ -646,6 +655,35 @@ export class _mainPage {
toggleRightSidebar() { toggleRightSidebar() {
cy.get(".nc-toggle-right-navbar").should("exist").click(); cy.get(".nc-toggle-right-navbar").should("exist").click();
} }
openMiscTab() {
// open Project metadata tab
//
settingsPage.openMenu(settingsPage.PROJ_METADATA);
settingsPage.openTab(settingsPage.MISC);
}
toggleShowMMSetting() {
// toggle show MM setting
//
this.openMiscTab();
cy.get(".nc-settings-meta-misc").click();
settingsPage.openTab(settingsPage.TEAM_N_AUTH);
this.closeMetaTab();
}
openErdTab() {
// open Project metadata tab
//
settingsPage.openMenu(settingsPage.PROJ_METADATA);
settingsPage.openTab(settingsPage.ERD);
}
openTableErdView() {
cy.get(".nc-actions-menu-btn").should("exist").click();
cy.get(".nc-view-action-erd").should("exist").click();
}
} }
export const mainPage = new _mainPage(); export const mainPage = new _mainPage();

10
scripts/cypress/support/page_objects/projectConstants.js

@ -156,3 +156,13 @@ export function setProjectString(projStr) {
export function getProjectString() { export function getProjectString() {
return xcdbProjectString; return xcdbProjectString;
} }
const sakilaTables = [
'actor', 'address', 'category', 'city', 'country', 'customer', 'film', 'film_text', 'language', 'payment', 'rental', 'staff'
]
const sakilaSqlViews = [
'actor_info', 'customer_list', 'film_list', 'nicer_but_slower_film_list', 'sales_by_film_category', 'sales_by_store', 'staff_list'
]
export { sakilaTables, sakilaSqlViews }

6
scripts/sdk/swagger.json

@ -6169,6 +6169,12 @@
}, },
"project_id": { "project_id": {
"type": "string" "type": "string"
},
"mm": {
"type": [
"boolean",
"number"
]
} }
}, },
"required": [ "required": [

Loading…
Cancel
Save