mirror of
https://github.com/nocodb/nocodb.git
synced 2026-04-25 04:35:09 +00:00
feat: row height for grid view
Signed-off-by: mertmit <mertmit99@gmail.com>
This commit is contained in:
5
packages/nc-gui/components.d.ts
vendored
5
packages/nc-gui/components.d.ts
vendored
@@ -222,6 +222,10 @@ declare module '@vue/runtime-core' {
|
||||
MdiScriptTextKeyOutline: typeof import('~icons/mdi/script-text-key-outline')['default']
|
||||
MdiScriptTextOutline: typeof import('~icons/mdi/script-text-outline')['default']
|
||||
MdiShieldKeyOutline: typeof import('~icons/mdi/shield-key-outline')['default']
|
||||
MdiSizeL: typeof import('~icons/mdi/size-l')['default']
|
||||
MdiSizeM: typeof import('~icons/mdi/size-m')['default']
|
||||
MdiSizeS: typeof import('~icons/mdi/size-s')['default']
|
||||
MdiSizeXl: typeof import('~icons/mdi/size-xl')['default']
|
||||
MdiSlack: typeof import('~icons/mdi/slack')['default']
|
||||
MdiSort: typeof import('~icons/mdi/sort')['default']
|
||||
MdiSortAscending: typeof import('~icons/mdi/sort-ascending')['default']
|
||||
@@ -233,6 +237,7 @@ declare module '@vue/runtime-core' {
|
||||
MdiTableColumnPlusAfter: typeof import('~icons/mdi/table-column-plus-after')['default']
|
||||
MdiTableColumnPlusBefore: typeof import('~icons/mdi/table-column-plus-before')['default']
|
||||
MdiTableLarge: typeof import('~icons/mdi/table-large')['default']
|
||||
MdiTableRowHeight: typeof import('~icons/mdi/table-row-height')['default']
|
||||
MdiText: typeof import('~icons/mdi/text')['default']
|
||||
MdiThumbUp: typeof import('~icons/mdi/thumb-up')['default']
|
||||
MdiTrashCan: typeof import('~icons/mdi/trash-can')['default']
|
||||
|
||||
@@ -281,7 +281,7 @@ const onTagClick = (e: Event, onClose: Function) => {
|
||||
v-model:value="vModel"
|
||||
v-model:open="isOpen"
|
||||
mode="multiple"
|
||||
class="w-full"
|
||||
class="w-full overflow-hidden"
|
||||
:bordered="false"
|
||||
clear-icon
|
||||
show-search
|
||||
@@ -402,4 +402,8 @@ const onTagClick = (e: Event, onClose: Function) => {
|
||||
:deep(.ant-select-selection-overflow-item) {
|
||||
@apply "flex overflow-hidden";
|
||||
}
|
||||
|
||||
:deep(.ant-select-selection-overflow) {
|
||||
@apply flex-nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { GridType } from 'nocodb-sdk'
|
||||
import type { VNodeRef } from '@vue/runtime-core'
|
||||
import { EditModeInj, inject, useVModel } from '#imports'
|
||||
import { ActiveViewInj, EditModeInj, inject, useVModel } from '#imports'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string | number
|
||||
@@ -10,9 +11,26 @@ const emits = defineEmits(['update:modelValue'])
|
||||
|
||||
const editEnabled = inject(EditModeInj)
|
||||
|
||||
const view = inject(ActiveViewInj, ref())
|
||||
|
||||
const vModel = useVModel(props, 'modelValue', emits, { defaultValue: '' })
|
||||
|
||||
const focus: VNodeRef = (el) => (el as HTMLTextAreaElement)?.focus()
|
||||
|
||||
const rowHeight = computed(() => {
|
||||
if ((view.value?.view as GridType)?.row_height !== undefined) {
|
||||
switch ((view.value?.view as GridType)?.row_height) {
|
||||
case 0:
|
||||
return 1
|
||||
case 1:
|
||||
return 2
|
||||
case 2:
|
||||
return 4
|
||||
case 3:
|
||||
return 6
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -35,5 +53,14 @@ const focus: VNodeRef = (el) => (el as HTMLTextAreaElement)?.focus()
|
||||
@mousedown.stop
|
||||
/>
|
||||
|
||||
<a-textarea
|
||||
v-else-if="rowHeight"
|
||||
:key="rowHeight"
|
||||
v-model:value="vModel"
|
||||
class="w-full h-full"
|
||||
:auto-size="{ minRows: rowHeight, maxRows: rowHeight }"
|
||||
:bordered="false"
|
||||
/>
|
||||
|
||||
<span v-else>{{ vModel }}</span>
|
||||
</template>
|
||||
|
||||
@@ -35,6 +35,8 @@ const { allowCSVDownload } = useSharedView()
|
||||
|
||||
<LazySmartsheetToolbarSortListMenu v-if="isGrid || isGallery || isKanban" />
|
||||
|
||||
<LazySmartsheetToolbarRowHeight v-if="isGrid" />
|
||||
|
||||
<LazySmartsheetToolbarShareView v-if="(isForm || isGrid || isKanban || isGallery) && !isPublic" />
|
||||
|
||||
<LazySmartsheetToolbarExport v-if="(!isPublic && !isUIAllowed('dataInsert')) || (isPublic && allowCSVDownload)" />
|
||||
|
||||
70
packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue
Normal file
70
packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { GridType } from 'nocodb-sdk'
|
||||
import { ActiveViewInj, IsLockedInj, ReloadViewDataHookInj, inject, ref, useMenuCloseOnEsc } from '#imports'
|
||||
|
||||
const view = inject(ActiveViewInj, ref())
|
||||
const isLocked = inject(IsLockedInj, ref(false))
|
||||
const reloadDataHook = inject(ReloadViewDataHookInj)
|
||||
|
||||
const { $api } = useNuxtApp()
|
||||
|
||||
const open = ref(false)
|
||||
|
||||
const updateRowHeight = (rh: number) => {
|
||||
if (view.value?.id) {
|
||||
try {
|
||||
$api.dbView.gridUpdate(view.value.id, {
|
||||
row_height: rh,
|
||||
})
|
||||
;(view.value.view as GridType).row_height = rh
|
||||
|
||||
message.success('View updated successfully!')
|
||||
|
||||
reloadDataHook?.trigger()
|
||||
|
||||
open.value = false
|
||||
} catch (e) {
|
||||
message.error('There was an error while updating view!')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useMenuCloseOnEsc(open)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-dropdown v-model:visible="open" offset-y class="" :trigger="['click']" overlay-class-name="nc-dropdown-height-menu">
|
||||
<div>
|
||||
<a-button v-e="['c:row-height']" class="nc-height-menu-btn nc-toolbar-btn" :disabled="isLocked">
|
||||
<div class="flex items-center gap-1">
|
||||
<MdiTableRowHeight />
|
||||
|
||||
<!-- Row Height -->
|
||||
<span class="text-capitalize !text-sm font-weight-normal">Row Height</span>
|
||||
<MdiMenuDown class="text-grey" />
|
||||
</div>
|
||||
</a-button>
|
||||
</div>
|
||||
<template #overlay>
|
||||
<div class="w-full bg-gray-50 shadow-lg menu-filter-dropdown !border" data-testid="nc-height-menu">
|
||||
<div class="text-gray-500 !text-xs px-4 py-2">Select a row height</div>
|
||||
<div class="flex flex-col w-full text-sm" @click.stop>
|
||||
<div class="flex items-center py-1 px-2 hover:bg-gray-200" @click="updateRowHeight(0)">
|
||||
<MdiSizeS class="text-xl mr-3" />Short
|
||||
</div>
|
||||
<div class="flex items-center py-1 px-2 hover:bg-gray-200" @click="updateRowHeight(1)">
|
||||
<MdiSizeM class="text-xl mr-3" />Medium
|
||||
</div>
|
||||
<div class="flex items-center py-1 px-2 hover:bg-gray-200" @click="updateRowHeight(2)">
|
||||
<MdiSizeL class="text-xl mr-3" />Tall
|
||||
</div>
|
||||
<div class="flex items-center py-1 px-2 hover:bg-gray-200" @click="updateRowHeight(3)">
|
||||
<MdiSizeXl class="text-xl mr-3" />Extra
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -340,6 +340,7 @@ export interface GridType {
|
||||
deleted?: boolean;
|
||||
order?: number;
|
||||
lock_type?: 'collaborative' | 'locked' | 'personal';
|
||||
row_height?: number;
|
||||
}
|
||||
|
||||
export interface GalleryType {
|
||||
@@ -2499,6 +2500,24 @@ export class Api<
|
||||
...params,
|
||||
}),
|
||||
|
||||
/**
|
||||
* No description
|
||||
*
|
||||
* @tags DB view
|
||||
* @name GridUpdate
|
||||
* @request PATCH:/api/v1/db/meta/grids/{viewId}
|
||||
* @response `200` `any` OK
|
||||
*/
|
||||
gridUpdate: (viewId: string, data: GridType, params: RequestParams = {}) =>
|
||||
this.request<any, any>({
|
||||
path: `/api/v1/db/meta/grids/${viewId}`,
|
||||
method: 'PATCH',
|
||||
body: data,
|
||||
type: ContentType.Json,
|
||||
format: 'json',
|
||||
...params,
|
||||
}),
|
||||
|
||||
/**
|
||||
* No description
|
||||
*
|
||||
|
||||
@@ -12,6 +12,7 @@ import Project from '../../models/Project';
|
||||
import View from '../../models/View';
|
||||
import ncMetaAclMw from '../helpers/ncMetaAclMw';
|
||||
import { metaApiMetrics } from '../helpers/apiMetrics';
|
||||
import GridView from '../../models/GridView';
|
||||
|
||||
// @ts-ignore
|
||||
export async function gridViewCreate(req: Request<any, any>, res) {
|
||||
@@ -25,10 +26,20 @@ export async function gridViewCreate(req: Request<any, any>, res) {
|
||||
res.json(view);
|
||||
}
|
||||
|
||||
export async function gridViewUpdate(req, res) {
|
||||
Tele.emit('evt', { evt_type: 'view:updated', type: 'grid' });
|
||||
res.json(await GridView.update(req.params.viewId, req.body));
|
||||
}
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
router.post(
|
||||
'/api/v1/db/meta/tables/:tableId/grids/',
|
||||
metaApiMetrics,
|
||||
ncMetaAclMw(gridViewCreate, 'gridViewCreate')
|
||||
);
|
||||
router.patch(
|
||||
'/api/v1/db/meta/grids/:viewId',
|
||||
metaApiMetrics,
|
||||
ncMetaAclMw(gridViewUpdate, 'gridViewUpdate')
|
||||
);
|
||||
export default router;
|
||||
|
||||
@@ -12,6 +12,7 @@ import * as nc_021_add_fields_in_token from './v2/nc_021_add_fields_in_token';
|
||||
import * as nc_022_qr_code_column_type from './v2/nc_022_qr_code_column_type';
|
||||
import * as nc_023_multiple_source from './v2/nc_023_multiple_source';
|
||||
import * as nc_024_barcode_column_type from './v2/nc_024_barcode_column_type';
|
||||
import * as nc_025_add_row_height from './v2/nc_025_add_row_height';
|
||||
|
||||
// Create a custom migration source class
|
||||
export default class XcMigrationSourcev2 {
|
||||
@@ -35,6 +36,7 @@ export default class XcMigrationSourcev2 {
|
||||
'nc_022_qr_code_column_type',
|
||||
'nc_023_multiple_source',
|
||||
'nc_024_barcode_column_type',
|
||||
'nc_025_add_row_height',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -72,6 +74,8 @@ export default class XcMigrationSourcev2 {
|
||||
return nc_023_multiple_source;
|
||||
case 'nc_024_barcode_column_type':
|
||||
return nc_024_barcode_column_type;
|
||||
case 'nc_025_add_row_height':
|
||||
return nc_025_add_row_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Knex } from 'knex';
|
||||
import { MetaTable } from '../../utils/globals';
|
||||
|
||||
const up = async (knex: Knex) => {
|
||||
await knex.schema.alterTable(MetaTable.GRID_VIEW, (table) => {
|
||||
table.integer('row_height');
|
||||
});
|
||||
};
|
||||
|
||||
const down = async (knex) => {
|
||||
await knex.schema.alterTable(MetaTable.GRID_VIEW, (table) => {
|
||||
table.dropColumns('row_height');
|
||||
});
|
||||
};
|
||||
|
||||
export { up, down };
|
||||
@@ -5,18 +5,15 @@ import View from './View';
|
||||
import NocoCache from '../cache/NocoCache';
|
||||
|
||||
export default class GridView {
|
||||
title: string;
|
||||
show: boolean;
|
||||
is_default: boolean;
|
||||
order: number;
|
||||
|
||||
fk_view_id: string;
|
||||
|
||||
columns?: GridViewColumn[];
|
||||
|
||||
project_id?: string;
|
||||
base_id?: string;
|
||||
|
||||
meta?: string;
|
||||
row_height?: number;
|
||||
|
||||
columns?: GridViewColumn[];
|
||||
|
||||
constructor(data: GridView) {
|
||||
Object.assign(this, data);
|
||||
}
|
||||
@@ -47,6 +44,7 @@ export default class GridView {
|
||||
fk_view_id: view.fk_view_id,
|
||||
project_id: view.project_id,
|
||||
base_id: view.base_id,
|
||||
row_height: view.row_height,
|
||||
};
|
||||
if (!(view.project_id && view.base_id)) {
|
||||
const viewRef = await View.get(view.fk_view_id, ncMeta);
|
||||
@@ -63,4 +61,31 @@ export default class GridView {
|
||||
const view = await this.get(id, ncMeta);
|
||||
return view;
|
||||
}
|
||||
|
||||
static async update(
|
||||
viewId: string,
|
||||
body: Partial<GridView>,
|
||||
ncMeta = Noco.ncMeta
|
||||
) {
|
||||
// get existing cache
|
||||
const key = `${CacheScope.GRID_VIEW}:${viewId}`;
|
||||
const o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT);
|
||||
if (o) {
|
||||
o.row_height = body.row_height;
|
||||
// set cache
|
||||
await NocoCache.set(key, o);
|
||||
}
|
||||
// update meta
|
||||
return await ncMeta.metaUpdate(
|
||||
null,
|
||||
null,
|
||||
MetaTable.GRID_VIEW,
|
||||
{
|
||||
row_height: body.row_height,
|
||||
},
|
||||
{
|
||||
fk_view_id: viewId,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3024,6 +3024,44 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/db/meta/grids/{viewId}": {
|
||||
"parameters": [
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": "viewId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"patch": {
|
||||
"summary": "",
|
||||
"operationId": "db-view-grid-update",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"DB view"
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Grid"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/db/meta/grids/{gridId}/grid-columns": {
|
||||
"parameters": [
|
||||
{
|
||||
@@ -8508,6 +8546,9 @@
|
||||
"locked",
|
||||
"personal"
|
||||
]
|
||||
},
|
||||
"row_height": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
|
||||
Reference in New Issue
Block a user