Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Modified indicators incorrectly displayed for some UI5 controls in Adaptation Project #2264

Merged
merged 68 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 67 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
0e58c1a
fix: incorrectly placed modified indicators
mmilko01 Aug 21, 2024
21d92fd
refacor: enhance types
mmilko01 Aug 27, 2024
0c74987
fix: type
mmilko01 Aug 27, 2024
3f485ce
refactor: get control instance based on App Component
mmilko01 Aug 28, 2024
8e35073
fix: check if change is available
mmilko01 Aug 28, 2024
5c8efed
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Aug 28, 2024
d67e8eb
refactor: dynamically import ChangeHandlerAPI
mmilko01 Aug 29, 2024
0035131
refactor: get control id via JsControlTreeModifier
mmilko01 Aug 29, 2024
5eefabb
refactor: use different FL API based on UI5 Version
mmilko01 Aug 30, 2024
92f9fb5
test: amend tests
mmilko01 Sep 11, 2024
c4aafd3
chore: merge with main
mmilko01 Sep 11, 2024
e9018da
chore: fix main merge conflicts
mmilko01 Sep 11, 2024
11bd958
chore: create changeset
mmilko01 Sep 11, 2024
2b73513
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Sep 11, 2024
130ba00
chore: fix lint error
mmilko01 Sep 11, 2024
dbc093f
Merge branch 'fix/2263/incorrect-modified-indicators' of https://gith…
mmilko01 Sep 11, 2024
0e6a23a
test: add tests
mmilko01 Sep 12, 2024
55b6b23
fix: sonar issue
mmilko01 Sep 12, 2024
b4f4ee6
test: improve coverage
mmilko01 Sep 12, 2024
4c99027
fix: lint issue
mmilko01 Sep 12, 2024
5dfca73
doc: fix JSDoc
mmilko01 Sep 12, 2024
1931d00
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Sep 13, 2024
9931f05
refactor: do not leak change files to UI
mmilko01 Sep 13, 2024
67f0abf
Merge branch 'fix/2263/incorrect-modified-indicators' of https://gith…
mmilko01 Sep 13, 2024
748bd9d
refactor: change Selector type
mmilko01 Sep 13, 2024
75d7ba3
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Sep 13, 2024
574c393
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Sep 16, 2024
809dc7f
refactor: change changeFiles type
mmilko01 Sep 16, 2024
21ab914
refactor: define changedFiles as object
mmilko01 Sep 16, 2024
64b1527
fix: resolve conflicts
mmilko01 Oct 15, 2024
5a86c0d
fix: correctly display control changes
mmilko01 Oct 17, 2024
729bc12
feat: add control change component
nikmace Oct 17, 2024
fa6bd6e
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Oct 17, 2024
9c4030d
chore: return cap.ts to original state
mmilko01 Oct 17, 2024
65d7d2f
refactor: rename interface
nikmace Oct 18, 2024
ad7ef97
fix: delete icon showing on pending renameLabel change
nikmace Oct 21, 2024
c673d03
fix: initialize pending changes on event
mmilko01 Oct 21, 2024
643100c
refactor: improve change stack render conditions
nikmace Oct 21, 2024
9c15ee1
fix: skip getting control id for unknown changes
mmilko01 Oct 21, 2024
0d505ba
test: enhance tests
mmilko01 Oct 21, 2024
5a2ec88
feat: improve control group and tests
nikmace Oct 22, 2024
caf5fe2
feat: improve control change component
nikmace Oct 22, 2024
e6d9787
refactor: add jsdoc
nikmace Oct 22, 2024
1be38fc
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Oct 22, 2024
3ef81e4
fix: reduce complexity, solve sonar code smells
nikmace Oct 22, 2024
4e1f2d6
Merge branch 'fix/2263/incorrect-modified-indicators' of https://gith…
nikmace Oct 22, 2024
a73f653
Linting auto fix commit
github-actions[bot] Oct 22, 2024
ee385fe
test: enhance tests
mmilko01 Oct 22, 2024
e243d61
test: fix search bar test
mmilko01 Oct 22, 2024
e407a50
refactor: change jsdoc
nikmace Oct 23, 2024
c0d8284
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Oct 23, 2024
a8f6195
test: enhance tests
mmilko01 Oct 23, 2024
7d27b43
Merge branch 'fix/2263/incorrect-modified-indicators' of https://gith…
mmilko01 Oct 23, 2024
4f845bf
fix: handler multiple events in lower UI5 versions
mmilko01 Oct 23, 2024
73e9a3f
fix: sonar issues
mmilko01 Oct 23, 2024
a77c4c9
refactor: fix name spelling
nikmace Oct 23, 2024
f640875
Merge branch 'fix/2263/incorrect-modified-indicators' of https://gith…
nikmace Oct 23, 2024
518ab96
chore: prettier'd file
nikmace Oct 23, 2024
c650c99
refactor: add jsdocs
nikmace Oct 23, 2024
9a4f0f5
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Oct 23, 2024
62033a5
refactor: remove hungarian notations
nikmace Oct 23, 2024
778161b
refactor: remove unused declaration
nikmace Oct 23, 2024
e2c1ff2
Merge branch 'fix/2263/incorrect-modified-indicators' of https://gith…
nikmace Oct 23, 2024
a31cc76
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Oct 24, 2024
85eabaf
chore: delete changeset to refresh
mmilko01 Oct 24, 2024
e555c37
chore: refresh changeset
mmilko01 Oct 24, 2024
f1de383
Merge branch 'main' into fix/2263/incorrect-modified-indicators
mmilko01 Oct 25, 2024
d475015
chore: update changeset
mmilko01 Oct 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/gorgeous-rockets-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@sap-ux-private/control-property-editor-common": patch
"@sap-ux/control-property-editor": patch
"@sap-ux-private/preview-middleware-client": patch
---

Modified indicators incorrectly displayed for some UI5 controls in Adaptation Project
24 changes: 20 additions & 4 deletions packages/control-property-editor-common/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export const PENDING_CHANGE_TYPE = 'pending';
export const SAVED_CHANGE_TYPE = 'saved';
export const PROPERTY_CHANGE_KIND = 'property';
export const UNKNOWN_CHANGE_KIND = 'unknown';
export const CONTROL_CHANGE_KIND = 'control';
export interface PendingPropertyChange<T extends PropertyValue = PropertyValue> extends PropertyChange<T> {
type: typeof PENDING_CHANGE_TYPE;
kind: typeof PROPERTY_CHANGE_KIND;
Expand All @@ -134,13 +135,20 @@ export interface PendingOtherChange {
kind: typeof UNKNOWN_CHANGE_KIND;
isActive: boolean;
changeType: string;
fileName: string;
}

export interface PendingControlChange {
type: typeof PENDING_CHANGE_TYPE;
kind: typeof CONTROL_CHANGE_KIND;
isActive: boolean;
changeType: string;
controlId: string;
controlName: string;
fileName: string;
}

export type PendingChange = PendingPropertyChange | PendingOtherChange;
export type SavedChange = SavedPropertyChange | UnknownSavedChange;
export type PendingChange = PendingPropertyChange | PendingOtherChange | PendingControlChange;
export type SavedChange = SavedPropertyChange | UnknownSavedChange | SavedControlChange;

export interface SavedPropertyChange<T extends PropertyValue = PropertyValue> extends PropertyChange<T> {
type: typeof SAVED_CHANGE_TYPE;
Expand All @@ -154,7 +162,15 @@ export interface UnknownSavedChange {
kind: typeof UNKNOWN_CHANGE_KIND;
fileName: string;
changeType: string;
controlId?: string;
timestamp?: number;
}

export interface SavedControlChange {
type: typeof SAVED_CHANGE_TYPE;
kind: typeof CONTROL_CHANGE_KIND;
controlId: string;
fileName: string;
changeType: string;
timestamp?: number;
}

Expand Down
171 changes: 128 additions & 43 deletions packages/control-property-editor/src/panels/changes/ChangeStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { Stack } from '@fluentui/react';
import type { Change } from '@sap-ux-private/control-property-editor-common';
import {
CONTROL_CHANGE_KIND,
convertCamelCaseToPascalCase,
PENDING_CHANGE_TYPE,
PROPERTY_CHANGE_KIND,
Expand All @@ -22,6 +23,8 @@ import type { FilterOptions } from '../../slice';
import { FilterName } from '../../slice';
import type { RootState } from '../../store';
import { getFormattedDateAndTime } from './utils';
import type { ControlItemProps } from './ControlChange';
import { ControlChange } from './ControlChange';

export interface ChangeStackProps {
changes: Change[];
Expand All @@ -44,31 +47,57 @@ export function ChangeStack(changeStackProps: ChangeStackProps): ReactElement {
const stackName = changes[0].type === PENDING_CHANGE_TYPE ? 'unsaved-changes-stack' : 'saved-changes-stack';
return (
<Stack data-testid={stackName} tokens={{ childrenGap: 5, padding: '5px 0px 5px 0px' }}>
{groups.map((item, i) => [
isControlGroup(item) ? (
<Stack.Item
data-testid={`${stackName}-${item.controlId}-${item.index}`}
key={`${item.controlId}-${item.index}`}>
<ControlGroup {...item} />
</Stack.Item>
) : (
<Stack.Item key={`${item.fileName}`}>
<UnknownChange {...item} />
</Stack.Item>
),

i + 1 < groups.length ? (
<Stack.Item key={getKey(i)}>
<Separator className={styles.item} />
</Stack.Item>
) : (
<></>
)
])}
{groups.map((item, i) => [renderChangeItem(item, stackName), renderSeparator(i, groups)])}
</Stack>
);
}

/**
* Renders the appropriate change item component based on the type of the item.
*
* @param item - The current item from the group to be rendered.
* @param stackName - The name of the stack used for test IDs.
* @returns The rendered change item (`ControlGroup`, `ControlChange`, or `UnknownChange`).
*/
function renderChangeItem(item: Item, stackName: string): ReactElement {
if (isPropertyGroup(item)) {
return (
<Stack.Item
data-testid={`${stackName}-${item.controlId}-${item.index}`}
key={`${item.controlId}-${item.index}`}>
<ControlGroup {...item} />
</Stack.Item>
);
} else if (isControlItem(item)) {
return (
<Stack.Item key={`${item.fileName}`}>
<ControlChange {...item} />
</Stack.Item>
);
} else {
return (
<Stack.Item key={`${item.fileName}`}>
<UnknownChange {...item} />
</Stack.Item>
);
}
}

/**
* Renders a separator between items, except for the last one.
*
* @param i - The index of the current item in the group.
* @param groups - The array of all groups to check if it's the last item.
* @returns {ReactElement | null} The rendered separator or `null` if it's the last item.
*/
function renderSeparator(i: number, groups: Item[]): ReactElement | null {
return i + 1 < groups.length ? (
<Stack.Item key={getKey(i)}>
<Separator className={styles.item} />
</Stack.Item>
) : null;
}

/**
* Generate react attribute key.
*
Expand All @@ -79,42 +108,38 @@ function getKey(i: number): string {
return `${i}-separator`;
}

type Item = ControlGroupProps | UnknownChangeProps;
type Item = ControlGroupProps | UnknownChangeProps | ControlItemProps;

/**
* Method to convert changes to unknown or control group.
* Converts an array of changes into an array of items, grouping changes by controlId and handling different kinds of changes.
*
* @param changes Change[]
* @returns Item[]
* @param {Change[]} changes - An array of changes to be converted.
* @returns {Item[]} An array of items, some of which may be control groups.
*/
function convertChanges(changes: Change[]): Item[] {
const items: Item[] = [];
let i = 0;
while (i < changes.length) {
const change: Change = changes[i];
let group: ControlGroupProps;
if (change.kind === UNKNOWN_CHANGE_KIND && change.type === SAVED_CHANGE_TYPE) {
items.push({
fileName: change.fileName,
timestamp: change.timestamp,
header: true,
controlId: change.controlId ?? ''
});
if (change.kind === UNKNOWN_CHANGE_KIND) {
items.push(handleUnknownChange(change));
i++;
} else if (change.kind === CONTROL_CHANGE_KIND) {
items.push(handleControlChange(change));
i++;
} else {
group = {
controlId: change.controlId,
controlName: change.controlName,
text: convertCamelCaseToPascalCase(change.controlName),
index: i,
changes: [change]
};
group = handleGroupedChange(change, i);
items.push(group);
i++;
while (i < changes.length) {
// We don't need to add header again if the next control is the same
const nextChange = changes[i];
if (nextChange.kind === UNKNOWN_CHANGE_KIND || change.controlId !== nextChange.controlId) {
if (
nextChange.kind === UNKNOWN_CHANGE_KIND ||
nextChange.kind === CONTROL_CHANGE_KIND ||
change.controlId !== nextChange.controlId
) {
break;
}
group.changes.push(nextChange);
Expand All @@ -125,16 +150,76 @@ function convertChanges(changes: Change[]): Item[] {
return items;
}

/**
* Handles changes of kind `unknown` and creates an item with a header.
*
* @param {Change} change - The change object of kind `unknown`.
* @returns {Item} An item object containing the filename and header information.
*/
function handleUnknownChange(change: Change): Item {
return {
fileName: change.fileName,
header: true,
timestamp: change.type === SAVED_CHANGE_TYPE ? change.timestamp : undefined
};
}

/**
* Handles changes of kind `control` and creates an item with controlId and type.
*
* @param {Change} change - The change object of kind `control`.
* @returns {Item} An item object containing the filename, controlId, type, and optional timestamp.
*/
function handleControlChange(change: Change & { controlId: string }): Item {
return {
fileName: change.fileName,
controlId: change.controlId,
timestamp: change.type === SAVED_CHANGE_TYPE ? change.timestamp : undefined,
type: change.type
};
}

/**
* Handles grouped changes by initializing a control group with a list of changes that share the same controlId.
*
* @param {Change} change - The initial change object to start the group.
* @param {number} i - The index of the initial change in the list.
* @returns {ControlGroupProps} A control group object containing grouped changes.
*/
function handleGroupedChange(
change: Change & { controlId: string; controlName: string },
i: number
): ControlGroupProps {
return {
controlId: change.controlId,
controlName: change.controlName,
text: convertCamelCaseToPascalCase(change.controlName),
index: i,
changes: [change],
timestamp: change.type === SAVED_CHANGE_TYPE ? change.timestamp : undefined
};
}

/**
* Checks if item is of type {@link ControlGroupProps}.
*
* @param item ControlGroupProps | UnknownChangeProps
* @param item ControlGroupProps | UnknownChangeProps | ControlItemProps
* @returns boolean
*/
function isControlGroup(item: ControlGroupProps | UnknownChangeProps): item is ControlGroupProps {
function isPropertyGroup(item: ControlGroupProps | UnknownChangeProps | ControlItemProps): item is ControlGroupProps {
return (item as ControlGroupProps).controlName !== undefined;
}

/**
* Checks if item is of type {@link ControlItemProps}.
*
* @param item UnknownChangeProps | ControlItemProps
* @returns boolean
*/
function isControlItem(item: UnknownChangeProps | ControlItemProps): item is ControlItemProps {
return item?.controlId !== undefined;
}

const filterPropertyChanges = (changes: Change[], query: string): Change[] => {
return changes.filter((item): boolean => {
if (item.kind === PROPERTY_CHANGE_KIND) {
Expand Down Expand Up @@ -184,7 +269,7 @@ function filterGroup(model: Item[], query: string): Item[] {
}
for (const item of model) {
let parentMatch = false;
if (!isControlGroup(item)) {
if (!isPropertyGroup(item)) {
if (isQueryMatchesChange(item, query)) {
filteredModel.push({ ...item, changes: [] });
}
Expand Down
Loading
Loading