Skip to content

Commit

Permalink
Merge pull request #5502 from gooddata/SHA_master
Browse files Browse the repository at this point in the history
feat: alerts per attribute, search + repairs
  • Loading branch information
hackerstanislav authored Oct 23, 2024
2 parents 433fd03 + dcba709 commit b45eda3
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 36 deletions.
30 changes: 29 additions & 1 deletion libs/sdk-model/src/objRef/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,9 @@ export function objRefToString(objRef: ObjRef | ObjRefInScope): string {
* @public
*/
export function serializeObjRef(objRef: ObjRef | ObjRefInScope): string {
return stringify(objRef, { space: 0 });
const normalized = normalizeObjRef(objRef);

return stringify(normalized, { space: 0 });
}

/**
Expand Down Expand Up @@ -250,3 +252,29 @@ export function areObjRefsEqual<T extends ObjRefInScope | null | undefined>(a: T

return isLocalIdRef(a) && isLocalIdRef(b) && a.localIdentifier === b.localIdentifier;
}

/**
* Returns a value that normalizes the ObjRef instance to a canonical form.
*/
function normalizeObjRef(objRef: ObjRef | ObjRefInScope): ObjRef | ObjRefInScope {
if (isIdentifierRef(objRef)) {
return {
identifier: objRef.identifier,
type: objRef.type,
};
}

if (isUriRef(objRef)) {
return {
uri: objRef.uri,
};
}

if (isLocalIdRef(objRef)) {
return {
localIdentifier: objRef.localIdentifier,
};
}

return objRef;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
// (C) 2019-2024 GoodData Corporation
import React, { useRef, useState } from "react";
import { Button, Menu, ItemsWrapper, Item, SubMenu, Separator } from "@gooddata/sdk-ui-kit";
import {
Button,
Menu,
ItemsWrapper,
Item,
SubMenu,
Separator,
InvertableSelectSearchBar,
} from "@gooddata/sdk-ui-kit";
import cx from "classnames";
import { useIntl } from "react-intl";
import { areObjRefsEqual, IAttributeMetadataObject } from "@gooddata/sdk-model";

import { AlertAttribute } from "../../types.js";
import {
DASHBOARD_OVERLAYS_FILTER_Z_INDEX,
DASHBOARD_DIALOG_OVERS_Z_INDEX,
IGNORED_CONFIGURATION_MENU_CLICK_CLASS,
} from "../../../../constants/index.js";
import { IExecutionResultEnvelope } from "../../../../../model/index.js";
Expand Down Expand Up @@ -38,10 +46,12 @@ export const AlertAttributeSelect = ({
const selectedAttr =
selectedAttribute && getSelectedCatalogAttribute(catalogAttributes, selectedAttribute);

const [searchString, setSearchString] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [isOpenAttribute, setIsOpenAttribute] = useState<string | null>(null);

const { isResultLoading, getAttributeValues } = useAttributeValuesFromExecResults(execResult);
const opened = Boolean(isOpen && !isResultLoading);

return (
<div className="gd-alert-attribute-select">
Expand All @@ -54,14 +64,17 @@ export const AlertAttributeSelect = ({
>
<Button
className={cx("gd-alert-attribute-select__button s-alert-attribute-select", {
"is-active": isOpen,
"is-active": opened,
})}
size="small"
disabled={isResultLoading}
variant="secondary"
iconLeft="gd-icon-attribute"
iconRight={`gd-icon-navigate${isOpen ? "up" : "down"}`}
iconRight={`gd-icon-navigate${opened ? "up" : "down"}`}
onClick={() => {
if (isResultLoading) {
return;
}
setIsOpen(!isOpen);
setIsOpenAttribute(null);
}}
Expand All @@ -83,7 +96,7 @@ export const AlertAttributeSelect = ({
</div>
}
togglerWrapperClassName="gd-alert-attribute-select__button_wrapper"
opened={isOpen}
opened={opened}
onOpenedChange={({ opened }) => {
setIsOpen(opened);
}}
Expand All @@ -92,7 +105,7 @@ export const AlertAttributeSelect = ({
<ItemsWrapper
style={{
width: ref.current?.offsetWidth ?? 0,
zIndex: DASHBOARD_OVERLAYS_FILTER_Z_INDEX,
zIndex: DASHBOARD_DIALOG_OVERS_Z_INDEX,
}}
className={IGNORED_CONFIGURATION_MENU_CLICK_CLASS}
>
Expand Down Expand Up @@ -143,15 +156,28 @@ export const AlertAttributeSelect = ({
setIsOpenAttribute(
opened ? attribute.attribute.attribute.localIdentifier : null,
);
setSearchString("");
}}
>
<ItemsWrapper
style={{
zIndex: DASHBOARD_OVERLAYS_FILTER_Z_INDEX + 1,
zIndex: DASHBOARD_DIALOG_OVERS_Z_INDEX + 1,
}}
className={IGNORED_CONFIGURATION_MENU_CLICK_CLASS}
>
<div className="s-alert-attribute-submenu-content">
{values.length > 5 && (
<div>
<InvertableSelectSearchBar
onSearch={setSearchString}
searchString={searchString}
searchPlaceholder={intl.formatMessage({
id: "attributesDropdown.placeholder",
})}
className="gd-alert-attribute-select__menu-item_search"
/>
</div>
)}
<Item
className="gd-alert-attribute-select__menu-item_wrapper"
checked={Boolean(isSelected && !selectedValue)}
Expand All @@ -172,26 +198,35 @@ export const AlertAttributeSelect = ({
</Item>
<Separator />
<div className="gd-alert-attribute-select__menu-item__values">
{values.map((value, j) => (
<Item
key={j}
checked={Boolean(
isSelected && value.value === selectedValue,
)}
className="gd-alert-attribute-select__menu-item_wrapper"
onClick={(e) => {
onAttributeChange(attribute, value.value);
setIsOpen(false);
setIsOpenAttribute(null);
e.preventDefault();
e.stopPropagation();
}}
>
<div className="gd-alert-attribute-select__menu-item s-menu-alert-attribute-item-value">
{value.title ?? value.name}
</div>
</Item>
))}
{values
.filter((item) => {
if (searchString) {
return item.title
.toLowerCase()
.includes(searchString.toLowerCase());
}
return true;
})
.map((value, j) => (
<Item
key={j}
checked={Boolean(
isSelected && value.value === selectedValue,
)}
className="gd-alert-attribute-select__menu-item_wrapper"
onClick={(e) => {
onAttributeChange(attribute, value.value);
setIsOpen(false);
setIsOpenAttribute(null);
e.preventDefault();
e.stopPropagation();
}}
>
<div className="gd-alert-attribute-select__menu-item s-menu-alert-attribute-item-value">
{value.title ?? value.name}
</div>
</Item>
))}
</div>
</div>
</ItemsWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function findHeader(dataView: DataViewFacade | null, attr: IAttributeMetadataObj
}

/**
* This will find indexes for provided attribute descriptor in the execution results data view.
* This will find attribute elements array indexes for provided attribute descriptor in the execution results data view.
* @param dataView - DataViewFacade object to work with execution results data
* @param header - attribute header to find indexes for
*/
Expand All @@ -92,15 +92,18 @@ function findDimIndexes(
}

/**
* Based on found indexes in the execution results data view, this function will return attribute values
* Based on found indexes in the execution results data view, this function will return attribute elements
* that are present in the data view.
* @param dataView - DataViewFacade object to work with execution results data
* @param i - index of the dimension
* @param j - index of the item in the dimension
* @param dimensionIndex - index of the dimension
* @param elementsIndex - index of the item in the dimension
*/
function findAttributeValues(dataView: DataViewFacade | null, [i, j]: [number, number]) {
function findAttributeValues(
dataView: DataViewFacade | null,
[dimensionIndex, elementsIndex]: [number, number],
) {
const headers = dataView?.meta().allHeaders() ?? [];
const data = (headers[i] ?? [])[j] ?? [];
const data = (headers[dimensionIndex] ?? [])[elementsIndex] ?? [];

return data
.map((item) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
IAutomationMetadataObject,
IAutomationMetadataObjectDefinition,
IInsightWidget,
widgetRef,
} from "@gooddata/sdk-model";
import { useToastMessage } from "@gooddata/sdk-ui-kit";
import { useCallback, useEffect, useMemo, useState } from "react";
Expand Down Expand Up @@ -64,7 +63,8 @@ export const useInsightWidgetAlerting = ({ widget, closeInsightWidgetMenu }: IIn
const users = useDashboardSelector(selectUsers);
const dashboard = useDashboardSelector(selectDashboardId);
const insight = useDashboardSelector(selectInsightByWidgetRef(widget?.ref));
const execResult = useDashboardSelector(selectExecutionResultByRef(widget && widgetRef(widget)));
const execResult = useDashboardSelector(selectExecutionResultByRef(widget?.ref));

const allAutomationsCount = useDashboardSelector(selectAllAutomationsCount);
const maxAutomationsEntitlement = useDashboardSelector(selectEntitlementMaxAutomations);
const unlimitedAutomationsEntitlement = useDashboardSelector(selectEntitlementUnlimitedAutomations);
Expand Down
6 changes: 6 additions & 0 deletions libs/sdk-ui-dashboard/styles/scss/alerting.scss
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,12 @@
}
}

.gd-alert-attribute-select__menu-item_search {
font-size: 13px;
margin: 5px 10px 5px 10px;
width: auto;
}

.gd-alert-attribute-select__menu-item {
position: relative;

Expand Down

0 comments on commit b45eda3

Please sign in to comment.