Skip to content

Commit

Permalink
Merge pull request #19 from brasov2de/feature/datatypes
Browse files Browse the repository at this point in the history
Feature/datatypes
  • Loading branch information
brasov2de authored Dec 2, 2021
2 parents 09ae8a8 + 212dd8c commit 0eead5b
Show file tree
Hide file tree
Showing 20 changed files with 3,559 additions and 1,348 deletions.
22 changes: 22 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#ab307e",
"activityBar.activeBorder": "#25320e",
"activityBar.background": "#ab307e",
"activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799",
"activityBarBadge.background": "#25320e",
"activityBarBadge.foreground": "#e7e7e7",
"statusBar.background": "#832561",
"statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#ab307e",
"titleBar.activeBackground": "#832561",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#83256199",
"titleBar.inactiveForeground": "#e7e7e799",
"sash.hoverBorder": "#ab307e",
"statusBarItem.remoteBackground": "#832561",
"statusBarItem.remoteForeground": "#e7e7e7"
},
"peacock.color": "#832561"
}
5 changes: 3 additions & 2 deletions ColorfulOptionsetGrid/App/ColorfulGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';

import {DetailsList, IColumn, DetailsListLayoutMode, IDetailsHeaderProps, SelectionMode} from '@fluentui/react/lib/DetailsList';
import {DetailsList, IColumn, DetailsListLayoutMode, IDetailsHeaderProps, SelectionMode, ConstrainMode} from '@fluentui/react/lib/DetailsList';
import {mergeStyles, DefaultFontStyles } from '@fluentui/react/lib/Styling';
import {initializeIcons} from '@fluentui/react/lib/Icons';
import {ScrollablePane} from '@fluentui/react/lib/ScrollablePane';
Expand Down Expand Up @@ -84,7 +84,7 @@ export const ColorfulGrid = React.memo(function ColorfulGridApp({
const isOptionSetRenderer : boolean = metadataAttributes?.has(column.original.name);
const columnDefaultIcon = displayIconType==="NAME" ? defaultIconNames.get(column.original.name)??defaultIcon : defaultIcon;
return {
...getDefaultColumnSetup(column, dataset),
...getDefaultColumnSetup(column, dataset),
onRender: isOptionSetRenderer===true ? (item : any) => {
return <ColorfulCell
item={item}
Expand Down Expand Up @@ -112,6 +112,7 @@ export const ColorfulGrid = React.memo(function ColorfulGridApp({
selectionPreservedOnEmptyClick={true}
selectionMode={SelectionMode.multiple}
layoutMode={DetailsListLayoutMode.justified}
constrainMode={ConstrainMode.unconstrained}
onItemInvoked={onItemInvoked}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
Expand Down
59 changes: 29 additions & 30 deletions ColorfulOptionsetGrid/App/Controls/ColorfulCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as React from 'react';
import { render } from 'react-dom';
import { IGridColumn } from '../Generic/Hooks/useColumns';
import { ISetupSchemaValue } from '../Utils/interfaces';
import { ColorfulCellItem } from './ColorfulCellItem';

export interface IColorfulCellProps {
item: any;
Expand All @@ -14,37 +15,35 @@ export interface IColorfulCellProps {
}

export const ColorfulCell = function ColorfulCell({item, column, metadataOptions, displayTextType, displayIconType, defaultIcon} : IColorfulCellProps) : JSX.Element{
const currentOptionSetValue= item.raw.getValue(column.original.name) as number;
let color = metadataOptions?.get(currentOptionSetValue?.toString() ?? "")?.color ?? "gray";
if(color==="white"){
color = "gray"

if(item.raw.getValue(column.original.name) ==null){
return <div></div>;
}
const icon = metadataOptions?.get(currentOptionSetValue?.toString() ?? "")?.icon ?? defaultIcon;
const iconColor = displayTextType==="BOX" ? "white" : color;
const renderIcon = displayIconType!=="NONE" ? <Icon className="colorIcon" style={{color: iconColor , marginRight: "5px"}} iconName={icon} aria-hidden="true" /> : "";
const style = {
"BORDER" : {
borderWidth: "1px",
borderStyle: "solid",
borderColor: color,
color: color,
borderRadius: "5px"
},
"BOX" : {
backgroundColor: color==="white" ? "gray" : color, color: iconColor, borderRadius: "5px"
},
"SIMPLE" : {
},
"NOTEXT": {
cursor: "pointer"
}
}[displayTextType];
const content = item[column.original.name];
const renderText = displayTextType!=="NOTEXT" ? <span className="cell">{content}</span> : ""
return(<div className="ColorfulCell" style={style} title={content}>
{renderIcon}
{renderText}
</div>);
if(column.original.dataType==="MultiSelectOptionSet" || column.original.dataType==="MultiSelectPicklist"){
const currentValues = (item.raw.getValue(column.original.name) as string ?? "").split(",");
const currentDisplayNames = (item.raw.getFormattedValue(column.original.name) as string ?? "").split(";");
return (<div className="ColorfulCell_MultiSelectOptionSet">
{currentValues.map((currentValue, index) => {
return (<ColorfulCellItem className='ColorfulCellItem'
currentValue={parseInt(currentValue)}
currentDisplayName={currentDisplayNames[index] ?? ""}
defaultIcon={defaultIcon}
displayIconType={displayIconType}
displayTextType={displayTextType}
metadataOptions={metadataOptions}
/>)
})}
</div>)
}
const currentOptionSetValue= item.raw.getValue(column.original.name) as number;
return(<ColorfulCellItem className='ColorfulCell'
currentValue={currentOptionSetValue}
currentDisplayName={item[column.original.name]}
defaultIcon={defaultIcon}
displayIconType={displayIconType}
displayTextType={displayTextType}
metadataOptions={metadataOptions}
/>);


};
53 changes: 53 additions & 0 deletions ColorfulOptionsetGrid/App/Controls/ColorfulCellItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Icon } from '@fluentui/react/lib/Icon';
import * as React from 'react';
import { render } from 'react-dom';
import { IGridColumn } from '../Generic/Hooks/useColumns';
import { ISetupSchemaValue } from '../Utils/interfaces';

export interface IColorfulCellItemProps {
currentValue ?: number;
currentDisplayName ?: string;
metadataOptions : Map<string, ISetupSchemaValue> | undefined;
displayTextType: "SIMPLE" | "BOX" | "BORDER" | "NOTEXT";
displayIconType : "NONE" | "NAME";//| "ENVIRONMENT";
defaultIcon: string;
className ?: string;
}

export const ColorfulCellItem = function ColorfulCellItem({currentValue, currentDisplayName, metadataOptions, displayTextType, displayIconType, defaultIcon, className} : IColorfulCellItemProps) : JSX.Element{
if(currentValue==null){
return <div></div>;
}
let color = metadataOptions?.get(currentValue?.toString() ?? "")?.color ?? "gray";
if(color==="white"){
color = "gray"
}
const icon = metadataOptions?.get(currentValue?.toString() ?? "")?.icon ?? defaultIcon;
const iconColor = displayTextType==="BOX" ? "white" : color;
const renderIcon = displayIconType!=="NONE" ? <Icon className="colorIcon" style={{color: iconColor , marginRight: "5px"}} iconName={icon} aria-hidden="true" /> : "";
const style = {
"BORDER" : {
borderWidth: "1px",
borderStyle: "solid",
borderColor: color,
color: color,
borderRadius: "5px"
},
"BOX" : {
backgroundColor: color==="white" ? "gray" : color, color: iconColor, borderRadius: "5px"
},
"SIMPLE" : {
},
"NOTEXT": {
cursor: "pointer"
}
}[displayTextType];
const content = currentDisplayName;
const renderText = displayTextType!=="NOTEXT" ? <span className="cell">{content}</span> : ""
return(<div className={className} style={style} title={content}>
{renderIcon}
{renderText}
</div>);


};
6 changes: 3 additions & 3 deletions ColorfulOptionsetGrid/App/Generic/Components/GridFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export const GridFooter = ({dataset, selectedCount} : IGridFooterProps) => {
<Stack grow horizontal horizontalAlign="space-between" >
<Stack.Item grow={1} align="center" >{firstItemNumber} - {lastItemNumber} of {totalRecords} ({selectedCount} selected)</Stack.Item>
<Stack.Item grow={1} align="center" className="FooterRight">
<IconButton className="FooterIcon" iconProps={{ iconName: "DoubleChevronLeft"}} onClick={moveToFirst} disabled={!dataset.paging.hasPreviousPage}/>
<IconButton className="FooterIcon" iconProps={{ iconName: "ChevronLeft"}} onClick={movePrevious} disabled={!dataset.paging.hasPreviousPage}/>
<IconButton className="FooterIcon" iconProps={{ iconName: "Rewind"}} onClick={moveToFirst} disabled={!dataset.paging.hasPreviousPage}/>
<IconButton className="FooterIcon" iconProps={{ iconName: "Previous"}} onClick={movePrevious} disabled={!dataset.paging.hasPreviousPage}/>
<span >Page {currentPage}</span>
<IconButton className="FooterIcon" iconProps={{ iconName: "ChevronRight" }} onClick={moveNext} disabled={!dataset.paging.hasNextPage}/>
<IconButton className="FooterIcon" iconProps={{ iconName: "Next" }} onClick={moveNext} disabled={!dataset.paging.hasNextPage}/>
</Stack.Item>
</Stack>
</Stack.Item>
Expand Down
5 changes: 4 additions & 1 deletion ColorfulOptionsetGrid/App/Generic/Components/GridHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ export function gridHeader(onColumnClick : Function) : ((props: IDetailsHeaderPr
onColumnClick(name);
}
return ((props: IDetailsHeaderProps | undefined, defaultRender?: IRenderFunction<IDetailsHeaderProps>) => (
props && defaultRender ?
<Sticky stickyPosition={StickyPositionType.Header} isScrollSynced={true} >
{defaultRender!({...props!, onColumnClick : onColumnHeaderClick })}
</Sticky>)
</Sticky>
: <></>
)
);
}

Expand Down
7 changes: 6 additions & 1 deletion ColorfulOptionsetGrid/App/Generic/Hooks/useColumns.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ColumnActionsMode } from '@fluentui/react';
import * as React from 'react';
type DataSet = ComponentFramework.PropertyTypes.DataSet;
import DataSetInterfaces = ComponentFramework.PropertyHelper.DataSetApi;
Expand Down Expand Up @@ -50,6 +51,7 @@ function parseColumns(originalColumns: ComponentFramework.PropertyHelper.DataSet
features: {
width : width,
isVisible : !column.isHidden===true,
isSortable: column.dataType!="MultiSelectPicklist",
order: column.order===-1 ? 100 : column.order
},
minWidth:0,
Expand Down Expand Up @@ -96,7 +98,10 @@ export const useColumns = (dataset: DataSet, availableWidth?: number, columnWidt
const [sorting, setSorting] = React.useState<DataSetInterfaces.SortStatus[]>(dataset.sorting);

function onColumnClick(columnClicked : string){
const oldSorting = (sorting || []).find((sort) => sort.name===columnClicked);
const oldSorting = (sorting || []).find((sort) => sort.name===columnClicked);
if(dataset.columns.find((column) => column.name === columnClicked)?.dataType==="MultiSelectPicklist"){
return; //This column is not sortabke
}
const newValue : DataSetInterfaces.SortStatus = {
name: columnClicked,
sortDirection : oldSorting!= null ? (oldSorting.sortDirection === 0 ? 1 : 0) : 0 //0 = ascendinf
Expand Down
2 changes: 1 addition & 1 deletion ColorfulOptionsetGrid/App/Hooks/useConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const useConfig= (dataset: DataSet, defaultIcon: string, utils: Component
setConfigs(myConfigs);
const myOptionSetColumns = customizedColumnsArray.length >0 //found customized, or take all optionset columns otherwise
? customizedColumnsArray.map((setup) => setup.column?.name ?? "")
: dataset.columns.filter((column) => column.dataType==="OptionSet").map((column) => column.name);
: dataset.columns.filter((column) => column.dataType==="OptionSet" || column.dataType==="TwoOptions" || column.dataType==="MultiSelectOptionSet" || column.dataType==="MultiSelectPicklist").map((column) => column.name);
setOptionSetColumns(myOptionSetColumns);
getAttributes(dataset.getTargetEntityType(), myOptionSetColumns, utils , new Map(myConfigs))
.then(setMetadataAttributes);
Expand Down
11 changes: 8 additions & 3 deletions ColorfulOptionsetGrid/ControlManifest.Input.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
<manifest>
<control namespace="ORBIS" constructor="ColorfulOptionsetGrid" version="0.0.16" display-name-key="ORBIS_ColorfulOptionsetGrid" description-key="ORBIS_ColorfulOptionsetGrid_Description" control-type="standard" preview-image="css/imgs/Preview.png">
<!-- dataset node represents a set of entity records on CDS; allow more than one datasets -->
<type-group name="colorfulTypes">
<type>OptionSet</type>
<type>TwoOptions</type>
<type>MultiSelectOptionSet</type>
</type-group>
<data-set name="dataset" display-name-key="Dataset" cds-data-set-options="displayCommandBar:true;displayViewSelector:true;displayquickfind:true">
<!-- 'property-set' node represents a unique, configurable property that each record in the dataset must provide. -->
<property-set name="optionset1" display-name-key="Optionset 1" description-key="Property_Desc_Key" of-type="OptionSet" usage="bound" required="false" />
<property-set name="optionset2" display-name-key="Optionset 2" description-key="Property_Desc_Key" of-type="OptionSet" usage="bound" required="false" />
<property-set name="optionset3" display-name-key="Optionset 3" description-key="Property_Desc_Key" of-type="OptionSet" usage="bound" required="false" />
<property-set name="optionset1" display-name-key="Optionset 1" description-key="Property_Desc_Key" of-type-group="colorfulTypes" usage="bound" required="false" />
<property-set name="optionset2" display-name-key="Optionset 2" description-key="Property_Desc_Key" of-type-group="colorfulTypes" usage="bound" required="false" />
<property-set name="optionset3" display-name-key="Optionset 3" description-key="Property_Desc_Key" of-type-group="colorfulTypes" usage="bound" required="false" />
<!-- UNCOMMENT TO ADD PROPERTY-SET NODE
<property-set name="samplePropertySet" display-name-key="Property_Display_Key" description-key="Property_Desc_Key" of-type="SingleLine.Text" usage="bound" required="true" />
-->
Expand Down
41 changes: 36 additions & 5 deletions ColorfulOptionsetGrid/css/ColorfulOptionSetGrid.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
width: 100%;
position: relative;
min-height: 200px ;
font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
}

.ORBIS\.ColorfulOptionsetGrid .gridContainer{
Expand All @@ -17,7 +19,8 @@
padding-top: 3px;
padding-left: 4px;
padding-bottom: 3px;
height:20px;
padding-right: 4px;
height:20px;
/* display: inline;*/
font-family: 'SegoeUI', 'Segoe UI';
/* font-size: medium;
Expand All @@ -26,6 +29,23 @@
padding-top: 3px;
padding-bottom: 3px; */
}

.ORBIS\.ColorfulOptionsetGrid .ColorfulCellItem{
overflow: hidden;
padding-top: 3px;
padding-left: 4px;
padding-bottom: 3px;
padding-right: 4px;
height:20px;
margin-left: 4px;
margin-top: 2px;
font-family: 'SegoeUI', 'Segoe UI';
}

.ORBIS\.ColorfulOptionsetGrid .ColorfulCell_MultiSelectOptionSet{
display: flex;
flex-wrap: wrap;
}

.ORBIS\.ColorfulOptionsetGrid .Footer{
height: 32px;
Expand All @@ -37,16 +57,27 @@
border-top: 1px solid #edebe9;
}

.ORBIS\.ColorfulOptionsetGrid .Footer span,
.ORBIS\.ColorfulOptionsetGrid .Footer div{
font-size: 12px;
font-weight: 400;
color: rgb(50, 49, 48);
}

.ORBIS\.ColorfulOptionsetGrid .FooterRight{
text-align: right;
margin-right:10px;
}

.ORBIS\.ColorfulOptionsetGrid .FooterIcon i{
color: #333333;
font-size: 11px;
font-size: 12px;
}
.ORBIS\.ColorfulOptionsetGrid .FooterIcon span{
color: #0078D4;
}
.ORBIS\.ColorfulOptionsetGrid .FooterIcon span:disabled{
color: gray;
}



.ORBIS\.ColorfulOptionsetGrid .colorIcon{
Expand All @@ -56,7 +87,7 @@

.ORBIS\.ColorfulOptionsetGrid div{
font-weight: normal;
font-size: 15px;
font-size: 14px;
vertical-align: baseline;
}

Expand Down
4 changes: 2 additions & 2 deletions ColorfulOptionsetGrid/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {IInputs, IOutputs} from "./generated/ManifestTypes";
import DataSetInterfaces = ComponentFramework.PropertyHelper.DataSetApi;
import ReactDOM = require("react-dom");
import React = require("react");
import * as ReactDOM from "react-dom";
import * as React from "react";
import { ColorfulGrid, IColorfulGridProps } from "./App/ColorfulGrid";

type DataSet = ComponentFramework.PropertyTypes.DataSet;
Expand Down
Binary file added Docs/img/NewDataTypes/Background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Docs/img/NewDataTypes/Border.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Docs/img/NewDataTypes/Dot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Docs/img/NewDataTypes/Dot_Border.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

The family of ColorfulOptionset Controls has a new member: ColorfulOptionsetGrid. Using this control, you can show the OptionsSets using the colors customized using the standard experience.
The Grid is not limited to showing the color "with a dot". You can choose from different possibities: with/no icon of your choice, whowing a border or a filled box.
Starting with the release 8, the ColorfulOptionsetGrid works also for Boolean/TwoOptions and for MultiSelectOptionset/MultiSelectPicklist.

![ColorfulOptionsetGrid](./Docs/img/ColorfulOptionsetGrid.png)
![ColorfulOptionsetGrid](./Docs/img/ColorfulOptionsetGrid.gif)

Expand Down Expand Up @@ -66,6 +68,21 @@ In this case only the icon will be shown, while the text will be visible only in
![NoText](./Docs/img/TextDisplayOption_NoText.png)
Unfortunatelly there is no possibility to set this option on each optionset (would get too complicated to customize). In case you choose this option, it will apply to all optionset columns.

## Screenshots for all data types: optionset/multiple optionset/boolean

![Border](./Docs/img/NewDataTypes/Border.png)

![Border](./Docs/img/NewDataTypes/OnlyThreeSelectedColumns.png)

![All data types](./Docs/img/NewDataTypes/ColumnConfig_AllDataTypes.png)

![Dot](./Docs/img/NewDataTypes/Dot.png)

![Dor Border](./Docs/img/NewDataTypes/Dot_Border.png)

![Background](./Docs/img/NewDataTypes/Background.png)


## Icons configuration
When the default icon is not enough, and you have to specify another icon per column, or in case you want to specify an icon per Optionset value, you need to define first the columns. You can specify up to 3 columns. Then the other columns will be ignored, and shown without colors.
![DefineColumns](./Docs/img/config/ChooseColumns.png)
Expand Down
Loading

0 comments on commit 0eead5b

Please sign in to comment.