Skip to content

Commit

Permalink
Merge pull request #145 from eccenca/release/v23.4.0
Browse files Browse the repository at this point in the history
Release v23.4.0 into main branch
  • Loading branch information
haschek authored Feb 7, 2024
2 parents a2d03d8 + 3767176 commit 1c95842
Show file tree
Hide file tree
Showing 45 changed files with 1,053 additions and 630 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "react", "simple-import-sort"],
"plugins": ["@typescript-eslint", "react", "react-hooks", "simple-import-sort"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-candidate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
steps:
- name: Get branch name
id: branch-name
uses: tj-actions/branch-names@v6
uses: tj-actions/branch-names@v8
- name: Allow only for release branch
run: |
if [[ ${{ steps.branch-name.outputs.current_branch }} != release* ]] ;
Expand Down
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
# Change Log
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- `<PropertyValuePair />`, `<PropertyName />`, `<PropertyValue />`
- `nowrap`: force display on one line without breaks
- `<Skeleton />`
- provides a loading state display of its children elements
- `<TableCell />`
- `alignHorizontal`: allow to center cell contents
- `<ActivityControlWidget />`
- added extra line to show timer for execution period
- `<ExtendedCodeEditor />`
- replaces `<SingleLineCodeEditor />` to get used for the `<AutoSuggestion />` component
- new icons
- `data-string`, `data-url`, `data-date`, `data-time`, `data-datetime`, `data-number`

### Fixed

- `<Pagination />`
- adjust color of arrow in disabled navigation button

## [23.3.1] - 2023-11-15

### Fixed
Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@eccenca/gui-elements",
"description": "GUI elements based on other libraries, usable in React application, written in Typescript.",
"version": "23.3.1",
"version": "23.4.0-rc.1",
"license": "Apache-2.0",
"homepage": "https://github.com/eccenca/gui-elements",
"bugs": "https://github.com/eccenca/gui-elements/issues",
Expand Down Expand Up @@ -66,7 +66,7 @@
"@blueprintjs/popover2": "^1.14.1",
"@blueprintjs/select": "^4.9.14",
"@carbon/icons": "^11.19.0",
"@carbon/icons-react": "^11.19.0",
"@carbon/icons-react": "^11.34.1",
"@carbon/styles": "1.32.0",
"@mavrin/remark-typograf": "^2.2.0",
"carbon-components-react": "^8.28.0",
Expand Down Expand Up @@ -120,6 +120,7 @@
"chromatic": "^6.17.4",
"eslint": "^8.49.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-simple-import-sort": "^10.0.0",
"husky": "4",
"identity-obj-proxy": "^3.0.0",
Expand Down Expand Up @@ -148,14 +149,16 @@
"peerDependencies": {
"@carbon/styles": "<1.33.0",
"@types/carbon-components-react": ">=7",
"@carbon/icons-react": ">=11.34.1",
"react": ">=16",
"react-dom": ">=16"
},
"resolutions": {
"**/@babel/traverse": "^7.23.2",
"**/@types/react": "^17.0.59",
"**/postcss": "^8.4.31",
"**/parse5": "^6.0.1"
"**/parse5": "^6.0.1",
"**/@carbon/icons-react": "^11.34.1"
},
"husky": {
"hooks": {
Expand Down
2 changes: 2 additions & 0 deletions src/cmem/ActivityControl/ActivityControlTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export interface IActivityStatus {
runtime?: number;
// The start time as date time, e.g. "2021-09-07T09:34:53.153Z"
startTime?: string;
// The queue time spent waiting before workflow is executed as date time, e.g. "2021-09-07T09:34:53.153Z"
queueTime?: string;
}
export type SilkActivityStatusProps = IActivityStatus;

Expand Down
6 changes: 6 additions & 0 deletions src/cmem/ActivityControl/ActivityControlWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export interface ActivityControlWidgetProps extends TestableComponent {
* if this is set the spinner is replaced when the progress has finished from 0 - 1
*/
progressSpinnerFinishedIcon?: React.ReactElement<IconProps> | React.ReactElement<TestIconProps>;
/**
* execution timer messages for waiting and running times.
*/
timerExecutionMsg?: JSX.Element | null
}

// @deprecated use `ActivityControlWidgetProps`
Expand Down Expand Up @@ -122,6 +126,7 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
canShrink,
tags,
progressSpinnerFinishedIcon,
timerExecutionMsg = "",
labelWrapper = <OverflowText inline={true} />,
} = props;
const spinnerClassNames = (progressSpinner?.className ?? "") + ` ${eccgui}-spinner--permanent`;
Expand Down Expand Up @@ -170,6 +175,7 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
)}
</OverviewItemLine>
)}
{timerExecutionMsg && <OverviewItemLine small>{timerExecutionMsg}</OverviewItemLine>}
</OverviewItemDescription>
<OverviewItemActions>
{activityActions &&
Expand Down
124 changes: 78 additions & 46 deletions src/cmem/ActivityControl/SilkActivityControl.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {TestableComponent} from "../../components/interfaces";
import {ActivityControlWidget, ActivityControlWidgetProps } from "./ActivityControlWidget";
import React, {useEffect, useRef, useState} from "react";
import {SilkActivityStatusConcrete, SilkActivityStatusProps} from "./ActivityControlTypes";
import {Intent} from "@blueprintjs/core/src/common/intent";
import {ActivityExecutionErrorReportModal} from "./ActivityExecutionErrorReportModal";
import {Icon, Spacing} from "../../";
import {ElapsedDateTimeDisplay, TimeUnits} from "../DateTimeDisplay/ElapsedDateTimeDisplay";
import {IntentTypes} from "../../common/Intent";
import React, { useEffect, useRef, useState } from "react";
import { Intent } from "@blueprintjs/core/src/common/intent";

import { Icon, Spacing } from "../../";
import { IntentTypes } from "../../common/Intent";
import { TestableComponent } from "../../components/interfaces";
import { ElapsedDateTimeDisplay, TimeUnits } from "../DateTimeDisplay/ElapsedDateTimeDisplay";

import { SilkActivityStatusConcrete, SilkActivityStatusProps } from "./ActivityControlTypes";
import { ActivityControlWidget, ActivityControlWidgetProps } from "./ActivityControlWidget";
import { ActivityExecutionErrorReportModal } from "./ActivityExecutionErrorReportModal";

const progressBreakpointIndetermination = 10;
const progressBreakpointAnimation = 99;
Expand Down Expand Up @@ -59,7 +61,11 @@ export interface SilkActivityControlProps extends TestableComponent {
// configure how the widget is displayed
layoutConfig?: SilkActivityControlLayoutProps;
/** Configures when the status message should be hidden, e.g. because it is uninteresting. */
hideMessageOnStatus?: (concreteStatus: SilkActivityStatusConcrete | undefined) => boolean
hideMessageOnStatus?: (concreteStatus: SilkActivityStatusConcrete | undefined) => boolean;
/**
* The translation of the time units
*/
translateUnits?: (unit: TimeUnits) => string;
}

export interface SilkActivityControlLayoutProps {
Expand Down Expand Up @@ -130,15 +136,20 @@ export type IActivityExecutionReport = SilkActivityExecutionReportProps;

interface IStacktrace {
// The final error message of the stacktrace
errorMessage?: String;
errorMessage?: string;
// The individual elements of the stack trace
lines: string[];
// In case of nested stacktraces this may contain the cause of the failure
cause?: IStacktrace;
}

// @deprecated use `SilkActivityControlTranslationKeys`
export type ActivityControlTranslationKeys = "startActivity" | "stopActivity" | "reloadActivity" | "showErrorReport" | "startPrioritized";
export type ActivityControlTranslationKeys =
| "startActivity"
| "stopActivity"
| "reloadActivity"
| "showErrorReport"
| "startPrioritized";
export type SilkActivityControlTranslationKeys = ActivityControlTranslationKeys;
// @deprecated use `SilkActivityControlAction`
export type ActivityAction = "start" | "cancel" | "restart";
Expand Down Expand Up @@ -167,38 +178,40 @@ export function useSilkActivityControl({
layoutConfig = defaultLayout,
hideMessageOnStatus = () => false,
executePrioritized,
translateUnits = (unit: TimeUnits) => unit.toString(),
...props
}: SilkActivityControlProps) {
const [activityStatus, setActivityStatus] = useState<SilkActivityStatusProps | undefined>(initialStatus);
const currentStatus = useRef<SilkActivityStatusProps | undefined>(initialStatus)
const [showStartPrioritized, setShowStartPrioritized] = useState(false)
const currentStatus = useRef<SilkActivityStatusProps | undefined>(initialStatus);
const [showStartPrioritized, setShowStartPrioritized] = useState(false);
const [errorReport, setErrorReport] = useState<string | SilkActivityExecutionReportProps | undefined>(undefined);

// Register update function
useEffect(() => {
const updateActivityStatus = (status: SilkActivityStatusProps | undefined) => {
if(status?.concreteStatus !== "Waiting") {
setShowStartPrioritized(false)
} else if(executePrioritized) {
// Show start prioritized button only-if the activity is still in Waiting status after 2s
setTimeout(() => {
if(currentStatus.current?.concreteStatus === "Waiting") {
setShowStartPrioritized(true)
}
}, 2000)
}
currentStatus.current = status
setActivityStatus(status)
}
registerForUpdates(updateActivityStatus)
return unregisterFromUpdates
},
useEffect(
() => {
const updateActivityStatus = (status: SilkActivityStatusProps | undefined) => {
if (status?.concreteStatus !== "Waiting") {
setShowStartPrioritized(false);
} else if (executePrioritized) {
// Show start prioritized button only-if the activity is still in Waiting status after 2s
setTimeout(() => {
if (currentStatus.current?.concreteStatus === "Waiting") {
setShowStartPrioritized(true);
}
}, 2000);
}
currentStatus.current = status;
setActivityStatus(status);
};
registerForUpdates(updateActivityStatus);
return unregisterFromUpdates;
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);

// Create activity actions
const actions: ActivityControlWidgetProps['activityActions'] = [];
const actions: ActivityControlWidgetProps["activityActions"] = [];

if (failureReportAction && activityStatus?.failed && activityStatus.concreteStatus !== "Cancelled") {
actions.push({
Expand All @@ -211,13 +224,13 @@ export function useSilkActivityControl({
}

if (showStartAction) {
if(showStartPrioritized && executePrioritized) {
if (showStartPrioritized && executePrioritized) {
actions.push({
"data-test-id": "activity-start-prioritized-activity",
icon: "item-skip-forward",
action: executePrioritized,
tooltip: translate("startPrioritized"),
})
});
} else {
actions.push({
"data-test-id": "activity-start-activity",
Expand Down Expand Up @@ -286,9 +299,24 @@ export function useSilkActivityControl({
/>
</>
) : (
<>{label}</>
label
);

const timerExecutionMessage =
(activityStatus?.startTime || activityStatus?.queueTime) && activityStatus.statusName !== "Finished" ? (
<ElapsedDateTimeDisplay
includeSeconds
dateTime={
(activityStatus.statusName === "Running"
? activityStatus?.startTime
: activityStatus.statusName === "Waiting"
? activityStatus.queueTime
: activityStatus?.startTime)!
}
translateUnits={translateUnits}
/>
) : null;

const { visualization, ...otherLayoutConfig } = layoutConfig;
let visualizationProps = {}; // visualization==="none" or undefined
const runningProgress = activityStatus && activityStatus.isRunning;
Expand Down Expand Up @@ -342,7 +370,10 @@ export function useSilkActivityControl({
data-test-id={props["data-test-id"]}
label={activityControlLabel}
activityActions={actions}
statusMessage={hideMessageOnStatus(activityStatus?.concreteStatus) ? undefined : activityStatus?.message}
timerExecutionMsg={timerExecutionMessage}
statusMessage={
hideMessageOnStatus(activityStatus?.concreteStatus) ? undefined : activityStatus?.message
}
{...visualizationProps}
{...otherLayoutConfig}
/>
Expand All @@ -363,16 +394,17 @@ export function useSilkActivityControl({
);

return {
elapsedDateTime: activityStatus?.startTime && elapsedTimeOfLastStart ? (
<ElapsedDateTimeDisplay
dateTime={activityStatus.startTime}
translateUnits={elapsedTimeOfLastStart.translate}
/>
) : (
<></>
),
elapsedDateTime:
activityStatus?.startTime && elapsedTimeOfLastStart ? (
<ElapsedDateTimeDisplay
dateTime={activityStatus.startTime}
translateUnits={elapsedTimeOfLastStart.translate}
/>
) : (
<></>
),
intent,
widget
widget,
} as const;
}

Expand Down
16 changes: 12 additions & 4 deletions src/cmem/DateTimeDisplay/ElapsedDateTimeDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {useEffect, useState} from "react";
import {TestableComponent} from "../../components/interfaces";

// @deprecated use `ElapsedDateTimeDisplayUnits`
export type TimeUnits = "minute" | "minutes" | "hour" | "hours" | "day" | "days"
export type TimeUnits = "second"| "seconds" | "minute" | "minutes" | "hour" | "hours" | "day" | "days"
export type ElapsedDateTimeDisplayUnits = TimeUnits;

export interface ElapsedDateTimeDisplayProps extends TestableComponent {
Expand All @@ -16,6 +16,7 @@ export interface ElapsedDateTimeDisplayProps extends TestableComponent {
showDateTimeTooltip?: boolean
// Translate time related vocabulary
translateUnits: (unit: ElapsedDateTimeDisplayUnits) => string
includeSeconds?:boolean
}

const dateTimeToElapsedTimeInMs = (dateTime: string | number) => {
Expand Down Expand Up @@ -46,14 +47,20 @@ export const elapsedTimeSegmented = (elapsedTimeInMs: number): number[] => {
* Returns the simplified elapsed time
* @deprecated moved to `elapsedDateTimeDisplayUtils.simplifiedElapsedTime`
*/
export const simplifiedElapsedTime = (timeSegments: number[], translateUnits: (unit: ElapsedDateTimeDisplayUnits) => string) => {
export const simplifiedElapsedTime = (timeSegments: number[], translateUnits: (unit: ElapsedDateTimeDisplayUnits) => string, includeSeconds = false) => {
const units: ElapsedDateTimeDisplayUnits[] = ["day", "hour", "minute"]

if(includeSeconds){
units.push("second")
}

// Find first non-null value
let idx = 0
while(idx < 3 && timeSegments[idx] === 0) {
idx++
}
if(idx === 3) {

if(idx === 3 && !includeSeconds) {
// Do not show exact seconds
return `< 1 ${translateUnits("minute")}`
} else {
Expand All @@ -70,6 +77,7 @@ export const ElapsedDateTimeDisplay = ({
suffix = "",
showDateTimeTooltip = true,
translateUnits,
includeSeconds,
...otherProps
}: ElapsedDateTimeDisplayProps) => {
const [elapsedTime, setElapsedTime] = useState<number>(dateTimeToElapsedTimeInMs(dateTime))
Expand All @@ -82,7 +90,7 @@ export const ElapsedDateTimeDisplay = ({
}, [dateTime])

return <span data-test-id={otherProps["data-test-id"]} title={showDateTimeTooltip ? new Date(dateTime).toString() : ""}>
{prefix + simplifiedElapsedTime(elapsedTimeSegmented(elapsedTime), translateUnits) + suffix}
{prefix + simplifiedElapsedTime(elapsedTimeSegmented(elapsedTime), translateUnits, includeSeconds) + suffix}
</span>
}

Expand Down
Loading

0 comments on commit 1c95842

Please sign in to comment.