Skip to content

Commit

Permalink
Multiple enhancements, adjustments, and bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenthoms committed Nov 18, 2024
1 parent 74164ca commit 8deaf16
Show file tree
Hide file tree
Showing 21 changed files with 398 additions and 133 deletions.
8 changes: 7 additions & 1 deletion frontend/src/framework/ModuleDataTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export enum ModuleDataTagId {
OBSERVATIONS = "observations",
SEISMIC = "seismic",
WELL_COMPLETIONS = "well-completions",
VFP = "vfp"
VFP = "vfp",
POLYGONS = "polygons",
}

export type ModuleDataTag = {
Expand All @@ -30,6 +31,11 @@ export const ModuleDataTags: ModuleDataTag[] = [
name: "3D grid model",
description: "3D grid model",
},
{
id: ModuleDataTagId.POLYGONS,
name: "Polygons",
description: "Polygons",
},
{
id: ModuleDataTagId.GROUP_TREE,
name: "Group tree",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/framework/WorkbenchSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export class WorkbenchSession {
}
}

function createEnsembleRealizationFilterFuncForWorkbenchSession(workbenchSession: WorkbenchSession) {
export function createEnsembleRealizationFilterFuncForWorkbenchSession(workbenchSession: WorkbenchSession) {
return function ensembleRealizationFilterFunc(ensembleIdent: EnsembleIdent): readonly number[] {
const realizationFilterSet = workbenchSession.getRealizationFilterSet();
const realizationFilter = realizationFilterSet.getRealizationFilterForEnsembleIdent(ensembleIdent);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { Ensemble } from "@framework/Ensemble";
import { EnsembleIdent } from "@framework/EnsembleIdent";
import { EnsembleSet } from "@framework/EnsembleSet";
import { ColorTile } from "@lib/components/ColorTile";
import { Dropdown, DropdownOption, DropdownProps } from "@lib/components/Dropdown";

type EnsembleDropdownProps = {
ensembleSet: EnsembleSet;
ensembleSet?: EnsembleSet;
ensembles?: Ensemble[];
value: EnsembleIdent | null;
onChange: (ensembleIdent: EnsembleIdent | null) => void;
} & Omit<DropdownProps<string>, "options" | "value" | "onChange">;

export function EnsembleDropdown(props: EnsembleDropdownProps): JSX.Element {
const { ensembleSet, value, onChange, ...rest } = props;
const ensembleArr = props.ensembles ?? ensembleSet?.getEnsembleArr() ?? [];

function handleSelectionChanged(selectedEnsembleIdentStr: string) {
const foundEnsemble = ensembleSet.findEnsembleByIdentString(selectedEnsembleIdentStr);
const foundEnsemble = ensembleArr.find(
(ensemble) => ensemble.getIdent().toString() === selectedEnsembleIdentStr
);
onChange(foundEnsemble ? foundEnsemble.getIdent() : null);
}

const optionsArr: DropdownOption[] = [];
for (const ens of ensembleSet.getEnsembleArr()) {
for (const ens of ensembleArr) {
optionsArr.push({
value: ens.getIdent().toString(),
label: ens.getDisplayName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ function DetailsPopup(props: DetailsPopupProps): React.ReactNode {
</div>
{makeDevState(props.module.getDevState())}
<div className="text-xs mt-2">{props.module.getDescription()}</div>
<div className="text-xs mt-2 flex gap-2 text-bold">{makeDataTags()}</div>
<div className="text-xs mt-2 flex gap-2 text-bold flex-wrap">{makeDataTags()}</div>
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/framework/utils/colorPalettes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const defaultContinuousSequentialColorPalettes = [
export const defaultContinuousDivergingColorPalettes = [
new ColorPalette({
name: "Red to Blue",
colors: ["#b2182b", "#ef8a62", "#fddbc7", "#f8f6e9", "#d1e5f0", "#67a9cf", "#2166ac"],
colors: ["#b2182b", "#ef8a62", "#fddbc7", "#fff", "#d1e5f0", "#67a9cf", "#2166ac"],
id: "red-to-blue",
}),
new ColorPalette({
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/lib/components/Input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,22 @@ export const Input = React.forwardRef((props: InputProps, ref: React.ForwardedRe
setValue(event.target.value);

if (props.onChange) {
if (props.type === "number") {
let newValue = 0;

if (!isNaN(parseFloat(event.target.value as string))) {
newValue = parseFloat((event.target.value as string) || "0");
if (props.min !== undefined) {
newValue = Math.max(props.min, newValue);
}

if (props.max !== undefined) {
newValue = Math.min(props.max, newValue);
}
}

event.target.value = newValue.toString();
}
props.onChange(event);
}
}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/lib/components/MenuButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { MenuButton } from "./menuButton";
export type { MenuButtonProps } from "./menuButton";
19 changes: 19 additions & 0 deletions frontend/src/lib/components/MenuButton/menuButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";

import { MenuButton as MuiMenuButton } from "@mui/base/MenuButton";

export type MenuButtonProps = {
ref?: React.Ref<HTMLButtonElement>;
label?: string;
disabled?: boolean;
children?: React.ReactNode;
};

export function MenuButton(props: MenuButtonProps): React.ReactNode {
return (
<MuiMenuButton
{...props}
className="hover:bg-blue-200 focus:outline-blue-600 p-1 text-sm rounded flex gap-1 items-center focus:outline focus:outline-1 hover:text-gray-900 text-gray-600"
/>
);
}
14 changes: 13 additions & 1 deletion frontend/src/lib/components/MenuHeading/menuHeading.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { resolveClassNames } from "@lib/utils/resolveClassNames";

export type MenuHeadingProps = {
classNames?: string;
style?: React.CSSProperties;
children: React.ReactNode;
};

export function MenuHeading(props: MenuHeadingProps): React.ReactNode {
return (
<div className="text-xs text-gray-500 uppercase font-semibold tracking-wider px-3 py-1">{props.children}</div>
<div
className={resolveClassNames(
"text-xs text-gray-500 uppercase font-semibold tracking-wider px-3 py-1",
props.classNames ?? ""
)}
style={props.style}
>
{props.children}
</div>
);
}
4 changes: 2 additions & 2 deletions frontend/src/lib/components/SortableList/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export { SortableList } from "./sortableList";
export { SortableList, ItemType } from "./sortableList";
export { SortableListItem } from "./sortableListItem";
export { SortableListGroup } from "./sortableListGroup";

export type { SortableListProps } from "./sortableList";
export type { SortableListProps, IsMoveAllowedArgs } from "./sortableList";
export type { SortableListItemProps } from "./sortableListItem";
export type { SortableListGroupProps } from "./sortableListGroup";
31 changes: 20 additions & 11 deletions frontend/src/lib/components/SortableList/sortableListGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import { createPortal } from "@lib/utils/createPortal";
import { resolveClassNames } from "@lib/utils/resolveClassNames";
import { DragIndicator, ExpandLess, ExpandMore } from "@mui/icons-material";

import { isEqual } from "lodash";

import { HoveredArea, SortableListContext } from "./sortableList";
import { SortableListDropIndicator } from "./sortableListDropIndicator";
import { SortableListItemProps } from "./sortableListItem";

import { DenseIconButton } from "../DenseIconButton";

export type SortableListGroupProps = {
id: string;
title: React.ReactNode;
initiallyExpanded?: boolean;
expanded?: boolean;
startAdornment?: React.ReactNode;
endAdornment?: React.ReactNode;
headerStyle?: React.CSSProperties;
Expand All @@ -26,18 +30,24 @@ export type SortableListGroupProps = {
* @param {SortableListGroupProps} props Object of properties for the SortableListGroup component (see below for details).
* @param {string} props.id ID that is unique among all components inside the sortable list.
* @param {React.ReactNode} props.title Title of the list item.
* @param {boolean} props.initiallyExpanded Whether the group should be expanded by default.
* @param {boolean} props.expanded Whether the group should be expanded.
* @param {React.ReactNode} props.startAdornment Start adornment to display to the left of the title.
* @param {React.ReactNode} props.endAdornment End adornment to display to the right of the title.
* @param {React.CSSProperties} props.headerStyle Style object to apply to the header of the group.
* @param {React.CSSProperties} props.contentStyle Style object to apply to the content of the group.
* @param {React.ReactNode} props.contentWhenEmpty Content to display when the group is empty.
* @param {React.ReactNode} props.children Child components to display as the content of the list item.
*
* @returns {React.ReactNode} A sortable list group component.
*/
export function SortableListGroup(props: SortableListGroupProps): React.ReactNode {
const [isExpanded, setIsExpanded] = React.useState<boolean>(props.initiallyExpanded ?? true);
const [isExpanded, setIsExpanded] = React.useState<boolean>(props.expanded ?? true);
const [prevExpanded, setPrevExpanded] = React.useState<boolean | undefined>(props.expanded);

if (!isEqual(props.expanded, prevExpanded)) {
if (props.expanded !== undefined) {
setIsExpanded(props.expanded);
}
setPrevExpanded(props.expanded);
}

const divRef = React.useRef<HTMLDivElement>(null);
const boundingClientRect = useElementBoundingRect(divRef);
Expand Down Expand Up @@ -71,11 +81,11 @@ export function SortableListGroup(props: SortableListGroupProps): React.ReactNod
})}
></div>
<Header
{...props}
onToggleExpanded={handleToggleExpanded}
expanded={isExpanded}
expandable={hasContent}
hovered={isHeaderHovered}
{...props}
/>
{isDragging &&
dragPosition &&
Expand Down Expand Up @@ -143,17 +153,16 @@ function Header(props: HeaderProps): React.ReactNode {
<DragIndicator fontSize="inherit" className="pointer-events-none" />
</div>
{props.expandable && (
<div
className="hover:cursor-pointer hover:text-blue-800 p-0.5 rounded"
<DenseIconButton
onClick={props.onToggleExpanded}
title={props.expanded ? "Hide children" : "Show children"}
>
{props.expanded ? <ExpandLess fontSize="inherit" /> : <ExpandMore fontSize="inherit" />}
</div>
</DenseIconButton>
)}
<div className="flex items-center gap-2 flex-grow">
<div className="flex items-center gap-2 flex-grow min-w-0">
{props.startAdornment}
<div className="flex-grow font-bold">{props.title}</div>
<div className="flex-grow font-bold min-w-0">{props.title}</div>
{props.endAdornment}
</div>
</div>
Expand Down
9 changes: 3 additions & 6 deletions frontend/src/lib/components/SortableList/sortableListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export type SortableListItemProps = {
* @param {SortableListItemProps} props Object of properties for the SortableListItem component (see below for details).
* @param {string} props.id ID that is unique among all components inside the sortable list.
* @param {React.ReactNode} props.title Title component of the list item.
* @param {string} props.headerClassNames Class names to apply to the header of the list item.
* @param {React.ReactNode} props.startAdornment Start adornment to display to the left of the title.
* @param {React.ReactNode} props.endAdornment End adornment to display to the right of the title.
* @param {React.ReactNode} props.children Child components to display as the content of the list item.
Expand Down Expand Up @@ -69,9 +68,7 @@ export function SortableListItem(props: SortableListItemProps): React.ReactNode
<Header {...props} />
</div>
)}
{props.children !== undefined && (
<div className={resolveClassNames("bg-white border-b shadow")}>{props.children}</div>
)}
<div className={resolveClassNames("bg-white border-b shadow")}>{props.children}</div>
</div>
{isHovered && sortableListContext.hoveredArea === HoveredArea.BOTTOM && <SortableListDropIndicator />}
</>
Expand All @@ -96,9 +93,9 @@ function Header(props: HeaderProps): React.ReactNode {
<div className={resolveClassNames("sortable-list-element-indicator hover:cursor-grab")}>
<DragIndicator fontSize="inherit" className="pointer-events-none" />
</div>
<div className="flex items-center gap-2 flex-grow">
<div className="flex items-center gap-2 flex-grow min-w-0">
{props.startAdornment}
<div className="flex-grow">{props.title}</div>
<div className="flex-grow min-w-0">{props.title}</div>
{props.endAdornment}
</div>
</div>
Expand Down
22 changes: 22 additions & 0 deletions frontend/src/lib/utils/ColorPalette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ export type ColorPaletteOptions = {
id: string;
};

export type ColorPaletteSerialization = {
name: string;
colors: string[];
id: string;
};

export class ColorPalette {
private _id: string;
private _name: string;
Expand Down Expand Up @@ -123,4 +129,20 @@ export class ColorPalette {

return gradient;
}

serialize(): ColorPaletteSerialization {
return {
name: this._name,
colors: this.getColors(),
id: this._id,
};
}

static fromSerialized(serialized: ColorPaletteSerialization): ColorPalette {
return new ColorPalette({
name: serialized.name,
colors: serialized.colors,
id: serialized.id,
});
}
}
46 changes: 45 additions & 1 deletion frontend/src/lib/utils/ColorScale.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ColorPalette } from "@lib/utils/ColorPalette";
import { ColorPalette, ColorPaletteSerialization } from "@lib/utils/ColorPalette";

export enum ColorScaleType {
Discrete = "discrete",
Expand Down Expand Up @@ -49,6 +49,16 @@ export type ColorScaleOptions = {
divMidPoint?: number;
};

export type ColorScaleSerialization = {
type: ColorScaleType;
colorPalette: ColorPaletteSerialization;
gradientType: ColorScaleGradientType;
steps: number;
min?: number;
max?: number;
divMidPoint?: number;
};

export class ColorScale {
private _colorPalette: ColorPalette;
private _min: number;
Expand Down Expand Up @@ -100,6 +110,14 @@ export class ColorScale {
getColorForValue(value: number): string {
let color = "";

// Clamp colors
if (value < this._min) {
value = this._min;
}
if (value > this._max) {
value = this._max;
}

if (this._type === ColorScaleType.Discrete) {
const colors = this.sampleColors(this._steps);
const normalizedValue = this.calcNormalizedValue(value, this._min, this._max);
Expand Down Expand Up @@ -270,4 +288,30 @@ export class ColorScale {
divMidPoint: this._divMidPoint,
});
}

serialize(): ColorScaleSerialization {
return {
type: this._type,
colorPalette: this._colorPalette.serialize(),
gradientType: this._gradientType,
steps: this._steps,
min: this._min,
max: this._max,
divMidPoint: this._divMidPoint,
};
}

static fromSerialized(serialization: ColorScaleSerialization): ColorScale {
const colorPalette = ColorPalette.fromSerialized(serialization.colorPalette);

return new ColorScale({
type: serialization.type,
colorPalette,
gradientType: serialization.gradientType,
steps: serialization.steps,
min: serialization.min,
max: serialization.max,
divMidPoint: serialization.divMidPoint,
});
}
}
Loading

0 comments on commit 8deaf16

Please sign in to comment.