Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Signed-off-by: Andrea Lamparelli <a.lamparelli95@gmail.com>
  • Loading branch information
lampajr committed Oct 24, 2024
1 parent bc4eaf2 commit 42f965e
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 101 deletions.
66 changes: 66 additions & 0 deletions horreum-web/src/domain/alerting/ChangeModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {Change} from "../../generated";
import {useEffect, useState} from "react";
import {
ActionGroup, Button,
Form,
FormGroup,
Modal,
Switch, TextArea
} from "@patternfly/react-core";

type ChangeModalProps = {
change?: Change
isOpen: boolean
onClose(): void
onUpdate(change: Change): void
}

export const ChangeModal = ({ change, isOpen, onClose, onUpdate }: ChangeModalProps) => {
const [description, setDescription] = useState(change?.description)
const [confirmed, setConfirmed] = useState(change?.confirmed)
useEffect(() => {
setDescription(change?.description)
setConfirmed(change?.confirmed)
}, [change])
return (
<Modal title={change?.confirmed ? "Confirm change" : "Edit change"} isOpen={isOpen} onClose={onClose}>
<Form>
<FormGroup label="Confirmed" fieldId="confirmed">
<Switch
id="confirmed"
isChecked={confirmed}
onChange={(_event, val) => setConfirmed(val)}
label="Confirmed"
labelOff="Not confirmed"
/>
</FormGroup>
<FormGroup label="Description" fieldId="description">
<TextArea
value={description || ""}
type="text"
id="description"
aria-describedby="description-helper"
name="description"
onChange={(_event, val) => setDescription(val)}
/>
</FormGroup>
</Form>
<ActionGroup>
<Button
variant="primary"
onClick={() => {
if (change) {
onUpdate({ ...change, description: description || "", confirmed: !!confirmed })
}
onClose()
}}
>
Save
</Button>
<Button variant="secondary" onClick={onClose}>
Cancel
</Button>
</ActionGroup>
</Modal>
)
}
92 changes: 13 additions & 79 deletions horreum-web/src/domain/alerting/ChangeTable.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,32 @@
import {useState, useEffect, useContext} from "react"
import { useState, useEffect, useContext } from "react"
import {
ActionGroup,
Button,
ExpandableSection,
Form,
FormGroup,
Modal,
Tab,
Tabs,
TextArea,
Switch,
Dropdown,
DropdownItem,
MenuToggle,
MenuToggleElement
Dropdown, DropdownItem,
ExpandableSection, MenuToggle, MenuToggleElement,
Tab,
Tabs
} from '@patternfly/react-core';
import { CheckIcon } from "@patternfly/react-icons"
import { NavLink } from "react-router-dom"
import {alertingApi, Change, FingerprintValue, Variable} from "../../api"
import { alertingApi, Change, FingerprintValue, Variable } from "../../api"
import { fingerprintToString, formatDateTime } from "../../utils"
import { Column, UseSortByColumnOptions } from "react-table"
import { useTester } from "../../auth"
import {AppContext} from "../../context/appContext";
import {AppContextType} from "../../context/@types/appContextTypes";
import { AppContext } from "../../context/appContext";
import { AppContextType } from "../../context/@types/appContextTypes";
import CustomTable from "../../components/CustomTable";

import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
import { ChangeModal } from "./ChangeModal";
import EllipsisVIcon from "@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon";

type C = Column<Change> & UseSortByColumnOptions<Change>

type ChangeMenuProps = {
change: Change
onDelete(id: number): void
onUpdate(change: Change): void
}

const ChangeMenu = ({ change, onDelete, onUpdate }: ChangeMenuProps) => {
export const ChangeMenu = ({ change, onDelete, onUpdate }: ChangeMenuProps) => {
const [open, setOpen] = useState(false)
const [modalChange, setModalChange] = useState<Change>()
const onSelect = () => {
Expand Down Expand Up @@ -95,65 +88,6 @@ const ChangeMenu = ({ change, onDelete, onUpdate }: ChangeMenuProps) => {
)
}

type C = Column<Change> & UseSortByColumnOptions<Change>

type ChangeModalProps = {
change?: Change
isOpen: boolean
onClose(): void
onUpdate(change: Change): void
}

const ChangeModal = ({ change, isOpen, onClose, onUpdate }: ChangeModalProps) => {
const [description, setDescription] = useState(change?.description)
const [confirmed, setConfirmed] = useState(change?.confirmed)
useEffect(() => {
setDescription(change?.description)
setConfirmed(change?.confirmed)
}, [change])
return (
<Modal title={change?.confirmed ? "Confirm change" : "Edit change"} isOpen={isOpen} onClose={onClose}>
<Form>
<FormGroup label="Confirmed" fieldId="confirmed">
<Switch
id="confirmed"
isChecked={confirmed}
onChange={(_event, val) => setConfirmed(val)}
label="Confirmed"
labelOff="Not confirmed"
/>
</FormGroup>
<FormGroup label="Description" fieldId="description">
<TextArea
value={description || ""}
type="text"
id="description"
aria-describedby="description-helper"
name="description"
onChange={(_event, val) => setDescription(val)}
/>
</FormGroup>
</Form>
<ActionGroup>
<Button
variant="primary"
onClick={() => {
if (change) {
onUpdate({ ...change, description: description || "", confirmed: !!confirmed })
}
onClose()
}}
>
Save
</Button>
<Button variant="secondary" onClick={onClose}>
Cancel
</Button>
</ActionGroup>
</Modal>
)
}

type ChangesProps = {
varId: number
fingerprint: FingerprintValue | undefined
Expand Down
53 changes: 34 additions & 19 deletions horreum-web/src/domain/alerting/Changes.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useState, useEffect, useMemo, useCallback, useContext} from "react"
import React, {useState, useEffect, useMemo, useCallback, useContext} from "react"
import { ChangesTabs } from "./ChangeTable"
import { SelectedTest } from "../../components/TestSelect"
import LabelsSelect, { convertLabels } from "../../components/LabelsSelect"
Expand All @@ -13,7 +13,7 @@ import {
alertingApi,
testApi,
changesApi,
FingerprintValue,
FingerprintValue, Change,
} from "../../api"

import {
Expand All @@ -39,6 +39,7 @@ import { useNavigate } from "react-router-dom"
import {AppContext} from "../../context/appContext";
import {AppContextType} from "../../context/@types/appContextTypes";
import {useSelector} from "react-redux";
import {ChangeModal} from "./ChangeModal";

type TimespanSelectProps = {
value?: number
Expand Down Expand Up @@ -245,6 +246,10 @@ export default function Changes(props: ChangesProps) {
const [timespan, setTimespan] = useState<number>(toNumber(params.get("timespan")) || MONTH)
const [lineType, setLineType] = useState(params.get("line") || "linear")

// selected change
// const [changesMap, setChangesMap] = useState<Map<number, Map<number, Change>>>()
const [modalChange, setModalChange] = useState<Change>()

const createQuery = (alwaysEndTime: boolean) => {
let query = ""
if (selectedFingerprint) {
Expand Down Expand Up @@ -294,8 +299,8 @@ export default function Changes(props: ChangesProps) {
setDate(newDate)
}
}, [endTime /* date omitted intentionally */])
const [selectedChange, setSelectedChange] = useState<number>()
const [selectedVariable, setSelectedVariable] = useState<number>()
const [selectedChangeId, setSelectedChangeId] = useState<number>()
const [selectedVariableId, setSelectedVariableId] = useState<number>()

const fingerprintSource = useCallback(() => {
if (!selectedTest) {
Expand Down Expand Up @@ -398,19 +403,15 @@ export default function Changes(props: ChangesProps) {
timespan={timespan}
lineType={lineType}
onChangeSelected={(changeId, variableId) => {
setSelectedChange(changeId)
setSelectedVariable(variableId)
// we cannot scroll to an element that's not visible yet
window.setTimeout(() => {
const element = document.getElementById(
"change_" + changeId
)
if (element && element !== null) {
element.scrollIntoView()
}
// this is hacky way to reopen tabs on subsequent click
setSelectedVariable(undefined)
}, 100)
setSelectedVariableId(variableId)
setSelectedChangeId(changeId)
alertingApi.changes(variableId, fingerprintToString(selectedFingerprint)).then(
changes => {
const filteredChanges = changes.filter(c => c.id === changeId)
setModalChange(filteredChanges.length > 0 ? filteredChanges[0] : undefined)
},
error => alerting.dispatchError(error, "DASHBOARD_FETCH", "Failed to fetch changes")
)
}}
/>
</DataListCell>,
Expand All @@ -425,8 +426,8 @@ export default function Changes(props: ChangesProps) {
variables={p.variables}
fingerprint={selectedFingerprint}
testOwner={selectedTest?.owner}
selectedChangeId={selectedChange}
selectedVariableId={selectedVariable}
selectedChangeId={selectedChangeId}
selectedVariableId={selectedVariableId}
/>
</DataListCell>,
]}
Expand All @@ -435,6 +436,20 @@ export default function Changes(props: ChangesProps) {
</DataListItem>
</DataList>
))}
<ChangeModal
change={modalChange}
isOpen={!!modalChange}
onClose={() => setModalChange(undefined)}
onUpdate={change =>
alertingApi.updateChange(change.id, change).then(
_ => {
return
},
error =>
alerting.dispatchError(error,"CHANGE_UPDATE", "Failed to update change " + change.id)
)
}
/>
</CardBody>
</Card>
)
Expand Down
6 changes: 3 additions & 3 deletions horreum-web/src/domain/alerting/PanelChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import {
} from "recharts"
import { Bullseye, Button, EmptyState, Spinner, EmptyStateHeader, EmptyStateFooter, } from "@patternfly/react-core"
import { DateTime } from "luxon"
import {alertingApi, AnnotationDefinition, FingerprintValue, TimeseriesTarget} from "../../api"
import {alertingApi, AnnotationDefinition, Change, FingerprintValue, TimeseriesTarget} from "../../api"
import { fingerprintToString } from "../../utils"
import { fetchDatapoints, fetchAllAnnotations } from "./Changes"
import {AppContext} from "../../context/appContext";
import {AppContextType} from "../../context/@types/appContextTypes";
import {ChangeModal} from "./ChangeModal";

function tsToDate(timestamp: number) {
return DateTime.fromMillis(timestamp).toFormat("yyyy-LL-dd")
Expand Down Expand Up @@ -95,7 +96,7 @@ export default function PanelChart({
endTime,
setEndTime,
lineType,
onChangeSelected: propOnChangeSelected,
onChangeSelected,
}: PanelProps) {
const { alerting } = useContext(AppContext) as AppContextType;
const [legend, setLegend] = useState<any[]>() // Payload is not exported
Expand Down Expand Up @@ -151,7 +152,6 @@ export default function PanelChart({
})
return [...series.values()].sort((a, b) => a.timestamp - b.timestamp)
}, [datapoints])
const onChangeSelected = propOnChangeSelected
const changes = useMemo(
() =>
annotations?.map(a => {
Expand Down

0 comments on commit 42f965e

Please sign in to comment.