Merge branch 'master' into legend_order
This commit is contained in:
Коммит
85ac000480
|
@ -33,6 +33,13 @@ body {
|
|||
font-style: normal;
|
||||
}
|
||||
|
||||
li::marker {
|
||||
list-style: none;
|
||||
background-image: none;
|
||||
background-repeat: none;
|
||||
background-position: 0;
|
||||
}
|
||||
|
||||
// CSS Rule format:
|
||||
// module__element-subelement--variant
|
||||
|
||||
|
|
|
@ -273,6 +273,8 @@
|
|||
height: 14px;
|
||||
line-height: 14px;
|
||||
cursor: not-allowed;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
&.is-selectable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable max-lines-per-function */
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
import {
|
||||
|
@ -6,7 +7,16 @@ import {
|
|||
} from "./fluent_ui_data_field_selector";
|
||||
import { Dataset, Expression, getById, Specification } from "../../../core";
|
||||
import { AppStore } from "../../stores";
|
||||
import { IContextualMenuItem } from "@fluentui/react";
|
||||
import {
|
||||
Callout,
|
||||
ContextualMenu,
|
||||
DirectionalHint,
|
||||
Dropdown,
|
||||
IContextualMenuItem,
|
||||
IContextualMenuListProps,
|
||||
IRenderFunction,
|
||||
Label,
|
||||
} from "@fluentui/react";
|
||||
import {
|
||||
DerivedColumnDescription,
|
||||
isKindAcceptable,
|
||||
|
@ -21,6 +31,16 @@ import { strings } from "../../../strings";
|
|||
import { MappingType } from "../../../core/specification";
|
||||
import React = require("react");
|
||||
import { AggregationFunctionDescription } from "../../../core/expression";
|
||||
import {
|
||||
defaultLabelStyle,
|
||||
defaultStyle,
|
||||
defultBindButtonSize,
|
||||
FluentDataBindingMenuItem,
|
||||
FluentDataBindingMenuLabel,
|
||||
} from "../panels/widgets/controls/fluentui_customized_components";
|
||||
import { CollapsiblePanel } from "../panels/widgets/controls/collapsiblePanel";
|
||||
|
||||
import { getTheme } from "@fluentui/react";
|
||||
|
||||
export interface IDefaultValue {
|
||||
table: string;
|
||||
|
@ -103,7 +123,7 @@ class MenuItemsCreator {
|
|||
ev?: React.MouseEvent<HTMLButtonElement>,
|
||||
item?: IContextualMenuItem
|
||||
): void {
|
||||
ev && ev.preventDefault();
|
||||
ev && ev.preventDefault && ev.preventDefault();
|
||||
|
||||
if (item && field) {
|
||||
this.selectedKey = field.columnName + DELIMITER + item.key;
|
||||
|
@ -292,7 +312,7 @@ class MenuItemsCreator {
|
|||
) => {
|
||||
const transformedField = this.transformField(field, item?.key);
|
||||
if (mapping?.type === MappingType.text) {
|
||||
this.textMappingOnClick(transformedField.expression, field)
|
||||
this.textMappingOnClick(transformedField.expression, field);
|
||||
} else {
|
||||
this.onClick(transformedField);
|
||||
}
|
||||
|
@ -336,9 +356,7 @@ class MenuItemsCreator {
|
|||
|
||||
const itemText =
|
||||
field.columnName +
|
||||
(subMenuProps && subMenuCheckedItem && mapping
|
||||
? ` (${subMenuCheckedItem})`
|
||||
: "");
|
||||
(subMenuProps && subMenuCheckedItem && mapping ? `` : "");
|
||||
|
||||
return {
|
||||
key:
|
||||
|
@ -500,7 +518,9 @@ class MenuItemsCreator {
|
|||
aggregationMenuItem
|
||||
);
|
||||
|
||||
if (mapping?.type === MappingType.scale) {
|
||||
if (mapping?.type === MappingType.text) {
|
||||
this.textMappingOnClick(menuExpr, field);
|
||||
} else {
|
||||
this.onClick(
|
||||
this.transformDerivedField(
|
||||
field,
|
||||
|
@ -508,8 +528,6 @@ class MenuItemsCreator {
|
|||
item?.key
|
||||
)
|
||||
);
|
||||
} else if (mapping?.type === MappingType.text) {
|
||||
this.textMappingOnClick(menuExpr, field);
|
||||
}
|
||||
|
||||
//update selection key
|
||||
|
@ -578,9 +596,7 @@ class MenuItemsCreator {
|
|||
const itemText =
|
||||
field.columnName +
|
||||
strings.objects.derivedColumns.menuSuffix +
|
||||
(subMenuProps && subMenuCheckedItem && mapping
|
||||
? ` (${subMenuCheckedItem})`
|
||||
: "");
|
||||
(subMenuProps && subMenuCheckedItem && mapping ? `` : "");
|
||||
|
||||
const derivedColumnsField = {
|
||||
key: field.columnName,
|
||||
|
@ -756,4 +772,175 @@ export class Director {
|
|||
this.builder.buildMenu();
|
||||
return this.builder.getMenuItems();
|
||||
}
|
||||
|
||||
public getMenuRender(): IRenderFunction<IContextualMenuListProps> {
|
||||
const theme = getTheme();
|
||||
|
||||
const CustomMenuRender: React.FC<{
|
||||
item: IContextualMenuItem;
|
||||
defaultKey: string;
|
||||
}> = ({ item, defaultKey }) => {
|
||||
let currentFunction: IContextualMenuItem;
|
||||
if (item.subMenuProps) {
|
||||
currentFunction = item.subMenuProps.items.find((i) => i.isChecked);
|
||||
if (currentFunction) {
|
||||
defaultKey = currentFunction.key;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<FluentDataBindingMenuItem
|
||||
key={item.key}
|
||||
backgroundColor={
|
||||
currentFunction
|
||||
? theme.semanticColors.buttonBackgroundChecked
|
||||
: null
|
||||
}
|
||||
backgroundColorHover={theme.semanticColors.buttonBackgroundHovered}
|
||||
>
|
||||
<FluentDataBindingMenuLabel>
|
||||
<Label
|
||||
onClick={(e) => {
|
||||
const agr = item.subMenuProps?.items.find(
|
||||
(item) => item.key === defaultKey
|
||||
);
|
||||
if (agr) {
|
||||
agr.onClick(e as any, agr);
|
||||
} else {
|
||||
item.onClick(e as any, item);
|
||||
}
|
||||
}}
|
||||
styles={defaultLabelStyle}
|
||||
>
|
||||
{item.text}
|
||||
</Label>
|
||||
</FluentDataBindingMenuLabel>
|
||||
{item.subMenuProps ? (
|
||||
<Dropdown
|
||||
styles={{
|
||||
...(defaultStyle as any),
|
||||
title: {
|
||||
...defaultStyle.title,
|
||||
lineHeight: defultBindButtonSize.height,
|
||||
borderWidth: "0px",
|
||||
},
|
||||
dropdownOptionText: {
|
||||
boxSizing: "unset",
|
||||
lineHeight: defultBindButtonSize.height,
|
||||
},
|
||||
}}
|
||||
selectedKey={defaultKey}
|
||||
options={item.subMenuProps.items.map((i) => ({
|
||||
key: i.key,
|
||||
text: i.text,
|
||||
}))}
|
||||
onChange={(e, opt) => {
|
||||
const agr = item.subMenuProps.items.find(
|
||||
(item) => item.key === opt.key
|
||||
);
|
||||
if (agr) {
|
||||
agr.onClick(e as any, agr);
|
||||
} else {
|
||||
item.onClick(e as any, item);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</FluentDataBindingMenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
return (props) => {
|
||||
const calloutKey = "mappingMenuAnchor";
|
||||
|
||||
// find current mapping
|
||||
let mapping = null;
|
||||
const currentColumn = props.items
|
||||
.filter((item) => item.subMenuProps) // exclude None
|
||||
.flatMap((items) => {
|
||||
if (
|
||||
items.subMenuProps &&
|
||||
items.subMenuProps.items.find((i) => i.key === "year")
|
||||
) {
|
||||
return items.subMenuProps.items;
|
||||
} else {
|
||||
return items;
|
||||
}
|
||||
})
|
||||
.find(
|
||||
(item) =>
|
||||
item.subMenuProps.items.filter((i) => i.isChecked && i.subMenuProps)
|
||||
.length > 0
|
||||
); // Exclude unselected columns
|
||||
|
||||
if (currentColumn) {
|
||||
const aggregationFunction = currentColumn.subMenuProps.items.find(
|
||||
(i) => i.isChecked && i.subMenuProps
|
||||
);
|
||||
|
||||
const currentMapping = aggregationFunction.subMenuProps.items.find(
|
||||
(i) => i.key === "mapping"
|
||||
); // Select mapping of column
|
||||
|
||||
// set current mapping
|
||||
mapping = currentMapping;
|
||||
}
|
||||
|
||||
return (
|
||||
<div id={calloutKey}>
|
||||
{mapping ? (
|
||||
<Callout
|
||||
target={`#${calloutKey}`}
|
||||
directionalHint={DirectionalHint.leftCenter}
|
||||
>
|
||||
{mapping.onRender(mapping, () => null)}
|
||||
</Callout>
|
||||
) : null}
|
||||
{!props.items.find(
|
||||
(item) => item.key === "first" || item.key === "avg"
|
||||
) ? (
|
||||
<>
|
||||
{props.items.map((item) => {
|
||||
if (item.subMenuProps?.items.find((i) => i.key === "year")) {
|
||||
const expand = item.subMenuProps.items.find((columns) =>
|
||||
columns.subMenuProps.items.find((func) => func.isChecked)
|
||||
);
|
||||
return (
|
||||
<CollapsiblePanel
|
||||
key={item.key}
|
||||
header={() => (
|
||||
<Label styles={defaultLabelStyle}>{item.text}</Label>
|
||||
)}
|
||||
isCollapsed={expand === null}
|
||||
widgets={item.subMenuProps.items.map((item) => {
|
||||
const currentKey = item.subMenuProps?.items[0].key;
|
||||
return (
|
||||
<CustomMenuRender
|
||||
key={item.key}
|
||||
item={item}
|
||||
defaultKey={currentKey}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
const currentKey = item.subMenuProps?.items[0].key;
|
||||
return (
|
||||
<CustomMenuRender
|
||||
key={item.key}
|
||||
item={item}
|
||||
defaultKey={currentKey}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</>
|
||||
) : (
|
||||
<ContextualMenu {...props} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import {
|
|||
GroupedList,
|
||||
GroupHeader,
|
||||
IGroupHeaderProps,
|
||||
IRenderFunction,
|
||||
Label,
|
||||
SelectionMode,
|
||||
} from "@fluentui/react";
|
||||
import * as React from "react";
|
||||
|
@ -14,7 +16,7 @@ import {
|
|||
} from "./fluentui_customized_components";
|
||||
|
||||
export const CollapsiblePanel: React.FunctionComponent<{
|
||||
header: string;
|
||||
header: string | IRenderFunction<IGroupHeaderProps>;
|
||||
widgets: JSX.Element[];
|
||||
isCollapsed?: boolean;
|
||||
}> = ({ header, widgets, isCollapsed }) => {
|
||||
|
@ -34,6 +36,15 @@ export const CollapsiblePanel: React.FunctionComponent<{
|
|||
onToggleCollapse={(group) => {
|
||||
setIsCollapsed(!group.isCollapsed);
|
||||
}}
|
||||
onGroupHeaderClick={(group) => {
|
||||
props.onToggleCollapse(group);
|
||||
setIsCollapsed(group.isCollapsed);
|
||||
}}
|
||||
onRenderTitle={
|
||||
typeof header === "string"
|
||||
? () => <Label>{header}</Label>
|
||||
: header
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
@ -64,7 +75,7 @@ export const CollapsiblePanel: React.FunctionComponent<{
|
|||
count: widgets.length,
|
||||
key: "group",
|
||||
level: 0,
|
||||
name: header,
|
||||
name: typeof header === "string" ? header : "",
|
||||
startIndex: 0,
|
||||
isCollapsed: groupState,
|
||||
},
|
||||
|
|
|
@ -62,6 +62,31 @@ export const FluentRowLayout = styled.div`
|
|||
flex-direction: row;
|
||||
`;
|
||||
|
||||
export const FluentDataBindingMenuItem = styled.div<{
|
||||
backgroundColor?: string;
|
||||
backgroundColorHover?: string;
|
||||
}>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
height: 26px;
|
||||
line-height: unset;
|
||||
background-color: ${({ backgroundColor }) => backgroundColor || null};
|
||||
&:hover {
|
||||
background-color: ${({ backgroundColorHover }) =>
|
||||
backgroundColorHover || null};
|
||||
}
|
||||
.ms-Dropdown-container {
|
||||
margin-top: 2px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const FluentDataBindingMenuLabel = styled.div`
|
||||
flex: 1;
|
||||
margin-left: 5px;
|
||||
`;
|
||||
|
||||
export const FluentColumnLayout = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -130,6 +155,9 @@ export const groupHeaderStyles: IStyleFunctionOrObject<
|
|||
expand: {
|
||||
...defultBindButtonSize,
|
||||
},
|
||||
dropIcon: {
|
||||
display: "none",
|
||||
},
|
||||
};
|
||||
|
||||
export const groupStyles: IStyleFunctionOrObject<
|
||||
|
|
|
@ -32,6 +32,8 @@ import {
|
|||
Label,
|
||||
IContextualMenuItem,
|
||||
Callout,
|
||||
Dropdown,
|
||||
ContextualMenu,
|
||||
} from "@fluentui/react";
|
||||
import {
|
||||
defaultLabelStyle,
|
||||
|
@ -40,6 +42,9 @@ import {
|
|||
defultComponentsHeight,
|
||||
FluentActionButton,
|
||||
FluentButton,
|
||||
FluentDataBindingMenuItem,
|
||||
FluentDataBindingMenuLabel,
|
||||
FluentRowLayout,
|
||||
labelRender,
|
||||
} from "./controls/fluentui_customized_components";
|
||||
import { ObjectClass } from "../../../../core/prototypes";
|
||||
|
@ -230,6 +235,7 @@ export class FluentMappingEditor extends React.Component<
|
|||
table,
|
||||
options.acceptKinds
|
||||
);
|
||||
const menuRender = this.director.getMenuRender();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -256,6 +262,7 @@ export class FluentMappingEditor extends React.Component<
|
|||
numberOptions={this.props.options.numberOptions}
|
||||
stopPropagation={this.props.options.stopPropagation}
|
||||
mainMenuItems={mainMenuItems}
|
||||
menuRender={menuRender}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -415,6 +422,7 @@ export class FluentMappingEditor extends React.Component<
|
|||
table,
|
||||
options.acceptKinds
|
||||
);
|
||||
const menuRender = this.director.getMenuRender();
|
||||
|
||||
if (scaleMapping.scale) {
|
||||
return (
|
||||
|
@ -439,6 +447,7 @@ export class FluentMappingEditor extends React.Component<
|
|||
title={strings.mappingEditor.bindData}
|
||||
menuProps={{
|
||||
items: mainMenuItems,
|
||||
onRenderMenuList: menuRender,
|
||||
onMenuOpened: () => {
|
||||
const currentMapping = parent.getAttributeMapping(
|
||||
attribute
|
||||
|
@ -507,11 +516,13 @@ export class FluentMappingEditor extends React.Component<
|
|||
const valueIndex = currentMapping && (currentMapping as any).valueIndex;
|
||||
|
||||
if (this.props.options.openMapping) {
|
||||
FluentMappingEditor.openEditor(
|
||||
(currentMapping as Specification.ScaleMapping)?.expression,
|
||||
true,
|
||||
this.mappingButton
|
||||
);
|
||||
setTimeout(() => {
|
||||
FluentMappingEditor.openEditor(
|
||||
(currentMapping as Specification.ScaleMapping)?.expression,
|
||||
true,
|
||||
this.mappingButton
|
||||
);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
const table = currentMapping
|
||||
|
@ -529,9 +540,10 @@ export class FluentMappingEditor extends React.Component<
|
|||
table,
|
||||
options.acceptKinds
|
||||
);
|
||||
const menuRender = this.director.getMenuRender();
|
||||
|
||||
return (
|
||||
<div ref={(e) => (this.noneLabel = e)}>
|
||||
<div ref={(e) => (this.noneLabel = e)} key={attribute}>
|
||||
<DropZoneView
|
||||
filter={(data) => {
|
||||
if (!shouldShowBindData) {
|
||||
|
@ -620,6 +632,7 @@ export class FluentMappingEditor extends React.Component<
|
|||
checked={isDataMapping}
|
||||
menuProps={{
|
||||
items: mainMenuItems,
|
||||
onRenderMenuList: menuRender,
|
||||
}}
|
||||
/>
|
||||
</FluentButton>
|
||||
|
@ -754,10 +767,10 @@ export class FluentMappingEditor extends React.Component<
|
|||
setTimeout(() => {
|
||||
menuItem?.click();
|
||||
FluentMappingEditor.menuKeyClick(derivedExpression);
|
||||
}, 100);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -634,7 +634,6 @@ export class FluentUIWidgetManager
|
|||
properties instanceof Array ? properties[0] : properties;
|
||||
this.eventListener = new UIManagerListener(this);
|
||||
this.eventManager.subscribe(EventType.UPDATE_FIELD, this.eventListener);
|
||||
console.log(properties);
|
||||
switch (options.type) {
|
||||
case "checkbox-fill-width":
|
||||
case "checkbox": {
|
||||
|
@ -928,6 +927,7 @@ export class FluentUIWidgetManager
|
|||
defaultValue,
|
||||
this.store
|
||||
);
|
||||
const menuRender = this.director.getMenuRender();
|
||||
|
||||
return (
|
||||
<DropZoneView
|
||||
|
@ -958,6 +958,7 @@ export class FluentUIWidgetManager
|
|||
onMenuOpened: () => {
|
||||
FluentMappingEditor.openEditor(currentExpression, false, null);
|
||||
},
|
||||
onRenderMenuList: menuRender,
|
||||
}}
|
||||
/>
|
||||
</FluentButton>
|
||||
|
@ -1228,6 +1229,7 @@ export class FluentUIWidgetManager
|
|||
defaultValue,
|
||||
this.store
|
||||
);
|
||||
const menuRender = this.director.getMenuRender();
|
||||
|
||||
return (
|
||||
<DropZoneView
|
||||
|
@ -1259,6 +1261,7 @@ export class FluentUIWidgetManager
|
|||
}}
|
||||
menuProps={{
|
||||
items: menu,
|
||||
onRenderMenuList: menuRender,
|
||||
}}
|
||||
styles={{
|
||||
menuIcon: {
|
||||
|
|
|
@ -7,6 +7,8 @@ import {
|
|||
DefaultButton,
|
||||
Dropdown,
|
||||
IContextualMenuItem,
|
||||
IContextualMenuListProps,
|
||||
IRenderFunction,
|
||||
Label,
|
||||
TextField,
|
||||
} from "@fluentui/react";
|
||||
|
@ -60,6 +62,7 @@ export interface ValueEditorProps {
|
|||
numberOptions?: InputNumberOptions;
|
||||
stopPropagation?: boolean;
|
||||
mainMenuItems?: IContextualMenuItem[];
|
||||
menuRender: IRenderFunction<IContextualMenuListProps>;
|
||||
}
|
||||
|
||||
export class FluentValueEditor extends ContextedComponent<
|
||||
|
@ -313,6 +316,7 @@ export class FluentValueEditor extends ContextedComponent<
|
|||
text={strings.attributesPanel.conditionedBy}
|
||||
menuProps={{
|
||||
items: this.props.mainMenuItems ?? [],
|
||||
onRenderMenuList: this.props.menuRender ?? null,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
|
Загрузка…
Ссылка в новой задаче