mirror of
https://github.com/nocodb/nocodb.git
synced 2026-04-25 03:35:37 +00:00
Nc fix/rich perf (#10528)
* fix: rich text performance issue * fix: rich text limit number of chars for canvas * fix: flaky barcode tests * fix: avoid duplicate trigger * test: flaky kanban * test: flaky meta sync * test: flaky grid * test: add flag to kanban calls Signed-off-by: mertmit <mertmit99@gmail.com> --------- Signed-off-by: mertmit <mertmit99@gmail.com> Co-authored-by: mertmit <mertmit99@gmail.com>
This commit is contained in:
@@ -51,7 +51,7 @@ const onChange = (e: boolean, updateValue = false) => {
|
||||
<slot />
|
||||
</span>
|
||||
<a-switch
|
||||
v-model:checked="checked"
|
||||
:checked="checked"
|
||||
:disabled="disabled"
|
||||
class="nc-switch"
|
||||
:class="{
|
||||
|
||||
@@ -1426,6 +1426,7 @@ const colSlice = ref({
|
||||
const lastScrollTop = ref()
|
||||
const lastScrollLeft = ref()
|
||||
const lastTotalRows = ref()
|
||||
const lastTotalFields = ref()
|
||||
|
||||
// Store the previous results for binary search to avoid redundant calculations
|
||||
let prevScrollLeft = -1
|
||||
@@ -1503,7 +1504,8 @@ const calculateSlices = () => {
|
||||
lastScrollLeft.value &&
|
||||
lastScrollLeft.value === scrollLeft.value &&
|
||||
Math.abs(lastScrollTop.value - scrollTop.value) < 32 * (ROW_VIRTUAL_MARGIN - 2) &&
|
||||
lastTotalRows.value === totalRows.value
|
||||
lastTotalRows.value === totalRows.value &&
|
||||
lastTotalFields.value === fields.value.length
|
||||
) {
|
||||
return
|
||||
}
|
||||
@@ -1511,6 +1513,7 @@ const calculateSlices = () => {
|
||||
// Cache the current scroll positions
|
||||
lastScrollLeft.value = scrollLeft.value
|
||||
lastScrollTop.value = scrollTop.value
|
||||
lastTotalFields.value = fields.value.length
|
||||
|
||||
// Determine visible column range using binary search
|
||||
const { renderStart, renderEnd } = binarySearchForStart(scrollLeft.value, gridWrapper.value.clientWidth)
|
||||
|
||||
@@ -394,8 +394,8 @@ export const wrapTextToLines = (
|
||||
const ellipsis = '...'
|
||||
const ellipsisWidth = ctx.measureText(ellipsis).width
|
||||
|
||||
while (width + ellipsisWidth > maxWidth && line.length > 0) {
|
||||
line = line.slice(0, -1) // Remove one character at a time
|
||||
if (width + ellipsisWidth > maxWidth && line.length > 0) {
|
||||
line = truncateText(ctx, line, maxWidth - ellipsisWidth, false, false) // Truncate the line to fit within maxWidth
|
||||
width = ctx.measureText(line).width
|
||||
}
|
||||
|
||||
@@ -466,7 +466,7 @@ export const renderMarkdownBlocks = (
|
||||
maxLines?: number
|
||||
maxWidth: number
|
||||
lineHeight: number
|
||||
cellRenderStore: CellRenderStore
|
||||
cellRenderStore?: CellRenderStore
|
||||
fillStyle?: string
|
||||
mousePosition?: { x: number; y: number }
|
||||
},
|
||||
@@ -519,8 +519,9 @@ export const renderMarkdownBlocks = (
|
||||
let tokenWidth = ctx.measureText(tokenText).width
|
||||
|
||||
// Truncate the token if it exceeds the max width of the line
|
||||
while (cursorX + tokenWidth > x + maxWidth && tokenText.length > 0) {
|
||||
tokenText = tokenText.slice(0, -1)
|
||||
if (cursorX + tokenWidth > x + maxWidth && tokenText.length > 0) {
|
||||
// cursorX starts at x, so we need to subtract x to get used space
|
||||
tokenText = truncateText(ctx, tokenText, maxWidth - (cursorX - x), false, false)
|
||||
tokenWidth = ctx.measureText(tokenText).width
|
||||
}
|
||||
|
||||
@@ -556,8 +557,9 @@ export const renderMarkdownBlocks = (
|
||||
const ellipsisWidth = ctx.measureText(ellipsis).width
|
||||
|
||||
if (cursorX + tokenWidth + ellipsisWidth > x + maxWidth || tokenIndex === tokens.length - 1) {
|
||||
while (cursorX + tokenWidth + ellipsisWidth > x + maxWidth && tokenText.length > 0) {
|
||||
tokenText = tokenText.slice(0, -1)
|
||||
if (cursorX + tokenWidth + ellipsisWidth > x + maxWidth && tokenText.length > 0) {
|
||||
// cursorX starts at x, so we need to subtract x to get used space
|
||||
tokenText = truncateText(ctx, tokenText, maxWidth - (cursorX - x) - ellipsisWidth, false, false)
|
||||
tokenWidth = ctx.measureText(tokenText).width
|
||||
}
|
||||
|
||||
@@ -586,7 +588,7 @@ export const renderMarkdownBlocks = (
|
||||
renderedLineCount++
|
||||
}
|
||||
|
||||
cellRenderStore.links = links
|
||||
if (cellRenderStore) cellRenderStore.links = links
|
||||
|
||||
// Restore the original font
|
||||
ctx.font = defaultFont
|
||||
@@ -823,10 +825,8 @@ export const renderMarkdown = (
|
||||
textAlign = 'left',
|
||||
verticalAlign = 'middle',
|
||||
render = true,
|
||||
underline,
|
||||
py = 10,
|
||||
mousePosition = { x: 0, y: 0 },
|
||||
spriteLoader,
|
||||
cellRenderStore,
|
||||
isTagLabel = false,
|
||||
} = params
|
||||
@@ -861,7 +861,10 @@ export const renderMarkdown = (
|
||||
width = cachedText.width
|
||||
blocks = cachedText.blocks
|
||||
} else {
|
||||
const renderText = NcMarkdownParser.preprocessMarkdown(text, true)
|
||||
// Render 2000 characters of the text in the canvas
|
||||
const processText = text.length > 2000 ? text.slice(0, 2000) : text
|
||||
|
||||
const renderText = NcMarkdownParser.preprocessMarkdown(processText, true)
|
||||
|
||||
width = maxWidth
|
||||
blocks = parseMarkdown(renderText)
|
||||
@@ -893,12 +896,9 @@ export const renderMarkdown = (
|
||||
verticalAlign,
|
||||
lineHeight,
|
||||
maxLines,
|
||||
fontSize,
|
||||
fillStyle,
|
||||
underline,
|
||||
maxWidth,
|
||||
mousePosition,
|
||||
spriteLoader,
|
||||
cellRenderStore,
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -101,6 +101,7 @@ export class ColumnPageObject extends BasePage {
|
||||
webhookIndex?: number;
|
||||
}) {
|
||||
if (insertBeforeColumnTitle) {
|
||||
await this.grid.renderColumn(insertBeforeColumnTitle);
|
||||
await this.grid.get().locator(`th[data-title="${insertBeforeColumnTitle}"]`).scrollIntoViewIfNeeded();
|
||||
await this.grid.get().locator(`th[data-title="${insertBeforeColumnTitle}"] .nc-ui-dt-dropdown`).click();
|
||||
if (isDisplayValue) {
|
||||
@@ -109,6 +110,7 @@ export class ColumnPageObject extends BasePage {
|
||||
}
|
||||
await this.rootPage.locator('li[role="menuitem"]:has-text("Insert left"):visible').click();
|
||||
} else if (insertAfterColumnTitle) {
|
||||
await this.grid.renderColumn(insertAfterColumnTitle);
|
||||
await this.grid.get().locator(`th[data-title="${insertAfterColumnTitle}"]`).scrollIntoViewIfNeeded();
|
||||
await this.grid.get().locator(`th[data-title="${insertAfterColumnTitle}"] .nc-ui-dt-dropdown`).click();
|
||||
await this.rootPage.locator('li[role="menuitem"]:has-text("Insert right"):visible').click();
|
||||
@@ -386,6 +388,7 @@ export class ColumnPageObject extends BasePage {
|
||||
timeFormat?: string;
|
||||
selectType?: boolean;
|
||||
}) {
|
||||
await this.grid.renderColumn(title);
|
||||
// when clicked on the dropdown cell header
|
||||
await this.getColumnHeader(title).locator('.nc-ui-dt-dropdown').scrollIntoViewIfNeeded();
|
||||
await this.getColumnHeader(title).locator('.nc-ui-dt-dropdown').click();
|
||||
@@ -525,6 +528,7 @@ export class ColumnPageObject extends BasePage {
|
||||
return await expect(this.getColumnHeader(title)).not.toBeVisible();
|
||||
}
|
||||
if (scroll) {
|
||||
await this.grid.renderColumn(title);
|
||||
await this.getColumnHeader(title).scrollIntoViewIfNeeded();
|
||||
}
|
||||
await expect(this.getColumnHeader(title)).toContainText(title);
|
||||
|
||||
@@ -34,7 +34,7 @@ export class MetaDataPage extends BasePage {
|
||||
await this.get().locator(`button:has-text("Sync Now")`).click();
|
||||
await this.verifyToast({ message: 'Table metadata recreated successfully' });
|
||||
// wait for clickability of the sync button
|
||||
await this.get().locator(`.sync-completed`).waitFor({ state: 'visible' });
|
||||
await this.get().locator(`.sync-completed`).waitFor({ state: 'visible', timeout: 10000 });
|
||||
await this.get().locator(`.sync-completed`).click();
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ export class ToolbarFieldsPage extends BasePage {
|
||||
await this.toolbar.parent.waitLoading();
|
||||
}
|
||||
|
||||
async toggleShowAllFields({ isLocallySaved }: { isLocallySaved?: boolean } = {}) {
|
||||
async toggleShowAllFields({ isLocallySaved, isKanban }: { isLocallySaved?: boolean, isKanban?: boolean } = {}) {
|
||||
await this.toolbar.clickFields();
|
||||
await this.waitForResponse({
|
||||
uiAction: () => this.get().locator(`.nc-fields-toggle-show-all-fields`).click(),
|
||||
@@ -95,6 +95,10 @@ export class ToolbarFieldsPage extends BasePage {
|
||||
httpMethodsToMatch: ['GET'],
|
||||
timeout: 30000, // for Kanban, show all fields can take a long time
|
||||
});
|
||||
|
||||
// TODO: fix this (Show all for kanban takes time to load)
|
||||
if (isKanban) await new Promise((r) => setTimeout(r, 2000));
|
||||
|
||||
await this.toolbar.clickFields();
|
||||
}
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ test.describe('View', () => {
|
||||
});
|
||||
|
||||
// hide fields
|
||||
await toolbar.fields.toggleShowAllFields({ isLocallySaved: false });
|
||||
await toolbar.fields.toggleShowAllFields({ isLocallySaved: false });
|
||||
await toolbar.fields.toggleShowAllFields({ isLocallySaved: false, isKanban: true });
|
||||
await toolbar.fields.toggleShowAllFields({ isLocallySaved: false, isKanban: true });
|
||||
await toolbar.fields.toggle({ title: 'Title' });
|
||||
await kanban.verifyCardCount({
|
||||
count: [0, 25, 25, 25, 25, 25],
|
||||
@@ -221,8 +221,8 @@ test.describe('View', () => {
|
||||
});
|
||||
await toolbar.clickFilter();
|
||||
|
||||
await toolbar.fields.toggleShowAllFields();
|
||||
await toolbar.fields.toggleShowAllFields();
|
||||
await toolbar.fields.toggleShowAllFields({ isKanban: true });
|
||||
await toolbar.fields.toggleShowAllFields({ isKanban: true });
|
||||
await toolbar.fields.toggle({ title: 'Title' });
|
||||
|
||||
await dashboard.viewSidebar.copyView({ title: 'Film Kanban' });
|
||||
@@ -279,8 +279,8 @@ test.describe('View', () => {
|
||||
await kanban.verifyCollapseStackCount({ count: 0 });
|
||||
|
||||
// add record to stack & verify
|
||||
await toolbar.fields.toggleShowAllFields();
|
||||
await toolbar.fields.toggleShowAllFields();
|
||||
await toolbar.fields.toggleShowAllFields({ isKanban: true });
|
||||
await toolbar.fields.toggleShowAllFields({ isKanban: true });
|
||||
await toolbar.fields.toggleShowSystemFields();
|
||||
await toolbar.fields.toggle({ title: 'LanguageId' });
|
||||
await toolbar.fields.toggle({ title: 'Title' });
|
||||
|
||||
Reference in New Issue
Block a user