Browse Source

Merge pull request #5117 from nocodb/chore/rename-pv

chore: rename primary value to display value
pull/5119/head
աɨռɢӄաօռɢ 2 years ago committed by GitHub
parent
commit
bf8e8a8e9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      packages/nc-gui/components/smartsheet/expanded-form/Header.vue
  2. 4
      packages/nc-gui/components/smartsheet/header/Menu.vue
  3. 12
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  4. 2
      packages/nc-gui/components/template/Editor.vue
  5. 6
      packages/nc-gui/components/virtual-cell/BelongsTo.vue
  6. 6
      packages/nc-gui/components/virtual-cell/HasMany.vue
  7. 6
      packages/nc-gui/components/virtual-cell/ManyToMany.vue
  8. 4
      packages/nc-gui/components/virtual-cell/components/ListChildItems.vue
  9. 4
      packages/nc-gui/components/virtual-cell/components/ListItems.vue
  10. 6
      packages/nc-gui/composables/useExpandedFormStore.ts
  11. 22
      packages/nc-gui/composables/useLTARStore.ts
  12. 36
      packages/noco-docs/content/en/setup-and-usages/display-value.md
  13. 4
      packages/noco-docs/content/en/setup-and-usages/table-operations.md
  14. 12
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts
  15. 12
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts
  16. 2
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/getAst.ts
  17. 4
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts
  18. 8
      packages/nocodb/src/lib/db/sql-mgr/code/models/xc/BaseModelXcMeta.ts
  19. 2
      packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaMssql.ts
  20. 2
      packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaMysql.ts
  21. 2
      packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaOracle.ts
  22. 2
      packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaPg.ts
  23. 2
      packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaSnowflake.ts
  24. 2
      packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaSqlite.ts
  25. 10
      packages/nocodb/src/lib/meta/api/columnApis.ts
  26. 2
      packages/nocodb/src/lib/meta/api/dataApis/helpers.ts
  27. 4
      packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts
  28. 10
      packages/nocodb/src/lib/meta/api/metaDiffApis.ts
  29. 2
      packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts
  30. 8
      packages/nocodb/src/lib/meta/api/sync/helpers/job.ts
  31. 4
      packages/nocodb/src/lib/meta/api/tableApis.ts
  32. 2
      packages/nocodb/src/lib/meta/helpers/mapDefaultDisplayValue.ts
  33. 4
      packages/nocodb/src/lib/models/Model.ts
  34. 6
      packages/nocodb/src/lib/models/View.ts
  35. 4
      packages/nocodb/src/lib/utils/common/BaseApiBuilder.ts
  36. 4
      packages/nocodb/src/lib/version-upgrader/ncStickyColumnUpgrader.ts
  37. 10
      tests/playwright/pages/Dashboard/Grid/Column/index.ts
  38. 4
      tests/playwright/tests/columnMenuOperations.spec.ts

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

@ -18,7 +18,7 @@ const route = useRoute()
const { meta, isSqlView } = useSmartsheetStoreOrThrow()
const { commentsDrawer, primaryValue, primaryKey, save: _save, loadRow } = useExpandedFormStoreOrThrow()
const { commentsDrawer, displayValue, primaryKey, save: _save, loadRow } = useExpandedFormStoreOrThrow()
const { isNew, syncLTARRefs, state } = useSmartsheetRowStoreOrThrow()
@ -99,7 +99,7 @@ const onConfirmDeleteRowClick = async () => {
{{ meta.title }}
</template>
<template v-if="primaryValue">: {{ primaryValue }}</template>
<template v-if="displayValue">: {{ displayValue }}</template>
</h5>
<div class="flex-1" />

4
packages/nc-gui/components/smartsheet/header/Menu.vue

@ -68,7 +68,7 @@ const deleteColumn = () =>
},
})
const setAsPrimaryValue = async () => {
const setAsDisplayValue = async () => {
try {
await $api.dbTableColumn.primaryColumnSet(column?.value?.id as string)
@ -280,7 +280,7 @@ const hideField = async () => {
</a-menu-item>
<a-divider class="!my-0" />
<a-menu-item v-if="(!virtual || column?.uidt === UITypes.Formula) && !column?.pv" @click="setAsPrimaryValue">
<a-menu-item v-if="(!virtual || column?.uidt === UITypes.Formula) && !column?.pv" @click="setAsDisplayValue">
<div class="nc-column-set-primary nc-header-menu-item">
<MdiStar class="text-primary" />

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

@ -68,7 +68,7 @@ watch(
const numberOfHiddenFields = computed(() => filteredFieldList.value?.filter((field) => !field.show)?.length)
const gridPrimaryValueField = computed(() => {
const gridDisplayValueField = computed(() => {
if (activeView.value?.type !== ViewTypes.GRID) return null
const pvCol = Object.values(metaColumnById.value)?.find((col) => col?.pv)
return filteredFieldList.value?.find((field) => field.fk_column_id === pvCol?.id)
@ -194,7 +194,7 @@ useMenuCloseOnEsc(open)
<Draggable v-model="fields" item-key="id" @change="onMove($event)">
<template #item="{ element: field, index: index }">
<div
v-if="filteredFieldList.filter((el) => el !== gridPrimaryValueField).includes(field)"
v-if="filteredFieldList.filter((el) => el !== gridDisplayValueField).includes(field)"
:key="field.id"
class="px-2 py-1 flex items-center"
:data-testid="`nc-fields-menu-${field.title}`"
@ -220,15 +220,15 @@ useMenuCloseOnEsc(open)
</template>
<template v-if="activeView?.type === ViewTypes.GRID" #header>
<div
v-if="gridPrimaryValueField"
:key="`pv-${gridPrimaryValueField.id}`"
v-if="gridDisplayValueField"
:key="`pv-${gridDisplayValueField.id}`"
class="px-2 py-1 flex items-center"
:data-testid="`nc-fields-menu-${gridPrimaryValueField.title}`"
:data-testid="`nc-fields-menu-${gridDisplayValueField.title}`"
@click.stop
>
<a-tooltip placement="bottom">
<template #title>
<span class="text-sm">Primary Value</span>
<span class="text-sm">Display Value</span>
</template>
<MdiTableKey class="text-xs" />

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

@ -516,7 +516,7 @@ async function importTemplate() {
tab.title = createdTable.title as string
}
// set primary value
// set display value
if (createdTable?.columns?.[0]?.id) {
await $api.dbTableColumn.primaryColumnSet(createdTable.columns[0].id as string)
}

6
packages/nc-gui/components/virtual-cell/BelongsTo.vue

@ -44,7 +44,7 @@ const listItemsDlg = ref(false)
const { state, isNew, removeLTARRef } = useSmartsheetRowStoreOrThrow()
const { loadRelatedTableMeta, relatedTablePrimaryValueProp, unlink } = useProvideLTARStore(
const { loadRelatedTableMeta, relatedTableDisplayValueProp, unlink } = useProvideLTARStore(
column as Ref<Required<ColumnType>>,
row,
isNew,
@ -85,8 +85,8 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
<template>
<div class="flex w-full chips-wrapper items-center" :class="{ active }">
<div class="chips flex items-center flex-1">
<template v-if="value && relatedTablePrimaryValueProp">
<VirtualCellComponentsItemChip :item="value" :value="value[relatedTablePrimaryValueProp]" @unlink="unlinkRef(value)" />
<template v-if="value && relatedTableDisplayValueProp">
<VirtualCellComponentsItemChip :item="value" :value="value[relatedTableDisplayValueProp]" @unlink="unlinkRef(value)" />
</template>
</div>

6
packages/nc-gui/components/virtual-cell/HasMany.vue

@ -40,7 +40,7 @@ const { isUIAllowed } = useUIPermission()
const { state, isNew, removeLTARRef } = useSmartsheetRowStoreOrThrow()
const { loadRelatedTableMeta, relatedTablePrimaryValueProp, unlink } = useProvideLTARStore(
const { loadRelatedTableMeta, relatedTableDisplayValueProp, unlink } = useProvideLTARStore(
column as Ref<Required<ColumnType>>,
row,
isNew,
@ -60,9 +60,9 @@ const localCellValue = computed<any[]>(() => {
const cells = computed(() =>
localCellValue.value.reduce((acc, curr) => {
if (!relatedTablePrimaryValueProp.value) return acc
if (!relatedTableDisplayValueProp.value) return acc
const value = curr[relatedTablePrimaryValueProp.value]
const value = curr[relatedTableDisplayValueProp.value]
if (!value) return acc

6
packages/nc-gui/components/virtual-cell/ManyToMany.vue

@ -42,7 +42,7 @@ const { isUIAllowed } = useUIPermission()
const { state, isNew, removeLTARRef } = useSmartsheetRowStoreOrThrow()
const { loadRelatedTableMeta, relatedTablePrimaryValueProp, unlink } = useProvideLTARStore(
const { loadRelatedTableMeta, relatedTableDisplayValueProp, unlink } = useProvideLTARStore(
column as Ref<Required<ColumnType>>,
row,
isNew,
@ -62,9 +62,9 @@ const localCellValue = computed<any[]>(() => {
const cells = computed(() =>
localCellValue.value.reduce((acc, curr) => {
if (!relatedTablePrimaryValueProp.value) return acc
if (!relatedTableDisplayValueProp.value) return acc
const value = curr[relatedTablePrimaryValueProp.value]
const value = curr[relatedTableDisplayValueProp.value]
if (!value) return acc

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

@ -37,7 +37,7 @@ const {
deleteRelatedRow,
loadChildrenList,
childrenListPagination,
relatedTablePrimaryValueProp,
relatedTableDisplayValueProp,
unlink,
getRelatedTableRowId,
relatedTableMeta,
@ -146,7 +146,7 @@ const onClick = (row: Row) => {
>
<div class="flex items-center">
<div class="flex-1 overflow-hidden min-w-0">
{{ row[relatedTablePrimaryValueProp] }}
{{ row[relatedTableDisplayValueProp] }}
<span class="text-gray-400 text-[11px] ml-1">(Primary key : {{ getRelatedTableRowId(row) }})</span>
</div>

4
packages/nc-gui/components/virtual-cell/components/ListItems.vue

@ -32,7 +32,7 @@ const {
childrenExcludedList,
loadChildrenExcludedList,
childrenExcludedListPagination,
relatedTablePrimaryValueProp,
relatedTableDisplayValueProp,
link,
getRelatedTableRowId,
relatedTableMeta,
@ -201,7 +201,7 @@ const activeRow = (vNode?: InstanceType<typeof Card>) => {
:class="{ 'nc-selected-row': selectedRowIndex === i }"
@click="linkRow(refRow)"
>
{{ refRow[relatedTablePrimaryValueProp] }}
{{ refRow[relatedTableDisplayValueProp] }}
<span class="hidden group-hover:(inline) text-gray-400 text-[11px] ml-1">
({{ $t('labels.primaryKey') }} : {{ getRelatedTableRowId(refRow) }})
</span>

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

@ -49,7 +49,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
const { sharedView } = useSharedView()
// getters
const primaryValue = computed(() => {
const displayValue = computed(() => {
if (row?.value?.row) {
const col = meta?.value?.columns?.find((c) => c.pv)
@ -199,7 +199,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
addOrEditStackRow(row.value, isNewRow)
}
message.success(`${primaryValue.value || 'Row'} updated successfully.`)
message.success(`${displayValue.value || 'Row'} updated successfully.`)
changedColumns.value = new Set()
} catch (e: any) {
@ -237,7 +237,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
isYou,
commentsDrawer,
row,
primaryValue,
displayValue,
save,
changedColumns,
loadRow,

22
packages/nc-gui/composables/useLTARStore.ts

@ -94,14 +94,14 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
await getMeta(colOptions.fk_related_model_id as string)
}
const relatedTablePrimaryValueProp = computed(() => {
const relatedTableDisplayValueProp = computed(() => {
return (relatedTableMeta.value?.columns?.find((c) => c.pv) || relatedTableMeta?.value?.columns?.[0])?.title || ''
})
const relatedTablePrimaryKeyProps = computed(() => {
return relatedTableMeta.value?.columns?.filter((c) => c.pk)?.map((c) => c.title) ?? []
})
const primaryValueProp = computed(() => {
const displayValueProp = computed(() => {
return (meta.value?.columns?.find((c: Required<ColumnType>) => c.pv) || relatedTableMeta?.value?.columns?.[0])?.title
})
@ -125,8 +125,8 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
offset: childrenExcludedListPagination.size * (childrenExcludedListPagination.page - 1),
where:
childrenExcludedListPagination.query &&
`(${relatedTablePrimaryValueProp.value},like,${childrenExcludedListPagination.query})`,
fields: [relatedTablePrimaryValueProp.value, ...relatedTablePrimaryKeyProps.value],
`(${relatedTableDisplayValueProp.value},like,${childrenExcludedListPagination.query})`,
fields: [relatedTableDisplayValueProp.value, ...relatedTablePrimaryKeyProps.value],
} as RequestParams,
},
)
@ -142,8 +142,8 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
offset: childrenExcludedListPagination.size * (childrenExcludedListPagination.page - 1),
where:
childrenExcludedListPagination.query &&
`(${relatedTablePrimaryValueProp.value},like,${childrenExcludedListPagination.query})`,
fields: [relatedTablePrimaryValueProp.value, ...relatedTablePrimaryKeyProps.value],
`(${relatedTableDisplayValueProp.value},like,${childrenExcludedListPagination.query})`,
fields: [relatedTableDisplayValueProp.value, ...relatedTablePrimaryKeyProps.value],
} as any,
)
} else {
@ -160,7 +160,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
// todo: where clause is missing from type
where:
childrenExcludedListPagination.query &&
`(${relatedTablePrimaryValueProp.value},like,${childrenExcludedListPagination.query})`,
`(${relatedTableDisplayValueProp.value},like,${childrenExcludedListPagination.query})`,
} as any,
)
}
@ -183,7 +183,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
limit: String(childrenListPagination.size),
offset: String(childrenListPagination.size * (childrenListPagination.page - 1)),
where:
childrenListPagination.query && `(${relatedTablePrimaryValueProp.value},like,${childrenListPagination.query})`,
childrenListPagination.query && `(${relatedTableDisplayValueProp.value},like,${childrenListPagination.query})`,
} as any,
)
} else {
@ -198,7 +198,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
limit: String(childrenListPagination.size),
offset: String(childrenListPagination.size * (childrenListPagination.page - 1)),
where:
childrenListPagination.query && `(${relatedTablePrimaryValueProp.value},like,${childrenListPagination.query})`,
childrenListPagination.query && `(${relatedTableDisplayValueProp.value},like,${childrenListPagination.query})`,
} as any,
)
}
@ -320,13 +320,13 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
return {
relatedTableMeta,
loadRelatedTableMeta,
relatedTablePrimaryValueProp,
relatedTableDisplayValueProp,
childrenExcludedList,
childrenList,
rowId,
childrenExcludedListPagination,
childrenListPagination,
primaryValueProp,
displayValueProp,
meta,
unlink,
link,

36
packages/noco-docs/content/en/setup-and-usages/primary-value.md → packages/noco-docs/content/en/setup-and-usages/display-value.md

@ -1,40 +1,42 @@
---
title: "Primary Value"
description: "Understanding Primary Value in NocoDB!"
title: "Display Value"
description: "Understanding Display Value in NocoDB!"
position: 580
category: "Product"
menuTitle: "Primary Value"
menuTitle: "Display Value"
---
## What is a Primary Value ?
- Primary value as the name stands is the primary or main value within a row of a table that you generally associate that row with.
## What is a Display Value ?
- Display Value as the name stands is the primary or main value within a row of a table that you generally associate that row with.
- It should be usually associated with a column which is uniquely identifiable. However, this uniqueness is not enforced at the database level.
- Before v0.105.0, Display Value was known as Primary Value.
## What is the use of Primary Value ?
- Within a spreadsheet, primary value are always highlighted so that it is easier to recognise what row we are in.
- And when LinkToAnotherRecord is created between two tables - it is the primary value that appears in LinkToAnotheRecord column.
## What is the use of Display Value ?
- Within a spreadsheet, Display Value are always highlighted so that it is easier to recognise what row we are in.
- And when LinkToAnotherRecord is created between two tables - it is the Display Value that appears in LinkToAnotheRecord column.
#### Example : Primary Value highlighted in Actor table
#### Example : Display Value highlighted in Actor table
<img width="646" alt="image" src="https://user-images.githubusercontent.com/35857179/189114321-58ebaa16-20e2-4615-abda-39417a5df5bf.png">
#### Example : Primary Value highlighted in Film table
#### Example : Display Value highlighted in Film table
<img width="643" alt="image" src="https://user-images.githubusercontent.com/35857179/189114462-a7fef0e2-f9ac-4943-98d5-fee9f60a4ab5.png">
#### Example : Primary Value associated when LinkToAnotherRecord is created
#### Example : Display Value associated when LinkToAnotherRecord is created
<img width="311" alt="image" src="https://user-images.githubusercontent.com/35857179/189114548-193acc4d-f714-4204-a560-97668db7884c.png">
## How to set Primary Value ?
## How to set Display Value ?
Click down arrow in the target column. Click `Set as Primary Value`.
Click down arrow in the target column. Click `Set as Display Value`.
<img width="251" alt="image" src="https://user-images.githubusercontent.com/35857179/189114857-b452aa6b-5cdb-4a74-9980-cb839d7d15fd.png">
![image](https://user-images.githubusercontent.com/35857179/219339727-dee5fdea-6db7-4a06-9e48-df7113cc63b1.png)
## How is Primary Value identfied for existing database tables ?
## How is Display Value identfied for existing database tables ?
- It is usually the first column after the primary key which is not a number.
- If there is no column which is not a number then the column adjacent to primary key is chosen.
## Can I change the Primary Value to another column within tables ?
## Can I change the Display Value to another column within tables ?
- Yes, you can use the same way mentioned above to set Primary Value.
- Yes, you can use the same way mentioned above to set Display Value.

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

@ -159,7 +159,7 @@ You can use Quick Import when you have data from external sources such as Airtab
- **Use First Row as Headers**: If it is checked, the first row will be treated as header row.
- **Import Data**: If it is checked, all data will be imported. Otherwise, only table will be created.
![image](https://user-images.githubusercontent.com/35857179/197454479-1ed18dce-1d0b-4ee3-88b3-9b6a132dea2a.png)
- You can revise the table name by double clicking it, column name and column type. By default, the first column will be chosen as <a href="./primary-value" target="_blank">Primary Value</a> and cannot be deleted.
- You can revise the table name by double clicking it, column name and column type. By default, the first column will be chosen as <a href="./display-value" target="_blank">Display Value</a> and cannot be deleted.
![image](https://user-images.githubusercontent.com/35857179/197454633-5b30323e-2b13-4c55-843a-948c093d373e.png)
- Click `Import` to start importing process. The table will be created and the data will be imported.
![image](https://user-images.githubusercontent.com/35857179/197455547-2d93df5e-a7f0-4c88-af53-990067625967.png)
@ -172,7 +172,7 @@ You can use Quick Import when you have data from external sources such as Airtab
- **Use First Row as Headers**: If it is checked, the first row will be treated as header row.
- **Import Data**: If it is checked, all data will be imported. Otherwise, only table will be created.
![image](https://user-images.githubusercontent.com/35857179/197455788-8dd8a7d1-38f3-48c3-a05e-6ab0cf25045c.png)
- You can revise the table name, column name and column type. By default, the first column will be chosen as <a href="./primary-value" target="_blank">Primary Value</a> and cannot be deleted.
- You can revise the table name, column name and column type. By default, the first column will be chosen as <a href="./display-value" target="_blank">Display Value</a> and cannot be deleted.
<alert>
Note: If your Excel file contains multiple sheets, each sheet will be stored in a separate table.
</alert>

12
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts

@ -119,7 +119,7 @@ const parseConditionV2 = async (
? negatedMapping[filter.comparison_op]
: {}),
fk_model_id: childModel.id,
fk_column_id: childModel?.primaryValue?.id,
fk_column_id: childModel?.displayValue?.id,
}),
knex,
aliasCount
@ -154,7 +154,7 @@ const parseConditionV2 = async (
? negatedMapping[filter.comparison_op]
: {}),
fk_model_id: parentModel.id,
fk_column_id: parentModel?.primaryValue?.id,
fk_column_id: parentModel?.displayValue?.id,
}),
knex,
aliasCount
@ -209,7 +209,7 @@ const parseConditionV2 = async (
? negatedMapping[filter.comparison_op]
: {}),
fk_model_id: parentModel.id,
fk_column_id: parentModel?.primaryValue?.id,
fk_column_id: parentModel?.displayValue?.id,
}),
knex,
aliasCount
@ -841,7 +841,7 @@ async function nestedConditionJoin(
new Filter({
...filter,
fk_model_id: childModel.id,
fk_column_id: childModel.primaryValue?.id,
fk_column_id: childModel.displayValue?.id,
}),
knex,
aliasCount,
@ -857,7 +857,7 @@ async function nestedConditionJoin(
new Filter({
...filter,
fk_model_id: parentModel.id,
fk_column_id: parentModel?.primaryValue?.id,
fk_column_id: parentModel?.displayValue?.id,
}),
knex,
aliasCount,
@ -873,7 +873,7 @@ async function nestedConditionJoin(
new Filter({
...filter,
fk_model_id: parentModel.id,
fk_column_id: parentModel.primaryValue?.id,
fk_column_id: parentModel.displayValue?.id,
}),
knex,
aliasCount,

12
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts

@ -269,7 +269,7 @@ async function _formulaQueryBuilder(
);
cn = knex.raw('??.??', [
nestedAlias,
parentModel?.primaryValue?.column_name,
parentModel?.displayValue?.column_name,
]);
}
break;
@ -283,7 +283,7 @@ async function _formulaQueryBuilder(
);
cn = knex.raw('??.??', [
nestedAlias,
childModel?.primaryValue?.column_name,
childModel?.displayValue?.column_name,
]);
}
break;
@ -311,7 +311,7 @@ async function _formulaQueryBuilder(
}
cn = knex.raw('??.??', [
nestedAlias,
parentModel?.primaryValue?.column_name,
parentModel?.displayValue?.column_name,
]);
}
@ -424,7 +424,7 @@ async function _formulaQueryBuilder(
let selectQb;
if (relation.type === 'bt') {
selectQb = knex(parentModel.table_name)
.select(parentModel?.primaryValue?.column_name)
.select(parentModel?.displayValue?.column_name)
.where(
`${parentModel.table_name}.${parentColumn.column_name}`,
knex.raw(`??`, [
@ -447,7 +447,7 @@ async function _formulaQueryBuilder(
getAggregateFn(fn)({
qb,
knex,
cn: childModel?.primaryValue?.column_name,
cn: childModel?.displayValue?.column_name,
})
)
.wrap('(', ')');
@ -499,7 +499,7 @@ async function _formulaQueryBuilder(
getAggregateFn(fn)({
qb,
knex,
cn: parentModel?.primaryValue?.column_name,
cn: parentModel?.displayValue?.column_name,
})
)
.wrap('(', ')');

2
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/getAst.ts

@ -24,7 +24,7 @@ const getAst = async ({
...(model.primaryKeys
? model.primaryKeys.reduce((o, pk) => ({ ...o, [pk.title]: 1 }), {})
: {}),
...(model.primaryValue ? { [model.primaryValue.title]: 1 } : {}),
...(model.displayValue ? { [model.displayValue.title]: 1 } : {}),
};
}

4
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts

@ -153,7 +153,7 @@ export default async function sortV2(
`${nestedAlias}.${parentColumn.column_name}`,
`${prevAlias}.${childColumn.column_name}`
)
.select(parentModel?.primaryValue?.column_name);
.select(parentModel?.displayValue?.column_name);
}
break;
case UITypes.Formula:
@ -201,7 +201,7 @@ export default async function sortV2(
await parentModel.getColumns();
const selectQb = knex(parentModel.table_name)
.select(parentModel?.primaryValue?.column_name)
.select(parentModel?.displayValue?.column_name)
.where(
`${parentModel.table_name}.${parentColumn.column_name}`,
knex.raw(`??`, [

8
packages/nocodb/src/lib/db/sql-mgr/code/models/xc/BaseModelXcMeta.ts

@ -1,5 +1,5 @@
import BaseRender from '../../BaseRender';
import mapDefaultPrimaryValue from '../../../../../meta/helpers/mapDefaultPrimaryValue';
import mapDefaultDisplayValue from '../../../../../meta/helpers/mapDefaultDisplayValue';
import { UITypes } from 'nocodb-sdk';
abstract class BaseModelXcMeta extends BaseRender {
@ -79,7 +79,7 @@ abstract class BaseModelXcMeta extends BaseRender {
columnsArr.push(columnObj);
}
this.mapDefaultPrimaryValue(columnsArr);
this.mapDefaultDisplayValue(columnsArr);
return columnsArr;
}
@ -127,8 +127,8 @@ abstract class BaseModelXcMeta extends BaseRender {
return virtualColumns;
}
public mapDefaultPrimaryValue(columnsArr: any[]): void {
mapDefaultPrimaryValue(columnsArr);
public mapDefaultDisplayValue(columnsArr: any[]): void {
mapDefaultDisplayValue(columnsArr);
}
}

2
packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaMssql.ts

@ -544,7 +544,7 @@ class ModelXcMetaMssql extends BaseModelXcMeta {
columnsArr.push(columnObj);
}
this.mapDefaultPrimaryValue(columnsArr);
this.mapDefaultDisplayValue(columnsArr);
return columnsArr;
}*/

2
packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaMysql.ts

@ -163,7 +163,7 @@ class ModelXcMetaMysql extends BaseModelXcMeta {
columnsArr.push(columnObj);
}
this.mapDefaultPrimaryValue(columnsArr);
this.mapDefaultDisplayValue(columnsArr);
return columnsArr;
}
*/

2
packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaOracle.ts

@ -163,7 +163,7 @@ class ModelXcMetaOracle extends BaseModelXcMeta {
columnsArr.push(columnObj);
}
this.mapDefaultPrimaryValue(columnsArr);
this.mapDefaultDisplayValue(columnsArr);
return columnsArr;
}
*/

2
packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaPg.ts

@ -953,7 +953,7 @@ class ModelXcMetaPg extends BaseModelXcMeta {
columnsArr.push(columnObj);
}
this.mapDefaultPrimaryValue(columnsArr);
this.mapDefaultDisplayValue(columnsArr);
return columnsArr;
}*/

2
packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaSnowflake.ts

@ -953,7 +953,7 @@ class ModelXcMetaSnowflake extends BaseModelXcMeta {
columnsArr.push(columnObj);
}
this.mapDefaultPrimaryValue(columnsArr);
this.mapDefaultDisplayValue(columnsArr);
return columnsArr;
}*/

2
packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaSqlite.ts

@ -504,7 +504,7 @@ class ModelXcMetaSqlite extends BaseModelXcMeta {
columnsArr.push(columnObj);
}
this.mapDefaultPrimaryValue(columnsArr);
this.mapDefaultDisplayValue(columnsArr);
return columnsArr;
}
*/

10
packages/nocodb/src/lib/meta/api/columnApis.ts

@ -31,7 +31,7 @@ import NcMetaIO from '../NcMetaIO';
import ncMetaAclMw from '../helpers/ncMetaAclMw';
import { NcError } from '../helpers/catchError';
import getColumnPropsFromUIDT from '../helpers/getColumnPropsFromUIDT';
import mapDefaultPrimaryValue from '../helpers/mapDefaultPrimaryValue';
import mapDefaultDisplayValue from '../helpers/mapDefaultDisplayValue';
import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2';
import { metaApiMetrics } from '../helpers/apiMetrics';
import FormulaColumn from '../../models/FormulaColumn';
@ -1592,11 +1592,11 @@ export async function columnDelete(req: Request, res: Response<TableType>) {
await table.getColumns();
const primaryValueColumn = mapDefaultPrimaryValue(table.columns);
if (primaryValueColumn) {
const displayValueColumn = mapDefaultDisplayValue(table.columns);
if (displayValueColumn) {
await Model.updatePrimaryColumn(
primaryValueColumn.fk_model_id,
primaryValueColumn.id
displayValueColumn.fk_model_id,
displayValueColumn.id
);
}

2
packages/nocodb/src/lib/meta/api/dataApis/helpers.ts

@ -225,7 +225,7 @@ export async function serializeCellValue({
await relatedModel.getColumns();
return [...(Array.isArray(value) ? value : [value])]
.map((v) => {
return v[relatedModel.primaryValue?.title];
return v[relatedModel.displayValue?.title];
})
.join(', ');
}

4
packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts

@ -10,7 +10,7 @@ import getTableNameAlias, {
} from '../../helpers/getTableName';
import LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn';
import getColumnUiType from '../../helpers/getColumnUiType';
import mapDefaultPrimaryValue from '../../helpers/mapDefaultPrimaryValue';
import mapDefaultDisplayValue from '../../helpers/mapDefaultDisplayValue';
import { extractAndGenerateManyToManyRelations } from '../metaDiffApis';
import { ModelTypes, UITypes, ViewTypes } from 'nocodb-sdk';
import { IGNORE_TABLES } from '../../../utils/common/BaseApiBuilder';
@ -90,7 +90,7 @@ export async function populateMeta(base: Base, project: Project): Promise<any> {
? []
: tableRelations.filter((r) => r.tn === table.tn);
mapDefaultPrimaryValue(columns);
mapDefaultDisplayValue(columns);
// add vitual columns
const virtualColumns = [

10
packages/nocodb/src/lib/meta/api/metaDiffApis.ts

@ -14,7 +14,7 @@ import LinkToAnotherRecordColumn from '../../models/LinkToAnotherRecordColumn';
import { getUniqueColumnAliasName } from '../helpers/getUniqueName';
import NcHelp from '../../utils/NcHelp';
import getTableNameAlias, { getColumnNameAlias } from '../helpers/getTableName';
import mapDefaultPrimaryValue from '../helpers/mapDefaultPrimaryValue';
import mapDefaultDisplayValue from '../helpers/mapDefaultDisplayValue';
import getColumnUiType from '../helpers/getColumnUiType';
import { metaApiMetrics } from '../helpers/apiMetrics';
@ -602,7 +602,7 @@ export async function metaDiffSync(req, res) {
await sqlClient.columnList({ tn: table_name })
)?.data?.list?.map((c) => ({ ...c, column_name: c.cn }));
mapDefaultPrimaryValue(columns);
mapDefaultDisplayValue(columns);
const model = await Model.insert(project.id, base.id, {
table_name: table_name,
@ -630,7 +630,7 @@ export async function metaDiffSync(req, res) {
await sqlClient.columnList({ tn: table_name })
)?.data?.list?.map((c) => ({ ...c, column_name: c.cn }));
mapDefaultPrimaryValue(columns);
mapDefaultDisplayValue(columns);
const model = await Model.insert(project.id, base.id, {
table_name: table_name,
@ -798,7 +798,7 @@ export async function baseMetaDiffSync(req, res) {
await sqlClient.columnList({ tn: table_name })
)?.data?.list?.map((c) => ({ ...c, column_name: c.cn }));
mapDefaultPrimaryValue(columns);
mapDefaultDisplayValue(columns);
const model = await Model.insert(project.id, base.id, {
table_name: table_name,
@ -826,7 +826,7 @@ export async function baseMetaDiffSync(req, res) {
await sqlClient.columnList({ tn: table_name })
)?.data?.list?.map((c) => ({ ...c, column_name: c.cn }));
mapDefaultPrimaryValue(columns);
mapDefaultDisplayValue(columns);
const model = await Model.insert(project.id, base.id, {
table_name: table_name,

2
packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts

@ -237,7 +237,7 @@ async function serializeCellValue({
await relatedModel.getColumns();
return [...(Array.isArray(value) ? value : [value])]
.map((v) => {
return v[relatedModel.primaryValue?.title];
return v[relatedModel.displayValue?.title];
})
.join(', ');
}

8
packages/nocodb/src/lib/meta/api/sync/helpers/job.ts

@ -1292,7 +1292,7 @@ export default async (
async function nocoSetPrimary(aTblSchema) {
for (let idx = 0; idx < aTblSchema.length; idx++) {
logDetailed(
`[${idx + 1}/${aTblSchema.length}] Configuring Primary value : ${
`[${idx + 1}/${aTblSchema.length}] Configuring Display value : ${
aTblSchema[idx].name
}`
);
@ -2232,10 +2232,10 @@ export default async (
logDetailed('Migrating Lookup form Rollup columns completed');
}
}
logDetailed('Configuring Primary value column');
// configure primary values
logDetailed('Configuring Display Value column');
// configure Display Value
await nocoSetPrimary(aTblSchema);
logDetailed('Configuring primary value column completed');
logDetailed('Configuring Display Value column completed');
logBasic('Configuring User(s)');
// add users

4
packages/nocodb/src/lib/meta/api/tableApis.ts

@ -20,7 +20,7 @@ import ncMetaAclMw from '../helpers/ncMetaAclMw';
import { xcVisibilityMetaGet } from './modelVisibilityApis';
import View from '../../models/View';
import getColumnPropsFromUIDT from '../helpers/getColumnPropsFromUIDT';
import mapDefaultPrimaryValue from '../helpers/mapDefaultPrimaryValue';
import mapDefaultDisplayValue from '../helpers/mapDefaultDisplayValue';
import { NcError } from '../helpers/catchError';
import getTableNameAlias, { getColumnNameAlias } from '../helpers/getTableName';
import Column from '../../models/Column';
@ -195,7 +195,7 @@ export async function tableCreate(req: Request<any, any, TableReqType>, res) {
ip: (req as any).clientIp,
}).then(() => {});
mapDefaultPrimaryValue(req.body.columns);
mapDefaultDisplayValue(req.body.columns);
Tele.emit('evt', { evt_type: 'table:created' });

2
packages/nocodb/src/lib/meta/helpers/mapDefaultPrimaryValue.ts → packages/nocodb/src/lib/meta/helpers/mapDefaultDisplayValue.ts

@ -1,6 +1,6 @@
import { ColumnType } from 'nocodb-sdk';
export default function mapDefaultPrimaryValue<T extends ColumnType>(
export default function mapDefaultDisplayValue<T extends ColumnType>(
columnsArr: Array<T>
): void | T {
if (!columnsArr.some((column) => column.pv)) {

4
packages/nocodb/src/lib/models/Model.ts

@ -84,7 +84,7 @@ export default class Model implements TableType {
return this.columns?.filter((c) => c.pk);
}
public get primaryValue(): Column {
public get displayValue(): Column {
if (!this.columns) return null;
const pCol = this.columns?.find((c) => c.pv);
if (pCol) return pCol;
@ -561,7 +561,7 @@ export default class Model implements TableType {
ncMeta = Noco.ncMeta
) {
const model = await this.getWithInfo({ id: tableId });
const currentPvCol = model.primaryValue;
const currentPvCol = model.displayValue;
const newPvCol = model.columns.find((c) => c.id === columnId);
if (!newPvCol) NcError.badRequest('Column not found');

6
packages/nocodb/src/lib/models/View.ts

@ -375,10 +375,10 @@ export default class View implements ViewType {
let kanbanShowLimit = 0;
if (view.type === ViewTypes.KANBAN && !copyFromView) {
// sort by primary value & attachment first, then by singleLineText & Number
// sort by display value & attachment first, then by singleLineText & Number
// so that later we can handle control `show` easily
columns.sort((a, b) => {
const primaryValueOrder = b.pv - a.pv;
const displayValueOrder = b.pv - a.pv;
const attachmentOrder =
+(b.uidt === UITypes.Attachment) - +(a.uidt === UITypes.Attachment);
const singleLineTextOrder =
@ -388,7 +388,7 @@ export default class View implements ViewType {
+(b.uidt === UITypes.Number) - +(a.uidt === UITypes.Number);
const defaultOrder = b.order - a.order;
return (
primaryValueOrder ||
displayValueOrder ||
attachmentOrder ||
singleLineTextOrder ||
numberOrder ||

4
packages/nocodb/src/lib/utils/common/BaseApiBuilder.ts

@ -2511,11 +2511,11 @@ export default abstract class BaseApiBuilder<T extends Noco>
ctx,
filename: '',
}).getVitualColumns();
// set default primary values
// set default display values
ModelXcMetaFactory.create(
this.connectionConfig,
{}
).mapDefaultPrimaryValue(meta.columns);
).mapDefaultDisplayValue(meta.columns);
// update meta
await this.xcMeta.metaUpdate(
this.projectId,

4
packages/nocodb/src/lib/version-upgrader/ncStickyColumnUpgrader.ts

@ -1,9 +1,9 @@
import { NcUpgraderCtx } from './NcUpgrader';
import { MetaTable } from '../utils/globals';
// before 0.104.3, primary value column can be in any position in table
// before 0.104.3, display value column can be in any position in table
// with this upgrade we introduced sticky primary column feature
// this upgrader will make primary value column first column in grid views
// this upgrader will make display value column first column in grid views
export default async function ({ ncMeta }: NcUpgraderCtx) {
const grid_columns = await ncMeta.metaList2(

10
tests/playwright/pages/Dashboard/Grid/Column/index.ts

@ -44,7 +44,7 @@ export class ColumnPageObject extends BasePage {
timeFormat = '',
insertAfterColumnTitle,
insertBeforeColumnTitle,
isPrimaryValue = false,
isDisplayValue = false,
}: {
title: string;
type?: string;
@ -61,12 +61,12 @@ export class ColumnPageObject extends BasePage {
timeFormat?: string;
insertBeforeColumnTitle?: string;
insertAfterColumnTitle?: string;
isPrimaryValue?: boolean;
isDisplayValue?: boolean;
}) {
if (insertBeforeColumnTitle) {
await this.grid.get().locator(`th[data-title="${insertBeforeColumnTitle}"] .nc-ui-dt-dropdown`).click();
if (isPrimaryValue) {
if (isDisplayValue) {
await expect(this.rootPage.locator('li[role="menuitem"]:has-text("Insert Before")')).toHaveCount(0);
return;
}
@ -321,10 +321,10 @@ export class ColumnPageObject extends BasePage {
await this.grid.get().locator(`th[data-title="${expectedTitle}"]`).isVisible();
}
async hideColumn({ title, isPrimaryValue = false }: { title: string; isPrimaryValue?: boolean }) {
async hideColumn({ title, isDisplayValue = false }: { title: string; isDisplayValue?: boolean }) {
await this.grid.get().locator(`th[data-title="${title}"] .nc-ui-dt-dropdown`).click();
if (isPrimaryValue) {
if (isDisplayValue) {
await expect(this.rootPage.locator('li[role="menuitem"]:has-text("Hide Field")')).toHaveCount(0);
return;
}

4
tests/playwright/tests/columnMenuOperations.spec.ts

@ -91,7 +91,7 @@ test.describe('Column menu operations', () => {
title: 'InsertBeforeColumn',
type: 'SingleLineText',
insertBeforeColumnTitle: 'Title',
isPrimaryValue: true,
isDisplayValue: true,
});
await dashboard.grid.column.create({
@ -108,7 +108,7 @@ test.describe('Column menu operations', () => {
await dashboard.grid.column.hideColumn({
title: 'Title',
isPrimaryValue: true,
isDisplayValue: true,
});
await dashboard.grid.column.hideColumn({

Loading…
Cancel
Save