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. 97
      packages/nc-gui/components/smartsheet/Gallery.vue
  19. 56
      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. 5
      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. 74
      packages/nc-gui/utils/validation.ts
  71. 13
      packages/noco-docs/content/en/setup-and-usages/meta-management.md
  72. 666
      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. 394
      scripts/cypress/integration/common/1b_table_column_operations.js
  76. 218
      scripts/cypress/integration/common/2b_table_with_m2m_column.js
  77. 379
      scripts/cypress/integration/common/3a_filter_sort_fields_operations.js
  78. 238
      scripts/cypress/integration/common/3c_lookup_column.js
  79. 314
      scripts/cypress/integration/common/3d_rollup_column.js
  80. 571
      scripts/cypress/integration/common/3e_duration_column.js
  81. 153
      scripts/cypress/integration/common/3f_link_to_another_record.js
  82. 861
      scripts/cypress/integration/common/4f_grid_view_share.js
  83. 201
      scripts/cypress/integration/common/4g_table_view_expanded_form.js
  84. 259
      scripts/cypress/integration/common/6g_base_share.js
  85. 778
      scripts/cypress/integration/common/8a_webhook.js
  86. 373
      scripts/cypress/integration/common/9b_ERD.js
  87. 514
      scripts/cypress/integration/spec/roleValidation.spec.js
  88. 2
      scripts/cypress/integration/test/pg-restViews.js
  89. 14
      scripts/cypress/integration/test/restMisc.js
  90. 33
      scripts/cypress/integration/test/restTableOps.js
  91. 18
      scripts/cypress/integration/test/restViews.js
  92. 117
      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/**"
- ".github/workflows/ci-cd.yml"
pull_request:
types: [ready_for_review]
branches: [develop]
paths:
- "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
# else HEAD will be taken
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
TARGET_SHA=$(git rev-parse HEAD)
TARGET_SHA=$(git rev-list -n 1 HEAD | tail -1)
fi
echo "::set-output name=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 '@braks/vue-flow/dist/style.css';
@import '@braks/vue-flow/dist/theme-default.css';
:root {
--header-height: 42px;
@ -248,3 +250,8 @@ a {
.ant-dropdown-menu-submenu-title{
@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']
MdiExitToApp: typeof import('~icons/mdi/exit-to-app')['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']
MdiFileDocumentOutline: typeof import('~icons/mdi/file-document-outline')['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']
MdiNumeric: typeof import('~icons/mdi/numeric')['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']
MdiPlus: typeof import('~icons/mdi/plus')['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']
MdiTable: typeof import('~icons/mdi/table')['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']
MdiThumbUp: typeof import('~icons/mdi/thumb-up')['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-row items-center w-full mb-4 gap-2">
<!-- 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')
}}</a-checkbox>
</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 UIAcl from './UIAcl.vue'
import Misc from './Misc.vue'
import Erd from './Erd.vue'
import { useNuxtApp } from '#app'
import { useI18n, useUIPermission, useVModel, watch } from '#imports'
import ApiTokenManagement from '~/components/tabs/auth/ApiTokenManagement.vue'
@ -90,7 +91,7 @@ const tabsInfo: TabGroup = {
$e('c:settings:appstore')
},
},
metaData: {
projMetaData: {
// Project Metadata
title: t('title.projMeta'),
icon: MultipleTableIcon,
@ -108,6 +109,13 @@ const tabsInfo: TabGroup = {
$e('c:table:ui-acl')
},
},
erd: {
title: t('title.erdView'),
body: Erd,
onClick: () => {
$e('c:settings:erd')
},
},
misc: {
title: t('general.misc'),
body: Misc,

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

@ -65,8 +65,8 @@ const syncSource = ref({
})
const validators = computed(() => ({
'details.apiKey': [fieldRequiredValidator],
'details.syncSourceUrlOrId': [fieldRequiredValidator],
'details.apiKey': [fieldRequiredValidator()],
'details.syncSourceUrlOrId': [fieldRequiredValidator()],
}))
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 validators = computed(() => ({
url: [fieldRequiredValidator, importUrlValidator, isImportTypeCsv.value ? importCsvUrlValidator : importExcelUrlValidator],
maxRowsToParse: [fieldRequiredValidator],
url: [fieldRequiredValidator(), importUrlValidator, isImportTypeCsv.value ? importCsvUrlValidator : importExcelUrlValidator],
maxRowsToParse: [fieldRequiredValidator()],
}))
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,
} 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()

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

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

@ -1,4 +1,5 @@
<script lang="ts" setup>
import { onMounted } from '@vue/runtime-core'
import { isVirtualCol } from 'nocodb-sdk'
import {
ActiveViewInj,
@ -11,7 +12,8 @@ import {
OpenNewRecordFormHookInj,
PaginationDataInj,
ReadonlyInj,
ReloadViewDataHookInj,
ReloadViewMetaHookInj,
extractPkFromRow,
inject,
provide,
useViewData,
@ -26,7 +28,7 @@ interface Attachment {
const meta = inject(MetaInj, ref())
const view = inject(ActiveViewInj, ref())
const reloadViewDataHook = inject(ReloadViewDataHookInj)
const reloadViewMetaHook = inject(ReloadViewMetaHookInj)
const openNewRecordFormHook = inject(OpenNewRecordFormHookInj, createEventHook())
const expandedFormDlg = ref(false)
@ -54,6 +56,10 @@ provide(ReadonlyInj, !isUIAllowed('xcDatatableEditable'))
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 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 val = record.row[col.title]
if (!val) return true
@ -90,22 +85,23 @@ 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 () => {
await loadData()
await loadGalleryData()
reloadAttachments.value = true
nextTick(() => {
reloadAttachments.value = false
})
})
const rowId = extractPkFromRow(row.row, meta.value.columns)
const expandForm = (row: RowType, state?: Record<string, any>) => {
if (!isUIAllowed('xcDatatableEditable')) return
expandedFormRow.value = row
expandedFormRowState.value = state
expandedFormDlg.value = true
if (rowId) {
router.push({
query: {
...route.query,
rowId,
},
})
} else {
expandedFormRow.value = row
expandedFormRowState.value = state
expandedFormDlg.value = true
}
}
const expandFormClick = async (e: MouseEvent, row: RowType) => {
@ -119,10 +115,40 @@ openNewRecordFormHook?.on(async () => {
const newRow = await addEmptyRow()
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>
<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 v-for="record in data" :key="`record-${record.row.id}`">
<Row :row="record">
@ -135,7 +161,9 @@ openNewRecordFormHook?.on(async () => {
<a-carousel v-if="!reloadAttachments && attachments(record).length" autoplay class="gallery-carousel" arrows>
<template #customPaging>
<a>
<div class="pt-[12px]"><div></div></div>
<div class="pt-[12px]">
<div></div>
</div>
</a>
</template>
<template #prevArrow>
@ -186,6 +214,17 @@ openNewRecordFormHook?.on(async () => {
:row="expandedFormRow"
:state="expandedFormRowState"
: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>
</template>

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

@ -17,6 +17,7 @@ import {
ReadonlyInj,
ReloadViewDataHookInj,
createEventHook,
extractPkFromRow,
inject,
onClickOutside,
onMounted,
@ -27,6 +28,7 @@ import {
useEventListener,
useGridViewColumnWidth,
useI18n,
useRoute,
useSmartsheetStoreOrThrow,
useUIPermission,
useViewData,
@ -53,6 +55,9 @@ const openNewRecordFormHook = inject(OpenNewRecordFormHookInj, createEventHook()
const { isUIAllowed } = useUIPermission()
const hasEditPermission = isUIAllowed('xcDatatableEditable')
const route = useRoute()
const router = useRouter()
// todo: get from parent ( inject or use prop )
const isView = false
@ -130,10 +135,21 @@ reloadViewDataHook?.on(async (shouldShowLoading) => {
const skipRowRemovalOnCancel = ref(false)
const expandForm = (row: Row, state?: Record<string, any>, fromToolbar = false) => {
expandedFormRow.value = row
expandedFormRowState.value = state
expandedFormDlg.value = true
skipRowRemovalOnCancel.value = !fromToolbar
const rowId = extractPkFromRow(row.row, meta.value.columns)
if (rowId) {
router.push({
query: {
...route.query,
rowId,
},
})
} else {
expandedFormRow.value = row
expandedFormRowState.value = state
expandedFormDlg.value = true
skipRowRemovalOnCancel.value = !fromToolbar
}
}
openNewRecordFormHook?.on(async () => {
@ -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>
<template>
@ -611,12 +648,23 @@ onBeforeUnmount(async () => {
:row="expandedFormRow"
:state="expandedFormRowState"
:meta="meta"
:view="view"
@update:model-value="
() => {
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>
</template>

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

@ -1,4 +1,6 @@
<script lang="ts" setup>
import { message } from 'ant-design-vue'
import type { ViewType } from 'nocodb-sdk'
import {
ReloadRowDataHookInj,
useExpandedFormStoreOrThrow,
@ -7,11 +9,15 @@ import {
useUIPermission,
} from '#imports'
const props = defineProps<{ view?: ViewType }>()
const emit = defineEmits(['cancel'])
const route = useRoute()
const { meta, isSqlView } = useSmartsheetStoreOrThrow()
const { commentsDrawer, primaryValue, save: _save, loadRow } = useExpandedFormStoreOrThrow()
const { commentsDrawer, primaryValue, primaryKey, save: _save, loadRow } = useExpandedFormStoreOrThrow()
const { isNew, syncLTARRefs } = useSmartsheetRowStoreOrThrow()
@ -26,15 +32,29 @@ const save = async () => {
reloadTrigger?.trigger()
} else {
await _save()
reloadTrigger?.trigger()
}
}
// todo: accept as a prop / inject
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>
<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">
<mdi-table-arrow-right :style="{ color: iconColor }" />
@ -55,7 +75,14 @@ const iconColor = '#1890ff'
<template #title>
<div class="text-center w-full">{{ $t('general.reload') }}</div>
</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 v-if="!isSqlView" placement="bottom">
<!-- Toggle comments draw -->
@ -65,17 +92,17 @@ const iconColor = '#1890ff'
<MdiCommentTextOutline
v-if="isUIAllowed('rowComments') && !isNew"
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"
/>
</a-tooltip>
<a-button class="!text" @click="emit('cancel')">
<a-button class="!text mx-1 nc-expand-form-close-btn" @click="emit('cancel')">
<!-- Cancel -->
{{ $t('general.cancel') }}
</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 -->
{{ $t('activity.saveRow') }}
</a-button>

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

@ -1,4 +1,5 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import type { TableType, ViewType } from 'nocodb-sdk'
import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import type { Ref } from 'vue'
@ -17,6 +18,7 @@ import {
toRef,
useProvideExpandedFormStore,
useProvideSmartsheetStore,
useRouter,
useVModel,
watch,
} from '#imports'
@ -29,6 +31,8 @@ interface Props {
meta: TableType
loadRow?: boolean
useMetaFields?: boolean
rowId?: string
view?: ViewType
}
const props = defineProps<Props>()
@ -41,6 +45,8 @@ const state = toRef(props, 'state')
const meta = toRef(props, 'meta')
const router = useRouter()
const fields = computedInject(FieldsInj, (_fields) => {
if (props.useMetaFields) {
return (meta.value.columns ?? []).filter((col) => !isSystemColumn(col))
@ -56,6 +62,18 @@ if (props.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)
provide(IsFormInj, ref(true))
@ -117,10 +135,10 @@ export default {
:closable="false"
class="nc-drawer-expanded-form"
>
<Header @cancel="onClose" />
<Header :view="view" @cancel="onClose" />
<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-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
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 */
function onCreate(view: ViewType) {
views.value.push(view)
activeView.value = view
router.push({ params: { viewTitle: view.title || '' } })
modalOpen = false
$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 reloadEventHook = createEventHook<void>()
const reloadViewMetaEventHook = createEventHook<void>()
const openNewRecordFormHook = createEventHook<void>()
const reloadKanbanMetaHook = createEventHook<void>()
@ -50,6 +51,7 @@ provide(ActiveViewInj, activeView)
provide(IsLockedInj, isLocked)
provide(ReloadViewDataHookInj, reloadEventHook)
provide(ReloadKanbanMetaHookInj, reloadKanbanMetaHook)
provide(ReloadViewMetaHookInj, reloadViewMetaEventHook)
provide(OpenNewRecordFormHookInj, openNewRecordFormHook)
provide(FieldsInj, fields)
provide(IsFormInj, isForm)
@ -71,7 +73,7 @@ watch(isLocked, (nextValue) => (treeViewIsLockedInj.value = nextValue), { immedi
<SmartsheetGallery v-else-if="isGallery" />
<SmartsheetForm v-else-if="isForm" />
<SmartsheetForm v-else-if="isForm && !$route.query.reload" />
<SmartsheetKanban v-else-if="isKanban" />
</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(() =>
data.tables.reduce<Record<string, [typeof fieldRequiredValidator]>>((acc, table, tableIdx) => {
acc[`tables.${tableIdx}.ref_table_name`] = [fieldRequiredValidator]
data.tables.reduce<Record<string, [ReturnType<typeof fieldRequiredValidator>]>>((acc, table, tableIdx) => {
acc[`tables.${tableIdx}.ref_table_name`] = [fieldRequiredValidator()]
hasSelectColumn.value[tableIdx] = false
table.columns?.forEach((column, columnIdx) => {
acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [fieldRequiredValidator]
acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator]
acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [fieldRequiredValidator()]
acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator()]
if (isSelect(column)) {
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 expandedFormRow = ref()
/** reload children list whenever cell value changes and list is visible */
watch(
() => props.cellValue,
() => {
if (!isNew.value) loadChildrenList()
if (!isNew.value && vModel.value) loadChildrenList()
},
)
</script>

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

@ -184,28 +184,28 @@ const methodList = ref([
const validators = computed(() => {
return {
'title': [fieldRequiredValidator],
'eventOperation': [fieldRequiredValidator],
'notification.type': [fieldRequiredValidator],
'title': [fieldRequiredValidator()],
'eventOperation': [fieldRequiredValidator()],
'notification.type': [fieldRequiredValidator()],
...(hook.notification.type === 'URL' && {
'notification.payload.method': [fieldRequiredValidator],
'notification.payload.path': [fieldRequiredValidator],
'notification.payload.method': [fieldRequiredValidator()],
'notification.payload.path': [fieldRequiredValidator()],
}),
...(hook.notification.type === 'Email' && {
'notification.payload.to': [fieldRequiredValidator],
'notification.payload.subject': [fieldRequiredValidator],
'notification.payload.body': [fieldRequiredValidator],
'notification.payload.to': [fieldRequiredValidator()],
'notification.payload.subject': [fieldRequiredValidator()],
'notification.payload.body': [fieldRequiredValidator()],
}),
...((hook.notification.type === 'Slack' ||
hook.notification.type === 'Microsoft Teams' ||
hook.notification.type === 'Discord' ||
hook.notification.type === 'Mattermost') && {
'notification.payload.channels': [fieldRequiredValidator],
'notification.payload.body': [fieldRequiredValidator],
'notification.payload.channels': [fieldRequiredValidator()],
'notification.payload.body': [fieldRequiredValidator()],
}),
...((hook.notification.type === 'Twilio' || hook.notification.type === 'Whatsapp Twilio') && {
'notification.payload.body': [fieldRequiredValidator],
'notification.payload.to': [fieldRequiredValidator],
'notification.payload.body': [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
const loadCommentsAndLogs = async () => {
if (!row.value) return
@ -179,13 +183,14 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
return data
}
const loadRow = async () => {
const loadRow = async (rowId?: string) => {
const record = await $api.dbTableRow.read(
NOCO,
(project?.value?.id || sharedView.value.view.project_id) as string,
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, {
row: record,
oldRow: { ...record },
@ -209,6 +214,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
save,
changedColumns,
loadRow,
primaryKey,
}
}, 'expanded-form-store')

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

@ -10,6 +10,12 @@ export function useMetas() {
const { tables } = useProject()
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 setMeta = async (model: any) => {
@ -91,5 +97,5 @@ export function useMetas() {
}
}
return { getMeta, clearAllMeta, metas, removeMeta, setMeta }
return { getMeta, clearAllMeta, metas, metasWithIdAsKey, removeMeta, setMeta }
}

5
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 { ComputedRef, Ref } from 'vue'
import { message } from 'ant-design-vue'
@ -174,7 +175,9 @@ export function useViewData(
: await fetchSharedViewData()
formattedData.value = formatData(response.list)
paginationData.value = response.pageInfo
await loadAggCommentsCount()
if (viewMeta.value?.type === ViewTypes.GRID) {
await loadAggCommentsCount()
}
}
async function loadGalleryData() {

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

@ -46,7 +46,6 @@ export function useViewFilters(
if (isNestedRoot) nestedFilters.value = value
nestedFilters.value = [...nestedFilters.value]
reloadHook?.trigger()
return
}
@ -174,6 +173,8 @@ export function useViewFilters(
fk_parent_id: parentId,
})
}
reloadHook?.trigger()
} catch (e: any) {
console.log(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) {
sorts.value[i] = sort
sorts.value = [...sorts.value]
reloadHook?.trigger()
return
}
@ -75,6 +76,7 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
sorts.value.splice(i, 1)
sorts.value = [...sorts.value]
reloadHook?.trigger()
$e('a:sort:delete')
} catch (e: any) {
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 }
}

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')
/** 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 ReloadViewMetaHookInj: InjectionKey<EventHook<boolean | void>> = Symbol('reload-view-meta-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 FieldsInj: InjectionKey<Ref<any[]>> = Symbol('fields-injection')

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

@ -103,7 +103,8 @@
"editor": "محرر",
"commenter": "معلق",
"viewer": "مشاهد"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "هوية",
@ -157,6 +158,7 @@
"isNotNull": "ليس فارغاً"
},
"title": {
"erdView": "ERD View",
"newProj": "مشروع جديد",
"myProject": "مشاريعي",
"formTitle": "عنوان النموذج",
@ -406,7 +408,14 @@
"linkRecord": "اربط سجل",
"addNewRecord": "إضافة سجل جديد",
"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": {
"saveChanges": "حفظ التغييرات",
@ -616,7 +625,20 @@
"rowUpdateFailed": "فشل تحديث الصف",
"deleteRowFailed": "فشل في حذف الصف",
"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": {
"exportMetadata": "تصدير البيانات الوصفية للمشروع بنجاح",

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

@ -103,7 +103,8 @@
"editor": "সমদক",
"commenter": "মনতবযক",
"viewer": "দরশক"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "আইডি",
@ -157,6 +158,7 @@
"isNotNull": "নল নয"
},
"title": {
"erdView": "ERD View",
"newProj": "নতন পরকলপ",
"myProject": "আমর পরকলপ",
"formTitle": "ফরম শিম",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "परिवरतनरकित कर",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "পরকলপ ম সফলভ রফতি কর",

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

@ -103,7 +103,8 @@
"editor": "Editor.",
"commenter": "Kommenter.",
"viewer": "Viewer."
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID.",
@ -157,6 +158,7 @@
"isNotNull": "er ikke null."
},
"title": {
"erdView": "ERD View",
"newProj": "Nyt projekt",
"myProject": "Mine projekter",
"formTitle": "Form titel",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Gem ændringer",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Project Metadata eksporteres med succes",

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

@ -103,7 +103,8 @@
"editor": "Bearbeiter",
"commenter": "Kommentator",
"viewer": "Zuschauer"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "ist nicht Null"
},
"title": {
"erdView": "ERD View",
"newProj": "Neues Projekt",
"myProject": "Meine Projekte",
"formTitle": "Formular Titel",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Änderungen speichern",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Projektmetadaten erfolgreich exportiert",

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

@ -103,7 +103,8 @@
"editor": "Editor",
"commenter": "Commenter",
"viewer": "Viewer"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "is not null"
},
"title": {
"erdView": "ERD View",
"newProj": "New Project",
"myProject": "My Projects",
"formTitle": "Form Title",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Save changes",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Project metadata exported successfully",

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

@ -103,7 +103,8 @@
"editor": "Editor",
"commenter": "Comentarista",
"viewer": "Visor"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "no es nulo"
},
"title": {
"erdView": "ERD View",
"newProj": "Nuevo proyecto",
"myProject": "Mis proyectos",
"formTitle": "Título del formulario",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Guardar cambios",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Metadatos del proyecto exportados con éxito.",

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

@ -103,7 +103,8 @@
"editor": "ویرایشگر",
"commenter": "نظردهنده",
"viewer": "بیننده"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "شناسه (ID)",
@ -157,6 +158,7 @@
"isNotNull": "تهی نیست"
},
"title": {
"erdView": "ERD View",
"newProj": "پروژه جدید",
"myProject": "پروژههای من",
"formTitle": "عنوان فرم",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "ذخیره تغییرات",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "فراداده پروژه با موفقیت خارج شد",

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

@ -103,7 +103,8 @@
"editor": "Toimittaja",
"commenter": "Kommentti",
"viewer": "Katselija"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "Id",
@ -157,6 +158,7 @@
"isNotNull": "ei ole nolla"
},
"title": {
"erdView": "ERD View",
"newProj": "Uusi projekti",
"myProject": "Omat hankkeet",
"formTitle": "Muodosta otsikko",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Tallenna muutokset",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Project Metadata viedään onnistuneesti",

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

@ -103,7 +103,8 @@
"editor": "Éditeur",
"commenter": "Commentateur",
"viewer": "Lecture seule"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "Identifiant",
@ -157,6 +158,7 @@
"isNotNull": "est non null"
},
"title": {
"erdView": "ERD View",
"newProj": "Nouveau projet",
"myProject": "Mes projets",
"formTitle": "Intitulé du formulaire",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Sauvegarder les modifications",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"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": "עוֹרֵך",
"commenter": "פרשן",
"viewer": "צוֹפֶה"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": ְעוּדַת זֶהוּת",
@ -157,6 +158,7 @@
"isNotNull": "is not null"
},
"title": {
"erdView": "ERD View",
"newProj": "פרוייקט חדש",
"myProject": "הפרויקטים שלי",
"formTitle": "טופס כותרת",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "שמור שינויים",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "פרויקט Metadata מיוצא בהצלחה",

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

@ -103,7 +103,8 @@
"editor": "सदक",
"commenter": "टिपणर",
"viewer": "दरशक"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "पहचन",
@ -157,6 +158,7 @@
"isNotNull": "निररथक नह"
},
"title": {
"erdView": "ERD View",
"newProj": "नयम",
"myProject": "म परिजन",
"formTitle": "परपतर शषक",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "परिवरतनरकित कर",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "परिजन सफलतवक नित क गई",

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

@ -103,7 +103,8 @@
"editor": "Urednik",
"commenter": "Komentator",
"viewer": "Preglednika"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "iskaznica",
@ -157,6 +158,7 @@
"isNotNull": "nije ništavan"
},
"title": {
"erdView": "ERD View",
"newProj": "Novi projekt",
"myProject": "Moji projekti",
"formTitle": "Naslov oblika",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Spremi promjene",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Projektni metapodaci su uspješno izvozili",

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

@ -103,7 +103,8 @@
"editor": "Editor",
"commenter": "Komentator",
"viewer": "Penonton"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "Indo",
@ -157,6 +158,7 @@
"isNotNull": "bukan null."
},
"title": {
"erdView": "ERD View",
"newProj": "Proyek baru",
"myProject": "Proyek saya",
"formTitle": "Bentuk judul",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Simpan perubahan",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Metadata proyek berhasil diekspor",

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

@ -103,7 +103,8 @@
"editor": "Editor",
"commenter": "Commentatore",
"viewer": "Spettatore"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "non è nullo"
},
"title": {
"erdView": "ERD View",
"newProj": "Nuovo progetto",
"myProject": "I miei progetti",
"formTitle": "Titolo del modulo",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Salva le modifiche",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Metadati del progetto esportati con successo",

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

@ -103,7 +103,8 @@
"editor": "編集者",
"commenter": "コメンター",
"viewer": "閲覧者"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "がnullでない"
},
"title": {
"erdView": "ERD View",
"newProj": "新規プロジェクト",
"myProject": "マイプロジェクト",
"formTitle": "フォームタイトル",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "変更を保存",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "プロジェクトメタデータは正常にエクスポートされました",

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

@ -103,7 +103,8 @@
"editor": "편집자",
"commenter": "해설자",
"viewer": "뷰어"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "is not null"
},
"title": {
"erdView": "ERD View",
"newProj": "새 프로젝트",
"myProject": "내 프로젝트",
"formTitle": "양식 제목",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "변경 사항 저장",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "프로젝트 메타 데이터를 성공적으로 내보냈습니다.",

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

@ -103,7 +103,8 @@
"editor": "Redaktors",
"commenter": "Komentētājs",
"viewer": "Skatītājs"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "nav null"
},
"title": {
"erdView": "ERD View",
"newProj": "Jauns projekts",
"myProject": "Mani projekti",
"formTitle": "Formas nosaukums",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Saglabāt izmaiņas",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Projekta metadati eksportēti veiksmīgi",

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

@ -103,7 +103,8 @@
"editor": "Bewerker",
"commenter": "Reviewer",
"viewer": "Kijker"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "is niet NULL"
},
"title": {
"erdView": "ERD View",
"newProj": "Nieuw Project",
"myProject": "Mijn Projecten",
"formTitle": "Formuliertitel",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Wijzigingen opslaan",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Project metadata met succes geëxporteerd",

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

@ -103,7 +103,8 @@
"editor": "Redaktør",
"commenter": "Kommenterer",
"viewer": "Seer."
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "Id.",
@ -157,6 +158,7 @@
"isNotNull": "er ikke null"
},
"title": {
"erdView": "ERD View",
"newProj": "Nytt prosjekt",
"myProject": "Mine prosjekter",
"formTitle": "Skjema tittel",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Lagre endringer",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Prosjektmetadata eksporteres vellykket",

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

@ -103,7 +103,8 @@
"editor": "Redaktor",
"commenter": "Komentator",
"viewer": "Widz"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "nie jest null."
},
"title": {
"erdView": "ERD View",
"newProj": "Nowy projekt",
"myProject": "Moje projekty",
"formTitle": "Tytuł formy",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Zapisz zmiany",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Pomyślnie wyeksportowano metadane projektu",

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

@ -103,7 +103,8 @@
"editor": "editor",
"commenter": "Comentarista",
"viewer": "Viewer."
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "identificação",
@ -157,6 +158,7 @@
"isNotNull": "não é nulo"
},
"title": {
"erdView": "ERD View",
"newProj": "Novo Projecto",
"myProject": "Os meus Projectos",
"formTitle": "Título de forma",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Salvar alterações",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Metadados do projeto exportado com sucesso",

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

@ -103,7 +103,8 @@
"editor": "editor",
"commenter": "Comentarista",
"viewer": "Viewer."
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "identificação",
@ -157,6 +158,7 @@
"isNotNull": "não é nulo"
},
"title": {
"erdView": "ERD View",
"newProj": "Novo Projeto",
"myProject": "Os meus Projetos",
"formTitle": "Título de forma",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Salvar alterações",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Metadados do projeto exportado com sucesso",

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

@ -103,7 +103,8 @@
"editor": "Редактор",
"commenter": "Комментатор",
"viewer": "Просмотр"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "Идентификатор",
@ -157,6 +158,7 @@
"isNotNull": "не ноль"
},
"title": {
"erdView": "ERD View",
"newProj": "Новый проект",
"myProject": "Мои проекты",
"formTitle": "Заголовк формы",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Сохранить изменения",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Метаданные проекта успешно экспортированы",

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

@ -103,7 +103,8 @@
"editor": "Urednik",
"commenter": "Komentar",
"viewer": "Gledalca."
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "Id",
@ -157,6 +158,7 @@
"isNotNull": "ni null"
},
"title": {
"erdView": "ERD View",
"newProj": "Novi projekt",
"myProject": "Moji projekti",
"formTitle": "Naslov obrazca",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Shrani spremembe",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Projekt Metapodatki se je uspešno izvozil",

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

@ -103,7 +103,8 @@
"editor": "Redaktör",
"commenter": "Kommentare",
"viewer": "Visare"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "Id",
@ -157,6 +158,7 @@
"isNotNull": "är inte noll"
},
"title": {
"erdView": "ERD View",
"newProj": "Nytt projekt",
"myProject": "Mina projekt",
"formTitle": "Formtitel",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Spara ändringar",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Projektmetadata exporterades framgångsrikt",

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

@ -103,7 +103,8 @@
"editor": "บรรณาธการ",
"commenter": "ผจารณ",
"viewer": "ผ"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "id",
@ -157,6 +158,7 @@
"isNotNull": "ไมเปนโมฆะ"
},
"title": {
"erdView": "ERD View",
"newProj": "โครงการใหม",
"myProject": "โครงการของฉน",
"formTitle": "ชอรปแบบ",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "บนทกการเปลยนแปลง",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "ขอมลเมตาของโครงการสงออกเรยบรอยแลว",

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

@ -103,7 +103,8 @@
"editor": "Editör",
"commenter": "Yorumcu",
"viewer": "İzleyici"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "null değil"
},
"title": {
"erdView": "ERD View",
"newProj": "Yeni proje",
"myProject": "Benim projelerim",
"formTitle": "Form başlığı",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Değişiklikleri Kaydet",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Proje metaverileri başarıyla dışa aktarıldı",

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

@ -103,7 +103,8 @@
"editor": "Редактор",
"commenter": "Коментатор",
"viewer": "Глядач"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "Ідентифікатор",
@ -157,6 +158,7 @@
"isNotNull": "не є нульовим"
},
"title": {
"erdView": "ERD View",
"newProj": "Новий проект",
"myProject": "Мої проекти",
"formTitle": "Назва форми",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Зберегти зміни",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "Метадані проекту успішно експортується",

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

@ -103,7 +103,8 @@
"editor": "Biên tập viên",
"commenter": "Bình luận",
"viewer": "Người xem"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "TÔI",
@ -157,6 +158,7 @@
"isNotNull": "không phải là null."
},
"title": {
"erdView": "ERD View",
"newProj": "Dự án mới",
"myProject": "Những dự án của tôi",
"formTitle": "Tiêu đề mẫu",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "Lưu thay đổi",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"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": "编辑",
"commenter": "评论者",
"viewer": "观众"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "不是空虚"
},
"title": {
"erdView": "ERD View",
"newProj": "创建新项目",
"myProject": "我的项目",
"formTitle": "表格标题",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "保存更改",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "项目元数据成功导出",

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

@ -103,7 +103,8 @@
"editor": "編輯",
"commenter": "評論者",
"viewer": "檢視者"
}
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
@ -157,6 +158,7 @@
"isNotNull": "不是空虛"
},
"title": {
"erdView": "ERD View",
"newProj": "建立新專案",
"myProject": "我的專案",
"formTitle": "表格標題",
@ -406,7 +408,14 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"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": {
"saveChanges": "儲存更動",
@ -616,7 +625,20 @@
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"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": {
"exportMetadata": "專案中繼資料已成功匯出",

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

@ -69,7 +69,7 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
}
} else {
/** 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 })
if (user?.roles?.user) {
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,
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: [
'virtual:windi.css',
'virtual:windi-devtools',
@ -46,9 +51,10 @@ export default defineNuxtConfig({
},
vite: {
// todo: minifiy again
build: {
minify: false,
commonjsOptions: {
ignoreTryCatch: false,
},
},
plugins: [
vueI18n({
@ -77,7 +83,8 @@ export default defineNuxtConfig({
],
define: {
'process.env.DEBUG': 'false',
'process.nextTick': () => {},
'process.nextTick': () => {
},
},
server: {
watch: {

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

@ -6,12 +6,14 @@
"": {
"hasInstallScript": true,
"dependencies": {
"@braks/vue-flow": "^0.4.39",
"@ckpack/vue-color": "^1.2.0",
"@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2",
"@vueuse/integrations": "^9.0.2",
"ant-design-vue": "^3.2.11",
"dagre": "^0.8.5",
"dayjs": "^1.11.3",
"file-saver": "^2.0.5",
"httpsnippet": "^2.0.0",
@ -53,6 +55,7 @@
"@intlify/vite-plugin-vue-i18n": "^6.0.1",
"@nuxt/image-edge": "^1.0.0-27657146.da85542",
"@types/axios": "^0.14.0",
"@types/dagre": "^0.7.48",
"@types/file-saver": "^2.0.5",
"@types/papaparse": "^5.3.2",
"@types/sortablejs": "^1.13.0",
@ -878,6 +881,103 @@
"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": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz",
@ -2347,6 +2447,12 @@
"@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": {
"version": "8.4.3",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.3.tgz",
@ -5144,6 +5250,111 @@
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
"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": {
"version": "4.0.0",
"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==",
"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": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz",
@ -15831,6 +16050,59 @@
"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": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz",
@ -16999,6 +17271,12 @@
"@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": {
"version": "8.4.3",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.3.tgz",
@ -19096,6 +19374,81 @@
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
"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": {
"version": "4.0.0",
"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==",
"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": {
"version": "7.0.0",
"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"
},
"dependencies": {
"@braks/vue-flow": "^0.4.39",
"@ckpack/vue-color": "^1.2.0",
"@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2",
"@vueuse/integrations": "^9.0.2",
"ant-design-vue": "^3.2.11",
"dagre": "^0.8.5",
"dayjs": "^1.11.3",
"file-saver": "^2.0.5",
"httpsnippet": "^2.0.0",
@ -62,6 +64,7 @@
"@intlify/vite-plugin-vue-i18n": "^6.0.1",
"@nuxt/image-edge": "^1.0.0-27657146.da85542",
"@types/axios": "^0.14.0",
"@types/dagre": "^0.7.48",
"@types/file-saver": "^2.0.5",
"@types/papaparse": "^5.3.2",
"@types/sortablejs": "^1.13.0",

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

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

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

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

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

@ -1,9 +1,14 @@
import { getI18n } from '~/plugins/a.i18n'
export const isEmail = (v: string) =>
/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i.test(v)
export function validateTableName(v: string, isGQL = false) {
const { t } = getI18n().global
if (!v) {
return 'Table name required'
// return 'Table name required'
return t('msg.error.tableNameRequired')
}
// GraphQL naming convention
@ -15,11 +20,13 @@ export function validateTableName(v: string, isGQL = false) {
}
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)
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 {
// 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.
const m = v.match(/[./\\]/g)
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
@ -35,8 +43,10 @@ export function validateTableName(v: string, isGQL = false) {
}
export function validateColumnName(v: string, isGQL = false) {
const { t } = getI18n().global
if (!v) {
return 'Column name required'
// return 'Column name required'
return t('msg.error.columnNameRequired')
}
// GraphQL naming convention
@ -47,11 +57,13 @@ export function validateColumnName(v: string, isGQL = false) {
}
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)
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 {
// 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.
const m = v.match(/[./\\]/g)
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
@ -68,36 +81,40 @@ export function validateColumnName(v: string, isGQL = false) {
export const projectTitleValidator = {
validator: (rule: any, value: any, callback: (errMsg?: string) => void) => {
const { t } = getI18n().global
if (value?.length > 50) {
callback('Project name exceeds 50 characters')
// callback('Project name exceeds 50 characters')
callback(t('msg.error.projectNameExceeds50Characters'))
}
if (value[0] === ' ') {
callback('Project name cannot start with space')
// callback('Project name cannot start with space')
callback(t('msg.error.projectNameCannotStartWithSpace'))
}
callback()
},
}
export const fieldRequiredValidator = {
required: true,
message: 'Field is required',
export const fieldRequiredValidator = () => {
const { t } = getI18n().global
return {
required: true,
// message: `Required field`,
message: t('msg.error.requiredField'),
}
}
export const getRequiredValidator = (field = 'Field') => ({
required: true,
message: `${field} is required`,
})
export const importUrlValidator = {
validator: (rule: any, value: any) => {
return new Promise((resolve, reject) => {
const { t } = getI18n().global
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(
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)
})
@ -107,8 +124,12 @@ export const importUrlValidator = {
export const importCsvUrlValidator = {
validator: (rule: any, value: any) => {
return new Promise((resolve, reject) => {
const { t } = getI18n().global
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)
})
@ -118,9 +139,13 @@ export const importCsvUrlValidator = {
export const importExcelUrlValidator = {
validator: (rule: any, value: any) => {
return new Promise((resolve, reject) => {
const { t } = getI18n().global
if (value && !/.*\.(xls|xlsx|xlsm|ods|ots)/.test(value)) {
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)
@ -131,12 +156,15 @@ export const importExcelUrlValidator = {
export const extraParameterValidator = {
validator: (_: unknown, value: { key: string; value: string }[]) => {
return new Promise((resolve, reject) => {
const { t } = getI18n().global
for (const param of value) {
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) {
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)

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.
<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
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
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">

666
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;
slug?: string;
project_id?: string;
mm?: boolean | number;
}
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 Base from '../../../models/Base';
import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2';
import { NcError } from '../../helpers/catchError';
import { PagedResponseImpl } from '../../helpers/PagedResponse';
import View from '../../../models/View';
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));
}
async function getDataList(model, view: View, req) {
const base = await Base.get(model.base_id);
@ -190,10 +192,16 @@ async function dataRead(req: Request, res: Response) {
dbDriver: NcConnectionMgrv2.get(base),
});
const row = await baseModel.readByPk(req.params.rowId);
if (!row) {
NcError.notFound();
}
res.json(
await nocoExecute(
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));
}
const router = Router({ mergeParams: true });
// table data crud apis

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

@ -1,201 +1,209 @@
import { mainPage } from "../../support/page_objects/mainPage";
import {
isTestSuiteActive,
isXcdb,
isTestSuiteActive,
isXcdb,
} from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
function addNewRow(index, cellValue) {
cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click();
// cy.get("#data-table-form-Title > input").first().type(cellValue);
cy.get(".nc-expand-col-Title").find(".nc-cell > input")
.should("exist")
.first()
.clear()
.type(cellValue);
cy.getActiveDrawer()
.find("button")
.contains("Save row")
.click({ force: true });
cy.toastWait("updated successfully");
cy.get("body").type("{esc}");
mainPage.getCell("Title", index).contains(cellValue).should("exist");
}
describe(`${apiType.toUpperCase()} api - Table Column`, () => {
const name = "tablex";
const colName = "column_name_a";
const updatedColName = "updated_column_name";
const randVal = "Test@1234.com";
const updatedRandVal = "Updated@1234.com";
// before(() => {
// cy.restoreLocalStorage();
// cy.createTable(name);
// })
beforeEach(() => {
cy.restoreLocalStorage();
})
afterEach(() => {
cy.saveLocalStorage();
})
// // delete table
// after(() => {
// cy.deleteTable(name, dbType);
// });
it("Create Table Column", () => {
cy.createTable(name);
mainPage.addColumn(colName, name);
});
// edit the newly created column
it("Edit table column - change datatype", () => {
if (!isXcdb()) {
cy.get(`th:contains(${colName}) .nc-icon.ant-dropdown-trigger`)
.trigger("mouseover", { force: true })
.click({ force: true });
// cy.get(".nc-column-edit").click();
// cy.get(".nc-column-edit").should("not.be.visible");
cy.getActiveMenu(".nc-dropdown-column-operations")
.find(".nc-column-edit")
.click();
// change column type and verify
// cy.get(".nc-column-type-input").last().click();
cy.getActiveMenu('.nc-dropdown-edit-column')
.find(".nc-column-type-input")
.last()
.click();
cy.getActiveSelection('.nc-dropdown-column-type')
.find('.ant-select-item-option')
.contains("LongText")
.click();
cy.getActiveMenu('.nc-dropdown-edit-column')
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait("Column updated");
}
});
// edit the newly created column
it("Edit table column - rename", () => {
cy.get(`th:contains(${colName}) .nc-icon.ant-dropdown-trigger`)
.trigger("mouseover", { force: true })
.click({ force: true });
// cy.get(".nc-column-edit").click();
// cy.get(".nc-column-edit").should("not.be.visible");
cy.getActiveMenu(".nc-dropdown-column-operations")
.find(".nc-column-edit")
.click();
// rename column and verify
cy.getActiveMenu(".nc-dropdown-edit-column").find('input.nc-column-name-input', { timeout: 3000 })
.should('exist')
.clear()
.type(updatedColName);
// cy.get(".ant-btn-primary:visible").contains("Save").click();
cy.getActiveMenu('.nc-dropdown-edit-column')
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait("Column updated");
cy.get(`th:contains(${colName})`).should("not.exist");
cy.get(`th:contains(${updatedColName})`).should("exist");
});
// delete the newly created column
it("Delete table column", () => {
mainPage.deleteColumn(updatedColName);
});
it("Add new row", () => {
addNewRow(1, randVal);
});
it("Update row", () => {
mainPage
.getRow(1)
.find('.nc-row-no').should('exist').eq(0).trigger('mouseover', { force: true })
cy.get(".nc-row-expand")
.click({ force: true });
cy.get(".nc-expand-col-Title").find(".nc-cell > input")
.should("exist")
.first()
.clear()
.type(updatedRandVal);
cy.getActiveDrawer()
.find("button")
.contains("Save row")
.click({ force: true });
// partial toast message
cy.toastWait("updated successfully");
cy.get("body").type("{esc}");
mainPage.getCell("Title", 1).contains(randVal).should("not.exist");
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.should("exist");
});
it("Delete Row", () => {
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.rightclick({ force: true });
// delete row
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.find('.ant-dropdown-menu-item:contains("Delete Row")')
.first()
.click({ force: true });
cy.get("td").contains(randVal).should("not.exist");
});
it("Select all row check-box validation", () => {
// add multiple rows
addNewRow(1, "a1");
addNewRow(2, "a2");
addNewRow(3, "a3");
addNewRow(4, "a4");
addNewRow(5, "a5");
cy.get('.nc-no-label').should('exist').eq(0).trigger('mouseover', { force: true })
cy.get(".ant-checkbox").should('exist')
.eq(0).click({ force: true });
// delete selected rows
mainPage.getCell("Title", 3).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Selected Rows")
.click({ force: true });
// verify if everything is wiped off
mainPage.getCell("Title", 1).contains("a1").should("not.exist");
// clean-up
cy.deleteTable(name, dbType);
});
if (!isTestSuiteActive(apiType, dbType)) return;
function addNewRow(index, cellValue) {
cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click();
// cy.get("#data-table-form-Title > input").first().type(cellValue);
cy.get(".nc-expand-col-Title")
.find(".nc-cell > input")
.should("exist")
.first()
.clear()
.type(cellValue);
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Save row")
.should("exist")
.click();
cy.toastWait("updated successfully");
cy.get("body").type("{esc}");
mainPage.getCell("Title", index).contains(cellValue).should("exist");
}
describe(`${apiType.toUpperCase()} api - Table Column`, () => {
const name = "tablex";
const colName = "column_name_a";
const updatedColName = "updated_column_name";
const randVal = "Test@1234.com";
const updatedRandVal = "Updated@1234.com";
// before(() => {
// cy.restoreLocalStorage();
// cy.createTable(name);
// })
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
// // delete table
// after(() => {
// cy.deleteTable(name, dbType);
// });
it("Create Table Column", () => {
cy.createTable(name);
mainPage.addColumn(colName, name);
});
// edit the newly created column
it("Edit table column - change datatype", () => {
if (!isXcdb()) {
cy.get(`th:contains(${colName}) .nc-icon.ant-dropdown-trigger`)
.trigger("mouseover", { force: true })
.click({ force: true });
// cy.get(".nc-column-edit").click();
// cy.get(".nc-column-edit").should("not.be.visible");
cy.getActiveMenu(".nc-dropdown-column-operations")
.find(".nc-column-edit")
.click();
// fix me! wait till the modal rendering (input highlight) is completed
cy.wait(500);
// change column type and verify
// cy.get(".nc-column-type-input").last().click();
cy.getActiveMenu(".nc-dropdown-edit-column")
.find(".nc-column-type-input")
.last()
.click();
cy.getActiveSelection(".nc-dropdown-column-type")
.find(".ant-select-item-option")
.contains("LongText")
.click();
cy.getActiveMenu(".nc-dropdown-edit-column")
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait("Column updated");
}
});
// edit the newly created column
it("Edit table column - rename", () => {
cy.get(`th:contains(${colName}) .nc-icon.ant-dropdown-trigger`)
.trigger("mouseover", { force: true })
.click({ force: true });
// cy.get(".nc-column-edit").click();
// cy.get(".nc-column-edit").should("not.be.visible");
cy.getActiveMenu(".nc-dropdown-column-operations")
.find(".nc-column-edit")
.click();
// rename column and verify
cy.getActiveMenu(".nc-dropdown-edit-column")
.find("input.nc-column-name-input", { timeout: 3000 })
.should("exist")
.clear()
.type(updatedColName);
// cy.get(".ant-btn-primary:visible").contains("Save").click();
cy.getActiveMenu(".nc-dropdown-edit-column")
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait("Column updated");
cy.get(`th:contains(${colName})`).should("not.exist");
cy.get(`th:contains(${updatedColName})`).should("exist");
});
// delete the newly created column
it("Delete table column", () => {
mainPage.deleteColumn(updatedColName);
});
it("Add new row", () => {
addNewRow(1, randVal);
});
it("Update row", () => {
mainPage
.getRow(1)
.find(".nc-row-no")
.should("exist")
.eq(0)
.trigger("mouseover", { force: true });
cy.get(".nc-row-expand").click({ force: true });
cy.get(".nc-expand-col-Title")
.find(".nc-cell > input")
.should("exist")
.first()
.clear()
.type(updatedRandVal);
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Save row")
.should("exist")
.click();
// partial toast message
cy.toastWait("updated successfully");
cy.get("body").type("{esc}");
mainPage.getCell("Title", 1).contains(randVal).should("not.exist");
mainPage.getCell("Title", 1).contains(updatedRandVal).should("exist");
});
it("Delete Row", () => {
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.rightclick({ force: true });
// delete row
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.find('.ant-dropdown-menu-item:contains("Delete Row")')
.first()
.click({ force: true });
cy.get("td").contains(randVal).should("not.exist");
});
it("Select all row check-box validation", () => {
// add multiple rows
addNewRow(1, "a1");
addNewRow(2, "a2");
addNewRow(3, "a3");
addNewRow(4, "a4");
addNewRow(5, "a5");
cy.get(".nc-no-label")
.should("exist")
.eq(0)
.trigger("mouseover", { force: true });
cy.get(".ant-checkbox").should("exist").eq(0).click({ force: true });
// delete selected rows
mainPage.getCell("Title", 3).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Selected Rows")
.click({ force: true });
// verify if everything is wiped off
mainPage.getCell("Title", 1).contains("a1").should("not.exist");
// clean-up
cy.deleteTable(name, dbType);
});
});
};
/**
@ -219,4 +227,4 @@ export const genTest = (apiType, dbType) => {
* 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/>.
*
*/
*/

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

@ -2,121 +2,135 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - M2M Column validation`, () => {
// before(() => {
// cy.openTableTab("Actor", 25);
// });
describe(`${apiType.toUpperCase()} api - M2M Column validation`, () => {
// before(() => {
// cy.openTableTab("Actor", 25);
// });
beforeEach(() => {
cy.restoreLocalStorage();
})
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
})
afterEach(() => {
cy.saveLocalStorage();
});
// after(() => {
// cy.closeTableTab("Actor");
// });
// after(() => {
// cy.closeTableTab("Actor");
// });
it("Table column header, URL validation", () => {
cy.openTableTab("Actor", 25);
// column name validation
// cy.get(`.project-tab:contains(Actor):visible`).should("exist");
// URL validation
cy.url().should("contain", `table/Actor`);
});
it("Table column header, URL validation", () => {
cy.openTableTab("Actor", 25);
// column name validation
// cy.get(`.project-tab:contains(Actor):visible`).should("exist");
// URL validation
cy.url().should("contain", `table/Actor`);
});
it("M2m chip content validation on grid", () => {
// grid m2m content validation
mainPage.getCell("Film List", 1)
.find('.nc-virtual-cell > .chips-wrapper > .chips > .group > .name')
.contains("ACADEMY DINOSAUR")
.should('exist');
mainPage.getCell("Film List", 1)
.find('.nc-virtual-cell > .chips-wrapper > .chips > .group > .name')
.contains("ANACONDA CONFESSIONS")
.should('exist');
});
it("M2m chip content validation on grid", () => {
// grid m2m content validation
mainPage
.getCell("Film List", 1)
.find(".nc-virtual-cell > .chips-wrapper > .chips > .group > .name")
.contains("ACADEMY DINOSAUR")
.should("exist");
mainPage
.getCell("Film List", 1)
.find(".nc-virtual-cell > .chips-wrapper > .chips > .group > .name")
.contains("ANACONDA CONFESSIONS")
.should("exist");
});
it("Expand m2m column", () => {
// expand first row
mainPage.getCell("Film List", 1).should("exist").trigger("mouseover").click();
cy.get('.nc-action-icon').eq(0).should('exist').click({ force: true });
it("Expand m2m column", () => {
// expand first row
mainPage
.getCell("Film List", 1)
.should("exist")
.trigger("mouseover")
.click();
cy.get(".nc-action-icon").eq(0).should("exist").click({ force: true });
// GUI-v2 Kludge:
// validations
// cy.getActiveModal().contains("Film").should("exist");
// cy.getActiveModal().find("button.mdi-reload").should("exist");
// cy.getActiveModal()
// .find("button:contains(Link to 'Film')")
// .should("exist");
cy.getActiveModal(".nc-modal-child-list")
.find(".ant-card")
.eq(0)
.contains("ACADEMY DINOSAUR")
.should("exist");
});
// GUI-v2 Kludge:
// validations
// cy.getActiveModal().contains("Film").should("exist");
// cy.getActiveModal().find("button.mdi-reload").should("exist");
// cy.getActiveModal()
// .find("button:contains(Link to 'Film')")
// .should("exist");
cy.getActiveModal(".nc-modal-child-list")
.find(".ant-card")
.eq(0)
.contains("ACADEMY DINOSAUR")
.should("exist");
it('Expand "Link to" record, validate', () => {
cy.getActiveModal(".nc-modal-child-list")
.find("button:contains(Link to 'Film')")
.click()
.then(() => {
// Link record form validation
cy.getActiveModal(".nc-modal-link-record")
.contains("Link record")
.should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find(".nc-reload")
.should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find('button:contains("Add new record")')
.should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find(".ant-card")
.eq(0)
.contains("ACE GOLDFINGER")
.should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find("button.ant-modal-close")
.click();
});
});
it('Expand "Link to" record, validate', () => {
cy.getActiveModal(".nc-modal-child-list")
.find("button:contains(Link to 'Film')")
.click()
.then(() => {
// Link record form validation
cy.getActiveModal(".nc-modal-link-record").contains("Link record").should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find(".nc-reload")
.should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find('button:contains("Add new record")')
.should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find(".ant-card")
.eq(0)
.contains("ACE GOLDFINGER")
.should("exist");
cy.getActiveModal(".nc-modal-link-record").find("button.ant-modal-close").click();
});
it("Expand first linked card, validate", () => {
// expand first row
mainPage
.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")
.find(".ant-card")
.eq(0)
.contains("ACADEMY DINOSAUR", { timeout: 2000 })
.click()
.then(() => {
// wait to ensure pop up appears before we proceed further
cy.wait(1000);
// Link card validation
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".text-lg")
.contains("ACADEMY DINOSAUR")
.should("exist");
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");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find('button:contains("Cancel")')
.should("exist")
.click();
cy.getActiveModal().find("button.ant-modal-close").click();
});
it("Expand first linked card, validate", () => {
// expand first row
mainPage.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")
.find(".ant-card")
.eq(0)
.contains("ACADEMY DINOSAUR", { timeout: 2000 })
.click()
.then(() => {
// wait to ensure pop up appears before we proceed further
cy.wait(1000)
// Link card validation
cy.getActiveDrawer()
.find(".text-lg")
.contains("ACADEMY DINOSAUR")
.should("exist");
cy.getActiveDrawer()
.find('button:contains("Save row")')
.should("exist");
cy.getActiveDrawer()
.find('button:contains("Cancel")')
.should("exist");
cy.getActiveDrawer()
.find('button:contains("Cancel")')
.click();
cy.getActiveModal().find("button.ant-modal-close").click();
});
cy.closeTableTab("Actor");
});
cy.closeTableTab("Actor");
});
});
};
/**

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

@ -1,201 +1,194 @@
import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage} from "../../support/page_objects/navigation";
import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - Grid operations`, () => {
// before(() => {
// // loginPage.loginAndOpenProject(apiType, dbType);
//
// // open country table
// cy.openTableTab("Country", 25);
// });
//
// after(() => {
// cy.closeTableTab("Country");
// });
beforeEach(() => {
cy.restoreLocalStorage();
})
afterEach(() => {
cy.saveLocalStorage();
})
it("Check country table - Pagination", () => {
cy.openTableTab("Country", 25);
cy.get(".nc-pagination").should("exist");
// verify > pagination option
mainPage.getPagination(">").click();
mainPage
.getPagination(2)
.should("have.class", "ant-pagination-item-active");
// verify < pagination option
mainPage.getPagination("<").click();
mainPage
.getPagination(1)
.should("have.class", "ant-pagination-item-active");
});
// create new row using + button in header
//
it("Add row using tool header button", () => {
// add a row to end of Country table
cy.get(".nc-add-new-row-btn").click();
cy.wait(1000);
cy.get(".nc-expand-col-Country").find(".nc-cell > input").first().type("Test Country");
cy.getActiveDrawer()
.find(".ant-btn-primary")
.contains("Save row")
.click();
// cy.get("#data-table-form-Country > input")
// .first()
// .type("Test Country");
// cy.contains("Save row").filter("button").click();
cy.toastWait("updated successfully");
cy.getActiveDrawer()
.find(".ant-btn")
.contains("Cancel")
.click();
// verify
mainPage.getPagination(5).click();
// kludge: flicker on load
cy.wait(3000)
mainPage
.getCell("Country", 10)
.contains("Test Country")
.should("exist");
});
// delete single row
//
it("Delete Row", () => {
// delete row added in previous step
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu(".nc-dropdown-grid-context-menu").contains("Delete Row").click();
// cy.toastWait('Deleted row successfully')
// verify
cy.get(`:nth-child(10) > [data-title="Country"]`).should("not.exist");
mainPage.getPagination(1).click();
});
// create new row using right click menu option
//
it.skip("Add row using rightclick menu option", () => {
// Temporary
mainPage.getPagination(5).click();
mainPage.getCell("Country", 9).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Insert New Row")
.click({ force: true });
mainPage
.getCell("Country", 10)
.dblclick()
.find("input")
.type("Test Country-1{enter}");
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Insert New Row")
.click({ force: true });
mainPage
.getCell("Country", 11)
.dblclick()
.find("input")
.type("Test Country-2{enter}");
// GUI-v2 Kludge:
// to move cursor away from input field; enter key is not recognized
// mainPage.getCell("Country", 10).click()
// verify
mainPage
.getCell("Country", 10)
.contains("Test Country-1")
.should("exist");
mainPage
.getCell("Country", 11)
.contains("Test Country-2")
.should("exist");
});
// delete selected rows (multiple)
//
it.skip("Delete Selected", () => {
cy.get(".ant-checkbox").should('exist')
.eq(10).click({ force: true });
cy.get(".ant-checkbox").should('exist')
.eq(11).click({ force: true });
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Selected Rows")
.click({ force: true });
// verify
// mainPage.getCell("Country", 10).should("not.exist");
// mainPage.getCell("Country", 11).should("not.exist");
cy.get(
`:nth-child(10) > [data-title="Country"]`
).should("not.exist");
cy.get(
`:nth-child(11) > [data-title="Country"]`
).should("not.exist");
mainPage.getPagination(1).click();
});
it("Enable sort", () => {
mainPage.sortField("Country", "Z → A");
cy.contains("Zambia").should("exist");
});
it("Disable sort", () => {
mainPage.clearSort();
cy.contains("Zambia").should("not.exist");
});
it("Hide field", () => {
mainPage.hideField("LastUpdate");
});
it("Show field", () => {
mainPage.unhideField("LastUpdate");
});
it("Create Filter", () => {
mainPage.filterField("Country", "is equal", "India");
// cy.get("td:contains(India)").should("exist");
mainPage.getCell("Country", 1)
.contains("India")
.should("exist");
});
it("Delete Filter", () => {
// remove sort and check
mainPage.filterReset();
mainPage.getCell("Country", 1)
.contains("India")
.should("not.exist");
// cy.contains("td:contains(India)").should("not.exist");
cy.closeTableTab("Country");
});
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - Grid operations`, () => {
// before(() => {
// // loginPage.loginAndOpenProject(apiType, dbType);
//
// // open country table
// cy.openTableTab("Country", 25);
// });
//
// after(() => {
// cy.closeTableTab("Country");
// });
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
it("Check country table - Pagination", () => {
cy.openTableTab("Country", 25);
cy.get(".nc-pagination").should("exist");
// verify > pagination option
mainPage.getPagination(">").click();
mainPage
.getPagination(2)
.should("have.class", "ant-pagination-item-active");
// verify < pagination option
mainPage.getPagination("<").click();
mainPage
.getPagination(1)
.should("have.class", "ant-pagination-item-active");
});
// create new row using + button in header
//
it("Add row using tool header button", () => {
// add a row to end of Country table
cy.get(".nc-add-new-row-btn").click();
cy.wait(1000);
cy.get(".nc-expand-col-Country")
.find(".nc-cell > input")
.first()
.type("Test Country");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".ant-btn-primary")
.contains("Save row")
.should("exist")
.click();
// cy.get("#data-table-form-Country > input")
// .first()
// .type("Test Country");
// cy.contains("Save row").filter("button").click();
cy.toastWait("updated successfully");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".ant-btn")
.contains("Cancel")
.should("exist")
.click();
// verify
mainPage.getPagination(5).click();
// kludge: flicker on load
cy.wait(3000);
mainPage.getCell("Country", 10).contains("Test Country").should("exist");
});
// delete single row
//
it("Delete Row", () => {
// delete row added in previous step
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Row")
.click();
// cy.toastWait('Deleted row successfully')
// verify
cy.get(`:nth-child(10) > [data-title="Country"]`).should("not.exist");
mainPage.getPagination(1).click();
});
// create new row using right click menu option
//
it.skip("Add row using rightclick menu option", () => {
// Temporary
mainPage.getPagination(5).click();
mainPage.getCell("Country", 9).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Insert New Row")
.click({ force: true });
mainPage
.getCell("Country", 10)
.dblclick()
.find("input")
.type("Test Country-1{enter}");
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Insert New Row")
.click({ force: true });
mainPage
.getCell("Country", 11)
.dblclick()
.find("input")
.type("Test Country-2{enter}");
// GUI-v2 Kludge:
// to move cursor away from input field; enter key is not recognized
// mainPage.getCell("Country", 10).click()
// verify
mainPage
.getCell("Country", 10)
.contains("Test Country-1")
.should("exist");
mainPage
.getCell("Country", 11)
.contains("Test Country-2")
.should("exist");
});
// delete selected rows (multiple)
//
it.skip("Delete Selected", () => {
cy.get(".ant-checkbox").should("exist").eq(10).click({ force: true });
cy.get(".ant-checkbox").should("exist").eq(11).click({ force: true });
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Selected Rows")
.click({ force: true });
// verify
// mainPage.getCell("Country", 10).should("not.exist");
// mainPage.getCell("Country", 11).should("not.exist");
cy.get(`:nth-child(10) > [data-title="Country"]`).should("not.exist");
cy.get(`:nth-child(11) > [data-title="Country"]`).should("not.exist");
mainPage.getPagination(1).click();
});
it("Enable sort", () => {
mainPage.sortField("Country", "Z → A");
cy.contains("Zambia").should("exist");
});
it("Disable sort", () => {
mainPage.clearSort();
cy.contains("Zambia").should("not.exist");
});
it("Hide field", () => {
mainPage.hideField("LastUpdate");
});
it("Show field", () => {
mainPage.unhideField("LastUpdate");
});
it("Create Filter", () => {
mainPage.filterField("Country", "is equal", "India");
// cy.get("td:contains(India)").should("exist");
mainPage.getCell("Country", 1).contains("India").should("exist");
});
it("Delete Filter", () => {
// remove sort and check
mainPage.filterReset();
mainPage.getCell("Country", 1).contains("India").should("not.exist");
// cy.contains("td:contains(India)").should("not.exist");
cy.closeTableTab("Country");
});
});
};
/**

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

@ -2,126 +2,126 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - LookUp column`, () => {
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".ant-row").click();
};
// Run once before test- create project (rest/graphql)
//
// before(() => {
// cy.fileHook();
// mainPage.tabReset();
// // open a table to work on views
// //
//
// // // kludge: wait for page load to finish
// // cy.wait(1000);
// // // close team & auth tab
// // cy.get('button.ant-tabs-tab-remove').should('exist').click();
// // cy.wait(1000);
//
// cy.openTableTab("City", 25);
// });
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
})
// after(() => {
// cy.closeTableTab("City");
// });
// Routine to create a new look up column
//
const addLookUpColumn = (childTable, childCol) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true,
});
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find('input.nc-column-name-input')
.should('exist')
.clear()
.type(childCol);
// cy.get(".nc-column-type-input").last().click().type("Lookup");
cy.getActiveMenu('.nc-dropdown-grid-add-column')
.find(".nc-column-type-input")
.last()
.click()
.type("Lookup");
cy.getActiveSelection('.nc-dropdown-column-type')
.find('.ant-select-item-option')
.contains("Lookup")
.click();
// Configure Child table & column names
fetchParentFromLabel("Child table");
cy.getActiveSelection('.nc-dropdown-relation-table')
.find('.ant-select-item-option')
.contains(childTable)
.click();
fetchParentFromLabel("Child column");
cy.getActiveSelection('.nc-dropdown-relation-column')
.find('.ant-select-item-option')
.contains(childCol)
.click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu('.nc-dropdown-grid-add-column')
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait(`Column created`);
cy.get(`th[data-title="${childCol}"]`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (childCol) => {
mainPage.deleteColumn(childCol);
};
///////////////////////////////////////////////////
// Test case
it("Add Lookup column (Address, PostalCode) & Delete", () => {
cy.openTableTab("City", 25);
addLookUpColumn("Address", "PostalCode");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
mainPage.getCell("PostalCode", 1)
.contains("4166")
.should("exist");
deleteColumnByName("PostalCode");
cy.closeTableTab("City");
});
it.skip("Add Lookup column (Country, CountryId) & Delete", () => {
addLookUpColumn("Country", "CountryId");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="CountryId"]`)
.contains("87")
.should("exist");
deleteColumnByName("CountryId");
});
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - LookUp column`, () => {
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".ant-row").click();
};
// Run once before test- create project (rest/graphql)
//
// before(() => {
// cy.fileHook();
// mainPage.tabReset();
// // open a table to work on views
// //
//
// // // kludge: wait for page load to finish
// // cy.wait(1000);
// // // close team & auth tab
// // cy.get('button.ant-tabs-tab-remove').should('exist').click();
// // cy.wait(1000);
//
// cy.openTableTab("City", 25);
// });
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
// after(() => {
// cy.closeTableTab("City");
// });
// Routine to create a new look up column
//
const addLookUpColumn = (childTable, childCol) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true,
});
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find("input.nc-column-name-input")
.should("exist")
.clear()
.type(childCol);
// cy.get(".nc-column-type-input").last().click().type("Lookup");
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".nc-column-type-input")
.last()
.click()
.type("Lookup");
cy.getActiveSelection(".nc-dropdown-column-type")
.find(".ant-select-item-option")
.contains("Lookup")
.click();
// wait for re-rendering & title selection to re-appear
cy.wait(500);
// Configure Child table & column names
fetchParentFromLabel("Child table");
cy.getActiveSelection(".nc-dropdown-relation-table")
.find(".ant-select-item-option")
.contains(childTable)
.click();
fetchParentFromLabel("Child column");
cy.getActiveSelection(".nc-dropdown-relation-column")
.find(".ant-select-item-option")
.contains(childCol)
.click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait(`Column created`);
cy.get(`th[data-title="${childCol}"]`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (childCol) => {
mainPage.deleteColumn(childCol);
};
///////////////////////////////////////////////////
// Test case
it("Add Lookup column (Address, PostalCode) & Delete", () => {
cy.openTableTab("City", 25);
addLookUpColumn("Address", "PostalCode");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
mainPage.getCell("PostalCode", 1).contains("4166").should("exist");
deleteColumnByName("PostalCode");
cy.closeTableTab("City");
});
it.skip("Add Lookup column (Country, CountryId) & Delete", () => {
addLookUpColumn("Country", "CountryId");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="CountryId"]`)
.contains("87")
.should("exist");
deleteColumnByName("CountryId");
});
});
};
/**

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

@ -2,164 +2,164 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - RollUp column`, () => {
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".ant-row").click();
cy.wait(500);
};
// Run once before test- create project (rest/graphql)
//
// before(() => {
// cy.fileHook();
// mainPage.tabReset();
//
// // // kludge: wait for page load to finish
// // cy.wait(1000);
// // // close team & auth tab
// // cy.get('button.ant-tabs-tab-remove').should('exist').click();
// // cy.wait(1000);
//
// // open a table to work on views
// //
// cy.openTableTab("Country", 25);
// });
beforeEach(() => {
cy.restoreLocalStorage();
})
afterEach(() => {
cy.saveLocalStorage();
})
// after(() => {
// cy.closeTableTab("Country");
// });
// Routine to create a new look up column
//
const addRollUpColumn = (
columnName,
childTable,
childCol,
aggregateFunc
) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true,
});
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find('input.nc-column-name-input')
.should('exist')
.clear()
.type(columnName);
// cy.get(".nc-column-type-input").last().click().type("RollUp");
cy.getActiveMenu('.nc-dropdown-grid-add-column')
.find(".nc-column-type-input")
.last()
.click()
.type("RollUp")
cy.getActiveSelection('.nc-dropdown-column-type')
.find('.ant-select-item-option')
.contains("Rollup")
.click();
// Configure Child table & column names
fetchParentFromLabel("Child table");
cy.getActiveSelection('.nc-dropdown-relation-table')
.find('.ant-select-item-option')
.contains(childTable)
.click();
fetchParentFromLabel("Child column");
cy.getActiveSelection('.nc-dropdown-relation-column')
.find('.ant-select-item-option')
.contains(childCol)
.click();
fetchParentFromLabel("Aggregate function");
cy.getActiveSelection('.nc-dropdown-rollup-function')
.find('.ant-select-item-option')
.contains(aggregateFunc)
.click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu('.nc-dropdown-grid-add-column')
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait(`Column created`);
cy.get(`th[data-title="${columnName}"]`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (columnName) => {
mainPage.deleteColumn(columnName);
};
// routine to edit column
//
// const editColumnByName = (oldName, newName) => {
// // verify if column exists before delete
// cy.get(`th:contains(${oldName})`).should("exist");
//
// // delete opiton visible on mouse-over
// cy.get(`th:contains(${oldName}) .mdi-menu-down`)
// .trigger("mouseover")
// .click();
//
// // edit/ save on pop-up
// cy.get(".nc-column-edit").click();
// cy.get(".nc-column-name-input input").clear().type(newName);
// cy.get(".nc-col-create-or-edit-card").contains("Save").click();
//
// cy.toastWait("Successfully updated alias");
//
// // validate if deleted (column shouldnt exist)
// cy.get(`th:contains(${oldName})`).should("not.exist");
// cy.get(`th:contains(${newName})`).should("exist");
// };
///////////////////////////////////////////////////
// Test case
it("Add Rollup column (City, City, count) & Delete", () => {
cy.openTableTab("Country", 25);
addRollUpColumn("RollUpCol", "City", "City", "count");
// 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
mainPage.getCell("RollUpCol", 4)
.contains("2")
.should("exist");
// editColumnByName("RollUpCol_2", "RollUpCol_New");
deleteColumnByName("RollUpCol");
cy.closeTableTab("Country");
});
it.skip("Add Rollup column (City, CountryId, count) & Delete", () => {
addRollUpColumn("RollUpCol_1", "City", "CountryId", "count");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(4) > [data-col="RollUpCol_1"]`)
.contains("2")
.should("exist");
// editColumnByName("RollUpCol_1", "RollUpCol_New");
deleteColumnByName("RollUpCol_New");
});
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - RollUp column`, () => {
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".ant-row").click();
cy.wait(500);
};
// Run once before test- create project (rest/graphql)
//
// before(() => {
// cy.fileHook();
// mainPage.tabReset();
//
// // // kludge: wait for page load to finish
// // cy.wait(1000);
// // // close team & auth tab
// // cy.get('button.ant-tabs-tab-remove').should('exist').click();
// // cy.wait(1000);
//
// // open a table to work on views
// //
// cy.openTableTab("Country", 25);
// });
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
// after(() => {
// cy.closeTableTab("Country");
// });
// Routine to create a new look up column
//
const addRollUpColumn = (
columnName,
childTable,
childCol,
aggregateFunc
) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true,
});
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find("input.nc-column-name-input")
.should("exist")
.clear()
.type(columnName);
// cy.get(".nc-column-type-input").last().click().type("RollUp");
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".nc-column-type-input")
.last()
.click()
.type("RollUp");
cy.getActiveSelection(".nc-dropdown-column-type")
.find(".ant-select-item-option")
.contains("Rollup")
.click();
// wait for re-rendering & title selection to re-appear
cy.wait(500);
// Configure Child table & column names
fetchParentFromLabel("Child table");
cy.getActiveSelection(".nc-dropdown-relation-table")
.find(".ant-select-item-option")
.contains(childTable)
.click();
fetchParentFromLabel("Child column");
cy.getActiveSelection(".nc-dropdown-relation-column")
.find(".ant-select-item-option")
.contains(childCol)
.click();
fetchParentFromLabel("Aggregate function");
cy.getActiveSelection(".nc-dropdown-rollup-function")
.find(".ant-select-item-option")
.contains(aggregateFunc)
.click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait(`Column created`);
cy.get(`th[data-title="${columnName}"]`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (columnName) => {
mainPage.deleteColumn(columnName);
};
// routine to edit column
//
// const editColumnByName = (oldName, newName) => {
// // verify if column exists before delete
// cy.get(`th:contains(${oldName})`).should("exist");
//
// // delete opiton visible on mouse-over
// cy.get(`th:contains(${oldName}) .mdi-menu-down`)
// .trigger("mouseover")
// .click();
//
// // edit/ save on pop-up
// cy.get(".nc-column-edit").click();
// cy.get(".nc-column-name-input input").clear().type(newName);
// cy.get(".nc-col-create-or-edit-card").contains("Save").click();
//
// cy.toastWait("Successfully updated alias");
//
// // validate if deleted (column shouldnt exist)
// cy.get(`th:contains(${oldName})`).should("not.exist");
// cy.get(`th:contains(${newName})`).should("exist");
// };
///////////////////////////////////////////////////
// Test case
it("Add Rollup column (City, City, count) & Delete", () => {
cy.openTableTab("Country", 25);
addRollUpColumn("RollUpCol", "City", "City", "count");
// 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
mainPage.getCell("RollUpCol", 4).contains("2").should("exist");
// editColumnByName("RollUpCol_2", "RollUpCol_New");
deleteColumnByName("RollUpCol");
cy.closeTableTab("Country");
});
it.skip("Add Rollup column (City, CountryId, count) & Delete", () => {
addRollUpColumn("RollUpCol_1", "City", "CountryId", "count");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(4) > [data-col="RollUpCol_1"]`)
.contains("2")
.should("exist");
// editColumnByName("RollUpCol_1", "RollUpCol_New");
deleteColumnByName("RollUpCol_New");
});
});
};
/**

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

@ -1,282 +1,301 @@
import { mainPage } from "../../support/page_objects/mainPage";
import {
isTestSuiteActive,
} from "../../support/page_objects/projectConstants";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - DURATION`, () => {
const tableName = "DurationTable";
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".ant-row").first().click();
};
// Run once before test- create table
//
before(() => {
mainPage.tabReset();
// // kludge: wait for page load to finish
// cy.wait(1000);
// // close team & auth tab
// cy.get('button.ant-tabs-tab-remove').should('exist').click();
// cy.wait(1000);
cy.createTable(tableName);
});
beforeEach(() => {
});
after(() => {
cy.deleteTable(tableName);
});
// Routine to create a new look up column
//
const addDurationColumn = (columnName, durationFormat) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true,
});
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find('input.nc-column-name-input', { timeout: 3000 })
.should('exist')
.clear()
.type(columnName);
// cy.get(".nc-column-type-input").last().click().type("Duration");
cy.getActiveMenu('.nc-dropdown-grid-add-column')
.find(".nc-column-type-input")
.last()
.click()
.type("Duration")
cy.getActiveSelection('.nc-dropdown-column-type')
.find('.ant-select-item-option')
.contains("Duration")
.click();
// Configure Duration format
fetchParentFromLabel("Duration Format");
cy.getActiveSelection('.nc-dropdown-duration-option')
.find('.ant-select-item-option')
.contains(durationFormat)
.click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu('.nc-dropdown-grid-add-column')
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait(`Column created`);
cy.get(`th[data-title="${columnName}"]`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (columnName) => {
mainPage.deleteColumn(columnName);
};
// routine to edit column
//
const editColumnByName = (oldName, newName, newDurationFormat) => {
cy.get(`th:contains(${oldName}) .nc-icon.ant-dropdown-trigger`)
.trigger("mouseover", { force: true })
.click({ force: true });
// cy.get(".nc-column-edit").click();
// cy.get(".nc-column-edit").should("not.be.visible");
cy.getActiveMenu(".nc-dropdown-column-operations")
.find(".nc-column-edit")
.click();
// rename column and verify
cy.getActiveMenu(".nc-dropdown-edit-column")
.find('input.nc-column-name-input', { timeout: 3000 })
.should('exist')
.clear()
.type(newName);
// Configure Duration format
fetchParentFromLabel("Duration Format");
cy.getActiveSelection('.nc-dropdown-duration-option')
.find('.ant-select-item-option')
.contains(newDurationFormat)
.click();
// cy.get(".ant-btn-primary:visible").contains("Save").click();
cy.getActiveMenu('.nc-dropdown-edit-column')
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait("Column updated");
cy.get(`th:contains(${oldName})`).should("not.exist");
cy.get(`th:contains(${newName})`).should("exist");
};
const addDurationData = (colName, index, cellValue, expectedValue, isNewRow = false) => {
if (isNewRow) {
cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.wait(500)
cy.get(".nc-add-new-row-btn").click();
} else {
// mainPage.getRow(index).find(".nc-row-expand-icon").click({ force: true });
cy.get(".nc-row-expand")
.eq(index-1)
.click({ force: true });
}
cy.get(".duration-cell-wrapper > input").first().should('exist').type(cellValue);
cy.getActiveDrawer().find("button").contains("Save row").click({ force: true });
cy.toastWait("Row updated successfully");
cy.getActiveDrawer().find("button").contains("Cancel").click({ force: true });
// mainPage.getCell(colName, index).find('input').then(($e) => {
// expect($e[0].value).to.equal(expectedValue)
// })
mainPage.getCell(colName, index)
.contains(expectedValue)
.should("exist");
}
///////////////////////////////////////////////////
// Test case
{
// Duration: h:mm
it("Duration: h:mm", () => {
addDurationColumn("NC_DURATION_0", "h:mm (e.g. 1:23)");
addDurationData("NC_DURATION_0", 1, "1:30", "01:30", true);
addDurationData("NC_DURATION_0", 2, "30", "00:30", true);
addDurationData("NC_DURATION_0", 3, "60", "01:00", true);
addDurationData("NC_DURATION_0", 4, "80", "01:20", true);
addDurationData("NC_DURATION_0", 5, "12:34", "12:34", true);
addDurationData("NC_DURATION_0", 6, "15:130", "17:10", true);
addDurationData("NC_DURATION_0", 7, "123123", "2052:03", true);
});
it("Duration: Edit Column NC_DURATION_0", () => {
editColumnByName(
"NC_DURATION_0",
"NC_DURATION_EDITED_0",
"h:mm:ss (e.g. 3:45, 1:23:40)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_0");
});
}
{
// Duration: h:mm:ss
it("Duration: h:mm:ss", () => {
addDurationColumn("NC_DURATION_1", "h:mm:ss (e.g. 3:45, 1:23:40)");
addDurationData("NC_DURATION_1", 1, "11:22:33", "11:22:33");
addDurationData("NC_DURATION_1", 2, "1234", "00:20:34");
addDurationData("NC_DURATION_1", 3, "50", "00:00:50");
addDurationData("NC_DURATION_1", 4, "1:1111", "00:19:31");
addDurationData("NC_DURATION_1", 5, "1:11:1111", "01:29:31");
addDurationData("NC_DURATION_1", 6, "15:130", "00:17:10");
addDurationData("NC_DURATION_1", 7, "123123", "34:12:03");
});
it("Duration: Edit Column NC_DURATION_1", () => {
editColumnByName(
"NC_DURATION_1",
"NC_DURATION_EDITED_1",
"h:mm:ss.s (e.g. 3:34.6, 1:23:40.0)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_1");
});
}
{
// 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)");
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", 3, "12:34:56", "12:34:56.0");
addDurationData("NC_DURATION_2", 4, "12:34:999", "12:50:39.0");
addDurationData("NC_DURATION_2", 5, "12:999:56", "28:39:56.0");
addDurationData("NC_DURATION_2", 6, "12:34:56.12", "12:34:56.1");
addDurationData("NC_DURATION_2", 7, "12:34:56.199", "12:34:56.2");
});
it("Duration: Edit Column NC_DURATION_2", () => {
editColumnByName(
"NC_DURATION_2",
"NC_DURATION_EDITED_2",
"h:mm:ss (e.g. 3:45, 1:23:40)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_2");
});
}
{
// 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)");
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", 3, "12:34:56", "12:34:56.00");
addDurationData("NC_DURATION_3", 4, "12:34:999", "12:50:39.00");
addDurationData("NC_DURATION_3", 5, "12:999:56", "28:39:56.00");
addDurationData("NC_DURATION_3", 6, "12:34:56.12", "12:34:56.12");
addDurationData("NC_DURATION_3", 7, "12:34:56.199", "12:34:56.20");
});
it("Duration: Edit Column NC_DURATION_3", () => {
editColumnByName(
"NC_DURATION_3",
"NC_DURATION_EDITED_3",
"h:mm:ss.ss (e.g. 3.45.67, 1:23:40.00)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_3");
});
}
{
// 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)");
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", 3, "12:34:56", "12:34:56.000");
addDurationData("NC_DURATION_4", 4, "12:34:999", "12:50:39.000");
addDurationData("NC_DURATION_4", 5, "12:999:56", "28:39:56.000");
addDurationData("NC_DURATION_4", 6, "12:34:56.12", "12:34:56.012");
addDurationData("NC_DURATION_4", 7, "12:34:56.199", "12:34:56.199");
});
it("Duration: Edit Column NC_DURATION_4", () => {
editColumnByName(
"NC_DURATION_4",
"NC_DURATION_EDITED_4",
"h:mm (e.g. 1:23)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_4");
});
}
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - DURATION`, () => {
const tableName = "DurationTable";
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".ant-row").first().click();
};
// Run once before test- create table
//
before(() => {
mainPage.tabReset();
// // kludge: wait for page load to finish
// cy.wait(1000);
// // close team & auth tab
// cy.get('button.ant-tabs-tab-remove').should('exist').click();
// cy.wait(1000);
cy.createTable(tableName);
});
beforeEach(() => {});
after(() => {
cy.deleteTable(tableName);
});
// Routine to create a new look up column
//
const addDurationColumn = (columnName, durationFormat) => {
cy.get(".nc-grid tr > th:last .nc-icon").click({
force: true,
});
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find("input.nc-column-name-input", { timeout: 3000 })
.should("exist")
.clear()
.type(columnName);
// cy.get(".nc-column-type-input").last().click().type("Duration");
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".nc-column-type-input")
.last()
.click()
.type("Duration");
cy.getActiveSelection(".nc-dropdown-column-type")
.find(".ant-select-item-option")
.contains("Duration")
.click();
// Configure Duration format
fetchParentFromLabel("Duration Format");
cy.getActiveSelection(".nc-dropdown-duration-option")
.find(".ant-select-item-option")
.contains(durationFormat)
.click();
// cy.get(".ant-btn-primary").contains("Save").should('exist').click();
cy.getActiveMenu(".nc-dropdown-grid-add-column")
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait(`Column created`);
cy.get(`th[data-title="${columnName}"]`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (columnName) => {
mainPage.deleteColumn(columnName);
};
// routine to edit column
//
const editColumnByName = (oldName, newName, newDurationFormat) => {
cy.get(`th:contains(${oldName}) .nc-icon.ant-dropdown-trigger`)
.trigger("mouseover", { force: true })
.click({ force: true });
// cy.get(".nc-column-edit").click();
// cy.get(".nc-column-edit").should("not.be.visible");
cy.getActiveMenu(".nc-dropdown-column-operations")
.find(".nc-column-edit")
.click();
// rename column and verify
cy.getActiveMenu(".nc-dropdown-edit-column")
.find("input.nc-column-name-input", { timeout: 3000 })
.should("exist")
.clear()
.type(newName);
// Configure Duration format
fetchParentFromLabel("Duration Format");
cy.getActiveSelection(".nc-dropdown-duration-option")
.find(".ant-select-item-option")
.contains(newDurationFormat)
.click();
// cy.get(".ant-btn-primary:visible").contains("Save").click();
cy.getActiveMenu(".nc-dropdown-edit-column")
.find(".ant-btn-primary:visible")
.contains("Save")
.click();
cy.toastWait("Column updated");
cy.get(`th:contains(${oldName})`).should("not.exist");
cy.get(`th:contains(${newName})`).should("exist");
};
const addDurationData = (
colName,
index,
cellValue,
expectedValue,
isNewRow = false
) => {
if (isNewRow) {
cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.wait(500);
cy.get(".nc-add-new-row-btn").click();
} else {
// mainPage.getRow(index).find(".nc-row-expand-icon").click({ force: true });
cy.get(".nc-row-expand")
.eq(index - 1)
.click({ force: true });
}
cy.get(".duration-cell-wrapper > input")
.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.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Cancel")
.should("exist")
.click();
// mainPage.getCell(colName, index).find('input').then(($e) => {
// expect($e[0].value).to.equal(expectedValue)
// })
mainPage.getCell(colName, index).contains(expectedValue).should("exist");
};
///////////////////////////////////////////////////
// Test case
{
// Duration: h:mm
it("Duration: h:mm", () => {
addDurationColumn("NC_DURATION_0", "h:mm (e.g. 1:23)");
addDurationData("NC_DURATION_0", 1, "1:30", "01:30", true);
addDurationData("NC_DURATION_0", 2, "30", "00:30", true);
addDurationData("NC_DURATION_0", 3, "60", "01:00", true);
addDurationData("NC_DURATION_0", 4, "80", "01:20", true);
addDurationData("NC_DURATION_0", 5, "12:34", "12:34", true);
addDurationData("NC_DURATION_0", 6, "15:130", "17:10", true);
addDurationData("NC_DURATION_0", 7, "123123", "2052:03", true);
});
it("Duration: Edit Column NC_DURATION_0", () => {
editColumnByName(
"NC_DURATION_0",
"NC_DURATION_EDITED_0",
"h:mm:ss (e.g. 3:45, 1:23:40)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_0");
});
}
{
// Duration: h:mm:ss
it("Duration: h:mm:ss", () => {
addDurationColumn("NC_DURATION_1", "h:mm:ss (e.g. 3:45, 1:23:40)");
addDurationData("NC_DURATION_1", 1, "11:22:33", "11:22:33");
addDurationData("NC_DURATION_1", 2, "1234", "00:20:34");
addDurationData("NC_DURATION_1", 3, "50", "00:00:50");
addDurationData("NC_DURATION_1", 4, "1:1111", "00:19:31");
addDurationData("NC_DURATION_1", 5, "1:11:1111", "01:29:31");
addDurationData("NC_DURATION_1", 6, "15:130", "00:17:10");
addDurationData("NC_DURATION_1", 7, "123123", "34:12:03");
});
it("Duration: Edit Column NC_DURATION_1", () => {
editColumnByName(
"NC_DURATION_1",
"NC_DURATION_EDITED_1",
"h:mm:ss.s (e.g. 3:34.6, 1:23:40.0)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_1");
});
}
{
// 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)"
);
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", 3, "12:34:56", "12:34:56.0");
addDurationData("NC_DURATION_2", 4, "12:34:999", "12:50:39.0");
addDurationData("NC_DURATION_2", 5, "12:999:56", "28:39:56.0");
addDurationData("NC_DURATION_2", 6, "12:34:56.12", "12:34:56.1");
addDurationData("NC_DURATION_2", 7, "12:34:56.199", "12:34:56.2");
});
it("Duration: Edit Column NC_DURATION_2", () => {
editColumnByName(
"NC_DURATION_2",
"NC_DURATION_EDITED_2",
"h:mm:ss (e.g. 3:45, 1:23:40)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_2");
});
}
{
// 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)"
);
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", 3, "12:34:56", "12:34:56.00");
addDurationData("NC_DURATION_3", 4, "12:34:999", "12:50:39.00");
addDurationData("NC_DURATION_3", 5, "12:999:56", "28:39:56.00");
addDurationData("NC_DURATION_3", 6, "12:34:56.12", "12:34:56.12");
addDurationData("NC_DURATION_3", 7, "12:34:56.199", "12:34:56.20");
});
it("Duration: Edit Column NC_DURATION_3", () => {
editColumnByName(
"NC_DURATION_3",
"NC_DURATION_EDITED_3",
"h:mm:ss.ss (e.g. 3.45.67, 1:23:40.00)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_3");
});
}
{
// 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)"
);
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", 3, "12:34:56", "12:34:56.000");
addDurationData("NC_DURATION_4", 4, "12:34:999", "12:50:39.000");
addDurationData("NC_DURATION_4", 5, "12:999:56", "28:39:56.000");
addDurationData("NC_DURATION_4", 6, "12:34:56.12", "12:34:56.012");
addDurationData("NC_DURATION_4", 7, "12:34:56.199", "12:34:56.199");
});
it("Duration: Edit Column NC_DURATION_4", () => {
editColumnByName(
"NC_DURATION_4",
"NC_DURATION_EDITED_4",
"h:mm (e.g. 1:23)"
);
});
it("Duration: Delete column", () => {
deleteColumnByName("NC_DURATION_EDITED_4");
});
}
});
};
/**
@ -299,4 +318,4 @@ export const genTest = (apiType, dbType) => {
* 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/>.
*
*/
*/

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

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

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

@ -1,6 +1,6 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage";
import {loginPage} from "../../support/page_objects/navigation";
import { loginPage } from "../../support/page_objects/navigation";
let storedURL = "";
@ -13,452 +13,457 @@ let storedURL = "";
let viewURL = {};
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
const generateViewLink = (viewName) => {
mainPage.shareView().click();
cy.wait(1000);
// wait, as URL initially will be /undefined
cy.getActiveModal(".nc-modal-share-view")
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.should("exist");
// copy link text, visit URL
cy.getActiveModal(".nc-modal-share-view")
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.then(($obj) => {
cy.get("body").type("{esc}");
// viewURL.push($obj.text())
viewURL[viewName] = $obj.text().trim();
});
};
if (!isTestSuiteActive(apiType, dbType)) return;
const generateViewLink = (viewName) => {
mainPage.shareView().click();
cy.wait(1000);
// wait, as URL initially will be /undefined
cy.getActiveModal(".nc-modal-share-view")
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.should("exist");
// copy link text, visit URL
cy.getActiveModal(".nc-modal-share-view")
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.then(($obj) => {
cy.get("body").type("{esc}");
// viewURL.push($obj.text())
viewURL[viewName] = $obj.text().trim();
});
cy.getActiveModal(".nc-modal-share-view").should("not.be.visible");
};
describe(`${apiType.toUpperCase()} api - GRID view (Share)`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
cy.restoreLocalStorage();
cy.openTableTab("Address", 25);
});
describe(`${apiType.toUpperCase()} api - GRID view (Share)`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
cy.restoreLocalStorage();
cy.openTableTab("Address", 25);
});
beforeEach(() => {
cy.restoreLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
after(() => {
// close table
// mainPage.deleteCreatedViews()
cy.restoreLocalStorage();
cy.closeTableTab("Address");
cy.saveLocalStorage();
});
after(() => {
// close table
// mainPage.deleteCreatedViews()
cy.restoreLocalStorage();
cy.closeTableTab("Address");
cy.saveLocalStorage();
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType.toUpperCase()} view`, () => {
// create a normal public view
cy.get(`.nc-create-${viewType}-view`).click();
cy.getActiveModal(".nc-modal-view-create")
.find("button:contains(Submit)")
.click();
cy.toastWait("View created successfully");
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
});
});
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`)
.contains("Grid-1")
.click();
mainPage.hideField("Address2");
mainPage.sortField("District", "Z → A");
mainPage.filterField("Address", "is like", "Ab");
generateViewLink("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`, () => {
// generate view link multiple times
generateViewLink("combined");
generateViewLink("combined");
// verify if only one link exists in table
mainPage.shareViewList().click();
cy.get('th:contains("View Link")').should("exist");
cy.get('th:contains("View Link")')
.parent()
.parent()
.next()
.find("tr")
.its("length")
.should("eq", 1)
.then(() => {
cy.get("button.ant-modal-close:visible").click();
});
cy.signOut();
});
it(`Share ${viewType.toUpperCase()} view : Visit URL, Verify title`, () => {
// visit public view
cy.visit(viewURL["combined"], {
baseUrl: null,
});
cy.wait(5000);
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 18);
// verify title
cy.get(".nc-shared-view-title").contains("Grid-1").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields hidden/open`, () => {
// verify column headers
cy.get('[data-title="Address"]').should("exist");
cy.get('[data-title="Address2"]').should("not.exist");
cy.get('[data-title="District"]').should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields sort/ filter`, () => {
// country column content verification before sort
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
mainPage.getCell("District", 2).contains("Tutuila").should("exist");
mainPage.getCell("District", 3).contains("Tamil Nadu").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Customer List,Staff List,City,Staff List`,
`1013 Tabuk Boulevard,West Bengali,96203,158399646978,[object Object],2,,Kanchrapara,`,
`1892 Nabereznyje Telny Lane,Tutuila,28396,478229987054,[object Object],2,,Tafuna,`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
}
};
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType.toUpperCase()} view`, () => {
// create a normal public view
cy.get(`.nc-create-${viewType}-view`).click();
cy.getActiveModal(".nc-modal-view-create").find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
});
});
it(`Share ${viewType.toUpperCase()} hide, sort, filter & verify`, () => {
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("Grid-1")
.click();
mainPage.hideField("Address2");
mainPage.sortField("District", "Z → A");
mainPage.filterField("Address", "is like", "Ab");
generateViewLink("combined");
cy.log(viewURL["combined"]);
});
it(`Share GRID view : ensure we have only one link even if shared multiple times`, () => {
// generate view link multiple times
generateViewLink("combined");
generateViewLink("combined");
// verify if only one link exists in table
mainPage.shareViewList().click();
cy.get('th:contains("View Link")').should("exist");
cy.get('th:contains("View Link")')
.parent()
.parent()
.next()
.find("tr")
.its("length")
.should("eq", 1)
.then(() => {
cy.get('button.ant-modal-close:visible').click();
});
cy.signOut();
});
it(`Share ${viewType.toUpperCase()} view : Visit URL, Verify title`, () => {
// visit public view
cy.visit(viewURL["combined"], {
baseUrl: null,
});
cy.wait(5000);
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 18);
// verify title
cy.get(".nc-shared-view-title").contains("Grid-1").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields hidden/open`, () => {
// verify column headers
cy.get('[data-title="Address"]').should("exist");
cy.get('[data-title="Address2"]').should("not.exist");
cy.get('[data-title="District"]').should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields sort/ filter`, () => {
// country column content verification before sort
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
mainPage
.getCell("District", 2)
.contains("Tutuila")
.should("exist");
mainPage
.getCell("District", 3)
.contains("Tamil Nadu")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Customer List,Staff List,City,Staff List`,
`1013 Tabuk Boulevard,West Bengali,96203,158399646978,[object Object],2,,Kanchrapara,`,
`1892 Nabereznyje Telny Lane,Tutuila,28396,478229987054,[object Object],2,,Tafuna,`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
}
};
// download & verify
mainPage.downloadAndVerifyCsvFromSharedView(
`Address_exported_1.csv`,
verifyCsv
);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Disable sort`, () => {
// remove sort and validate
mainPage.clearSort();
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Enable sort`, () => {
// Sort menu operations (Country Column, Z → A)
mainPage.sortField("District", "Z → A");
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Create Filter`, () => {
// add filter & validate
mainPage.filterField("District", "is like", "Tamil");
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 2);
mainPage
.getCell("District", 1)
.contains("Tamil")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV after local filter`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Customer List,Staff List,City,Staff List`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
// for (let i = 0; i < storedRecords.length; i++) {
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
// }
// ncv2@fixme
// for (let i = 0; i < storedRecords.length; i++) {
// let strCol = storedRecords[i].split(",");
// let retCol = retrievedRecords[i].split(",");
// for (let j = 0; j < 4; j++) {
// expect(strCol[j]).to.be.equal(retCol[j]);
// }
// }
};
mainPage.downloadAndVerifyCsvFromSharedView(
`Address_exported_1.csv`,
verifyCsv
);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Delete Filter`, () => {
// Remove sort and Validate
mainPage.filterReset();
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share GRID view : Virtual column validation > has many`, () => {
// verify column headers
cy.get('[data-title="Customer List"]').should("exist");
cy.get('[data-title="Staff List"]').should("exist");
cy.get('[data-title="City"]').should("exist");
cy.get('[data-title="Staff List"]').should("exist");
// has many field validation
mainPage
.getCell("Customer List", 3)
.click()
.find(".nc-icon.nc-unlink-icon")
.should("not.exist");
mainPage
.getCell("Customer List", 3)
.click()
.find(".nc-icon.nc-action-icon.nc-plus")
.should("not.exist");
// mainPage
// .getCell("Customer List", 3)
// .click()
// .find(".nc-icon.nc-action-icon.nc-arrow-expand")
// .click({ force: true });
//
// // reload button
// cy.getActiveModal().find(".nc-icon").should("exist");
// cy.getActiveModal()
// .find("button")
// .contains("Link to")
// .should("not.exist");
// cy.getActiveModal()
// .find(".ant-card")
// .contains("2")
// .should("exist");
// cy.getActiveModal()
// .find(".ant-card")
// .find("button")
// .should("not.exist");
// cy.get('button.ant-modal-close').click();
});
it(`Share GRID view : Virtual column validation > belongs to`, () => {
// belongs to field validation
mainPage
.getCell("City", 1)
.click()
.find(".nc-icon.nc-unlink-icon")
.should("not.exist");
mainPage
.getCell("City", 1)
.click()
.find(".nc-icon.nc-action-icon.nc-arrow-expand")
.should("not.exist");
mainPage
.getCell("City", 1)
.find(".chips")
.contains("Kanchrapara")
.should("exist");
});
it(`Share GRID view : Virtual column validation > many to many`, () => {
// many-to-many field validation
mainPage
.getCell("Staff List", 1)
.click()
.find(".nc-icon.nc-unlink-icon")
.should("not.exist");
mainPage
.getCell("Staff List", 1)
.click()
.find(".nc-icon.nc-action-icon.nc-plus")
.should("not.exist");
mainPage
.getCell("Staff List", 1)
.click()
.find(".nc-icon.nc-action-icon.nc-arrow-expand")
.click({ force: true });
// // reload button
// Fix me : ncv2@fixme
// cy.getActiveModal().find(".nc-icon").should("exist");
// cy.getActiveModal()
// .find("button")
// .contains("Link to")
// .should("not.exist");
// cy.get('button.ant-modal-close:visible').last().click();
});
it(`Delete ${viewType.toUpperCase()} view`, () => {
// go back to base page
loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Address", 25);
// number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.getActiveModal(".nc-modal-view-delete").find(".ant-btn-dangerous").click();
cy.toastWait("View deleted successfully");
// confirm if the number of veiw entries is reduced by 1
cy.get(".nc-view-item").its("length").should("eq", 1);
});
// download & verify
mainPage.downloadAndVerifyCsvFromSharedView(
`Address_exported_1.csv`,
verifyCsv
);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Disable sort`, () => {
// remove sort and validate
mainPage.clearSort();
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Enable sort`, () => {
// Sort menu operations (Country Column, Z → A)
mainPage.sortField("District", "Z → A");
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Create Filter`, () => {
// add filter & validate
mainPage.filterField("District", "is like", "Tamil");
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 2);
mainPage.getCell("District", 1).contains("Tamil").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV after local filter`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Customer List,Staff List,City,Staff List`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
// for (let i = 0; i < storedRecords.length; i++) {
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
// }
// ncv2@fixme
// for (let i = 0; i < storedRecords.length; i++) {
// let strCol = storedRecords[i].split(",");
// let retCol = retrievedRecords[i].split(",");
// for (let j = 0; j < 4; j++) {
// expect(strCol[j]).to.be.equal(retCol[j]);
// }
// }
};
mainPage.downloadAndVerifyCsvFromSharedView(
`Address_exported_1.csv`,
verifyCsv
);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Delete Filter`, () => {
// Remove sort and Validate
mainPage.filterReset();
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share GRID view : Virtual column validation > has many`, () => {
// verify column headers
cy.get('[data-title="Customer List"]').should("exist");
cy.get('[data-title="Staff List"]').should("exist");
cy.get('[data-title="City"]').should("exist");
cy.get('[data-title="Staff List"]').should("exist");
// has many field validation
mainPage
.getCell("Customer List", 3)
.click()
.find(".nc-icon.nc-unlink-icon")
.should("not.exist");
mainPage
.getCell("Customer List", 3)
.click()
.find(".nc-icon.nc-action-icon.nc-plus")
.should("not.exist");
// mainPage
// .getCell("Customer List", 3)
// .click()
// .find(".nc-icon.nc-action-icon.nc-arrow-expand")
// .click({ force: true });
//
// // reload button
// cy.getActiveModal().find(".nc-icon").should("exist");
// cy.getActiveModal()
// .find("button")
// .contains("Link to")
// .should("not.exist");
// cy.getActiveModal()
// .find(".ant-card")
// .contains("2")
// .should("exist");
// cy.getActiveModal()
// .find(".ant-card")
// .find("button")
// .should("not.exist");
// cy.get('button.ant-modal-close').click();
});
it(`Share GRID view : Virtual column validation > belongs to`, () => {
// belongs to field validation
mainPage
.getCell("City", 1)
.click()
.find(".nc-icon.nc-unlink-icon")
.should("not.exist");
mainPage
.getCell("City", 1)
.click()
.find(".nc-icon.nc-action-icon.nc-arrow-expand")
.should("not.exist");
mainPage
.getCell("City", 1)
.find(".chips")
.contains("Kanchrapara")
.should("exist");
});
it(`Share GRID view : Virtual column validation > many to many`, () => {
// many-to-many field validation
mainPage
.getCell("Staff List", 1)
.click()
.find(".nc-icon.nc-unlink-icon")
.should("not.exist");
mainPage
.getCell("Staff List", 1)
.click()
.find(".nc-icon.nc-action-icon.nc-plus")
.should("not.exist");
mainPage
.getCell("Staff List", 1)
.click()
.find(".nc-icon.nc-action-icon.nc-arrow-expand")
.click({ force: true });
// // reload button
// Fix me : ncv2@fixme
// cy.getActiveModal().find(".nc-icon").should("exist");
// cy.getActiveModal()
// .find("button")
// .contains("Link to")
// .should("not.exist");
// cy.get('button.ant-modal-close:visible').last().click();
});
it(`Delete ${viewType.toUpperCase()} view`, () => {
// go back to base page
loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Address", 25);
// number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.getActiveModal(".nc-modal-view-delete")
.find(".ant-btn-dangerous")
.click();
cy.toastWait("View deleted successfully");
// confirm if the number of veiw entries is reduced by 1
cy.get(".nc-view-item").its("length").should("eq", 1);
});
};
// below scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
});
// below scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
});
describe(`${apiType.toUpperCase()} api - Grid view/ row-column update verification`, () => {
before(() => {
cy.restoreLocalStorage();
describe(`${apiType.toUpperCase()} api - Grid view/ row-column update verification`, () => {
before(() => {
cy.restoreLocalStorage();
// Address table has belongs to, has many & many-to-many
cy.openTableTab("Country", 25);
// Address table has belongs to, has many & many-to-many
cy.openTableTab("Country", 25);
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
generateViewLink("rowColUpdate");
});
});
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
generateViewLink("rowColUpdate");
});
});
beforeEach(() => {
cy.restoreLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
after(() => {
cy.restoreLocalStorage();
cy.closeTableTab("Country");
cy.saveLocalStorage();
});
after(() => {
cy.restoreLocalStorage();
cy.closeTableTab("Country");
cy.saveLocalStorage();
});
it(`Generate default Shared GRID view URL`, () => {
// add row
cy.get(".nc-add-new-row-btn").click();
cy.get(".nc-expand-col-Country").find(".nc-cell > input")
.should("exist")
.first()
.clear({ force: true })
.type("a");
cy.getActiveDrawer()
.find("button")
.contains("Save row")
.click();
cy.toastWait("updated successfully");
cy.getActiveDrawer()
.find("button")
.contains("Cancel")
.click();
// add column
mainPage.addColumn("dummy", "Country");
cy.signOut();
// visit public view
cy.log(viewURL["rowColUpdate"]);
cy.visit(viewURL["rowColUpdate"], {
baseUrl: null,
});
cy.wait(5000);
// wait for public view page to load!
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 25);
});
it(`Generate default Shared GRID view URL`, () => {
// add row
cy.get(".nc-add-new-row-btn").click();
cy.get(".nc-expand-col-Country")
.find(".nc-cell > input")
.should("exist")
.first()
.clear({ force: true })
.type("a");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Save row")
.should("exist")
.click();
cy.toastWait("updated successfully");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Cancel")
.should("exist")
.click();
// add column
mainPage.addColumn("dummy", "Country");
cy.signOut();
// visit public view
cy.log(viewURL["rowColUpdate"]);
cy.visit(viewURL["rowColUpdate"], {
baseUrl: null,
});
cy.wait(5000);
// wait for public view page to load!
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 25);
});
it(`Share GRID view : new row visible`, () => {
// verify row
// cy.get(`.v-pagination > li:contains('5') button`).click();
cy.get(`.nc-pagination > .ant-pagination-item.ant-pagination-item-5`).click();
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage.getCell("Country", 10).contains("a").should("exist");
});
it(`Share GRID view : new row visible`, () => {
// verify row
// cy.get(`.v-pagination > li:contains('5') button`).click();
cy.get(
`.nc-pagination > .ant-pagination-item.ant-pagination-item-5`
).click();
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage.getCell("Country", 10).contains("a").should("exist");
});
it(`Share GRID view : new column visible`, () => {
// verify column headers
cy.get('[data-title="dummy"]').should("exist");
});
it(`Share GRID view : new column visible`, () => {
// verify column headers
cy.get('[data-title="dummy"]').should("exist");
});
it(`Clean up`, () => {
loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Country", 25)
// delete row
mainPage.getPagination(5).click();
// kludge: flicker on load
cy.wait(3000)
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.find('.ant-dropdown-menu-item:contains("Delete Row")')
.first()
.click();
// delete column
mainPage.deleteColumn("dummy");
mainPage.deleteCreatedViews();
});
it(`Clean up`, () => {
loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Country", 25);
// delete row
mainPage.getPagination(5).click();
// kludge: flicker on load
cy.wait(3000);
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.find('.ant-dropdown-menu-item:contains("Delete Row")')
.first()
.click();
// delete column
mainPage.deleteColumn("dummy");
mainPage.deleteCreatedViews();
});
});
};
/**

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
});
};

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

@ -3,101 +3,101 @@ import { projectsPage } from "../../support/page_objects/navigation";
import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import {
_advSettings,
_editSchema,
_editData,
_editComment,
_viewMenu,
_topRightMenu,
_advSettings,
_editSchema,
_editData,
_editComment,
_viewMenu,
_topRightMenu,
} from "../spec/roleValidation.spec";
import {linkSync} from "fs";
import { linkSync } from "fs";
// fix me
let linkText = "";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
const permissionValidation = (roleType) => {
it(`${roleType}: Visit base shared URL`, () => {
cy.log(linkText);
// visit URL & wait for page load to complete
cy.visit(linkText, {
baseUrl: null,
});
cy.wait(5000);
});
it(`${roleType}: Validate access permissions: advance menu`, () => {
// cy.restoreLocalStorage();
_advSettings(roleType, "baseShare");
});
if (!isTestSuiteActive(apiType, dbType)) return;
it(`${roleType}: Validate access permissions: edit schema`, () => {
// cy.restoreLocalStorage();
_editSchema(roleType, "baseShare");
});
const permissionValidation = (roleType) => {
it(`${roleType}: Visit base shared URL`, () => {
cy.log(linkText);
it(`${roleType}: Validate access permissions: edit data`, () => {
// cy.restoreLocalStorage();
_editData(roleType, "baseShare");
});
// visit URL & wait for page load to complete
cy.visit(linkText, {
baseUrl: null,
});
cy.wait(5000);
});
it(`${roleType}: Validate access permissions: edit comments`, () => {
// cy.restoreLocalStorage();
_editComment(roleType, "baseShare");
});
it(`${roleType}: Validate access permissions: advance menu`, () => {
// cy.restoreLocalStorage();
_advSettings(roleType, "baseShare");
});
it(`${roleType}: Validate access permissions: view's menu`, () => {
// cy.restoreLocalStorage();
_viewMenu(roleType, "baseShare");
});
};
describe(`${apiType.toUpperCase()} Base VIEW share`, () => {
before(() => {
// loginPage.loginAndOpenProject(apiType, dbType);
cy.restoreLocalStorage();
cy.openTableTab("Country", 25);
cy.saveLocalStorage();
});
it(`${roleType}: Validate access permissions: edit schema`, () => {
// cy.restoreLocalStorage();
_editSchema(roleType, "baseShare");
});
it(`${roleType}: Validate access permissions: edit data`, () => {
// cy.restoreLocalStorage();
_editData(roleType, "baseShare");
});
it(`${roleType}: Validate access permissions: edit comments`, () => {
// cy.restoreLocalStorage();
_editComment(roleType, "baseShare");
});
it(`${roleType}: Validate access permissions: view's menu`, () => {
// cy.restoreLocalStorage();
_viewMenu(roleType, "baseShare");
});
};
describe(`${apiType.toUpperCase()} Base VIEW share`, () => {
before(() => {
// loginPage.loginAndOpenProject(apiType, dbType);
cy.restoreLocalStorage();
cy.openTableTab("Country", 25);
cy.saveLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
})
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
})
afterEach(() => {
cy.saveLocalStorage();
});
it(`Generate base share URL`, () => {
// click SHARE
cy.get(".nc-share-base:visible").should('exist').click();
it(`Generate base share URL`, () => {
// click SHARE
cy.get(".nc-share-base:visible").should("exist").click();
// Click on readonly base text
cy.getActiveModal().find(".nc-disable-shared-base").click();
// Click on readonly base text
cy.getActiveModal().find(".nc-disable-shared-base").click();
cy.getActiveMenu(".nc-dropdown-shared-base-toggle")
.find(".ant-dropdown-menu-title-content")
.contains("Anyone with the link")
.click();
cy.getActiveMenu(".nc-dropdown-shared-base-toggle")
.find(".ant-dropdown-menu-title-content")
.contains("Anyone with the link")
.click();
cy.getActiveModal().find(".nc-shared-base-role").click();
cy.getActiveModal().find(".nc-shared-base-role").click();
cy.getActiveSelection('.nc-dropdown-share-base-role')
.find('.ant-select-item')
.eq(1)
.click();
cy.getActiveSelection(".nc-dropdown-share-base-role")
.find(".ant-select-item")
.eq(1)
.click();
// Copy URL
cy.getActiveModal(".nc-modal-invite-user-and-share-base")
.find(".nc-url")
.then(($obj) => {
cy.log($obj[0]);
linkText = $obj[0].innerText.trim();
// Copy URL
cy.getActiveModal(".nc-modal-invite-user-and-share-base")
.find(".nc-url")
.then(($obj) => {
cy.log($obj[0]);
linkText = $obj[0].innerText.trim();
const htmlFile = `
const htmlFile = `
<!DOCTYPE html>
<html>
<body>
@ -113,67 +113,72 @@ style="background: transparent; "></iframe>
</body>
</html>
`;
cy.writeFile(
"scripts/cypress/fixtures/sampleFiles/iFrame.html",
htmlFile
);
});
cy.log(linkText);
cy.signOut();
cy.writeFile(
"scripts/cypress/fixtures/sampleFiles/iFrame.html",
htmlFile
);
});
permissionValidation("viewer");
it("Update to EDITOR base share link", () => {
loginPage.loginAndOpenProject(apiType, dbType);
// click SHARE
cy.get(".nc-share-base:visible").should('exist').click();
cy.getActiveModal().find(".nc-shared-base-role").click();
cy.log(linkText);
cy.getActiveSelection('.nc-dropdown-share-base-role')
.find('.ant-select-item')
.eq(0)
.click();
cy.signOut();
});
permissionValidation("editor");
cy.signOut();
});
describe(`${apiType.toUpperCase()} iFrame Test`, () => {
// https://docs.cypress.io/api/commands/visit#Prefixes
it("Generate & verify embed HTML IFrame", {baseUrl: null}, () => {
permissionValidation("viewer");
let filePath = "scripts/cypress/fixtures/sampleFiles/iFrame.html";
cy.log(filePath);
cy.visit(filePath, {baseUrl: null});
it("Update to EDITOR base share link", () => {
loginPage.loginAndOpenProject(apiType, dbType);
// wait for iFrame to load
cy.frameLoaded(".nc-embed");
// click SHARE
cy.get(".nc-share-base:visible").should("exist").click();
// cy.openTableTab("Country", 25);
cy.iframe().find(`.nc-project-tree-tbl-Actor`, {timeout: 10000}).should("exist")
.first()
.click({force: true});
cy.getActiveModal().find(".nc-shared-base-role").click();
// validation for base menu opitons
cy.iframe().find(".nc-project-tree").should("exist");
cy.iframe().find(".nc-fields-menu-btn").should("exist");
cy.iframe().find(".nc-sort-menu-btn").should("exist");
cy.iframe().find(".nc-filter-menu-btn").should("exist");
cy.iframe().find(".nc-actions-menu-btn").should("exist");
cy.getActiveSelection(".nc-dropdown-share-base-role")
.find(".ant-select-item")
.eq(0)
.click();
// validate data (row-1)
cy.iframe().find(`.nc-grid-cell`).eq(1).contains("PENELOPE").should("exist");
cy.iframe().find(`.nc-grid-cell`).eq(2).contains("GUINESS").should("exist");
});
})
}
cy.signOut();
});
permissionValidation("editor");
});
describe(`${apiType.toUpperCase()} iFrame Test`, () => {
// https://docs.cypress.io/api/commands/visit#Prefixes
it("Generate & verify embed HTML IFrame", { baseUrl: null }, () => {
let filePath = "scripts/cypress/fixtures/sampleFiles/iFrame.html";
cy.log(filePath);
cy.visit(filePath, { baseUrl: null });
// wait for iFrame to load
cy.frameLoaded(".nc-embed");
// cy.openTableTab("Country", 25);
cy.iframe()
.find(`.nc-project-tree-tbl-Actor`, { timeout: 10000 })
.should("exist")
.first()
.click({ force: true });
// validation for base menu opitons
cy.iframe().find(".nc-project-tree").should("exist");
cy.iframe().find(".nc-fields-menu-btn").should("exist");
cy.iframe().find(".nc-sort-menu-btn").should("exist");
cy.iframe().find(".nc-filter-menu-btn").should("exist");
cy.iframe().find(".nc-actions-menu-btn").should("exist");
// validate data (row-1)
cy.iframe()
.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

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

@ -6,422 +6,442 @@ import { loginPage } from "../../support/page_objects/navigation";
let hookPath = "http://localhost:9090/hook";
function createWebhook(hook, test) {
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.get(".nc-btn-webhook").should("exist").click();
cy.get(".nc-btn-create-webhook").should("exist").click();
// hardcode "Content-type: application/json"
cy.get(".ant-tabs-tab-btn").contains("Headers").should("exist").click();
// kludge : as neither scrollIntoView nor scrollTo didn't yield any results
// cy.getActiveSelection().find('.ant-select-item').contains('Content-Type).scrollIntoView();
// cy.getActiveSelection().find('.rc-virtual-list').scrollTo('center');
// cy.getActiveSelection().select('Content-Type', { force: true });
cy.get(".nc-input-hook-header-key")
.should("exist")
.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}')
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")
.should("exist")
.clear({ force: true })
.type("application/json", { force: true });
cy.get('.nc-hook-header-tab-checkbox').find('input.ant-checkbox-input').should('exist').click();
// common routine for both create & modify to configure hook
configureWebhook(hook, test);
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.get(".nc-btn-webhook").should("exist").click();
cy.get(".nc-btn-create-webhook").should("exist").click();
// hardcode "Content-type: application/json"
cy.get(".ant-tabs-tab-btn").contains("Headers").should("exist").click();
// kludge : as neither scrollIntoView nor scrollTo didn't yield any results
// cy.getActiveSelection().find('.ant-select-item').contains('Content-Type).scrollIntoView();
// cy.getActiveSelection().find('.rc-virtual-list').scrollTo('center');
// cy.getActiveSelection().select('Content-Type', { force: true });
cy.get(".nc-input-hook-header-key")
.should("exist")
.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}");
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")
.should("exist")
.clear({ force: true })
.type("application/json", { force: true });
cy.get(".nc-hook-header-tab-checkbox")
.find("input.ant-checkbox-input")
.should("exist")
.click();
// common routine for both create & modify to configure hook
configureWebhook(hook, test);
}
function deleteWebhook(index) {
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.get(".nc-hook-delete-icon").eq(index).click({ force: true });
cy.toastWait("Hook deleted successfully");
cy.get("body").type("{esc}");
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.get(".nc-hook-delete-icon").eq(index).click({ force: true });
cy.toastWait("Hook deleted successfully");
cy.get("body").type("{esc}");
}
function openWebhook(index) {
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.get(".nc-actions-menu-btn").should("exist").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 });
}
function configureWebhook(hook, test) {
// configure what ever is present. ignore rest
// currently works for only URL type
if (hook?.title) {
cy.get(".nc-text-field-hook-title")
.should("exist")
.clear()
.type(hook.title);
}
// configure what ever is present. ignore rest
// currently works for only URL type
if (hook?.event) {
cy.get(".nc-text-field-hook-event").should("exist").click();
cy.getActiveSelection('.nc-dropdown-webhook-event')
.find(`.ant-select-item`)
.contains(hook.event)
.should("exist")
.click();
}
if (hook?.title) {
cy.get(".nc-text-field-hook-title")
.should("exist")
.clear()
.type(hook.title);
}
if (hook?.event) {
cy.get(".nc-text-field-hook-event").should("exist").click();
cy.getActiveSelection(".nc-dropdown-webhook-event")
.find(`.ant-select-item`)
.contains(hook.event)
.should("exist")
.click();
}
if (hook?.url?.path) {
cy.get(".nc-text-field-hook-url-path")
.should("exist")
.clear()
.type(hook.url.path);
}
if (hook?.url?.path) {
cy.get(".nc-text-field-hook-url-path")
.should("exist")
.clear()
.type(hook.url.path);
}
if (hook?.deleteCondition === true) {
cy.get(".nc-filter-item-remove-btn")
.should("exist")
.click({ force: true });
}
if (hook?.deleteCondition === true) {
cy.get(".nc-filter-item-remove-btn").should("exist").click({ force: true });
}
if (hook?.condition) {
cy.get(".nc-check-box-hook-condition").should("exist").click();
cy.get(".menu-filter-dropdown")
.last()
.find("button")
.contains("Add Filter")
.click();
cy.get(".nc-filter-field-select")
.should("exist")
.last()
.click()
cy.get('.ant-select-dropdown:visible')
.should('exist')
.find(`.ant-select-item`)
.contains(new RegExp("^" + hook.condition.column + "$", "g"))
.should('exist')
.click();
cy.wait(1000);
cy.get(".nc-filter-operation-select").should("exist").last().click();
cy.get('.ant-select-dropdown:visible')
.should('exist')
.find(`.ant-select-item`)
.contains(hook.condition.operator)
.should('exist')
.click();
if (hook.condition.operator != "is null" && hook.condition.operator != "is not null") {
cy.get(".nc-filter-value-select")
.should("exist")
.last()
.type(hook.condition.value);
cy.get(".nc-filter-operation-select").last().click();
}
}
if (hook?.condition) {
cy.get(".nc-check-box-hook-condition").should("exist").click();
cy.get(".menu-filter-dropdown")
.last()
.find("button")
.contains("Add Filter")
.click();
cy.get(".nc-filter-field-select").should("exist").last().click();
cy.get(".ant-select-dropdown:visible")
.should("exist")
.find(`.ant-select-item`)
.contains(new RegExp("^" + hook.condition.column + "$", "g"))
.should("exist")
.click();
cy.wait(1000);
if (test) {
cy.get(".nc-btn-webhook-test").should("exist").click();
cy.toastWait("Webhook tested successfully");
cy.get(".nc-filter-operation-select").should("exist").last().click();
cy.get(".ant-select-dropdown:visible")
.should("exist")
.find(`.ant-select-item`)
.contains(hook.condition.operator)
.should("exist")
.click();
if (
hook.condition.operator != "is null" &&
hook.condition.operator != "is not null"
) {
cy.get(".nc-filter-value-select")
.should("exist")
.last()
.type(hook.condition.value);
cy.get(".nc-filter-operation-select").last().click();
}
}
cy.get(".nc-btn-webhook-save").should("exist").click();
cy.toastWait("Webhook details updated successfully");
cy.get(".nc-icon-hook-navigate-left").should("exist").click();
cy.get("body").type("{esc}");
if (test) {
cy.get(".nc-btn-webhook-test").should("exist").click();
cy.toastWait("Webhook tested successfully");
}
cy.get(".nc-btn-webhook-save").should("exist").click();
cy.toastWait("Webhook details updated successfully");
cy.get(".nc-icon-hook-navigate-left").should("exist").click();
cy.get("body").type("{esc}");
}
function clearServerData() {
// clear stored data in server
cy.request("http://localhost:9090/hook/clear");
// ensure stored message count is 0
cy.request("http://localhost:9090/hook/count").then((msg) => {
cy.log(msg.body);
expect(msg.body).to.equal(0);
});
// clear stored data in server
cy.request("http://localhost:9090/hook/clear");
// ensure stored message count is 0
cy.request("http://localhost:9090/hook/count").then((msg) => {
cy.log(msg.body);
expect(msg.body).to.equal(0);
});
}
function addNewRow(index, cellValue) {
cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click();
cy.wait(1000);
cy.get(".nc-expand-col-Title").find(".nc-cell > input").first().type(cellValue);
cy.getActiveDrawer('.nc-drawer-expanded-form')
.find(".ant-btn-primary")
.click();
cy.toastWait("updated successfully");
cy.getActiveDrawer('.nc-drawer-expanded-form')
.find(".ant-btn")
.contains("Cancel")
.click();
mainPage.getCell("Title", index).contains(cellValue).should("exist");
cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click();
cy.wait(1000);
cy.get(".nc-expand-col-Title")
.find(".nc-cell > input")
.first()
.type(cellValue);
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".ant-btn-primary")
.click();
cy.toastWait("updated successfully");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".ant-btn")
.contains("Cancel")
.click();
mainPage.getCell("Title", index).contains(cellValue).should("exist");
}
function updateRow(index, cellValue) {
cy.get(".nc-row-expand")
.eq(index-1)
.click({ force: true });
cy.get(".nc-expand-col-Title").find(".nc-cell > input")
.should("exist")
.first()
.clear()
.type(cellValue);
cy.getActiveDrawer('.nc-drawer-expanded-form')
.find("button")
.contains("Save row")
.click({ force: true });
// partial toast message
cy.toastWait("updated successfully");
cy.getActiveDrawer('.nc-drawer-expanded-form')
.find("button")
.contains("Cancel")
.click({ force: true });
cy.get(".nc-row-expand")
.eq(index - 1)
.click({ force: true });
cy.get(".nc-expand-col-Title")
.find(".nc-cell > input")
.should("exist")
.first()
.clear()
.type(cellValue);
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Save row")
.should("exist")
.click();
// partial toast message
cy.toastWait("updated successfully");
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Cancel")
.click({ force: true });
}
function verifyHookTrigger(count, lastValue) {
cy.request("http://localhost:9090/hook/count").then((msg) => {
cy.log(msg.body);
expect(msg.body).to.equal(count);
// allow message to be received
cy.wait(500);
cy.request("http://localhost:9090/hook/count").then((msg) => {
cy.log(msg.body);
expect(msg.body).to.equal(count);
});
if (count) {
cy.request("http://localhost:9090/hook/last").then((msg) => {
cy.log(msg.body);
expect(msg.body.Title).to.equal(lastValue);
});
if (count) {
cy.request("http://localhost:9090/hook/last").then((msg) => {
cy.log(msg.body);
expect(msg.body.Title).to.equal(lastValue);
});
}
}
}
function deleteRow(index) {
mainPage
.getCell("Title", index)
.rightclick();
// delete row
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.find('.ant-dropdown-menu-item:contains("Delete Row")')
.first()
.click({ force: true });
mainPage.getCell("Title", index).rightclick();
// delete row
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.find('.ant-dropdown-menu-item:contains("Delete Row")')
.first()
.click();
}
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`Webhook`, () => {
before(() => {
loginPage.loginAndOpenProject(apiType, dbType);
cy.createTable("Temp");
cy.saveLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
})
after(() => {
cy.restoreLocalStorage();
cy.deleteTable("Temp");
cy.saveLocalStorage();
});
it("Create: 'After Insert' event", () => {
createWebhook({
title: "hook-1",
event: "After Insert",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
});
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(1, "Poole");
updateRow(1, "Delaware");
verifyHookTrigger(1, "Poole");
deleteRow(1);
verifyHookTrigger(1, "Poole");
});
it("Add 'After Update' event", () => {
createWebhook({
title: "hook-2",
event: "After Update",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
});
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(1, "Poole");
updateRow(1, "Delaware");
verifyHookTrigger(2, "Delaware");
deleteRow(1);
verifyHookTrigger(2, "Delaware");
});
it("Add 'After Delete' event", () => {
createWebhook({
title: "hook-3",
event: "After Delete",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
});
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(1, "Poole");
updateRow(1, "Delaware");
verifyHookTrigger(2, "Delaware");
deleteRow(1);
verifyHookTrigger(3, "Delaware");
});
it("Modify webhook", () => {
openWebhook(0);
configureWebhook({ event: "After Delete" });
openWebhook(1);
configureWebhook({ event: "After Delete" });
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(0, "");
updateRow(1, "Delaware");
verifyHookTrigger(0, "");
deleteRow(1);
verifyHookTrigger(3, "Delaware");
});
it("Delete webhook", () => {
deleteWebhook(2);
deleteWebhook(1);
deleteWebhook(0);
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(0, "");
updateRow(1, "Delaware");
verifyHookTrigger(0, "");
deleteRow(1);
verifyHookTrigger(0, "");
});
it("Create, with condition", () => {
// create 3 webhooks with all three events, with condition this time
createWebhook({
title: "hook-with-condition-1",
event: "After Insert",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
condition: {
column: "Title",
operator: "is like",
value: "Poole",
},
});
createWebhook({
title: "hook-with-condition-2",
event: "After Update",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
condition: {
column: "Title",
operator: "is like",
value: "Poole",
},
});
createWebhook({
title: "hook-with-condition-3",
event: "After Delete",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
condition: {
column: "Title",
operator: "is like",
value: "Poole",
},
});
clearServerData();
addNewRow(1, "Poole");
addNewRow(2, "Delaware");
verifyHookTrigger(1, "Poole");
updateRow(1, "Delaware");
updateRow(2, "Poole");
verifyHookTrigger(2, "Poole");
deleteRow(2);
deleteRow(1);
verifyHookTrigger(3, "Poole");
});
it("Modify trigger condition", () => {
openWebhook(0);
configureWebhook({ deleteCondition: true });
openWebhook(1);
configureWebhook({ deleteCondition: true });
openWebhook(2);
configureWebhook({ deleteCondition: true });
clearServerData();
addNewRow(1, "Poole");
addNewRow(2, "Delaware");
verifyHookTrigger(2, "Delaware");
updateRow(1, "Delaware");
updateRow(2, "Poole");
verifyHookTrigger(4, "Poole");
deleteRow(2);
deleteRow(1);
verifyHookTrigger(6, "Delaware");
});
it("Delete trigger condition", () => {
deleteWebhook(2);
deleteWebhook(1);
deleteWebhook(0);
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(0, "");
updateRow(1, "Delaware");
verifyHookTrigger(0, "");
deleteRow(1);
verifyHookTrigger(0, "");
});
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`Webhook`, () => {
before(() => {
loginPage.loginAndOpenProject(apiType, dbType);
cy.createTable("Temp");
cy.saveLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
after(() => {
cy.restoreLocalStorage();
cy.deleteTable("Temp");
cy.saveLocalStorage();
});
it("Create: 'After Insert' event", () => {
createWebhook({
title: "hook-1",
event: "After Insert",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
});
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(1, "Poole");
updateRow(1, "Delaware");
verifyHookTrigger(1, "Poole");
deleteRow(1);
verifyHookTrigger(1, "Poole");
});
it("Add 'After Update' event", () => {
createWebhook({
title: "hook-2",
event: "After Update",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
});
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(1, "Poole");
updateRow(1, "Delaware");
verifyHookTrigger(2, "Delaware");
deleteRow(1);
verifyHookTrigger(2, "Delaware");
});
it("Add 'After Delete' event", () => {
createWebhook({
title: "hook-3",
event: "After Delete",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
});
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(1, "Poole");
updateRow(1, "Delaware");
verifyHookTrigger(2, "Delaware");
deleteRow(1);
verifyHookTrigger(3, "Delaware");
});
it("Modify webhook", () => {
openWebhook(0);
configureWebhook({ event: "After Delete" });
openWebhook(1);
configureWebhook({ event: "After Delete" });
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(0, "");
updateRow(1, "Delaware");
verifyHookTrigger(0, "");
deleteRow(1);
verifyHookTrigger(3, "Delaware");
});
it("Delete webhook", () => {
deleteWebhook(2);
deleteWebhook(1);
deleteWebhook(0);
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(0, "");
updateRow(1, "Delaware");
verifyHookTrigger(0, "");
deleteRow(1);
verifyHookTrigger(0, "");
});
it("Create, with condition", () => {
// create 3 webhooks with all three events, with condition this time
createWebhook({
title: "hook-with-condition-1",
event: "After Insert",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
condition: {
column: "Title",
operator: "is like",
value: "Poole",
},
});
createWebhook({
title: "hook-with-condition-2",
event: "After Update",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
condition: {
column: "Title",
operator: "is like",
value: "Poole",
},
});
createWebhook({
title: "hook-with-condition-3",
event: "After Delete",
type: "URL",
url: {
method: "POST",
path: hookPath,
},
condition: {
column: "Title",
operator: "is like",
value: "Poole",
},
});
clearServerData();
addNewRow(1, "Poole");
addNewRow(2, "Delaware");
verifyHookTrigger(1, "Poole");
updateRow(1, "Delaware");
updateRow(2, "Poole");
verifyHookTrigger(2, "Poole");
deleteRow(2);
deleteRow(1);
verifyHookTrigger(3, "Poole");
});
it("Modify trigger condition", () => {
openWebhook(0);
configureWebhook({ deleteCondition: true });
openWebhook(1);
configureWebhook({ deleteCondition: true });
openWebhook(2);
configureWebhook({ deleteCondition: true });
clearServerData();
addNewRow(1, "Poole");
addNewRow(2, "Delaware");
verifyHookTrigger(2, "Delaware");
updateRow(1, "Delaware");
updateRow(2, "Poole");
verifyHookTrigger(4, "Poole");
deleteRow(2);
deleteRow(1);
verifyHookTrigger(6, "Delaware");
});
it("Delete trigger condition", () => {
deleteWebhook(2);
deleteWebhook(1);
deleteWebhook(0);
clearServerData();
addNewRow(1, "Poole");
verifyHookTrigger(0, "");
updateRow(1, "Delaware");
verifyHookTrigger(0, "");
deleteRow(1);
verifyHookTrigger(0, "");
});
});
};
/**

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/>.
*
*/

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

@ -7,151 +7,187 @@ import { roles } from "../../support/page_objects/projectConstants";
// 3. Preview mode menu
//
export function _advSettings(roleType, mode) {
cy.log(roleType, mode);
if(mode === 'baseShare') {
// open modal
cy.get('.nc-project-menu').should('exist').click()
cy.getActiveMenu(".nc-dropdown-project-menu").find(`[data-menu-id="language"]`).should('exist')
// click again to close modal
cy.get('.nc-project-menu').should('exist').click()
return;
}
let validationString =
true == roles[roleType].validations.advSettings ? "exist" : "not.exist";
// cy.get(".nc-team-settings").should(validationString);
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").find(`[data-menu-id="teamAndSettings"]:visible`).should(validationString)
if (true === roles[roleType].validations.advSettings) {
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="appStore"]`).should('exist')
cy.get(`[data-menu-id="metaData"]`).should('exist')
cy.get(`[data-menu-id="audit"]`).should('exist')
settingsPage.closeMenu()
} else {
cy.get('.nc-project-menu').should('exist').click()
}
// float menu in preview mode
if ("preview" === mode) {
cy.get(".nc-floating-preview-btn").should("exist");
cy.get('.nc-floating-preview-btn')
.find(`[type="radio"][value="${roles[roleType].name}"]`)
.should("be.checked");
}
// cy.get("body").click("bottomRight");
cy.log(roleType, mode);
if (mode === "baseShare") {
// open modal
cy.get(".nc-project-menu").should("exist").click();
cy.getActiveMenu(".nc-dropdown-project-menu")
.find(`[data-menu-id="language"]`)
.should("exist");
// click again to close modal
cy.get(".nc-project-menu").should("exist").click();
return;
}
let validationString =
true == roles[roleType].validations.advSettings ? "exist" : "not.exist";
// cy.get(".nc-team-settings").should(validationString);
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")
.find(`[data-menu-id="teamAndSettings"]:visible`)
.should(validationString);
if (true === roles[roleType].validations.advSettings) {
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="appStore"]`).should("exist");
cy.get(`[data-menu-id="projMetaData"]`).should("exist");
cy.get(`[data-menu-id="audit"]`).should("exist");
settingsPage.closeMenu();
} else {
cy.get(".nc-project-menu").should("exist").click();
}
// float menu in preview mode
if ("preview" === mode) {
cy.get(".nc-floating-preview-btn").should("exist");
cy.get(".nc-floating-preview-btn")
.find(`[type="radio"][value="${roles[roleType].name}"]`)
.should("be.checked");
}
// cy.get("body").click("bottomRight");
}
export function _editSchema(roleType, mode) {
let columnName = "City";
let validationString =
true === roles[roleType].validations.editSchema ? "exist" : "not.exist";
cy.openTableTab(columnName, 25);
// create table
cy.get(`.nc-add-new-table`).should(validationString);
// delete table option
cy.get(`.nc-project-tree-tbl-City`).should("exist").rightclick();
cy.get(".ant-dropdown-content:visible").should(validationString);
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").find('[role="menuitem"]').contains("Rename").should("exist");
// click on a cell to close table context menu
mainPage.getCell(columnName, 3).click();
}
// add new column option
//
cy.get(".nc-column-add").should(validationString);
// update column (edit/ delete menu)
cy.get('.nc-ui-dt-dropdown').should(validationString)
if(validationString === "exist"){
cy.get('.nc-import-menu').should('exist').click();
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").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')
}
let columnName = "City";
let validationString =
true === roles[roleType].validations.editSchema ? "exist" : "not.exist";
cy.openTableTab(columnName, 25);
// create table
cy.get(`.nc-add-new-table`).should(validationString);
// delete table option
cy.get(`.nc-project-tree-tbl-City`).should("exist").rightclick();
cy.get(".ant-dropdown-content:visible").should(validationString);
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")
.find('[role="menuitem"]')
.contains("Rename")
.should("exist");
// click on a cell to close table context menu
mainPage.getCell(columnName, 3).click();
}
// add new column option
//
cy.get(".nc-column-add").should(validationString);
// update column (edit/ delete menu)
cy.get(".nc-ui-dt-dropdown").should(validationString);
if (validationString === "exist") {
cy.get(".nc-import-menu").should("exist").click();
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")
.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");
}
}
export function _editData(roleType, mode) {
let columnName = "City";
let validationString =
true === roles[roleType].validations.editData ? "exist" : "not.exist";
let columnName = "City";
let validationString =
true === roles[roleType].validations.editData ? "exist" : "not.exist";
cy.openTableTab(columnName, 25);
cy.openTableTab(columnName, 25);
// add row button
cy.get(".nc-add-new-row-btn:visible").should(validationString);
// add row button
cy.get('.nc-add-new-row-btn:visible').should(validationString);
// add button at bottom of page
mainPage.getCell(columnName, 25).scrollIntoView();
cy.get(".nc-grid-add-new-cell:visible").should(validationString);
// add button at bottom of page
mainPage.getCell(columnName, 25).scrollIntoView();
cy.get('.nc-grid-add-new-cell:visible').should(validationString);
// update row option (right click)
//
mainPage.getCell("City", 5).rightclick();
cy.wait(100);
cy.get(".ant-dropdown-content:visible").should(validationString);
// update row option (right click)
if (validationString === "exist") {
// right click options will exist (only for 'exist' case)
//
mainPage.getCell("City", 5).rightclick();
cy.wait(100);
cy.get(".ant-dropdown-content:visible").should(validationString);
if (validationString === "exist") {
// 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").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}");
mainPage.getCell("City", 13).click();
// update cell contents option using row expander should be enabled
//
mainPage
.getRow(1)
.find('.nc-row-no').should('exist')
.eq(0)
.trigger('mouseover', { force: true })
cy.get(".nc-row-expand")
.should("exist")
.eq(10)
.click({ force: true });
cy.getActiveDrawer().find("button").contains("Save row").should("exist");
cy.getActiveDrawer().find("button").contains("Cancel").should("exist").click();
} else {
// update cell contents option using row expander should be disabled
//
cy.get(".nc-row-expand")
.should("exist")
.eq(10)
.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
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Insert New Row")
.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}");
mainPage.getCell("City", 13).click();
// update cell contents option using row expander should be enabled
//
mainPage
.getRow(1)
.find(".nc-row-no")
.should("exist")
.eq(0)
.trigger("mouseover", { force: true });
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")
.click();
} else {
// update cell contents option using row expander should be disabled
//
mainPage.getCell("City", 5)
.dblclick()
.find("input")
.should(validationString);
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")
.click();
}
// double click cell entries to edit
//
mainPage.getCell("City", 5).dblclick().find("input").should(validationString);
}
// read &/ update comment
@ -159,136 +195,140 @@ export function _editData(roleType, mode) {
// Everyone else: read &/ update
//
export function _editComment(roleType, mode) {
let columnName = "City";
let validationString =
true === roles[roleType].validations.editComment
? "Comment added successfully"
: "Not allowed";
let columnName = "City";
let validationString =
true === roles[roleType].validations.editComment
? "Comment added successfully"
: "Not allowed";
cy.openTableTab(columnName, 25);
cy.openTableTab(columnName, 25);
cy.wait(1000);
cy.wait(1000);
// click on comment icon & type comment
//
cy.get(".nc-row-expand")
.should("exist")
.eq(10)
.click({force:true});
// click on comment icon & type comment
//
cy.get(".nc-row-expand").should("exist").eq(10).click({ force: true });
// Expected response:
// Viewer: Not able to see comment option
// Everyone else: Comment added/read successfully
//
// Expected response:
// Viewer: Not able to see comment option
// Everyone else: Comment added/read successfully
//
cy.wait(3000);
if ("viewer" === roleType) {
cy.getActiveDrawer(".nc-drawer-expanded-form")
.should("exist")
.find(".nc-toggle-comments")
.should("not.exist");
} else {
cy.getActiveDrawer(".nc-drawer-expanded-form")
.should("exist")
.find(".nc-toggle-comments")
.should("exist")
.click();
cy.wait(3000);
if ("viewer" === roleType) {
cy.getActiveDrawer()
.should('exist')
.find(".nc-toggle-comments")
.should("not.exist");
} else {
cy.getActiveDrawer()
.should('exist')
.find(".nc-toggle-comments")
.should("exist")
.click();
cy.getActiveDrawer().find(".nc-comment-box").should('exist').type("Comment-1{enter}");
// cy.toastWait('Comment added successfully')
cy.getActiveDrawer().find(".nc-toggle-comments").click();
}
cy.getActiveDrawer()
.find("button")
.contains("Cancel")
.should("exist")
.click();
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".nc-comment-box")
.should("exist")
.type("Comment-1{enter}");
// cy.toastWait('Comment added successfully')
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find(".nc-toggle-comments")
.click();
}
cy.getActiveDrawer(".nc-drawer-expanded-form")
.find("button")
.contains("Cancel")
.should("exist")
.click();
}
// right navigation menu bar
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
export function _viewMenu(roleType, mode) {
let columnName = "City";
// Lock, Download, Upload
let menuWithSubmenuCount = 3;
// share view list, webhook
let menuWithoutSubmenuCount = 3;
cy.openTableTab(columnName, 25);
let validationString =
true === roles[roleType].validations.shareView ? "exist" : "not.exist";
if (roleType === "editor") {
// Download / Upload CSV
menuWithSubmenuCount = 2;
// Get API Snippet
menuWithoutSubmenuCount = 1
if(mode === 'baseShare') menuWithoutSubmenuCount = 0
} else if (roleType === "commenter" || roleType === "viewer") {
// Download CSV & Download excel
menuWithSubmenuCount = 0;
menuWithoutSubmenuCount = 2
}
// view list field (default GRID view)
cy.get(`.nc-view-item`).should("exist");
// view create option, exists only for owner/ creator
cy.get(`.nc-create-grid-view`).should(validationString);
cy.get(`.nc-create-gallery-view`).should(validationString);
cy.get(`.nc-create-form-view`).should(validationString);
// share view permissions are role specific
// actions menu (more), only download csv should be visible for non-previlaged users
cy.get(".nc-actions-menu-btn").click();
cy.getActiveMenu(".nc-dropdown-actions-menu")
.find('.ant-dropdown-menu-submenu:visible')
.should("have.length", menuWithSubmenuCount);
cy.getActiveMenu(".nc-dropdown-actions-menu")
.find('.ant-dropdown-menu-item:visible')
.should("have.length", menuWithoutSubmenuCount);
// click again to close menu
cy.get(".nc-actions-menu-btn").click();
let columnName = "City";
// Lock, Download, Upload
let menuWithSubmenuCount = 3;
// share view list, webhook, api snippet, erd
let menuWithoutSubmenuCount = 4;
cy.openTableTab(columnName, 25);
let validationString =
true === roles[roleType].validations.shareView ? "exist" : "not.exist";
if (roleType === "editor") {
// Download / Upload CSV
menuWithSubmenuCount = 2;
// Get API Snippet and ERD
menuWithoutSubmenuCount = 2;
// ERD
if (mode === "baseShare") menuWithoutSubmenuCount = 1;
} else if (roleType === "commenter" || roleType === "viewer") {
// Download CSV & Download excel
menuWithSubmenuCount = 0;
// Get API Snippet and ERD
menuWithoutSubmenuCount = 2;
}
// view list field (default GRID view)
cy.get(`.nc-view-item`).should("exist");
// view create option, exists only for owner/ creator
cy.get(`.nc-create-grid-view`).should(validationString);
cy.get(`.nc-create-gallery-view`).should(validationString);
cy.get(`.nc-create-form-view`).should(validationString);
// share view permissions are role specific
// actions menu (more), only download csv should be visible for non-previlaged users
cy.get(".nc-actions-menu-btn").click();
cy.getActiveMenu(".nc-dropdown-actions-menu")
.find(".ant-dropdown-menu-submenu:visible")
.should("have.length", menuWithSubmenuCount);
cy.getActiveMenu(".nc-dropdown-actions-menu")
.find(".ant-dropdown-menu-item:visible")
.should("have.length", menuWithoutSubmenuCount);
// click again to close menu
cy.get(".nc-actions-menu-btn").click();
}
export function _topRightMenu(roleType, mode) {
// kludge; download csv menu persists until clicked
let columnName = "City";
// cy.closeTableTab(columnName);
// cy.openTableTab(columnName, 25);
// kludge; download csv menu persists until clicked
let columnName = "City";
// cy.closeTableTab(columnName);
// cy.openTableTab(columnName, 25);
let validationString =
true == roles[roleType].validations.shareView ? "exist" : "not.exist";
let validationString =
true == roles[roleType].validations.shareView ? "exist" : "not.exist";
cy.get(`.nc-share-base`).should(validationString);
cy.get(".nc-menu-translate").should("exist");
cy.get(".nc-menu-accounts").should("exist");
cy.get(`.nc-share-base`).should(validationString);
cy.get(".nc-menu-translate").should("exist");
cy.get(".nc-menu-accounts").should("exist");
}
// Access control list
//
export function disableTableAccess(tbl, role) {
const cls = `.nc-acl-${tbl}-${role}-chkbox`;
cy.get(cls).find("input").should("be.checked").click({ force: true });
cy.get(cls).find("input").should("not.be.checked");
const cls = `.nc-acl-${tbl}-${role}-chkbox`;
cy.get(cls).find("input").should("be.checked").click({ force: true });
cy.get(cls).find("input").should("not.be.checked");
}
export function enableTableAccess(tbl, role) {
const cls = `.nc-acl-${tbl}-${role}-chkbox`;
cy.get(cls).find("input").should("not.be.checked").click({ force: true });
cy.get(cls).find("input").should("be.checked");
const cls = `.nc-acl-${tbl}-${role}-chkbox`;
cy.get(cls).find("input").should("not.be.checked").click({ force: true });
cy.get(cls).find("input").should("be.checked");
}
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-CustomerList`).should(validationString)
cy.get(`.nc-project-tree-tbl-Language`).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 t4e = require("../common/4e_form_view_share");
let t4f = require("../common/4f_pg_grid_view_share");
let t4g = require("../common/4g_table_view_expanded_form");
const {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
@ -20,6 +21,7 @@ const nocoTestSuite = (apiType, dbType) => {
t4b.genTest(apiType, dbType);
t4d.genTest(apiType, dbType);
t4e.genTest(apiType, dbType);
t4g.genTest(apiType, dbType);
// tbd t4f.genTest(apiType, dbType);
};

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

@ -7,7 +7,8 @@ let t6e = require("../common/6e_project_operations");
let t6f = require("../common/6f_attachments");
let t6g = require("../common/6g_base_share");
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 {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
@ -15,19 +16,22 @@ const {
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
t01.genTest(apiType, dbType);
t6b.genTest(apiType, dbType);
t6d.genTest(apiType, dbType);
// exclude@ncv2 t6c.genTest(apiType, dbType);
t6f.genTest(apiType, dbType);
t6g.genTest(apiType, dbType);
t9b.genTest(apiType, dbType);
t6g.genTest(apiType, dbType);
// webhook tests
t8a.genTest(apiType, dbType)
// **deletes created project, hence place it @ end
t6e.genTest(apiType, dbType);
// intended to keep this after earlier project deletion
// creates project using excel & deletes it
t7a.genTest(apiType, dbType);

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

@ -1,4 +1,3 @@
let t01 = require("../common/00_pre_configurations");
let t1a = require("../common/1a_table_operations");
let t1b = require("../common/1b_table_column_operations");
@ -14,26 +13,26 @@ let t3d = require("../common/3d_rollup_column");
let t3e = require("../common/3e_duration_column");
let t3f = require("../common/3f_link_to_another_record");
const {
setCurrentMode,
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
t01.genTest(apiType, dbType);
setCurrentMode(apiType, dbType);
t01.genTest(apiType, dbType);
t1a.genTest(apiType, dbType);
t1b.genTest(apiType, dbType);
t1c.genTest(apiType, dbType);
// NcGUI v2 t1d.genTest(apiType, dbType);
t1e.genTest(apiType, dbType);
t2a.genTest(apiType, dbType);
t2b.genTest(apiType, dbType);
t3a.genTest(apiType, dbType);
t3b.genTest(apiType, dbType);
t3c.genTest(apiType, dbType);
t3d.genTest(apiType, dbType);
// NcGUI v2 t3e.genTest(apiType, dbType);
t3f.genTest(apiType, dbType);
t1a.genTest(apiType, dbType);
t1b.genTest(apiType, dbType);
t1c.genTest(apiType, dbType);
// NcGUI v2 t1d.genTest(apiType, dbType);
t1e.genTest(apiType, dbType);
t2a.genTest(apiType, dbType);
t2b.genTest(apiType, dbType);
t3a.genTest(apiType, dbType);
t3b.genTest(apiType, dbType);
t3c.genTest(apiType, dbType);
t3d.genTest(apiType, dbType);
// NcGUI v2 t3e.genTest(apiType, dbType);
t3f.genTest(apiType, dbType);
};
nocoTestSuite("rest", "mysql");

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 t4e = require("../common/4e_form_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 {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
@ -15,15 +15,15 @@ const {
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
t01.genTest(apiType, dbType);
//
// // place plugin related activities at top
// t4c.genTest(apiType, dbType);
// t4a.genTest(apiType, dbType);
// t4b.genTest(apiType, dbType);
// t4d.genTest(apiType, dbType);
// t4e.genTest(apiType, dbType);
// t4f.genTest(apiType, dbType);
t4c.genTest(apiType, dbType);
t4a.genTest(apiType, dbType);
t4b.genTest(apiType, dbType);
t4d.genTest(apiType, dbType);
t4e.genTest(apiType, dbType);
t4f.genTest(apiType, dbType);
t4g.genTest(apiType, dbType);
t4h.genTest(apiType, dbType);
};
nocoTestSuite("rest", "mysql");

117
scripts/cypress/support/commands.js

@ -222,13 +222,16 @@ Cypress.Commands.add("saveLocalStorage", (name) => {
cy.printLocalStorage();
});
Cypress.Commands.add("restoreLocalStorage", (name) => {
const restoreLocalStorage = () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => {
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
});
cy.printLocalStorage();
});
};
Cypress.Commands.add("restoreLocalStorage", restoreLocalStorage);
// Cypress.on("window:before:load", restoreLocalStorage);
Cypress.Commands.add("deleteLocalStorage", () => {
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", () => {
cy.task("log", `[printLocalStorage]`);
cy.task("log", JSON.stringify(localStorage, null, 2));
cy.task("log", JSON.stringify(LOCAL_STORAGE_MEMORY, null, 2));
// cy.task('log', `[printLocalStorage]`);
// cy.task('log', JSON.stringify(localStorage, null, 2));
// cy.task('log', JSON.stringify(LOCAL_STORAGE_MEMORY, null, 2));
});
Cypress.Commands.add("getActiveModal", (wrapperSelector) => {
@ -387,9 +367,10 @@ Cypress.Commands.add("renameTable", (oldName, newName) => {
// });
Cypress.Commands.add("toastWait", (msg) => {
cy.get(".ant-message-notice-content:visible", { timeout: 60000 })
.contains(msg)
.should("exist");
// cy.get('.ant-message-notice-content:visible', { timout: 30000 }).should('exist')
cy.get(`.ant-message-notice-content:visible:contains("${msg}")`, {
timeout: 30000,
}).should("exist");
cy.get(".ant-message-notice-content:visible", { timeout: 12000 }).should(
"not.exist"
);
@ -503,78 +484,6 @@ Cypress.Commands.add("signOut", () => {
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
// refer: https://stackoverflow.com/a/55409853
/*
@ -684,4 +593,4 @@ Cypress.Commands.addAll(
dragTo,
}
)
*/
*/

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

@ -16,7 +16,7 @@ export class _settingsPage {
// menu
this.TEAM_N_AUTH = "teamAndAuth";
this.APPSTORE = "appStore";
this.PROJ_METADATA = "metaData";
this.PROJ_METADATA = "projMetaData";
this.AUDIT = "audit";
// submenu
@ -26,6 +26,8 @@ export class _settingsPage {
this.METADATA = "metaData";
this.UI_ACCESS_CONTROL = "acl";
this.AUDIT_LOG = "audit";
this.ERD = "erd";
this.MISC = "misc";
}
openMenu(menuId) {
@ -119,6 +121,13 @@ export class _mainPage {
// click on New User button, feed details
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(".ant-select.nc-user-roles").click();
@ -646,6 +655,35 @@ export class _mainPage {
toggleRightSidebar() {
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();

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

@ -156,3 +156,13 @@ export function setProjectString(projStr) {
export function getProjectString() {
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": {
"type": "string"
},
"mm": {
"type": [
"boolean",
"number"
]
}
},
"required": [

Loading…
Cancel
Save