Merge branch 'master' into legend_order

This commit is contained in:
Ilfat Galiev 2021-08-23 18:15:31 +03:00 коммит произвёл GitHub
Родитель eebb294b12 76eae1d750
Коммит 85ac000480
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 278 добавлений и 23 удалений

Просмотреть файл

@ -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,
}}
/>
</>