Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sources refactor #764

Merged
merged 10 commits into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import { NamedArray } from "immutable-class";
import * as React from "react";
import { ClientAppSettings } from "../../../common/models/app-settings/app-settings";
import { DataCube } from "../../../common/models/data-cube/data-cube";
import { ClientDataCube } from "../../../common/models/data-cube/data-cube";
import { Essence } from "../../../common/models/essence/essence";
import { isEnabled as isOAuthEnabled } from "../../../common/models/oauth/oauth";
import { Timekeeper } from "../../../common/models/timekeeper/timekeeper";
Expand Down Expand Up @@ -142,12 +142,12 @@ export class TurniloApplication extends React.Component<TurniloApplicationProps,
if (force) this.hashToState(hash);
}

updateCubeAndEssenceInHash = (dataCube: DataCube, essence: Essence, force: boolean) => {
updateCubeAndEssenceInHash = (dataCube: ClientDataCube, essence: Essence, force: boolean) => {
const newHash = `${dataCube.name}/${(urlHashConverter.toHash(essence))}`;
this.changeHash(newHash, force);
};

urlForEssence = (dataCube: DataCube, essence: Essence): string => {
urlForEssence = (dataCube: ClientDataCube, essence: Essence): string => {
return `${this.getUrlPrefix()}#${dataCube.name}/${(urlHashConverter.toHash(essence))}`;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import { Duration, Timezone } from "chronoshift";
import * as React from "react";
import { DataCube } from "../../../common/models/data-cube/data-cube";
import { ClientDataCube, getMaxTime } from "../../../common/models/data-cube/data-cube";
import { Stage } from "../../../common/models/stage/stage";
import { Timekeeper } from "../../../common/models/timekeeper/timekeeper";
import { Unary } from "../../../common/utils/functional/functional";
Expand Down Expand Up @@ -54,7 +54,7 @@ export interface AutoRefreshMenuProps {
autoRefreshRate: Duration;
setAutoRefreshRate: Unary<Duration, void>;
refreshMaxTime: Fn;
dataCube: DataCube;
dataCube: ClientDataCube;
timekeeper: Timekeeper;
timezone: Timezone;
}
Expand All @@ -71,14 +71,14 @@ function renderRefreshIntervalDropdown(autoRefreshRate: Duration, setAutoRefresh
/>;
}

function updatedText(dataCube: DataCube, timekeeper: Timekeeper, timezone: Timezone): string {
function updatedText(dataCube: ClientDataCube, timekeeper: Timekeeper, timezone: Timezone): string {
const { refreshRule } = dataCube;
if (refreshRule.isRealtime()) {
return "Updated ~1 second ago";
} else if (refreshRule.isFixed()) {
return `Fixed to ${formatDateTime(refreshRule.time, timezone)}`;
} else { // refreshRule is query
const maxTime = dataCube.getMaxTime(timekeeper);
const maxTime = getMaxTime(dataCube, timekeeper);
if (!maxTime) return null;
return `Updated ${formatTimeElapsed(maxTime, timezone)} ago`;
}
Expand Down
4 changes: 2 additions & 2 deletions src/client/components/debug-menu/debug-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import * as React from "react";
import { DataCube } from "../../../common/models/data-cube/data-cube";
import { ClientDataCube } from "../../../common/models/data-cube/data-cube";
import { Stage } from "../../../common/models/stage/stage";
import { Fn } from "../../../common/utils/general/general";
import { STRINGS } from "../../config/constants";
Expand All @@ -27,7 +27,7 @@ export interface DebugMenuProps {
openRawDataModal: Fn;
openViewDefinitionModal: Fn;
openDruidQueryModal: Fn;
dataCube: DataCube;
dataCube: ClientDataCube;
}

export const DebugMenu: React.SFC<DebugMenuProps> = ({ dataCube, openOn, onClose, openDruidQueryModal, openRawDataModal, openViewDefinitionModal }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import { expect } from "chai";
import { mount, shallow } from "enzyme";
import { List } from "immutable";
import * as React from "react";
import * as sinon from "sinon";
import { SinonSpy } from "sinon";
Expand Down Expand Up @@ -56,7 +55,7 @@ describe("<DimensionActions>", () => {

it("renders disabled action when dimension is only selected split", () => {
const dimension = DimensionFixtures.wikiCommentLength();
const essenceWithOneSplit = EssenceFixtures.wikiTable().changeSplits(Splits.fromDimensions(List.of(dimension)), VisStrategy.FairGame);
const essenceWithOneSplit = EssenceFixtures.wikiTable().changeSplits(Splits.fromDimensions([dimension]), VisStrategy.FairGame);

const actions = dimActions(dimension, essenceWithOneSplit);

Expand Down Expand Up @@ -93,7 +92,7 @@ describe("<DimensionActions>", () => {

it("calls onClose but not clicker.changeSplit when dimension is selected", () => {
const dimension = DimensionFixtures.countryURL();
const essenceWithOneSplit = EssenceFixtures.wikiTable().changeSplits(Splits.fromDimensions(List.of(dimension)), VisStrategy.FairGame);
const essenceWithOneSplit = EssenceFixtures.wikiTable().changeSplits(Splits.fromDimensions([dimension]), VisStrategy.FairGame);
const actions = dimActions(dimension, essenceWithOneSplit);

actions.find(".split").simulate("click");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import * as React from "react";
import { DragEvent, MouseEvent } from "react";
import { DimensionKind } from "../../../common/models/dimension/dimension";
import { classNames } from "../../utils/dom/dom";
import { HighlightString } from "../highlight-string/highlight-string";
import { InfoBubble } from "../info-bubble/info-bubble";
Expand All @@ -28,19 +29,19 @@ export interface DimensionItemProps {
name: string;
title: string;
description?: string;
classSuffix: string;
dimensionClick: DimensionClickHandler;
dimensionDragStart: DimensionDragStartHandler;
searchText: string;
selected: boolean;
kind: DimensionKind;
}

export type DimensionClickHandler = (dimensionName: string, e: MouseEvent<HTMLElement>) => void;
export type DimensionDragStartHandler = (dimensionName: string, e: DragEvent<HTMLElement>) => void;

export const DimensionItem: React.SFC<DimensionItemProps> = ({ name, title, dimensionClick, dimensionDragStart, description, classSuffix, searchText, selected }) => {
export const DimensionItem: React.SFC<DimensionItemProps> = ({ name, title, dimensionClick, dimensionDragStart, description, searchText, kind, selected }) => {
const infoBubbleClassName = "info-icon";
const className = classNames(DIMENSION_CLASS_NAME, "type-" + classSuffix, { selected });
const className = classNames(DIMENSION_CLASS_NAME, { selected });

const handleClick = (e: MouseEvent<HTMLElement>) => {
const target = e.currentTarget;
Expand All @@ -60,7 +61,7 @@ export const DimensionItem: React.SFC<DimensionItemProps> = ({ name, title, dime
>
<div className="label-icon-container" onClick={handleClick}>
<div className="icon">
<SvgIcon svg={require("../../icons/dim-" + classSuffix + ".svg")} />
<SvgIcon svg={require("../../icons/dim-" + kind + ".svg")} />
</div>
<HighlightString className={"label"} text={title} highlight={searchText} />
</div>
Expand Down
34 changes: 17 additions & 17 deletions src/client/components/dimension-list-tile/dimension-list-tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import * as React from "react";
import { Component, CSSProperties, DragEvent, MouseEvent } from "react";
import { Clicker } from "../../../common/models/clicker/clicker";
import { DataCube } from "../../../common/models/data-cube/data-cube";
import { Dimension } from "../../../common/models/dimension/dimension";
import { findDimensionByName } from "../../../common/models/dimension/dimensions";
import { Essence } from "../../../common/models/essence/essence";
import { Filter } from "../../../common/models/filter/filter";
import { Splits } from "../../../common/models/splits/splits";
Expand All @@ -32,7 +32,7 @@ import { SearchableTile } from "../searchable-tile/searchable-tile";
import { TileHeaderIcon } from "../tile-header/tile-header";
import { DIMENSION_CLASS_NAME } from "./dimension-item";
import "./dimension-list-tile.scss";
import { DimensionOrGroupForView, DimensionsConverter } from "./dimensions-converter";
import { convert, DimensionOrGroupForView } from "./dimensions-converter";
import { DimensionsRenderer } from "./dimensions-renderer";

export interface DimensionListTileProps {
Expand All @@ -55,21 +55,21 @@ const hasSearchTextPredicate = (searchText: string) => (dimension: Dimension): b
};

const isFilteredOrSplitPredicate = (essence: Essence) => (dimension: Dimension): boolean => {
const { dataCube, filter, splits } = essence;
return isFiltered(dimension, filter, dataCube) || isSplit(dimension, splits, dataCube);
const { filter, splits } = essence;
return isFiltered(dimension, filter) || isSplit(dimension, splits);
};

const isSplit = (dimension: Dimension, { splits }: Splits, dataCube: DataCube): boolean => {
const isSplit = (dimension: Dimension, { splits }: Splits): boolean => {
return splits
.map(split => dataCube.dimensions.getDimensionByName(split.reference))
.contains(dimension);
.map(split => split.reference)
.contains(dimension.name);
};

const isFiltered = (dimension: Dimension, filter: Filter, dataCube: DataCube): boolean => {
const isFiltered = (dimension: Dimension, filter: Filter): boolean => {
return filter
.clauses
.map(clause => dataCube.dimensions.getDimensionByName(clause.reference))
.contains(dimension);
.map(clause => clause.reference)
.contains(dimension.name);
};

const isSelectedDimensionPredicate = (menuDimension: Dimension) => (dimension: Dimension): boolean => {
Expand All @@ -93,7 +93,7 @@ export class DimensionListTile extends Component<DimensionListTileProps, Dimensi
}

const { essence: { dataCube } } = this.props;
const dimension = dataCube.dimensions.getDimensionByName(dimensionName);
const dimension = findDimensionByName(dataCube.dimensions, dimensionName);

this.setState({
menuOpenOn: target,
Expand All @@ -112,7 +112,7 @@ export class DimensionListTile extends Component<DimensionListTileProps, Dimensi

dragStart = (dimensionName: string, e: DragEvent<HTMLElement>) => {
const { essence: { dataCube } } = this.props;
const dimension = dataCube.dimensions.getDimensionByName(dimensionName);
const dimension = findDimensionByName(dataCube.dimensions, dimensionName);

const dataTransfer = e.dataTransfer;
dataTransfer.effectAllowed = "all";
Expand Down Expand Up @@ -141,8 +141,8 @@ export class DimensionListTile extends Component<DimensionListTileProps, Dimensi
};

renderMenu(): JSX.Element {
var { essence, clicker, menuStage, triggerFilterMenu } = this.props;
var { menuOpenOn, menuDimension } = this.state;
const { essence, clicker, menuStage, triggerFilterMenu } = this.props;
const { menuOpenOn, menuDimension } = this.state;
if (!menuDimension) return null;

return <DimensionActionsMenu
Expand Down Expand Up @@ -173,18 +173,18 @@ export class DimensionListTile extends Component<DimensionListTileProps, Dimensi
const { menuDimension, showSearch, searchText } = this.state;
const { dataCube } = essence;

const dimensionsConverter = new DimensionsConverter(
const dimensionsForView = convert(
dataCube.dimensions,
hasSearchTextPredicate(searchText),
isFilteredOrSplitPredicate(essence),
isSelectedDimensionPredicate(menuDimension)
);
const dimensionsForView = dataCube.dimensions.accept(dimensionsConverter);

const dimensionsRenderer = new DimensionsRenderer(this.clickDimension, this.dragStart, searchText);
const items = dimensionsRenderer.render(dimensionsForView);
const message = this.renderMessageIfNoDimensionsFound(dimensionsForView);

var icons: TileHeaderIcon[] = [
const icons: TileHeaderIcon[] = [
{
name: "search",
ref: "search",
Expand Down
74 changes: 38 additions & 36 deletions src/client/components/dimension-list-tile/dimensions-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@
* limitations under the License.
*/

import { Dimension } from "../../../common/models/dimension/dimension";
import { DimensionGroup, DimensionOrGroupVisitor } from "../../../common/models/dimension/dimension-group";
import { Dimension, DimensionKind } from "../../../common/models/dimension/dimension";
import { DimensionOrGroup, Dimensions, isDimensionId } from "../../../common/models/dimension/dimensions";

export type DimensionOrGroupForView = DimensionForView | DimensionGroupForView;

export interface DimensionForView {
name: string;
title: string;
description?: string;
classSuffix: string;
hasSearchText: boolean;
isFilteredOrSplit: boolean;
selected: boolean;
kind: DimensionKind;
type: DimensionForViewType.dimension;
}

Expand All @@ -45,42 +45,44 @@ export enum DimensionForViewType {
group = "group"
}

export class DimensionsConverter implements DimensionOrGroupVisitor<DimensionOrGroupForView> {
constructor(
private readonly hasSearchTextPredicate: (dimension: Dimension) => boolean,
private readonly isFilteredOrSplitPredicate: (dimension: Dimension) => boolean,
private readonly isSelectedDimensionPredicate: (dimension: Dimension) => boolean
) {
}
export function convert(
dimensions: Dimensions,
hasSearchTextPredicate: (dimension: Dimension) => boolean,
isFilteredOrSplitPredicate: (dimension: Dimension) => boolean,
isSelectedDimensionPredicate: (dimension: Dimension) => boolean): DimensionOrGroupForView[] {

visitDimension(dimension: Dimension): DimensionOrGroupForView {
const { hasSearchTextPredicate, isFilteredOrSplitPredicate, isSelectedDimensionPredicate } = this;
const { name, title, description, className } = dimension;
const { byName, tree } = dimensions;

return {
name,
title,
description,
classSuffix: className,
isFilteredOrSplit: isFilteredOrSplitPredicate(dimension),
hasSearchText: hasSearchTextPredicate(dimension),
selected: isSelectedDimensionPredicate(dimension),
type: DimensionForViewType.dimension
};
}
function convertElement(el: DimensionOrGroup): DimensionOrGroupForView {
if (isDimensionId(el)) {
const dimension = byName[el];
const { name, title, kind, description } = dimension;

visitDimensionGroup(dimensionGroup: DimensionGroup): DimensionOrGroupForView {
const { name, description, title, dimensions } = dimensionGroup;
const dimensionsForView = dimensions.map(item => item.accept(this));
return {
name,
title,
description,
kind,
isFilteredOrSplit: isFilteredOrSplitPredicate(dimension),
hasSearchText: hasSearchTextPredicate(dimension),
selected: isSelectedDimensionPredicate(dimension),
type: DimensionForViewType.dimension
};
} else {
const { name, description, title, dimensions } = el;
const dimensionsForView = dimensions.map(item => convertElement(item));

return {
name,
title,
description,
hasSearchText: dimensionsForView.some(item => item.hasSearchText),
isFilteredOrSplit: dimensionsForView.some(item => item.isFilteredOrSplit),
children: dimensionsForView,
type: DimensionForViewType.group
};
return {
name,
title,
description,
hasSearchText: dimensionsForView.some(item => item.hasSearchText),
isFilteredOrSplit: dimensionsForView.some(item => item.isFilteredOrSplit),
children: dimensionsForView,
type: DimensionForViewType.group
};
}
}

return tree.map(convertElement);
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,17 @@ export class DimensionsRenderer {

private renderDimension(dimensionView: DimensionForView): JSX.Element {
const { dimensionClick, dimensionDragStart, searchText } = this;
const { name, title, description, classSuffix, selected } = dimensionView;
const { name, title, description, kind, selected } = dimensionView;

return <DimensionItem
key={name}
name={name}
title={title}
description={description}
selected={selected}
kind={kind}
dimensionClick={dimensionClick}
dimensionDragStart={dimensionDragStart}
classSuffix={classSuffix}
searchText={searchText}
/>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { expect } from "chai";
import { shallow } from "enzyme";
import * as React from "react";
import { Clicker } from "../../../common/models/clicker/clicker";
import { DataCubeFixtures } from "../../../common/models/data-cube/data-cube.fixtures";
import { wikiClientDataCube } from "../../../common/models/data-cube/data-cube.fixtures";
import { EssenceFixtures } from "../../../common/models/essence/essence.fixtures";
import { ResizeHandle } from "../resize-handle/resize-handle";
import { DimensionMeasurePanel, initialPosition, MIN_PANEL_SIZE } from "./dimension-measure-panel";
Expand Down Expand Up @@ -56,7 +56,7 @@ describe("DimensionMeasurePanel", () => {
describe("initialPosition", () => {
[300, 500, 1000].forEach(height => {
it(`should calculate position according to ratio for height ${height}`, () => {
const position = initialPosition(height, DataCubeFixtures.wiki());
const position = initialPosition(height, wikiClientDataCube);

expect(position, "lower than total height").to.be.lt(height);
expect(position, "should leave minimal space for dimensions").to.be.gte(MIN_PANEL_SIZE);
Expand Down
Loading