src/app/devices/pnp/components/deviceProperties/devicePropertiesPerInterface.tsx (134 lines of code) (raw):
/***********************************************************
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License
**********************************************************/
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { DetailsListLayoutMode, IColumn, CheckboxVisibility, Label, Overlay, ActionButton, Panel, PanelType } from '@fluentui/react';
import { ResizableDetailsList } from '../../../../shared/resizeDetailsList/resizableDetailsList';
import { ResourceKeys } from '../../../../../localization/resourceKeys';
import { getLocalizedData } from '../../../../api/dataTransforms/modelDefinitionTransform';
import { RenderSimplyTypeValue } from '../../../shared/components/simpleReportedSection';
import { ComplexReportedFormPanel } from '../../../shared/components/complexReportedFormPanel';
import { SemanticUnit } from '../../../../shared/units/components/semanticUnit';
import { TwinWithSchema } from './dataHelper';
import { getSchemaType, isSchemaSimpleType } from '../../../../shared/utils/jsonSchemaAdaptor';
export interface DevicePropertiesDataProps {
twinAndSchema: TwinWithSchema[];
}
export const DevicePropertiesPerInterface: React.FC<DevicePropertiesDataProps> = (props: DevicePropertiesDataProps) => {
const { t } = useTranslation();
const [showOverlay, setShowOverlay] = React.useState<boolean>(false);
const [showReportedValuePanel, setShowReportedValuePanel] = React.useState<boolean>(false);
const [selectedItem, setSelectedItem] = React.useState(undefined);
const getColumns = (): IColumn[] => {
return [
{ key: 'name', name: t(ResourceKeys.deviceProperties.columns.name), fieldName: 'name', minWidth: 100, isMultiline: true },
{ key: 'schema', name: t(ResourceKeys.deviceProperties.columns.schema), fieldName: 'schema', minWidth: 100, isMultiline: true },
{ key: 'unit', name: t(ResourceKeys.deviceProperties.columns.unit), fieldName: 'unit', minWidth: 100, isMultiline: true },
{ key: 'value', name: t(ResourceKeys.deviceProperties.columns.value), fieldName: 'value', minWidth: 150, isMultiline: true }
];
};
const renderItemColumn = (item: TwinWithSchema, index: number, column: IColumn) => {
switch (column.key) {
case 'name':
return renderPropertyName(item);
case 'schema':
return renderPropertySchema(item);
case 'unit':
return renderPropertyUnit(item);
case 'value':
return renderPropertyReportedValue(item);
default:
return <></>;
}
};
const renderPropertyName = (item: TwinWithSchema) => {
const ariaLabel = t(ResourceKeys.deviceProperties.columns.name);
let displayName = getLocalizedData(item.propertyModelDefinition.displayName);
displayName = displayName ? displayName : '--';
let description = getLocalizedData(item.propertyModelDefinition.description);
description = description ? description : '--';
return <Label aria-label={ariaLabel}>{item.propertyModelDefinition.name} ({displayName} / {description})</Label>;
};
const renderPropertySchema = (item: TwinWithSchema) => {
const ariaLabel = t(ResourceKeys.deviceProperties.columns.schema);
const propertyModelDefinition = item.propertyModelDefinition;
const schemaType = getSchemaType(propertyModelDefinition.schema);
return <Label aria-label={ariaLabel}>{schemaType}</Label>;
};
const renderPropertyUnit = (item: TwinWithSchema) => {
const ariaLabel = t(ResourceKeys.deviceProperties.columns.unit);
return (
<Label aria-label={ariaLabel}>
<SemanticUnit unitHost={item.propertyModelDefinition} />
</Label>);
};
// tslint:disable-next-line:cyclomatic-complexity
const renderPropertyReportedValue = (item: TwinWithSchema) => {
if (!item) {
return <></>;
}
const ariaLabel = t(ResourceKeys.deviceProperties.columns.value);
// tslint:disable-next-line:no-any
const reportedValue = (item.reportedTwin as any)?.value || item.reportedTwin;
// tslint:disable-next-line:no-any
let displayValue = (item.propertyModelDefinition.schema as any)?.enumValues?.find((value: { enumValue: any; }) => value.enumValue === reportedValue)?.displayName || reportedValue;
// tslint:disable-next-line:no-any
displayValue = (displayValue as any)?.en || displayValue;
return (
<div aria-label={ariaLabel}>
{
item.propertySchema && isSchemaSimpleType(item.propertyModelDefinition.schema, item.propertySchema.$ref) ?
RenderSimplyTypeValue(
item.reportedTwin,
item.propertySchema,
displayValue,
t(ResourceKeys.deviceProperties.columns.error)) :
item.reportedTwin ?
<ActionButton
className="column-value-button"
ariaDescription={t(ResourceKeys.deviceProperties.command.openReportedValuePanel)}
onClick={onViewReportedValue(item)}
>
{t(ResourceKeys.deviceProperties.command.openReportedValuePanel)}
</ActionButton> : <Label>--</Label>
}
</div>
);
};
const onViewReportedValue = (item: TwinWithSchema) => () => {
setSelectedItem(item);
setShowOverlay(true);
setShowReportedValuePanel(true);
};
const createReportedValuePanel = () => {
if (!selectedItem) {
return <></>;
}
const { reportedTwin, propertyModelDefinition: modelDefinition, propertySchema: schema } = selectedItem;
return (
<Panel type={PanelType.medium} isOpen={showReportedValuePanel} isLightDismiss={true}>
<ComplexReportedFormPanel
showPanel={showReportedValuePanel}
formData={reportedTwin}
handleDismiss={removeOverlay}
schema={schema}
modelDefinition={modelDefinition}
/>
</Panel>
);
};
const removeOverlay = () => {
setSelectedItem(undefined);
setShowOverlay(false);
};
return (
<div className="pnp-detail-list scrollable-lg ms-Grid">
<div className="list-detail pnp-properties">
<ResizableDetailsList
checkboxVisibility={CheckboxVisibility.hidden}
onRenderItemColumn={renderItemColumn}
items={props.twinAndSchema}
columns={getColumns()}
layoutMode={DetailsListLayoutMode.justified}
/>
{showOverlay && <Overlay />}
{createReportedValuePanel()}
</div>
</div>
);
};