mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-26 18:06:03 +00:00
MINOR: fix the widget placement when adding new one (#17329)
* fix the widget placement when adding new one * fix the widget not adding in the right side add placeholders * added unit test for the same * fix sonar
This commit is contained in:
parent
a098c20c7c
commit
785e450e28
@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { expect, Page, test as base } from '@playwright/test';
|
||||||
|
import { PersonaClass } from '../../support/persona/PersonaClass';
|
||||||
|
import { UserClass } from '../../support/user/UserClass';
|
||||||
|
import { performAdminLogin } from '../../utils/admin';
|
||||||
|
import { redirectToHomePage, toastNotification } from '../../utils/common';
|
||||||
|
import {
|
||||||
|
checkAllDefaultWidgets,
|
||||||
|
navigateToCustomizeLandingPage,
|
||||||
|
removeAndCheckWidget,
|
||||||
|
setUserDefaultPersona,
|
||||||
|
} from '../../utils/customizeLandingPage';
|
||||||
|
|
||||||
|
const adminUser = new UserClass();
|
||||||
|
const persona = new PersonaClass();
|
||||||
|
const persona2 = new PersonaClass();
|
||||||
|
|
||||||
|
const test = base.extend<{ adminPage: Page; userPage: Page }>({
|
||||||
|
adminPage: async ({ browser }, use) => {
|
||||||
|
const adminPage = await browser.newPage();
|
||||||
|
await adminUser.login(adminPage);
|
||||||
|
await use(adminPage);
|
||||||
|
await adminPage.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
base.beforeAll('Setup pre-requests', async ({ browser }) => {
|
||||||
|
const { afterAction, apiContext } = await performAdminLogin(browser);
|
||||||
|
await adminUser.create(apiContext);
|
||||||
|
await adminUser.setAdminRole(apiContext);
|
||||||
|
await persona.create(apiContext, [adminUser.responseData.id]);
|
||||||
|
await persona2.create(apiContext);
|
||||||
|
await afterAction();
|
||||||
|
});
|
||||||
|
|
||||||
|
base.afterAll('Cleanup', async ({ browser }) => {
|
||||||
|
const { afterAction, apiContext } = await performAdminLogin(browser);
|
||||||
|
await adminUser.delete(apiContext);
|
||||||
|
await persona.delete(apiContext);
|
||||||
|
await persona2.delete(apiContext);
|
||||||
|
await afterAction();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Customize Landing Page Flow', () => {
|
||||||
|
test('Check all default widget present', async ({ adminPage }) => {
|
||||||
|
await redirectToHomePage(adminPage);
|
||||||
|
await adminPage.getByTestId('welcome-screen-close-btn').click();
|
||||||
|
await checkAllDefaultWidgets(adminPage);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Remove and check widget', async ({ adminPage }) => {
|
||||||
|
await redirectToHomePage(adminPage);
|
||||||
|
await setUserDefaultPersona(adminPage, persona.responseData.displayName);
|
||||||
|
await navigateToCustomizeLandingPage(adminPage, {
|
||||||
|
personaName: persona.responseData.name,
|
||||||
|
customPageDataResponse: 404,
|
||||||
|
});
|
||||||
|
|
||||||
|
await removeAndCheckWidget(adminPage, {
|
||||||
|
widgetTestId: 'activity-feed-widget',
|
||||||
|
widgetKey: 'KnowledgePanel.ActivityFeed',
|
||||||
|
});
|
||||||
|
await removeAndCheckWidget(adminPage, {
|
||||||
|
widgetTestId: 'following-widget',
|
||||||
|
widgetKey: 'KnowledgePanel.Following',
|
||||||
|
});
|
||||||
|
await removeAndCheckWidget(adminPage, {
|
||||||
|
widgetTestId: 'kpi-widget',
|
||||||
|
widgetKey: 'KnowledgePanel.KPI',
|
||||||
|
});
|
||||||
|
|
||||||
|
const saveResponse = adminPage.waitForResponse('/api/v1/docStore');
|
||||||
|
await adminPage.click('[data-testid="save-button"]');
|
||||||
|
await saveResponse;
|
||||||
|
|
||||||
|
await toastNotification(adminPage, 'Page layout created successfully.');
|
||||||
|
await redirectToHomePage(adminPage);
|
||||||
|
|
||||||
|
// Check if removed widgets are not present on landing adminPage
|
||||||
|
await expect(
|
||||||
|
adminPage.locator('[data-testid="activity-feed-widget"]')
|
||||||
|
).not.toBeVisible();
|
||||||
|
await expect(
|
||||||
|
adminPage.locator('[data-testid="following-widget"]')
|
||||||
|
).not.toBeVisible();
|
||||||
|
await expect(
|
||||||
|
adminPage.locator('[data-testid="kpi-widget"]')
|
||||||
|
).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Remove and add the widget in the same placeholder', async ({
|
||||||
|
adminPage,
|
||||||
|
}) => {
|
||||||
|
await redirectToHomePage(adminPage);
|
||||||
|
|
||||||
|
const feedResponse = adminPage.waitForResponse(
|
||||||
|
'/api/v1/feed?type=Conversation&*'
|
||||||
|
);
|
||||||
|
await navigateToCustomizeLandingPage(adminPage, {
|
||||||
|
personaName: persona2.responseData.name,
|
||||||
|
customPageDataResponse: 404,
|
||||||
|
});
|
||||||
|
|
||||||
|
await feedResponse;
|
||||||
|
|
||||||
|
await adminPage.waitForSelector('[data-testid="activity-feed-widget"]');
|
||||||
|
|
||||||
|
const followingElementStyle = await adminPage
|
||||||
|
.locator('[id="KnowledgePanel.Following"]')
|
||||||
|
.evaluate((node) => {
|
||||||
|
const computedStyle = window.getComputedStyle(node);
|
||||||
|
|
||||||
|
return {
|
||||||
|
transform: computedStyle.transform,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove and check the placement of Following widget.
|
||||||
|
await adminPage.click(
|
||||||
|
'[data-testid="following-widget"] [data-testid="remove-widget-button"]'
|
||||||
|
);
|
||||||
|
|
||||||
|
await adminPage.waitForSelector('[data-testid="following-widget"]', {
|
||||||
|
state: 'detached',
|
||||||
|
});
|
||||||
|
|
||||||
|
await adminPage.waitForSelector(
|
||||||
|
'[data-testid*="KnowledgePanel.Following"][data-testid$="EmptyWidgetPlaceholder"]'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add KPI widget in the same placeholder
|
||||||
|
const getWidgetList = adminPage.waitForResponse(
|
||||||
|
'api/v1/docStore?fqnPrefix=KnowledgePanel&*'
|
||||||
|
);
|
||||||
|
await adminPage.click(
|
||||||
|
'[data-testid="KnowledgePanel.Following.EmptyWidgetPlaceholder"] [data-testid="add-widget-button"]'
|
||||||
|
);
|
||||||
|
|
||||||
|
await getWidgetList;
|
||||||
|
|
||||||
|
await adminPage.waitForSelector('[role="dialog"].ant-modal');
|
||||||
|
|
||||||
|
expect(adminPage.locator('[role="dialog"].ant-modal')).toBeVisible();
|
||||||
|
|
||||||
|
await adminPage.click('[data-testid="KPI-widget-tab-label"]');
|
||||||
|
|
||||||
|
await adminPage
|
||||||
|
.locator('.ant-tabs-tabpane-active [data-testid="add-widget-button"]')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
await adminPage.waitForSelector('[role="dialog"].ant-modal', {
|
||||||
|
state: 'detached',
|
||||||
|
});
|
||||||
|
|
||||||
|
const kpiElement = adminPage.locator('[id^="KnowledgePanel.KPI-"]');
|
||||||
|
const kpiElementStyle = await kpiElement.evaluate((node) => {
|
||||||
|
const computedStyle = window.getComputedStyle(node);
|
||||||
|
|
||||||
|
return {
|
||||||
|
transform: computedStyle.transform,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if the KPI widget is added in the same placeholder,by their transform property or placement.
|
||||||
|
expect(kpiElementStyle.transform).toEqual(followingElementStyle.transform);
|
||||||
|
|
||||||
|
const saveResponse = adminPage.waitForResponse('/api/v1/docStore');
|
||||||
|
await adminPage.click('[data-testid="save-button"]');
|
||||||
|
await saveResponse;
|
||||||
|
|
||||||
|
await toastNotification(adminPage, 'Page layout created successfully.');
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { APIRequestContext } from '@playwright/test';
|
||||||
|
import { uuid } from '../../utils/common';
|
||||||
|
|
||||||
|
type ResponseDataType = {
|
||||||
|
name: string;
|
||||||
|
displayName: string;
|
||||||
|
description: string;
|
||||||
|
id?: string;
|
||||||
|
fullyQualifiedName?: string;
|
||||||
|
users?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export class PersonaClass {
|
||||||
|
id = uuid();
|
||||||
|
data: ResponseDataType;
|
||||||
|
responseData: ResponseDataType;
|
||||||
|
|
||||||
|
constructor(data?: ResponseDataType) {
|
||||||
|
this.data = data ?? {
|
||||||
|
name: `PW%Persona-${this.id}`,
|
||||||
|
displayName: `PW Persona ${this.id}`,
|
||||||
|
description: 'playwright for persona description',
|
||||||
|
users: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get() {
|
||||||
|
return this.responseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(apiContext: APIRequestContext, users?: string[]) {
|
||||||
|
const response = await apiContext.post('/api/v1/personas', {
|
||||||
|
data: { ...this.data, users },
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
this.responseData = data;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(apiContext: APIRequestContext) {
|
||||||
|
const response = await apiContext.delete(
|
||||||
|
`/api/v1/personas/${this.responseData.id}?hardDelete=true&recursive=false`
|
||||||
|
);
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async patch(apiContext: APIRequestContext, data: Record<string, unknown>[]) {
|
||||||
|
const response = await apiContext.patch(
|
||||||
|
`/api/v1/personas/${this.responseData.id}`,
|
||||||
|
{
|
||||||
|
data,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json-patch+json',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.responseData = await response.json();
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
}
|
||||||
|
}
|
@ -61,6 +61,19 @@ export class UserClass {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setAdminRole(apiContext: APIRequestContext) {
|
||||||
|
return this.patch({
|
||||||
|
apiContext,
|
||||||
|
patchData: [
|
||||||
|
{
|
||||||
|
op: 'replace',
|
||||||
|
path: '/isAdmin',
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async delete(apiContext: APIRequestContext) {
|
async delete(apiContext: APIRequestContext) {
|
||||||
const response = await apiContext.delete(
|
const response = await apiContext.delete(
|
||||||
`/api/v1/users/${this.responseData.id}?recursive=false&hardDelete=true`
|
`/api/v1/users/${this.responseData.id}?recursive=false&hardDelete=true`
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { expect, Page } from '@playwright/test';
|
||||||
|
import { GlobalSettingOptions } from '../constant/settings';
|
||||||
|
import { visitUserProfilePage } from './common';
|
||||||
|
import { settingClick } from './sidebar';
|
||||||
|
|
||||||
|
export const navigateToCustomizeLandingPage = async (
|
||||||
|
page: Page,
|
||||||
|
{ personaName, customPageDataResponse }
|
||||||
|
) => {
|
||||||
|
const getPersonas = page.waitForResponse('/api/v1/personas*');
|
||||||
|
|
||||||
|
await settingClick(page, GlobalSettingOptions.CUSTOMIZE_LANDING_PAGE);
|
||||||
|
|
||||||
|
await getPersonas;
|
||||||
|
|
||||||
|
// Navigate to the customize landing page
|
||||||
|
await page.click(
|
||||||
|
`[data-testid="persona-details-card-${personaName}"] [data-testid="customize-page-button"]`
|
||||||
|
);
|
||||||
|
|
||||||
|
const getCustomPageDataResponse = await page.waitForResponse(
|
||||||
|
`/api/v1/docStore/name/persona.${encodeURIComponent(
|
||||||
|
personaName
|
||||||
|
)}.Page.LandingPage`
|
||||||
|
);
|
||||||
|
|
||||||
|
// await getCustomPageDataResponse;
|
||||||
|
expect(getCustomPageDataResponse.status()).toBe(customPageDataResponse);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeAndCheckWidget = async (
|
||||||
|
page: Page,
|
||||||
|
{ widgetTestId, widgetKey }
|
||||||
|
) => {
|
||||||
|
// Click on remove widget button
|
||||||
|
await page.click(
|
||||||
|
`[data-testid="${widgetTestId}"] [data-testid="remove-widget-button"]`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if widget does not exist
|
||||||
|
await page.waitForSelector(`[data-testid="${widgetTestId}"]`, {
|
||||||
|
state: 'detached',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if empty widget placeholder is displayed in place of removed widget
|
||||||
|
await page.waitForSelector(
|
||||||
|
`[data-testid*="${widgetKey}"][data-testid$="EmptyWidgetPlaceholder"]`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove empty widget placeholder
|
||||||
|
await page.click(
|
||||||
|
`[data-testid*="${widgetKey}"][data-testid$="EmptyWidgetPlaceholder"] [data-testid="remove-widget-button"]`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if empty widget placeholder does not exist
|
||||||
|
await page.waitForSelector(
|
||||||
|
`[data-testid*="${widgetKey}"][data-testid$="EmptyWidgetPlaceholder"]`,
|
||||||
|
{ state: 'detached' }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const checkAllDefaultWidgets = async (
|
||||||
|
page: Page,
|
||||||
|
checkEmptyWidgetPlaceholder = false
|
||||||
|
) => {
|
||||||
|
await expect(page.getByTestId('activity-feed-widget')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('following-widget')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('recently-viewed-widget')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('data-assets-widget')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('my-data-widget')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('kpi-widget')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('total-assets-widget')).toBeVisible();
|
||||||
|
|
||||||
|
if (checkEmptyWidgetPlaceholder) {
|
||||||
|
await expect(
|
||||||
|
page.getByTestId('ExtraWidget.EmptyWidgetPlaceholder')
|
||||||
|
).toBeVisible();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setUserDefaultPersona = async (
|
||||||
|
page: Page,
|
||||||
|
personaName: string
|
||||||
|
) => {
|
||||||
|
await visitUserProfilePage(page);
|
||||||
|
|
||||||
|
await page
|
||||||
|
.locator(
|
||||||
|
'[data-testid="user-profile-details"] [data-testid="edit-persona"]'
|
||||||
|
)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
await page.waitForSelector(
|
||||||
|
'[role="tooltip"] [data-testid="selectable-list"]'
|
||||||
|
);
|
||||||
|
|
||||||
|
const setDefaultPersona = page.waitForResponse('/api/v1/users/*');
|
||||||
|
|
||||||
|
await page.getByTitle(personaName).click();
|
||||||
|
|
||||||
|
await setDefaultPersona;
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
page.locator('[data-testid="user-profile-details"]')
|
||||||
|
).toContainText(personaName);
|
||||||
|
};
|
@ -90,7 +90,6 @@ function AddWidgetTabContent({
|
|||||||
placement="bottom"
|
placement="bottom"
|
||||||
title={widgetAddable ? '' : t('message.can-not-add-widget')}>
|
title={widgetAddable ? '' : t('message.can-not-add-widget')}>
|
||||||
<Button
|
<Button
|
||||||
ghost
|
|
||||||
className="p-x-lg m-t-md"
|
className="p-x-lg m-t-md"
|
||||||
data-testid="add-widget-button"
|
data-testid="add-widget-button"
|
||||||
disabled={!widgetAddable}
|
disabled={!widgetAddable}
|
||||||
|
@ -208,5 +208,42 @@ export const mockAddWidgetReturnValues = [
|
|||||||
x: 0,
|
x: 0,
|
||||||
y: 100,
|
y: 100,
|
||||||
},
|
},
|
||||||
{ h: 3, i: 'KnowledgePanel.Following-1', static: false, w: 1, x: 0, y: 6 },
|
{ h: 3, i: 'KnowledgePanel.Following-1', static: false, w: 1, x: 0, y: 4 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const mockAddWidgetReturnValues2 = [
|
||||||
|
{
|
||||||
|
h: 6,
|
||||||
|
i: 'KnowledgePanel.ActivityFeed',
|
||||||
|
static: false,
|
||||||
|
w: 3,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
h: 3,
|
||||||
|
i: 'KnowledgePanel.RecentlyViewed',
|
||||||
|
static: false,
|
||||||
|
w: 1,
|
||||||
|
x: 3,
|
||||||
|
y: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
h: 2,
|
||||||
|
i: 'ExtraWidget.EmptyWidgetPlaceholder',
|
||||||
|
isDraggable: false,
|
||||||
|
static: false,
|
||||||
|
w: 4,
|
||||||
|
x: 0,
|
||||||
|
y: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
h: 3,
|
||||||
|
i: 'KnowledgePanel.dataAsset',
|
||||||
|
w: 1,
|
||||||
|
x: 2,
|
||||||
|
y: 4,
|
||||||
|
static: false,
|
||||||
|
},
|
||||||
|
{ h: 3, i: 'KnowledgePanel.Following-2', static: false, w: 1, x: 3, y: 4 },
|
||||||
];
|
];
|
||||||
|
@ -13,19 +13,41 @@
|
|||||||
import { mockWidget } from '../mocks/AddWidgetTabContent.mock';
|
import { mockWidget } from '../mocks/AddWidgetTabContent.mock';
|
||||||
import {
|
import {
|
||||||
mockAddWidgetReturnValues,
|
mockAddWidgetReturnValues,
|
||||||
|
mockAddWidgetReturnValues2,
|
||||||
mockCurrentAddWidget,
|
mockCurrentAddWidget,
|
||||||
} from '../mocks/CustomizablePage.mock';
|
} from '../mocks/CustomizablePage.mock';
|
||||||
import { getAddWidgetHandler } from './CustomizableLandingPageUtils';
|
import { getAddWidgetHandler } from './CustomizableLandingPageUtils';
|
||||||
|
|
||||||
describe('getAddWidgetHandler function', () => {
|
describe('getAddWidgetHandler function', () => {
|
||||||
it('should add new widget at EmptyWidgetPlaceholder place to be in the bottom', () => {
|
it('should add new widget at the bottom if not fit in the grid row', () => {
|
||||||
const result = getAddWidgetHandler(
|
const result = getAddWidgetHandler(
|
||||||
mockWidget,
|
mockWidget,
|
||||||
'ExtraWidget.EmptyWidgetPlaceholder',
|
'ExtraWidget.EmptyWidgetPlaceholder',
|
||||||
1,
|
1,
|
||||||
3
|
4
|
||||||
)(mockCurrentAddWidget);
|
)(mockCurrentAddWidget);
|
||||||
|
|
||||||
expect(result).toEqual(mockAddWidgetReturnValues);
|
expect(result).toEqual(mockAddWidgetReturnValues);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should add new widget at the same line if new widget can fit', () => {
|
||||||
|
const result = getAddWidgetHandler(
|
||||||
|
mockWidget,
|
||||||
|
'ExtraWidget.EmptyWidgetPlaceholder',
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
)([
|
||||||
|
...mockCurrentAddWidget,
|
||||||
|
{
|
||||||
|
h: 3,
|
||||||
|
i: 'KnowledgePanel.dataAsset',
|
||||||
|
w: 1,
|
||||||
|
x: 2,
|
||||||
|
y: 4,
|
||||||
|
static: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockAddWidgetReturnValues2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,47 @@ import { EntityReference } from '../generated/entity/type';
|
|||||||
import { WidgetConfig } from '../pages/CustomizablePage/CustomizablePage.interface';
|
import { WidgetConfig } from '../pages/CustomizablePage/CustomizablePage.interface';
|
||||||
import customizePageClassBase from './CustomizePageClassBase';
|
import customizePageClassBase from './CustomizePageClassBase';
|
||||||
|
|
||||||
|
const getNewWidgetPlacement = (
|
||||||
|
currentLayout: WidgetConfig[],
|
||||||
|
widgetWidth: number
|
||||||
|
) => {
|
||||||
|
const lowestWidgetLayout = currentLayout.reduce(
|
||||||
|
(acc, widget) => {
|
||||||
|
if (
|
||||||
|
widget.y >= acc.y &&
|
||||||
|
widget.i !== LandingPageWidgetKeys.EMPTY_WIDGET_PLACEHOLDER
|
||||||
|
) {
|
||||||
|
if (widget.y === acc.y && widget.x < acc.x) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ y: 0, x: 0, w: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if there's enough space to place the new widget on the same row
|
||||||
|
if (
|
||||||
|
customizePageClassBase.landingPageMaxGridSize -
|
||||||
|
(lowestWidgetLayout.x + lowestWidgetLayout.w) >=
|
||||||
|
widgetWidth
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
x: lowestWidgetLayout.x + lowestWidgetLayout.w,
|
||||||
|
y: lowestWidgetLayout.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, move to the next row
|
||||||
|
return {
|
||||||
|
x: 0,
|
||||||
|
y: lowestWidgetLayout.y + 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const getAddWidgetHandler =
|
export const getAddWidgetHandler =
|
||||||
(
|
(
|
||||||
newWidgetData: Document,
|
newWidgetData: Document,
|
||||||
@ -55,19 +96,14 @@ export const getAddWidgetHandler =
|
|||||||
if (
|
if (
|
||||||
placeholderWidgetKey === LandingPageWidgetKeys.EMPTY_WIDGET_PLACEHOLDER
|
placeholderWidgetKey === LandingPageWidgetKeys.EMPTY_WIDGET_PLACEHOLDER
|
||||||
) {
|
) {
|
||||||
const emptyWidgetPlaceholder = currentLayout.find(
|
|
||||||
(item) => item.i === LandingPageWidgetKeys.EMPTY_WIDGET_PLACEHOLDER
|
|
||||||
) ?? { x: 0, y: 99 };
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...moveEmptyWidgetToTheEnd(currentLayout),
|
...moveEmptyWidgetToTheEnd(currentLayout),
|
||||||
{
|
{
|
||||||
w: widgetWidth,
|
w: widgetWidth,
|
||||||
h: widgetHeight,
|
h: widgetHeight,
|
||||||
x: emptyWidgetPlaceholder.x,
|
|
||||||
y: emptyWidgetPlaceholder.y,
|
|
||||||
i: widgetFQN,
|
i: widgetFQN,
|
||||||
static: false,
|
static: false,
|
||||||
|
...getNewWidgetPlacement(currentLayout, widgetWidth),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,7 +47,7 @@ class CustomizePageClassBase {
|
|||||||
defaultWidgetHeight = 3;
|
defaultWidgetHeight = 3;
|
||||||
landingPageWidgetMargin = 16;
|
landingPageWidgetMargin = 16;
|
||||||
landingPageRowHeight = 100;
|
landingPageRowHeight = 100;
|
||||||
landingPageMaxGridSize = 3;
|
landingPageMaxGridSize = 4;
|
||||||
|
|
||||||
landingPageWidgetDefaultHeights: Record<string, number> = {
|
landingPageWidgetDefaultHeights: Record<string, number> = {
|
||||||
activityFeed: 6,
|
activityFeed: 6,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user