From f312f07ef3fd6c3563e3bc6a3137d752b1c8fb4c Mon Sep 17 00:00:00 2001 From: Omar Sadat Date: Mon, 10 May 2021 14:39:51 -0400 Subject: [PATCH] tree: use dot decoration on folders The following commit updates the rendering of tail decorations for composite tree nodes (nodes that contain children nodes like folders). The following updates the rendering of tail decorations for composite tree nodes (nodes that contain children nodes like folders). The updates include : - rendering a generic icon decoration (dot) for composite nodes with children with decoration data. - updates to the rendering logic to only render the decoration data with the highest priority so no duplicate generic icons are present. --- .../core/src/browser/tree/tree-widget.tsx | 95 ++++++++++++------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/packages/core/src/browser/tree/tree-widget.tsx b/packages/core/src/browser/tree/tree-widget.tsx index 085f2a9f6df73..d4c55bd0979eb 100644 --- a/packages/core/src/browser/tree/tree-widget.tsx +++ b/packages/core/src/browser/tree/tree-widget.tsx @@ -729,54 +729,81 @@ export class TreeWidget extends ReactWidget implements StatefulWidget { * @param node the tree node. * @param icon the icon. */ - protected decorateIcon(node: TreeNode, icon: React.ReactNode | null): React.ReactNode { - // eslint-disable-next-line no-null/no-null - if (icon === null) { - // eslint-disable-next-line no-null/no-null - return null; + protected decorateIcon(node: TreeNode, icon: React.ReactNode): React.ReactNode { + // icon can be null or undefined + if (!icon) { + return; } - const overlayIcons: React.ReactNode[] = []; - new Map(this.getDecorationData(node, 'iconOverlay').reverse().filter(notEmpty) - .map(overlay => [overlay.position, overlay] as [TreeDecoration.IconOverlayPosition, TreeDecoration.IconOverlay | TreeDecoration.IconClassOverlay])) - .forEach((overlay, position) => { - const iconClasses = [TreeDecoration.Styles.DECORATOR_SIZE_CLASS, TreeDecoration.IconOverlayPosition.getStyle(position)]; - const style = (color?: string) => color === undefined ? {} : { color }; - if (overlay.background) { - overlayIcons.push( - ); - } - const overlayIcon = (overlay as TreeDecoration.IconOverlay).icon || (overlay as TreeDecoration.IconClassOverlay).iconClass; - overlayIcons.push(); - }); - + // if multiple overlays have the same overlay.position attribute, we'll de-duplicate those and only process the first one from the decoration array + const positionToOverlay = new Map( + this.getDecorationData(node, 'iconOverlay').reverse().filter(notEmpty).map(overlay => [/* key */ overlay.position, /* value */ overlay]) + ); + for (const overlay of positionToOverlay.values()) { + const iconClasses = [TreeDecoration.Styles.DECORATOR_SIZE_CLASS, TreeDecoration.IconOverlayPosition.getStyle(overlay.position)]; + const style = (color?: string) => color === undefined ? {} : { color }; + if (overlay.background) { + overlayIcons.push(); + } + const overlayIcon = (overlay as TreeDecoration.IconOverlay).icon || (overlay as TreeDecoration.IconClassOverlay).iconClass; + overlayIcons.push(); + } if (overlayIcons.length > 0) { return
{icon}{overlayIcons}
; } - return icon; } + /** + * Get the generic icon decoration. + * @returns the class icon used for generic decorations. + */ + protected getGenericClassIconDecoration(): string[] { + return ['fa', 'fa-circle']; + } + /** * Render the tree node tail decorations. * @param node the tree node. * @param props the node properties. */ protected renderTailDecorations(node: TreeNode, props: NodeProps): React.ReactNode { - return - {this.getDecorationData(node, 'tailDecorations').filter(notEmpty).reduce((acc, current) => acc.concat(current), []).map((decoration, index) => { - const { tooltip } = decoration; - const { data, fontData } = decoration as TreeDecoration.TailDecoration; - const color = (decoration as TreeDecoration.TailDecorationIcon).color; - const icon = (decoration as TreeDecoration.TailDecorationIcon).icon || (decoration as TreeDecoration.TailDecorationIconClass).iconClass; - const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS].join(' '); - const style = fontData ? this.applyFontStyles({}, fontData) : color ? { color } : undefined; - const content = data ? data : icon ? : ''; - return
- {content} -
; - })} -
; + const decorationData = this.getDecorationData(node, 'tailDecorations').filter(notEmpty).reduce((acc, current) => acc.concat(current), []); + + if (decorationData.length === 0) { + return; + } + + if (CompositeTreeNode.is(node)) { + // If the node is a composite, we just want to use the decorationData with the highest priority (last element). + const decoration = decorationData.pop()!; + const { tooltip } = decoration as TreeDecoration.TailDecoration; + const { fontData } = decoration as TreeDecoration.TailDecoration; + const color = (decoration as TreeDecoration.TailDecorationIcon).color; + const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS].join(' '); + const style = fontData ? this.applyFontStyles({}, fontData) : color ? { color } : undefined; + const icon = this.getGenericClassIconDecoration(); + const content = ; + return
+ {content} +
; + } else { + return + {decorationData.map((decoration, index) => { + // If the node is not a composite, we apply the map method on the array of DecorationData. + const { tooltip } = decoration; + const { data, fontData } = decoration as TreeDecoration.TailDecoration; + const color = (decoration as TreeDecoration.TailDecorationIcon).color; + const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS].join(' '); + const style = fontData ? this.applyFontStyles({}, fontData) : color ? { color } : undefined; + const icon = (decoration as TreeDecoration.TailDecorationIcon).icon || (decoration as TreeDecoration.TailDecorationIconClass).iconClass; + const content = data ? data : icon ? : ''; + return
+ {content} +
; + })} +
; + } } /**