diff --git a/libs/gui-elements b/libs/gui-elements index bd8f403fcc..14310c606d 160000 --- a/libs/gui-elements +++ b/libs/gui-elements @@ -1 +1 @@ -Subproject commit bd8f403fcc02decf0476dfd2d82663cdbf3c55ac +Subproject commit 14310c606d0bac2631822e71a0644fb7fdaaf82f diff --git a/workspace/src/app/hooks/useModalError.tsx b/workspace/src/app/hooks/useModalError.tsx index 5fbc6eb62f..39589baf86 100644 --- a/workspace/src/app/hooks/useModalError.tsx +++ b/workspace/src/app/hooks/useModalError.tsx @@ -21,8 +21,9 @@ export const useModalError = ({ setError }: useModalParams) => { setError(errorWithContextName((e as FetchError).errorResponse)); } else if (e.title === "Network Error") { setError(errorWithContextName(e)); - } else if(typeof e.asString === "function" && !!e.status) { // If not a FetchError, seems to be an error response then - setError(errorWithContextName(e)) + } else if (typeof e.asString === "function" && !!e.status) { + // If not a FetchError, seems to be an error response then + setError(errorWithContextName(e)); } else { console.warn(e); } diff --git a/workspace/src/app/store/ducks/common/initialState.ts b/workspace/src/app/store/ducks/common/initialState.ts index 2b3fd062b0..66f3e2bf77 100644 --- a/workspace/src/app/store/ducks/common/initialState.ts +++ b/workspace/src/app/store/ducks/common/initialState.ts @@ -32,7 +32,7 @@ export function initialCommonState(): ICommonState { hotKeys: {}, templatingEnabled: false, assistantSupported: false, - mappingCreatorEnabled: false + mappingCreatorEnabled: false, }, exportTypes: [], artefactModal: initialArtefactModalState(), diff --git a/workspace/src/app/store/ducks/error/typings.ts b/workspace/src/app/store/ducks/error/typings.ts index 797d415aea..dc1125573f 100644 --- a/workspace/src/app/store/ducks/error/typings.ts +++ b/workspace/src/app/store/ducks/error/typings.ts @@ -35,4 +35,4 @@ export interface IErrorState { errors: Array; } -export type ApplicationError = DIErrorFormat & { errorNotificationInstanceId?: string, notAutoOpen?: boolean }; +export type ApplicationError = DIErrorFormat & { errorNotificationInstanceId?: string; notAutoOpen?: boolean }; diff --git a/workspace/src/app/store/ducks/workspace/requests.ts b/workspace/src/app/store/ducks/workspace/requests.ts index abd10b1cd7..cbe8d4ab88 100644 --- a/workspace/src/app/store/ducks/workspace/requests.ts +++ b/workspace/src/app/store/ducks/workspace/requests.ts @@ -68,7 +68,7 @@ export const requestRemoveProject = async (itemId: string): Promise> => { return await fetch({ url: @@ -110,7 +110,7 @@ export const requestCloneTask = async ( taskId: string, projectId: string, payload: any, - newTaskId?: string + newTaskId?: string, ): Promise> => { let body = { ...payload }; if (newTaskId) { @@ -191,9 +191,9 @@ export const requestProjectPrefixes = async (projectId: string): Promise => { - const {data} = await fetch({ + const { data } = await fetch({ url: workspaceApi(`/projects/${projectId}/prefixes/${prefixName}`), method: "PUT", body: prefixUri, @@ -203,7 +203,7 @@ export const requestChangePrefixes = async ( //missing-type export const requestRemoveProjectPrefix = async (prefixName: string, projectId: string): Promise => { - const {data} = await fetch({ + const { data } = await fetch({ url: workspaceApi(`/projects/${projectId}/prefixes/${prefixName}`), method: "DELETE", }); @@ -246,7 +246,7 @@ export const requestRemoveProjectResource = async (projectId: string, resourceNa /** Returns all tasks that depend on a specific resource. */ export const projectFileResourceDependents = async ( projectId: string, - resourceName: string + resourceName: string, ): Promise> => { return fetch({ url: legacyApiEndpoint(`/projects/${projectId}/files/usage`), @@ -288,7 +288,7 @@ const projectImportEndpoint = (projectImportId: string) => workspaceApi(`/projec /** Fetch the project import details for the previously uploaded project file. */ export const requestProjectImportDetails = async ( - projectImportId: string + projectImportId: string, ): Promise> => { return fetch({ url: projectImportEndpoint(projectImportId), @@ -311,7 +311,7 @@ export const requestDeleteProjectImport = async (projectImportId: string): Promi export const requestStartProjectImport = async ( projectImportId: string, generateNewId: boolean, - overwriteExistingProject: boolean + overwriteExistingProject: boolean, ): Promise> => { return fetch({ url: @@ -323,7 +323,7 @@ export const requestStartProjectImport = async ( /** When the actual project import has been started, this endpoint will inform about the progress. */ export const requestProjectImportExecutionStatus = async ( - projectImportId: string + projectImportId: string, ): Promise> => { return fetch({ url: projectImportEndpoint(projectImportId) + "/status", @@ -362,7 +362,7 @@ export const requestProjectUri = async (projectId: string): Promise> => { return fetch({ url: workspaceApi("vocabularies/property/search"), @@ -378,7 +378,7 @@ export const requestSearchForGlobalVocabularyProperties = async ( export const requestTaskContextInfo = async ( projectId: string, taskId: string, - taskContext: TaskContext + taskContext: TaskContext, ): Promise> => { return fetch({ url: projectApi(`/${projectId}/taskContext`), diff --git a/workspace/src/app/views/layout/Header/KeyboardShortcutsModal.tsx b/workspace/src/app/views/layout/Header/KeyboardShortcutsModal.tsx index dc5da14ff4..41f996e687 100644 --- a/workspace/src/app/views/layout/Header/KeyboardShortcutsModal.tsx +++ b/workspace/src/app/views/layout/Header/KeyboardShortcutsModal.tsx @@ -17,7 +17,7 @@ import { useSelector } from "react-redux"; import { commonSel } from "@ducks/common"; const sectionKeys = ["general", "workflow-editor", "rule-editors", "projects", "tasks"] as const; -const shortcuts: Record> = { +const shortcuts: Record<(typeof sectionKeys)[number], Array<{ key: string; commands: string[] }>> = { general: [ { key: "quick-search", commands: ["/"] }, { key: "help", commands: ["?"] }, @@ -116,12 +116,12 @@ export const KeyboardShortcutsModal = () => { labelProps={{ tooltip: t( `header.keyboardShortcutsModal.categories.${sectionKey}.shortcuts.${shortcut.key}Desc`, - "" + "", ), }} > {t( - `header.keyboardShortcutsModal.categories.${sectionKey}.shortcuts.${shortcut.key}` + `header.keyboardShortcutsModal.categories.${sectionKey}.shortcuts.${shortcut.key}`, )} { {" "}

{t( - `header.keyboardShortcutsModal.key-directives.${keyDirective}` + `header.keyboardShortcutsModal.key-directives.${keyDirective}`, )}

@@ -148,7 +148,7 @@ export const KeyboardShortcutsModal = () => { .map((key) => { return t( `header.keyboardShortcutsModal.keys.${key}`, - key + key, ); }) .join(" + ")} diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/HierarchicalMapping.jsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/HierarchicalMapping.jsx index 04c7789dac..bb18456c57 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/HierarchicalMapping.jsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/HierarchicalMapping.jsx @@ -135,7 +135,7 @@ class HierarchicalMapping extends React.Component { uri, type, parent, - label: displayLabel + label: displayLabel, }, askForRemove: true, removeFunction: this.handleConfirmRemove, diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/components/ObjectMapping/ObjectUriPattern.tsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/components/ObjectMapping/ObjectUriPattern.tsx index 292e9fd44a..cde3ccc296 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/components/ObjectMapping/ObjectUriPattern.tsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/components/ObjectMapping/ObjectUriPattern.tsx @@ -11,7 +11,7 @@ interface ObjectUriPatternProps { uriRule: any; onRemoveUriRule: () => void; openMappingEditor: () => void; - showLabel?: boolean + showLabel?: boolean; } const ObjectUriPattern = ({ uriRule, onRemoveUriRule, openMappingEditor, showLabel = true }: ObjectUriPatternProps) => { @@ -51,10 +51,9 @@ const ObjectUriPattern = ({ uriRule, onRemoveUriRule, openMappingEditor, showLab
- {showLabel ? -
{uriPatternLabel}
: - null - } + {showLabel ? ( +
{uriPatternLabel}
+ ) : null}
{uriPattern} { setError(error); setLoading(false); - } + }, ); }; @@ -181,19 +181,20 @@ export const ExampleView = ({ id, rawRule, ruleType, objectSourcePathContext, up - {resultsCount > 0 && examples.status.id === "with exceptions" && examples.status.msg ? + {resultsCount > 0 && examples.status.id === "with exceptions" && examples.status.msg ? ( - : - null - } + + ) : null} {_.map(examples.results, (result, index) => ( {sourcePaths.map((sourcePath, i) => ( @@ -232,7 +233,7 @@ export const ExampleView = ({ id, rawRule, ruleType, objectSourcePathContext, up > {transformedValue} - ) + ), )} )} diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/MappingRule.jsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/MappingRule.jsx index 9c8925ce8e..4fa3c232a3 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/MappingRule.jsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/MappingRule.jsx @@ -15,7 +15,7 @@ import MappingRuleRow from "./MappingRuleRow"; import NavigateButton from "../../elements/buttons/NavigateButton"; import ExpandButton from "../../elements/buttons/ExpandButton"; import { ContextMenu, MenuItem, Spinner } from "@eccenca/gui-elements"; -import {getRuleLabel} from "../../utils/getRuleLabel"; +import { getRuleLabel } from "../../utils/getRuleLabel"; export class MappingRule extends React.Component { // define property types @@ -136,9 +136,9 @@ export class MappingRule extends React.Component { this.props; const srcPath = sourcePath || sourcePaths; - const label = _.get(metadata, 'label', ''); - const ruleLabelData = getRuleLabel({label, uri: mappingTarget.uri}); - const ruleDisplayLabel = ruleLabelData.displayLabel + const label = _.get(metadata, "label", ""); + const ruleLabelData = getRuleLabel({ label, uri: mappingTarget.uri }); + const ruleDisplayLabel = ruleLabelData.displayLabel; const expandedView = this.props.expanded ? ( isRootOrObjectRule(type) ? ( diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/ObjectRule/ObjectRule.jsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/ObjectRule/ObjectRule.jsx index ffe1d5ac0e..2c924c196e 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/ObjectRule/ObjectRule.jsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/ObjectRule/ObjectRule.jsx @@ -24,7 +24,7 @@ import MetadataDesc from "../../../components/Metadata/MetadataDesc"; import { SourcePath } from "../../../components/SourcePath"; import TargetCardinality from "../../../components/TargetCardinality"; import { defaultUriPattern } from "./ObjectRule.utils"; -import {getRuleLabel} from "../../../utils/getRuleLabel"; +import { getRuleLabel } from "../../../utils/getRuleLabel"; class ObjectRule extends React.Component { static propTypes = { @@ -99,7 +99,7 @@ class ObjectRule extends React.Component { }, (err) => { console.error(err); - } + }, ); } else { this.props.openMappingEditor(uriRuleId); @@ -118,7 +118,7 @@ class ObjectRule extends React.Component { }, (err) => { console.error(err); - } + }, ); }; this.props.onClickedRemove(null, callbackFn); @@ -156,9 +156,9 @@ class ObjectRule extends React.Component { const { type, ruleData } = this.props; const { edit } = this.state; const { type: ruleType, metadata, mappingTarget } = ruleData; - const label = _.get(metadata, 'label', ''); - const ruleLabelData = getRuleLabel({label, uri: mappingTarget.uri}); - const ruleDisplayLabel = ruleLabelData.displayLabel + const label = _.get(metadata, "label", ""); + const ruleLabelData = getRuleLabel({ label, uri: mappingTarget.uri }); + const ruleDisplayLabel = ruleLabelData.displayLabel; if (edit) { return ( @@ -245,7 +245,7 @@ class ObjectRule extends React.Component { uri: this.props.ruleData.mappingTarget.uri, type: ruleType, parent: this.props.parentId, - displayLabel: ruleDisplayLabel + displayLabel: ruleDisplayLabel, }); }} /> diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/ValueRule/ValueRule.jsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/ValueRule/ValueRule.jsx index c2dfed36cc..db323c7176 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/ValueRule/ValueRule.jsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingRule/ValueRule/ValueRule.jsx @@ -168,7 +168,7 @@ class ValueRule extends React.Component { uri: mappingTarget.uri, type: this.props.type, parent: parentId, - displayLabel: this.props.displayLabel + displayLabel: this.props.displayLabel, }); }} /> diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingsList/MappingsList.tsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingsList/MappingsList.tsx index 81283990fb..e596be89be 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingsList/MappingsList.tsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/MappingsList/MappingsList.tsx @@ -23,7 +23,7 @@ interface MappingsListProps { handleClone?: (id, type, parent) => any; onClickedRemove?: () => any; onShowSuggestions?: () => any; - onRuleIdChange?: (param: any) => any; + onRuleIdChange?: (param: any) => any; onAskDiscardChanges?: (param: any) => any; openMappingEditor: () => void; startFullScreen: boolean; @@ -64,7 +64,7 @@ const MappingsList = ({ const childrenRules = reorderArray( items.map((a) => a.key), fromPos, - toPos + toPos, ); const { project, transformTask } = getApiDetails(); diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/RootMappingRule.jsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/RootMappingRule.jsx index fb2899d7de..81d8e7dd89 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/RootMappingRule.jsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/RootMappingRule.jsx @@ -101,7 +101,7 @@ class RootMappingRule extends React.Component { { expanded: !this.state.expanded, }, - this.updateQueryOnExpansion + this.updateQueryOnExpansion, ); } } diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/SuggestionNew/SuggestionContainer.tsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/SuggestionNew/SuggestionContainer.tsx index 147651d42a..4f6b84573c 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/SuggestionNew/SuggestionContainer.tsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/containers/SuggestionNew/SuggestionContainer.tsx @@ -37,7 +37,7 @@ import ErrorView from "../../components/ErrorView"; import _ from "lodash"; import { useTranslation } from "react-i18next"; import { GlobalMappingEditorContext } from "../../../contexts/GlobalMappingEditorContext"; -import {IInitFrontend} from "@ducks/common/typings"; +import { IInitFrontend } from "@ducks/common/typings"; interface ISuggestionListContext { // Can be deleted when popup issue gone @@ -168,7 +168,7 @@ export default function SuggestionContainer({ maxResults, selectedVocabs, true, - mappingEditorContext.taskContext + mappingEditorContext.taskContext, ); if (Array.isArray(data)) { return data.map((tp) => { @@ -233,7 +233,7 @@ export default function SuggestionContainer({ matchFromDataset: boolean, setLoader: boolean, executeMatching: boolean, - selectedVocabularies?: string[] + selectedVocabularies?: string[], ) => { const vocabs = selectedVocabularies ? selectedVocabularies : selectedVocabs; setData([]); @@ -249,7 +249,7 @@ export default function SuggestionContainer({ nrCandidates: 20, targetVocabularies: vocabs && vocabs.length > 0 ? vocabs : undefined, }, - executeMatching + executeMatching, ).subscribe( ({ suggestions, warnings, suggestionIssues }) => { try { @@ -267,7 +267,7 @@ export default function SuggestionContainer({ (error) => { setLoader && setLoading(false); reject(error); - } + }, ); }); }; @@ -282,7 +282,7 @@ export default function SuggestionContainer({ }, (err) => { reject(err); - } + }, ); }); }; @@ -303,7 +303,7 @@ export default function SuggestionContainer({ }, (err) => { reject(err); - } + }, ); }); }; @@ -341,12 +341,12 @@ export default function SuggestionContainer({ error .filter((err) => err?.error) .forEach( - (err) => (err.error.titlePrefix = "There has been a problem generating the mapping rules: ") + (err) => (err.error.titlePrefix = "There has been a problem generating the mapping rules: "), ); setErrorSafe(error); setLoading(false); }, - () => setLoading(false) + () => setLoading(false), ); }; diff --git a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/elements/RemoveMappingRuleDialog.jsx b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/elements/RemoveMappingRuleDialog.jsx index 41065b3f7d..eae25d7457 100644 --- a/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/elements/RemoveMappingRuleDialog.jsx +++ b/workspace/src/app/views/pages/MappingEditor/HierarchicalMapping/elements/RemoveMappingRuleDialog.jsx @@ -1,13 +1,11 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { ConfirmationDialog } from 'gui-elements-deprecated'; +import React from "react"; +import PropTypes from "prop-types"; +import { ConfirmationDialog } from "gui-elements-deprecated"; import { DismissiveButton, DisruptiveButton } from "@eccenca/gui-elements/src/legacy-replacements"; -import { MAPPING_RULE_TYPE_OBJECT } from '../utils/constants'; +import { MAPPING_RULE_TYPE_OBJECT } from "../utils/constants"; -const RemoveMappingRuleDialog = props => { - const { - mappingType, handleConfirmRemove, handleCancelRemove, label - } = props; +const RemoveMappingRuleDialog = (props) => { + const { mappingType, handleConfirmRemove, handleCancelRemove, label } = props; return ( { modal title="Remove mapping rule?" confirmButton={ - - Remove + + Remove } cancelButton={ - - Cancel + + Cancel } >

- When you click REMOVE the mapping rule{label ? ` '${label}'` : ""} - { - mappingType === MAPPING_RULE_TYPE_OBJECT - ? ' including all child rules ' - : ' ' - } - will be deleted permanently. + When you click REMOVE the mapping rule{label ? ` '${label}'` : ""} + {mappingType === MAPPING_RULE_TYPE_OBJECT ? " including all child rules " : " "} + will be deleted permanently.

); @@ -51,7 +39,7 @@ RemoveMappingRuleDialog.propTypes = { }; RemoveMappingRuleDialog.defaultProps = { - mappingType: '', + mappingType: "", }; export default RemoveMappingRuleDialog; diff --git a/workspace/src/app/views/pages/MappingEditor/api/silkRestApi.hooks.ts b/workspace/src/app/views/pages/MappingEditor/api/silkRestApi.hooks.ts index 0cc6798410..d367850fdd 100644 --- a/workspace/src/app/views/pages/MappingEditor/api/silkRestApi.hooks.ts +++ b/workspace/src/app/views/pages/MappingEditor/api/silkRestApi.hooks.ts @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import silkApi from "./silkRestApi"; import { setDefaultProjectPageSuffix } from "../../../../utils/routerUtils"; -import {IInitFrontend} from "@ducks/common/typings"; +import { IInitFrontend } from "@ducks/common/typings"; interface IProps { errorStatus: number; diff --git a/workspace/src/app/views/plugins/RegisteredCoreTaskPlugins.tsx b/workspace/src/app/views/plugins/RegisteredCoreTaskPlugins.tsx index b6900fc487..3bd1a3c188 100644 --- a/workspace/src/app/views/plugins/RegisteredCoreTaskPlugins.tsx +++ b/workspace/src/app/views/plugins/RegisteredCoreTaskPlugins.tsx @@ -61,7 +61,7 @@ export const registerCorePlugins = () => { projectId: string, taskId: string, viewActions: IViewActions, - startFullScreen: boolean + startFullScreen: boolean, ): JSX.Element { return ( { projectId: string, taskId: string, viewActions: IViewActions | undefined, - startFullScreen: boolean + startFullScreen: boolean, ): JSX.Element { setApiDetails({ project: projectId, transformTask: taskId }); return ( diff --git a/workspace/src/app/views/shared/ApplicationNotifications/NotificationsMenu.tsx b/workspace/src/app/views/shared/ApplicationNotifications/NotificationsMenu.tsx index 439ac12bc6..e099269c4c 100644 --- a/workspace/src/app/views/shared/ApplicationNotifications/NotificationsMenu.tsx +++ b/workspace/src/app/views/shared/ApplicationNotifications/NotificationsMenu.tsx @@ -34,7 +34,7 @@ export function NotificationsMenu({ autoDisplayNotifications = true, errorNotifi useApplicationHeaderOverModals( notificationQueue.messages.length > 0, - "diapp-applicationnotifications--filledqueue" + "diapp-applicationnotifications--filledqueue", ); const toggleNotifications = () => { @@ -121,7 +121,7 @@ export const parseErrorCauseMsg = (cause?: DIErrorTypes | null): string | undefi /** Decide if to show a message based on the instance ID. */ const showMessage = ( message?: DIErrorFormat & { errorNotificationInstanceId?: string }, - errorNotificationInstanceId?: string + errorNotificationInstanceId?: string, ): boolean => { return ( !!message && diff --git a/workspace/src/app/views/shared/FileUploader/FileSelectionMenu.tsx b/workspace/src/app/views/shared/FileUploader/FileSelectionMenu.tsx index 0883cc97aa..c9e968094f 100644 --- a/workspace/src/app/views/shared/FileUploader/FileSelectionMenu.tsx +++ b/workspace/src/app/views/shared/FileUploader/FileSelectionMenu.tsx @@ -1,10 +1,6 @@ import React from "react"; -import Uppy, { UppyFile } from "@uppy/core"; -import "@uppy/core/dist/style.css"; -import "@uppy/drag-drop/dist/style.css"; -import "@uppy/progress-bar/dist/style.css"; -import { Button, Divider, FieldItem, Icon, TextField } from "@eccenca/gui-elements"; +import { Button, Divider, FieldItem, Icon, TextField, Uppy, UppyFile } from "@eccenca/gui-elements"; import { IAutoCompleteFieldProps } from "@eccenca/gui-elements/src/components/AutocompleteField/AutoCompleteField"; import { UploadNewFile } from "./cases/UploadNewFile/UploadNewFile"; import { FileSelectionOptions, FileMenuItems } from "./FileSelectionOptions"; @@ -13,8 +9,6 @@ import { CreateNewFile } from "./cases/CreateNewFile"; import i18next from "../../../../language"; import { requestIfResourceExists } from "@ducks/workspace/requests"; import { legacyApiEndpoint } from "../../../utils/getApiEndpoint"; -import { withTranslation } from "react-i18next"; -import XHR from "@uppy/xhr-upload"; interface IUploaderInstance { /** @@ -41,7 +35,7 @@ export interface IUploaderOptions { defaultValue?: string; /** Indicator that there needs to be a value set/selected, else the file selection (from existing files) can e.g. be reset. */ - required: boolean; + required?: boolean; /** * return uploader API @@ -96,33 +90,15 @@ export interface IUploaderOptions { t(key: string, options?: object | string): string; /** When used inside a modal, the behavior of some components will be optimized. */ - insideModal: boolean; + insideModal?: boolean; /** Callback that is called when the state of all uploads being successfully done has changed. * Reasons for non-success are: uploads are in progress, user interaction is needed, errors have occurred.*/ allFilesSuccessfullyUploadedHandler?: (allSuccessful: boolean) => any; - listenToUploadedFiles: (files: UppyFile[]) => void -} - -interface IState { - // Selected File menu item - selectedFileMenu: FileMenuItems; - - //Show upload process - isUploading: boolean; - - //Update default value in case that file is already given - showActionsMenu: boolean; - - //Filename which shows in input for update action - inputFilename: string; + listenToUploadedFiles?: (files: UppyFile[]) => void; - //Toggle File delete dialog, contains filename or empty string - visibleFileDelete: string; - - // The ID of the file selection menu - id: string; + id?: string; } const noop = () => { @@ -134,212 +110,164 @@ const noop = () => { * with advanced = true, provides full FileUploader with 2 extra options * otherwise provides simple drag and drop uploader */ -class FileSelectionMenu extends React.Component { - private uppy = Uppy({ - // @ts-ignore - logger: Uppy.debugLogger, - }); - - /** - * @see Uppy.upload - */ - public upload = this.uppy.upload; - - /** - * @see Uppy.reset - */ - public reset = this.uppy.reset; - - /** - * @see Uppy.cancelAll - */ - public cancelAll = this.uppy.cancelAll; - - constructor(props) { - super(props); - - this.state = { - selectedFileMenu: props.advanced ? "SELECT" : "NEW", - isUploading: false, - showActionsMenu: false, - inputFilename: props.defaultValue || "", - visibleFileDelete: "", - id: props.id, - }; - - if (props.maxFileUploadSizeBytes) { - this.uppy.setOptions({ - restrictions: { - maxFileSize: props.maxFileUploadSizeBytes, - // Restrict to 1 file if allowMultiple == false - maxNumberOfFiles: props.allowMultiple ? undefined : 1, - }, +export const FileSelectionMenu: React.FC = (props) => { + const [inputFileName, setInputFileName] = React.useState(""); + const [selectedFileMenu, setSelectedFileMenu] = React.useState(props.advanced ? "SELECT" : "NEW"); + const [showActionsMenu, setShowActionMenu] = React.useState(false); + const [uppy, setUppy] = React.useState(); + + const upload = React.useCallback(() => uppy?.upload, [uppy]); + const reset = React.useCallback(() => uppy?.reset, [uppy]); + const cancelAll = React.useCallback(() => uppy?.cancelAll, [uppy]); + + React.useEffect(() => { + props.getInstance && + props.getInstance({ + reset: reset, + upload: upload, + cancelAll: cancelAll, }); - } - this.uppy.use(XHR, { - method: "PUT", - fieldName: "file", - allowMultipleUploads: props.allowMultiple, - // Only upload one file at the same time - limit: 1, - }); - } - - componentDidMount(): void { - if (this.props.getInstance) { - this.props.getInstance({ - reset: this.reset, - upload: this.upload, - cancelAll: this.cancelAll, - }); - } - } - - handleUploadSuccess = (file: any) => { - if (this.props.onUploadSuccess) { - this.props.onUploadSuccess(file); - } - this.setState({ - inputFilename: file.name, - }); - this.toggleFileResourceChange(); - }; - - handleFileMenuChange = (value: FileMenuItems) => { - this.setState({ - selectedFileMenu: value, - }); - this.reset(); - }; + }, []); + + const handleUploadSuccess = React.useCallback( + (file: any) => { + props.onUploadSuccess && props.onUploadSuccess(file); + setInputFileName(file.name); + toggleFileResourceChange(); + }, + [props.onUploadSuccess], + ); + + const handleFileMenuChange = React.useCallback((value: FileMenuItems) => { + setSelectedFileMenu(value); + reset(); + }, []); /** * "Abort and Keep File" Handler * revert value back */ - handleDiscardChanges = () => { - const isVisible = !this.state.showActionsMenu; - if (!isVisible) { - this.handleFileNameChange(this.state.inputFilename); - } else { - // just open - this.toggleFileResourceChange(); - } - }; + const handleDiscardChanges = React.useCallback(() => { + !showActionsMenu ? handleFileNameChange(inputFileName) : toggleFileResourceChange(); + }, [showActionsMenu, inputFileName]); /** * Open/close file uploader options */ - toggleFileResourceChange = () => { - this.setState({ - showActionsMenu: !this.state.showActionsMenu, - }); - }; + const toggleFileResourceChange = React.useCallback(() => setShowActionMenu((s) => !s), []); /** * Change readonly input value * @param value */ - handleFileNameChange = (value: string) => { - this.setState({ - inputFilename: value, - }); - this.props.onChange(value); - this.toggleFileResourceChange(); - }; - - validateBeforeFileAdded = async (fileName: string): Promise => { - return await requestIfResourceExists(this.props.projectId, fileName); - }; - - render() { - const { selectedFileMenu, showActionsMenu, inputFilename } = this.state; - const { allowMultiple, advanced, defaultValue, onProgress, projectId, onChange } = this.props; - - return ( -
- {defaultValue && !showActionsMenu && ( - - } - onClick={this.toggleFileResourceChange} - /> - } - /> - - )} - {defaultValue && showActionsMenu && ( - <> -
+ + )} +
+ ); +}; diff --git a/workspace/src/app/views/shared/FileUploader/cases/UploadNewFile/UploadNewFile.tsx b/workspace/src/app/views/shared/FileUploader/cases/UploadNewFile/UploadNewFile.tsx index 997bb09fd3..2d630f30e1 100644 --- a/workspace/src/app/views/shared/FileUploader/cases/UploadNewFile/UploadNewFile.tsx +++ b/workspace/src/app/views/shared/FileUploader/cases/UploadNewFile/UploadNewFile.tsx @@ -1,7 +1,16 @@ -import { DragDrop } from "@uppy/react"; import React, { useEffect, useState } from "react"; -import Uppy, { UppyFile } from "@uppy/core"; -import { Button, Icon, Notification, Spacing } from "@eccenca/gui-elements"; +import { + Button, + Icon, + Notification, + Restrictions, + Spacing, + Uppy, + UppyFile, + XHRUploadOptions, + FileUpload, + FileUploadDragDrop, +} from "@eccenca/gui-elements"; import { useTranslation } from "react-i18next"; import { NewFileItem } from "./NewFileItem"; import { ReplacementFileItem } from "./ReplacementFileItem"; @@ -14,7 +23,11 @@ import { CLASSPREFIX as eccgui } from "@eccenca/gui-elements/src/configuration/c interface IProps { // Uppy instance - uppy: Uppy.Uppy; + getUppyInstance?: (uppy?: Uppy) => void; + // xhr upload options + xhrUploadOptions: XHRUploadOptions; + // upload restrictions + restrictions?: Restrictions; // Allow multiple file upload allowMultiple?: boolean; @@ -49,6 +62,8 @@ interface IProps { /** If uploaded files can be deleted in the same dialog. */ allowFileDeletion?: boolean; + // parent uppy? instance + uppy?: Uppy; } /** @@ -56,7 +71,6 @@ interface IProps { */ export function UploadNewFile({ projectId, - uppy, onAdded, onUploadSuccess, validateBeforeAdd, @@ -67,7 +81,12 @@ export function UploadNewFile({ listenToUploadedFiles, uploadInitialFiles, allowFileDeletion, + xhrUploadOptions, + restrictions, + getUppyInstance, + ...restProps }: IProps) { + const [uppy, setUppy] = React.useState(restProps.uppy); // contains files, which need in replacements const [onlyReplacements, setOnlyReplacements] = useState([]); @@ -115,6 +134,7 @@ export function UploadNewFile({ checkFilesSuccessfullyUploaded(); const uploadInitialFilesAsNewFiles = React.useCallback(async () => { + if (!uppy) return; const files = uppy.getFiles(); for (let i = 0; i < files.length; i++) { await uploadAsNewFile(files[i]); @@ -131,28 +151,6 @@ export function UploadNewFile({ listenToUploadedFiles?.(uploadedFiles); }, [uploadedFiles]); - // register/unregister uppy events - useEffect(() => { - const unregisterEvents = () => { - uppy.off("file-added", handleFileAdded); - uppy.off("upload-progress", handleProgress); - uppy.off("upload-success", handleUploadSuccess); - uppy.off("upload-error", handleUploadError); - uppy.off("restriction-failed", onLocalRestrictionFailed); - }; - - // reset events, because of "file-added" store prev state values - unregisterEvents(); - - uppy.on("file-added", handleFileAdded); - uppy.on("upload-progress", handleProgress); - uppy.on("upload-success", handleUploadSuccess); - uppy.on("upload-error", handleUploadError); - uppy.on("restriction-failed", onLocalRestrictionFailed); - - return unregisterEvents; - }, [onlyReplacements, uploadedFiles, filesForRetry]); - /** If a restriction failed, e.g. file size too large, this is fired. */ const onLocalRestrictionFailed = (file: UppyFile & { error?: string }, error: any) => { if (error.isRestriction && error.message) { @@ -219,6 +217,7 @@ export function UploadNewFile({ }; const uploadAsNewFile = async (file: UppyFile) => { + if (!uppy) return; await validateBeforeUploadAsync(file); const notCompletedUploads = uppy.getFiles().filter((f) => !f.progress?.uploadComplete); @@ -236,7 +235,7 @@ export function UploadNewFile({ const upload = async (files): Promise => { try { files.forEach((file) => { - uppy.setFileState(file.id, { + uppy?.setFileState(file.id, { xhrUpload: { endpoint: attachFileNameToEndpoint ? `${uploadEndpoint}?path=${encodeURIComponent(file.name)}` @@ -245,7 +244,7 @@ export function UploadNewFile({ }); }); - await uppy.upload(); + await uppy?.upload(); } catch (e) { throw new Error(e); } @@ -317,6 +316,7 @@ export function UploadNewFile({ }; const handleAbort = (fileId: string) => { + if (!uppy) return; setProgresses((prevState) => { const newState = { ...prevState, @@ -329,13 +329,14 @@ export function UploadNewFile({ }; const handleReplace = (file: UppyFile) => { - uppy.addFile({ + uppy?.addFile({ ...file, source: "REPLACE_ACTION", }); }; const handleRetry = (fileId: string) => { + if (!uppy) return; const files = filesForRetry.filter((f) => f.id === fileId); removeFromRetry(fileId); @@ -349,18 +350,19 @@ export function UploadNewFile({ }; const handleRetryAll = () => { - const files = uppy.getFiles(); + if (!uppy) return; + const files = uppy?.getFiles(); - // reset uppy if all files should retry - uppy.reset(); + // reset uppy? if all files should retry + uppy?.reset(); files.forEach(uppy.addFile); }; const removeFromUppyQueue = (fileId: string) => { - uppy.removeFile(fileId); + uppy?.removeFile(fileId); - // call force on uppy change + // call force on uppy? change forceUpdate(); }; @@ -382,24 +384,68 @@ export function UploadNewFile({ }; const setFileError = (fileId: string, error: string) => { - uppy.setFileState(fileId, { + uppy?.setFileState(fileId, { error, }); // after every file state update forceUpdate required forceUpdate(); }; + // register/unregister uppy events + useEffect(() => { + if (uppy) { + const unregisterEvents = () => { + uppy.off("file-added", handleFileAdded); + uppy.off("upload-progress", handleProgress); + uppy.off("upload-success", handleUploadSuccess); + uppy.off("upload-error", handleUploadError); + uppy.off("restriction-failed", onLocalRestrictionFailed); + }; + + // reset events, because of "file-added" store prev state values + unregisterEvents(); + + uppy.on("file-added", handleFileAdded); + uppy.on("upload-progress", handleProgress); + uppy.on("upload-success", handleUploadSuccess); + uppy.on("upload-error", handleUploadError); + uppy.on("restriction-failed", onLocalRestrictionFailed); + + return unregisterEvents; + } + }, [onlyReplacements, uploadedFiles, filesForRetry, uppy]); + + const handleSetUppyInstance = React.useCallback( + (instance: Uppy) => { + if (!instance) return; + getUppyInstance && getUppyInstance(instance); + setUppy(instance); + }, + [getUppyInstance], + ); + return (
{projectId && showDeleteDialog && ( )} - {(uploadInitialFiles?.alsoAllowOther ?? true) && ( - - )} + + {(uploadInitialFiles?.alsoAllowOther ?? true) && + (!restProps.uppy ? ( + + ) : ( + + ))} {!error ? ( @@ -415,15 +461,17 @@ export function UploadNewFile({ onCancelRetry={removeFromRetry} /> ))} - {uppy.getFiles().map((file) => ( - - ))} + {uppy + ?.getFiles() + .map((file) => ( + + ))} {onlyReplacements.map((file) => ( ({ - enableErrorModal: NOP -}) + enableErrorModal: NOP, +}); diff --git a/workspace/src/app/views/shared/RuleEditor/model/test/RuleEditorModel.test.tsx b/workspace/src/app/views/shared/RuleEditor/model/test/RuleEditorModel.test.tsx index fd5c3f2943..d3f451f2dc 100644 --- a/workspace/src/app/views/shared/RuleEditor/model/test/RuleEditorModel.test.tsx +++ b/workspace/src/app/views/shared/RuleEditor/model/test/RuleEditorModel.test.tsx @@ -39,8 +39,8 @@ describe("Rule editor model", () => { JSON.stringify( currentContext() .ruleOperatorNodes() - .sort((n1, n2) => (n1.nodeId < n2.nodeId ? -1 : 1)) - ) + .sort((n1, n2) => (n1.nodeId < n2.nodeId ? -1 : 1)), + ), ); }; // Fetch the current react-flow nodes @@ -71,9 +71,9 @@ describe("Rule editor model", () => { validateConnection: ( fromRuleOperatorNode: RuleEditorValidationNode, toRuleOperatorNode: RuleEditorValidationNode, - targetPortIdx: number + targetPortIdx: number, ) => boolean = () => true, - stickyNotes: StickyNote[] = [] + stickyNotes: StickyNote[] = [], ) => { modelContext = undefined; const ruleModel = withMount( @@ -104,8 +104,8 @@ describe("Rule editor model", () => { - - ) + , + ), ); await waitFor(() => { expect(modelContext).toBeTruthy(); @@ -218,7 +218,7 @@ describe("Rule editor model", () => { const allStickyNodes = () => currentContext().elements.filter( - (elem) => elem.type === LINKING_NODE_TYPES.stickynote && modelUtils.isNode(elem) + (elem) => elem.type === LINKING_NODE_TYPES.stickynote && modelUtils.isNode(elem), ); /** Test UNDO and REDO behavior. The last check is always the current state. Each check before tests the states @@ -262,7 +262,7 @@ describe("Rule editor model", () => { node({ nodeId: "node A", portSpecification: { minInputPorts: 0 } }), node({ nodeId: "node B", inputs: ["node A"] }), ], - [operator("pluginA", 0)] + [operator("pluginA", 0)], ); // 2 nodes and 1 edge await waitFor(async () => { @@ -275,14 +275,14 @@ describe("Rule editor model", () => { it("should add new nodes and undo & redo", async () => { await ruleEditorModel( [node({ nodeId: "pluginA" }), node({ nodeId: "node B", inputs: ["pluginA"] })], - [operator("pluginA")] + [operator("pluginA")], ); const checkBeforeAdd = () => { expect(currentContext().elements).toHaveLength(3); expect( currentContext() .elements.map((e) => e.id) - .sort((left, right) => (left < right ? 1 : -1)) + .sort((left, right) => (left < right ? 1 : -1)), ).toStrictEqual(["pluginA", "node B", "1"]); }; checkBeforeAdd(); @@ -301,10 +301,10 @@ describe("Rule editor model", () => { expect( currentContext() .ruleOperatorNodes() - .map((node) => node.nodeId) + .map((node) => node.nodeId), ).toStrictEqual(["pluginA", "node B", "pluginA_2", "pluginA_3"]); expect( - modelUtils.asNode(currentContext().elements.find((n) => n.id === "pluginA_2"))!!.position + modelUtils.asNode(currentContext().elements.find((n) => n.id === "pluginA_2"))!!.position, ).toStrictEqual(position); expect(currentContext().ruleOperatorNodes()[2].position).toStrictEqual(position); }; @@ -329,7 +329,7 @@ describe("Rule editor model", () => { const checkAfterChange = () => { expect(modelUtils.nodeById(currentContext().elements, node.id)!!.data.style).not.toStrictEqual( - defaultStyle + defaultStyle, ); }; act(() => { @@ -351,7 +351,7 @@ describe("Rule editor model", () => { const newContent = "**new Content**"; const checkAfterChange = () => { expect(modelUtils.nodeById(currentContext().elements, node.id)!!.data.businessData.stickyNote).toEqual( - newContent + newContent, ); }; act(() => { @@ -373,7 +373,7 @@ describe("Rule editor model", () => { const randomNewNodeDimensions = { width: DEFAULT_NODE_WIDTH + 30, height: DEFAULT_NODE_HEIGHT + 10 }; const checkAfterChange = () => { expect(modelUtils.nodeById(currentContext().elements, node.id)!!.data.nodeDimensions).toEqual( - randomNewNodeDimensions + randomNewNodeDimensions, ); }; act(() => { @@ -391,7 +391,7 @@ describe("Rule editor model", () => { node({ nodeId: "nodeB", inputs: ["nodeA"] }), node({ nodeId: "nodeC", inputs: ["nodeA", "nodeB"] }), ], - [operator("pluginA")] + [operator("pluginA")], ); const checkBeforeDelete = () => { // 3 nodes, 3 edges @@ -410,7 +410,7 @@ describe("Rule editor model", () => { expect( currentContext() .ruleOperatorNodes() - .map((node) => node.nodeId) + .map((node) => node.nodeId), ).toStrictEqual(["nodeB", "nodeC"]); }; checkAfterDelete(); @@ -504,11 +504,11 @@ describe("Rule editor model", () => { node({ nodeId: "nodeB", inputs: ["nodeA"], position: { x: 2, y: 3 } }), node({ nodeId: "nodeC", position: { x: 3, y: 4 } }), ], - [operator("pluginA")] + [operator("pluginA")], ); const checkPositions = (data: [string, number, number][]) => { expect(currentOperatorNodes().map((n) => ({ pos: n.position, id: n.nodeId }))).toStrictEqual( - data.map((d) => ({ id: `node${d[0]}`, pos: { x: d[1], y: d[2] } })) + data.map((d) => ({ id: `node${d[0]}`, pos: { x: d[1], y: d[2] } })), ); }; const beforeUpdateCheck = () => { @@ -605,7 +605,7 @@ describe("Rule editor model", () => { }, }), ], - [operator("pluginA")] + [operator("pluginA")], ); act(() => { // Need to run this in separate act, since moveNode runs async @@ -626,7 +626,7 @@ describe("Rule editor model", () => { node({ nodeId: "nodeB", inputs: ["nodeA"] }), node({ nodeId: "nodeC", inputs: ["nodeA", "nodeB"] }), ], - [operator("pluginA")] + [operator("pluginA")], ); const checkBeforeDelete = () => { expect(currentContext().elements).toHaveLength(6); @@ -663,7 +663,7 @@ describe("Rule editor model", () => { // 2 nodes and 1 edge added expect(currentContext().elements).toHaveLength(9); expect(new Set(currentOperatorNodes().map((op) => op.nodeId)).size).toBe( - currentContext().ruleOperatorNodes().length + currentContext().ruleOperatorNodes().length, ); }; checkAfterCopyAndPaste(); @@ -677,7 +677,7 @@ describe("Rule editor model", () => { // 2 nodes and 1 edge added expect(currentContext().elements).toHaveLength(12); expect(new Set(currentOperatorNodes().map((op) => op.nodeId)).size).toBe( - currentContext().ruleOperatorNodes().length + currentContext().ruleOperatorNodes().length, ); }; checkAfterCopyAndPaste2nd(); @@ -714,7 +714,7 @@ describe("Rule editor model", () => { node({ nodeId: "nodeC", inputs: ["nodeA", "nodeB"] }), ]); const edge = currentContext().elements.find( - (elem) => modelUtils.isEdge(elem) && modelUtils.asEdge(elem)!!.target === "nodeB" + (elem) => modelUtils.isEdge(elem) && modelUtils.asEdge(elem)!!.target === "nodeB", ); const before = currentContext().elements.length; const checkBeforeDelete = () => { @@ -754,7 +754,7 @@ describe("Rule editor model", () => { const recordedTransaction = async ( stateLabel: string, changeAction: () => any, - additionalCheck: () => any | Promise = () => {} + additionalCheck: () => any | Promise = () => {}, ) => { act(() => { currentContext().executeModelEditOperation.startChangeTransaction(); @@ -791,7 +791,7 @@ describe("Rule editor model", () => { await waitFor(() => { expect(allNodes()).not.toStrictEqual(stateHistory[stateHistory.length - 1]); }); - } + }, ); await recordedTransaction("Change node parameter", () => { currentContext().executeModelEditOperation.changeNodeParameter("nodeA", "param A", "new param value"); @@ -827,7 +827,7 @@ describe("Rule editor model", () => { currentContext().executeModelEditOperation.changeStickyNodeProperties( "sticky", "#ffee12", - "another sticky note" + "another sticky note", ); }); @@ -976,13 +976,13 @@ describe("Rule editor model", () => { execute().deleteEdges( modelUtils .findEdges({ elements: currentContext().elements, source: "inputNode5", target: "nodeE" }) - .map((e) => e.id) + .map((e) => e.id), ); // This should reduce the number of inputs, since the last connection was removed. execute().deleteEdges( modelUtils .findEdges({ elements: currentContext().elements, source: "inputNode8", target: "nodeF" }) - .map((e) => e.id) + .map((e) => e.id), ); }); const checkAfterChange = () => { diff --git a/workspace/src/app/views/shared/RuleEditor/view/RuleEditorNotifications.tsx b/workspace/src/app/views/shared/RuleEditor/view/RuleEditorNotifications.tsx index 4ac7df3ef5..33e9c38855 100644 --- a/workspace/src/app/views/shared/RuleEditor/view/RuleEditorNotifications.tsx +++ b/workspace/src/app/views/shared/RuleEditor/view/RuleEditorNotifications.tsx @@ -28,19 +28,19 @@ export const RuleEditorNotifications = ({ const ruleEditorErrorMessages = messages.filter((diError) => diError.timestamp > generalNotificationMinDateTime); useEffect(() => { - if(ruleEditorErrorMessages.length && !ruleEditorErrorMessages[0]?.notAutoOpen) { + if (ruleEditorErrorMessages.length && !ruleEditorErrorMessages[0]?.notAutoOpen) { setIsOpen(true); } }, [ruleEditorErrorMessages.length > 0 ? ruleEditorErrorMessages[0] : undefined]); useEffect(() => { - if(queueEditorNotifications.length) { + if (queueEditorNotifications.length) { setIsOpen(true); } }, [queueEditorNotifications.length > 0 ? queueEditorNotifications[0] : undefined]); useEffect(() => { - if(queueNodeNotifications.length) { + if (queueNodeNotifications.length) { setIsOpen(true); } }, [queueNodeNotifications.length > 0 ? queueNodeNotifications[0] : undefined]); diff --git a/workspace/src/app/views/shared/RuleEditor/view/ruleNode/PathInputOperator.tsx b/workspace/src/app/views/shared/RuleEditor/view/ruleNode/PathInputOperator.tsx index 988dd0e234..424b802209 100644 --- a/workspace/src/app/views/shared/RuleEditor/view/ruleNode/PathInputOperator.tsx +++ b/workspace/src/app/views/shared/RuleEditor/view/ruleNode/PathInputOperator.tsx @@ -274,14 +274,14 @@ const LanguageSwitcherContext = React.createContext { +const LanguageSwitcher = ({ onLanguageChange, initialLanguage }: LanguageSwitcherProps) => { const [t] = useTranslation(); const [languageFilter, setLanguageFilter] = React.useState(initialLanguage); const currentLanguageFilter = React.useRef(); currentLanguageFilter.current = languageFilter; const context = React.useContext(LanguageSwitcherContext); - return context.showLanguageFilterButton ? + return context.showLanguageFilterButton ? ( inputProps={{ id: "language-filter-input", @@ -310,7 +310,7 @@ const LanguageSwitcher = ({onLanguageChange, initialLanguage}: LanguageSwitcherP ); } }} - itemRenderer={(lang, {handleClick, modifiers}) => { + itemRenderer={(lang, { handleClick, modifiers }) => { return lang === NO_LANG ? ( currentLanguageFilter.current ? ( )} - : - null + + ) : null; }; /** Extract the last property of the path that is not in a filter. */ diff --git a/workspace/src/app/views/shared/modals/CloneModal.tsx b/workspace/src/app/views/shared/modals/CloneModal.tsx index 5251320ee2..77b59abfe1 100644 --- a/workspace/src/app/views/shared/modals/CloneModal.tsx +++ b/workspace/src/app/views/shared/modals/CloneModal.tsx @@ -1,4 +1,4 @@ -import React, {KeyboardEventHandler, useEffect, useState} from "react"; +import React, { KeyboardEventHandler, useEffect, useState } from "react"; import { Button, FieldItem, @@ -7,17 +7,17 @@ import { SimpleDialog, Spacing, Spinner, - TextField + TextField, } from "@eccenca/gui-elements"; -import {ErrorResponse, FetchError} from "../../../services/fetch/responseInterceptor"; -import {requestCloneProject, requestCloneTask} from "@ducks/workspace/requests"; -import {requestProjectMetadata, requestTaskMetadata} from "@ducks/shared/requests"; -import {useTranslation} from "react-i18next"; -import {IModalItem} from "@ducks/shared/typings"; +import { ErrorResponse, FetchError } from "../../../services/fetch/responseInterceptor"; +import { requestCloneProject, requestCloneTask } from "@ducks/workspace/requests"; +import { requestProjectMetadata, requestTaskMetadata } from "@ducks/shared/requests"; +import { useTranslation } from "react-i18next"; +import { IModalItem } from "@ducks/shared/typings"; import useHotKey from "../HotKeyHandler/HotKeyHandler"; -import {requestProjectIdValidation, requestTaskIdValidation} from "@ducks/common/requests"; -import {debounce} from "lodash"; -import {TaskDocumentationModal} from "./CreateArtefactModal/TaskDocumentationModal"; +import { requestProjectIdValidation, requestTaskIdValidation } from "@ducks/common/requests"; +import { debounce } from "lodash"; +import { TaskDocumentationModal } from "./CreateArtefactModal/TaskDocumentationModal"; export interface ICloneOptions { item: IModalItem; @@ -137,7 +137,8 @@ export default function CloneModal({ item, onDiscard, onConfirmed }: ICloneOptio [item, description, newLabel, customId], ); - return - {initialLoading ? - : + {initialLoading ? ( + + ) : ( setNewLabel(e.target.value)} value={newLabel} autoFocus={true} /> - } + )} )} + ); } diff --git a/workspace/src/app/views/shared/modals/CopyToModal/CopyToModal.tsx b/workspace/src/app/views/shared/modals/CopyToModal/CopyToModal.tsx index 5f07c6f162..ccbe96197d 100644 --- a/workspace/src/app/views/shared/modals/CopyToModal/CopyToModal.tsx +++ b/workspace/src/app/views/shared/modals/CopyToModal/CopyToModal.tsx @@ -20,13 +20,13 @@ import { TitleSubsection, Tooltip, } from "@eccenca/gui-elements"; -import {ICloneOptions} from "../CloneModal"; -import {useTranslation} from "react-i18next"; -import {requestProjectMetadata, requestTaskMetadata} from "@ducks/shared/requests"; -import {requestCopyProject, requestCopyTask, requestSearchList} from "@ducks/workspace/requests"; +import { ICloneOptions } from "../CloneModal"; +import { useTranslation } from "react-i18next"; +import { requestProjectMetadata, requestTaskMetadata } from "@ducks/shared/requests"; +import { requestCopyProject, requestCopyTask, requestSearchList } from "@ducks/workspace/requests"; import ItemDepiction from "../../ItemDepiction"; -import {ErrorResponse} from "../../../../services/fetch/responseInterceptor"; -import {useModalError} from "../../../../hooks/useModalError"; +import { ErrorResponse } from "../../../../services/fetch/responseInterceptor"; +import { useModalError } from "../../../../hooks/useModalError"; //Component Interface interface CopyToModalProps extends ICloneOptions { diff --git a/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/InputMapper.tsx b/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/InputMapper.tsx index 593d6eefbb..8edd8ee3b0 100644 --- a/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/InputMapper.tsx +++ b/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/InputMapper.tsx @@ -3,7 +3,7 @@ import { INPUT_TYPES } from "../../../../../constants"; import { CodeEditor, Spinner, Switch, TextField } from "@eccenca/gui-elements"; import { ITaskParameter } from "@ducks/common/typings"; import { IntentTypes as Intent } from "@eccenca/gui-elements/src/common/Intent"; -import FileSelectionMenu from "../../../FileUploader/FileSelectionMenu"; +import { FileSelectionMenu } from "../../../FileUploader/FileSelectionMenu"; import { requestResourcesList } from "@ducks/shared/requests"; import { defaultValueAsJs, stringValueAsJs } from "../../../../../utils/transformers"; import { useSelector } from "react-redux"; @@ -157,6 +157,7 @@ export function InputMapper({ return ( "", }, }} allowMultiple={false} diff --git a/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/ParameterAutoCompletion.tsx b/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/ParameterAutoCompletion.tsx index 9249f72218..eb5de097d6 100644 --- a/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/ParameterAutoCompletion.tsx +++ b/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/ParameterAutoCompletion.tsx @@ -74,7 +74,6 @@ type StringOrReifiedValue = IAutocompleteDefaultResponse | string; const AUTOCOMPLETION_LIMIT = 100; - /** Component for parameter auto-completion. */ export const ParameterAutoCompletion = ({ paramId, diff --git a/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/TaskForm.tsx b/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/TaskForm.tsx index 8d32ab344c..f462d97e60 100644 --- a/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/TaskForm.tsx +++ b/workspace/src/app/views/shared/modals/CreateArtefactModal/ArtefactForms/TaskForm.tsx @@ -24,7 +24,7 @@ import useHotKey from "../../../HotKeyHandler/HotKeyHandler"; import utils from "@eccenca/gui-elements/src/cmem/markdown/markdown.utils"; import { commonOp } from "@ducks/common"; import { DependsOnParameterValueAny } from "./ParameterAutoCompletion"; -import {FieldValues, FormContextValues} from "react-hook-form"; +import { FieldValues, FormContextValues } from "react-hook-form"; export const READ_ONLY_PARAMETER = "readOnly"; @@ -128,7 +128,7 @@ export function TaskForm({ goBackOnEscape = () => {}, newTaskPreConfiguration, propagateExternallyChangedParameterValue, - showWarningMessage + showWarningMessage, }: IProps) { const { properties, required: requiredRootParameters } = artefact; const { register, errors, getValues, setValue, unregister, triggerValidation } = form; @@ -400,11 +400,11 @@ export function TaskForm({ // collect all dependent parameters const dependentParametersTransitiveSet = new Set(); // Dependent parameters that were actually reset - const resetDependentParameters: string[] = [] + const resetDependentParameters: string[] = []; const collect = (currentParamId: string) => { const params = dependentParameters.current?.get(currentParamId) ?? []; params.forEach((p: string) => { - if(!dependentParametersTransitiveSet.has(p)) { + if (!dependentParametersTransitiveSet.has(p)) { dependentParametersTransitiveSet.add(p); collect(p); } @@ -412,18 +412,20 @@ export function TaskForm({ }; collect(key); dependentParametersTransitiveSet.forEach((paramId) => { - const currentValue = getValues(paramId) - if(currentValue && paramId !== key) { - resetDependentParameters.push(parameterLabels.current.get(paramId) ?? paramId) + const currentValue = getValues(paramId); + if (currentValue && paramId !== key) { + resetDependentParameters.push(parameterLabels.current.get(paramId) ?? paramId); handleChange(paramId)(""); propagateExternallyChangedParameterValue(paramId, ""); } }); - if(resetDependentParameters.length) { - showWarningMessage(t("form.taskForm.resetMessage", { - parameters: resetDependentParameters.join(", "), - dependOn: parameterLabels.current.get(key) ?? key - })) + if (resetDependentParameters.length) { + showWarningMessage( + t("form.taskForm.resetMessage", { + parameters: resetDependentParameters.join(", "), + dependOn: parameterLabels.current.get(key) ?? key, + }), + ); } } }, diff --git a/workspace/src/app/views/shared/modals/CreateArtefactModal/CreateArtefactModal.tsx b/workspace/src/app/views/shared/modals/CreateArtefactModal/CreateArtefactModal.tsx index 9e0099e62a..9d2914d5bb 100644 --- a/workspace/src/app/views/shared/modals/CreateArtefactModal/CreateArtefactModal.tsx +++ b/workspace/src/app/views/shared/modals/CreateArtefactModal/CreateArtefactModal.tsx @@ -157,14 +157,14 @@ export function CreateArtefactModal() { const [taskActionResult, setTaskActionResult] = React.useState<{ label: string; message: string }>(); const [taskActionLoading, setTaskActionLoading] = React.useState(null); const [taskFormGeneralWarning, setTaskFormGeneralWarning] = React.useState(); - const generalWarningTimeout = React.useRef() + const generalWarningTimeout = React.useRef(); const taskFormWarning = React.useCallback((message: string) => { - if(generalWarningTimeout.current) { - clearTimeout(generalWarningTimeout.current) + if (generalWarningTimeout.current) { + clearTimeout(generalWarningTimeout.current); } - generalWarningTimeout.current = window.setTimeout(() => setTaskFormGeneralWarning(message), 250) - }, []) + generalWarningTimeout.current = window.setTimeout(() => setTaskFormGeneralWarning(message), 250); + }, []); React.useEffect(() => { if (infoMessage?.removeAfterSeconds && infoMessage.removeAfterSeconds > 0) { @@ -946,12 +946,9 @@ export function CreateArtefactModal() { ); } - if(taskFormGeneralWarning) { + if (taskFormGeneralWarning) { notifications.push( - setTaskFormGeneralWarning(undefined)} - />, + setTaskFormGeneralWarning(undefined)} />, ); } diff --git a/workspace/src/app/views/shared/modals/FileUploadModal/FileUploadModal.tsx b/workspace/src/app/views/shared/modals/FileUploadModal/FileUploadModal.tsx index 745e532197..0cbbc0f2a3 100644 --- a/workspace/src/app/views/shared/modals/FileUploadModal/FileUploadModal.tsx +++ b/workspace/src/app/views/shared/modals/FileUploadModal/FileUploadModal.tsx @@ -25,7 +25,7 @@ export function FileUploadModal({ isOpen, onDiscard, uploaderOptions = {} }: IFi const [t] = useTranslation(); useDebugValue(!projectId ? "Project ID not provided and upload url is not valid" : ""); - + if (!projectId) { return null; } @@ -49,8 +49,15 @@ export function FileUploadModal({ isOpen, onDiscard, uploaderOptions = {} }: IFi onClose={handleDiscard} preventSimpleClosing={isUploading} actions={ - } > @@ -64,6 +71,7 @@ export function FileUploadModal({ isOpen, onDiscard, uploaderOptions = {} }: IFi }} onProgress={(amount) => setIsUploading(amount > 0 && amount < 1)} // between 0 and 1 maxFileUploadSizeBytes={maxFileUploadSize} + t={t} /> diff --git a/workspace/src/app/views/shared/modals/ProjectImportModal.tsx b/workspace/src/app/views/shared/modals/ProjectImportModal.tsx index 9be6b89cee..a177247959 100644 --- a/workspace/src/app/views/shared/modals/ProjectImportModal.tsx +++ b/workspace/src/app/views/shared/modals/ProjectImportModal.tsx @@ -14,11 +14,11 @@ import { TitleSubsection, Markdown, StringPreviewContentBlobToggler, + Uppy, + UppyFile, } from "@eccenca/gui-elements"; import { useTranslation } from "react-i18next"; -import Uppy, { UppyFile } from "@uppy/core"; import { workspaceApi } from "../../../utils/getApiEndpoint"; -import XHR from "@uppy/xhr-upload"; import { requestDeleteProjectImport, requestProjectImportDetails, @@ -43,7 +43,7 @@ interface IProps { export function ProjectImportModal({ close, back, maxFileUploadSizeBytes }: IProps) { const [t] = useTranslation(); - const [uppy] = useState(Uppy()); + const [uppy, setUppy] = useState(); const dispatch = useDispatch(); const [loading, setLoading] = useState(false); const [projectImportId, setProjectImportId] = useState(null); @@ -58,25 +58,6 @@ export function ProjectImportModal({ close, back, maxFileUploadSizeBytes }: IPro [string, boolean, boolean] | null >(null); - useEffect(() => { - uppy.use(XHR, { - method: "POST", - fieldName: "file", - metaFields: [], - }); - uppy.getPlugin("XHRUpload").setOptions({ - endpoint: workspaceApi(`/projectImport`), - }); - - if (maxFileUploadSizeBytes) { - uppy.setOptions({ - restrictions: { - maxFileSize: maxFileUploadSizeBytes, - }, - }); - } - }, []); - useEffect(() => { if (projectImportId) { loadProjectImportDetails(projectImportId); @@ -122,7 +103,7 @@ export function ProjectImportModal({ close, back, maxFileUploadSizeBytes }: IPro const handleFileAdded = async () => { setUploadError(null); - await uppy.upload(); + await uppy?.upload(); }; const startProjectImport = async (generateNewProjectId: boolean, overWriteExistingProject: boolean) => { @@ -191,10 +172,15 @@ export function ProjectImportModal({ close, back, maxFileUploadSizeBytes }: IPro details: details, }), ); - uppy.reset(); + uppy?.reset(); }; + const onUploadSuccess = (file: UppyFile, response) => { - const projectImportId = response?.body?.projectImportId; + const projectImportId = + typeof response?.body === "string" + ? JSON.parse(response.body)?.projectImportId + : response?.body?.projectImportId; + if (projectImportId) { setProjectImportId(projectImportId); } else { @@ -204,12 +190,28 @@ export function ProjectImportModal({ close, back, maxFileUploadSizeBytes }: IPro "Invalid response received from project upload. Project import cannot proceed.", ), ); - uppy.reset(); + uppy?.reset(); } }; + + const restrictions = { + restrictions: maxFileUploadSizeBytes + ? { + maxFileSize: maxFileUploadSizeBytes, + } + : {}, + }; + const uploader = ( > => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}/pathCacheValue/${which}`), @@ -28,7 +28,7 @@ export const fetchLinkSpec = ( projectId: string, linkingTaskId: string, withLabels: boolean, - langPref: string = "en" + langPref: string = "en", ): Promise>> => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}`), @@ -43,7 +43,7 @@ export const fetchLinkSpec = ( export const updateLinkageRule = ( projectId: string, linkingTaskId: string, - linkingRule: ILinkingRule + linkingRule: ILinkingRule, ): Promise> => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}/rule`), @@ -57,7 +57,7 @@ export const evaluateLinkingRuleAgainstReferenceEntities = ( projectId: string, linkingTaskId: string, linkingRule: ILinkingRule, - linkLimit: number = 100 + linkLimit: number = 100, ): Promise> => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}/referenceLinksEvaluated`), @@ -78,7 +78,7 @@ export const evaluateLinkingRuleAgainstReferenceEntities = ( export const referenceLinksEvaluated = ( projectId: string, linkingTaskId: string, - withEntitiesAndSchema: boolean + withEntitiesAndSchema: boolean, ): Promise> => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}/referenceLinksEvaluated`), @@ -94,7 +94,7 @@ export const evaluateLinkingRule = ( linkingTaskId: string, linkingRule: ILinkingRule, linkLimit: number = 100, - timeoutInMs: number = 30000 + timeoutInMs: number = 30000, ): Promise> => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}/evaluateLinkageRule`), @@ -120,7 +120,7 @@ export const autoCompleteLinkingInputPaths = ( linkingTaskId: string, inputType: "source" | "target", searchQuery: string, - limit: number + limit: number, ): Promise> => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}/completions/inputPaths`), @@ -150,7 +150,7 @@ export const partialAutoCompleteLinkingInputPaths = ( inputString: string, cursorPosition: number, limit?: number, - langPref?: string + langPref?: string, ): Promise> => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}/completions/partialSourcePaths`), @@ -162,7 +162,7 @@ export const partialAutoCompleteLinkingInputPaths = ( inputString, cursorPosition, maxSuggestions: limit, - langPref + langPref, }, }); }; @@ -172,7 +172,7 @@ export const addPathToReferenceEntitiesCache = ( projectId: string, linkingTaskId: string, path: string, - toTarget: boolean + toTarget: boolean, ): Promise> => { return fetch({ url: legacyLinkingEndpoint(`/tasks/${projectId}/${linkingTaskId}/referenceEntitiesCache/path`), diff --git a/workspace/src/app/views/taskViews/linking/LinkingRuleEditor.tsx b/workspace/src/app/views/taskViews/linking/LinkingRuleEditor.tsx index bb68197479..14bd8f0b60 100644 --- a/workspace/src/app/views/taskViews/linking/LinkingRuleEditor.tsx +++ b/workspace/src/app/views/taskViews/linking/LinkingRuleEditor.tsx @@ -38,7 +38,7 @@ import { invalidValueResult } from "../../../views/shared/RuleEditor/view/ruleNo import { diErrorMessage } from "@ducks/error/typings"; import { Notification, highlighterUtils, StickyNote } from "@eccenca/gui-elements"; import { IPartialAutoCompleteResult } from "@eccenca/gui-elements/src/components/AutoSuggestion/AutoSuggestion"; -import {languageFilterRegex, PathInputOperatorContext} from "../../shared/RuleEditor/view/ruleNode/PathInputOperator"; +import { languageFilterRegex, PathInputOperatorContext } from "../../shared/RuleEditor/view/ruleNode/PathInputOperator"; export interface LinkingRuleEditorProps { /** Project ID the task is in. */ @@ -75,15 +75,15 @@ export const LinkingRuleEditor = ({ projectId, linkingTaskId, viewActions, insta const [t] = useTranslation(); const { registerError } = useErrorHandler(); const prefLang = useSelector(commonSel.localeSelector); - const langPref = React.useRef(prefLang) - langPref.current = prefLang + const langPref = React.useRef(prefLang); + langPref.current = prefLang; // Meta data and label data structures for input paths const sourcePathMetaData = React.useRef([]); const sourcePathLabels = React.useRef>(new Map()); const targetPathMetaData = React.useRef([]); const targetPathLabels = React.useRef>(new Map()); // In which language the path labels are available - const [pathLabelsAvailableForLang, setPathLabelsAvailableForLang] = React.useState() + const [pathLabelsAvailableForLang, setPathLabelsAvailableForLang] = React.useState(); const [loading, setLoading] = React.useState(true); const [initError, setInitError] = React.useState(undefined); const pendingRequests = React.useRef(2); @@ -94,7 +94,7 @@ export const LinkingRuleEditor = ({ projectId, linkingTaskId, viewActions, insta const optionalContext = React.useContext(LinkingRuleEditorOptionalContext); React.useEffect(() => { - fetchAllPaths() + fetchAllPaths(); }, [projectId, linkingTaskId, prefLang]); const reducePendingRequestCount = () => { @@ -146,8 +146,8 @@ export const LinkingRuleEditor = ({ projectId, linkingTaskId, viewActions, insta const fetchAllPaths = async () => { await fetchPaths("source"); await fetchPaths("target"); - setPathLabelsAvailableForLang(prefLang) - } + setPathLabelsAvailableForLang(prefLang); + }; /** Fetches the parameters of the linking task */ const fetchTaskData = async (projectId: string, taskId: string) => { @@ -342,7 +342,7 @@ export const LinkingRuleEditor = ({ projectId, linkingTaskId, viewActions, insta inputString, cursorPosition, 200, - langPref.current + langPref.current, ); return result.data; } catch (err) { @@ -444,57 +444,65 @@ export const LinkingRuleEditor = ({ projectId, linkingTaskId, viewActions, insta return ; } - return - - , IPluginDetails> + { - switch (pluginDetails.pluginType) { - case "ComparisonOperator": - return pluginDetails.distanceMeasureRange === "boolean" - ? [["weight", weightParameterSpec]] - : [ - ["threshold", thresholdParameterSpec(pluginDetails)], - ["weight", weightParameterSpec], - ]; - case "AggregationOperator": - return [["weight", weightParameterSpec]]; - default: - return []; - } - }} - validateConnection={ruleUtils.validateConnection} - tabs={tabs} - additionalToolBarComponents={() => [ - , - ]} - showRuleOnly={!!optionalContext.showRuleOnly} - hideMinimap={!!optionalContext.hideMinimap} - zoomRange={optionalContext.zoomRange ?? [0.25, 1.5]} - initialFitToViewZoomLevel={optionalContext.initialFitToViewZoomLevel} - instanceId={instanceId} - fetchDatasetCharacteristics={fetchDatasetCharacteristics} - pathMetaData={{ - inputPathPluginPathType, - inputPathLabel, - }} - /> - - ; + linkingTaskId={linkingTaskId} + numberOfLinkToShow={NUMBER_OF_LINKS_TO_SHOW} + > + , IPluginDetails> + projectId={projectId} + taskId={linkingTaskId} + fetchRuleData={fetchTaskData} + fetchRuleOperators={fetchLinkingRuleOperatorDetails} + partialAutoCompletion={fetchPartialAutoCompletionResult} + saveRule={saveLinkageRule} + getStickyNotes={utils.getStickyNotes} + convertRuleOperator={ruleUtils.convertRuleOperator} + viewActions={viewActions} + convertToRuleOperatorNodes={utils.convertLinkingTaskToRuleOperatorNodes} + additionalRuleOperators={[sourcePathInput(), targetPathInput()]} + addAdditionParameterSpecifications={(pluginDetails) => { + switch (pluginDetails.pluginType) { + case "ComparisonOperator": + return pluginDetails.distanceMeasureRange === "boolean" + ? [["weight", weightParameterSpec]] + : [ + ["threshold", thresholdParameterSpec(pluginDetails)], + ["weight", weightParameterSpec], + ]; + case "AggregationOperator": + return [["weight", weightParameterSpec]]; + default: + return []; + } + }} + validateConnection={ruleUtils.validateConnection} + tabs={tabs} + additionalToolBarComponents={() => [ + , + ]} + showRuleOnly={!!optionalContext.showRuleOnly} + hideMinimap={!!optionalContext.hideMinimap} + zoomRange={optionalContext.zoomRange ?? [0.25, 1.5]} + initialFitToViewZoomLevel={optionalContext.initialFitToViewZoomLevel} + instanceId={instanceId} + fetchDatasetCharacteristics={fetchDatasetCharacteristics} + pathMetaData={{ + inputPathPluginPathType, + inputPathLabel, + }} + /> + + + ); }; diff --git a/workspace/src/app/views/taskViews/linking/evaluation/LinkRuleNodeEvaluation.tsx b/workspace/src/app/views/taskViews/linking/evaluation/LinkRuleNodeEvaluation.tsx index e21d4ff744..c74d38e562 100644 --- a/workspace/src/app/views/taskViews/linking/evaluation/LinkRuleNodeEvaluation.tsx +++ b/workspace/src/app/views/taskViews/linking/evaluation/LinkRuleNodeEvaluation.tsx @@ -21,7 +21,7 @@ interface LinkRuleNodeEvaluationProps { /** Register for evaluation updates. */ registerForEvaluationResults: ( ruleOperatorId: string, - evaluationUpdate: (evaluationValues: EvaluationResultType | undefined) => void + evaluationUpdate: (evaluationValues: EvaluationResultType | undefined) => void, ) => void; unregister: () => void; /** A URL to link to when there is no result found. */ @@ -81,7 +81,7 @@ export const LinkRuleNodeEvaluation = ({ {error ? ( - + {error.error} diff --git a/workspace/src/app/views/taskViews/linking/evaluation/LinkingRuleEvaluation.tsx b/workspace/src/app/views/taskViews/linking/evaluation/LinkingRuleEvaluation.tsx index 2cef7c8fb9..419dc2a298 100644 --- a/workspace/src/app/views/taskViews/linking/evaluation/LinkingRuleEvaluation.tsx +++ b/workspace/src/app/views/taskViews/linking/evaluation/LinkingRuleEvaluation.tsx @@ -1,7 +1,7 @@ /** Component that handles the linking rule (inline) evaluation. */ import { RuleEditorEvaluationCallbackContext, - RuleEditorEvaluationContext + RuleEditorEvaluationContext, } from "../../../shared/RuleEditor/contexts/RuleEditorEvaluationContext"; import React, { ReactElement } from "react"; import { @@ -31,7 +31,7 @@ import { ruleEditorNodeParameterValue } from "../../../shared/RuleEditor/model/R import { PathNotInCacheModal } from "../../shared/evaluations/PathNotInCacheModal"; import evaluationUtils from "../../shared/evaluations/evaluationOperations"; import { SampleError } from "../../../shared/SampleError/SampleError"; -import {DIErrorTypes} from "@ducks/error/typings"; +import { DIErrorTypes } from "@ducks/error/typings"; type EvaluationChildType = ReactElement, IPluginDetails>>; @@ -66,15 +66,15 @@ export const LinkingRuleEvaluation = ({ const [evaluationScore, setEvaluationScore] = React.useState(undefined); const [evaluatesQuickly, setEvaluatesQuickly] = React.useState(false); const [nodeUpdateCallbacks] = React.useState( - new Map any>() + new Map any>(), ); const [referenceLinksUrl, setReferenceLinksUrl] = React.useState(undefined); const [evaluationResultsShown, setEvaluationResultsShown] = React.useState(false); const [ruleValidationError, setRuleValidationError] = React.useState(undefined); const [evaluatedRuleOperatorIds, setEvaluatedRuleOperatorIds] = React.useState([]); const [errorModalEnabled, setErrorModalEnabled] = React.useState(true); - const popupErrorsEnabled = React.useRef(true) - popupErrorsEnabled.current = errorModalEnabled + const popupErrorsEnabled = React.useRef(true); + popupErrorsEnabled.current = errorModalEnabled; // The root node of the sub-tree that will be evaluated const evaluatedSubTreeNode = React.useRef(); @@ -89,9 +89,9 @@ export const LinkingRuleEvaluation = ({ const registerError = (errorKey: string, error: DIErrorTypes) => { _registerError(errorKey, t(errorKey), error, { errorNotificationInstanceId: RULE_EDITOR_NOTIFICATION_INSTANCE, - notAutoOpen: !popupErrorsEnabled.current - }) - } + notAutoOpen: !popupErrorsEnabled.current, + }); + }; const clearRuleValidationErrors = () => { setRuleValidationError(undefined); @@ -99,8 +99,8 @@ export const LinkingRuleEvaluation = ({ }; const enableErrorModal = React.useCallback((enable: boolean) => { - setErrorModalEnabled(enable) - }, []) + setErrorModalEnabled(enable); + }, []); React.useEffect(() => { setEvaluationResult([]); @@ -135,7 +135,7 @@ export const LinkingRuleEvaluation = ({ updateCallback( !evaluatedRuleOperatorIds.includes(ruleOperatorId) ? undefined - : evaluationResultMap.get(ruleOperatorId) + : evaluationResultMap.get(ruleOperatorId), ); }); } else { @@ -149,14 +149,14 @@ export const LinkingRuleEvaluation = ({ const clearEntities = () => evaluationResultEntities.splice(0, evaluationResultEntities.length); const fetchReferenceLinksEvaluation: ( - linkageRule: ILinkingRule + linkageRule: ILinkingRule, ) => Promise = async (linkageRule: ILinkingRule) => { try { const result = await evaluateLinkingRuleAgainstReferenceEntities( projectId, linkingTaskId, linkageRule, - numberOfLinkToShow + numberOfLinkToShow, ); return result.data; } catch (ex) { @@ -184,7 +184,7 @@ export const LinkingRuleEvaluation = ({ const startEvaluation = async ( _ruleOperatorNodes: IRuleOperatorNode[], originalTask: any, - quickEvaluationOnly: boolean = false + quickEvaluationOnly: boolean = false, ) => { setEvaluationRunning(true); let ruleOperatorNodes = _ruleOperatorNodes; @@ -228,7 +228,7 @@ export const LinkingRuleEvaluation = ({ const pathNode = ruleOperatorNodes.find( (op) => op.pluginType === "PathInputOperator" && - ruleEditorNodeParameterValue(op.parameters.path) === path + ruleEditorNodeParameterValue(op.parameters.path) === path, ); if (pathNode) { setPathNotInCacheValidationError({ path, toTarget: pathNode.pluginId === "targetPathInput" }); @@ -249,7 +249,7 @@ export const LinkingRuleEvaluation = ({ /** Called by a rule operator node to register for evaluation updates. */ const registerForEvaluationResults = ( ruleOperatorId: string, - evaluationUpdate: (evaluationValues: EvaluationResultType | undefined) => void + evaluationUpdate: (evaluationValues: EvaluationResultType | undefined) => void, ) => { nodeUpdateCallbacks.set(ruleOperatorId, evaluationUpdate); evaluationUpdate(evaluationResultMap.get(ruleOperatorId)); @@ -272,43 +272,47 @@ export const LinkingRuleEvaluation = ({ triggerEvaluation.current = trigggerFn; }, []); - return - - {errorModalEnabled && pathNotInCacheValidationError && triggerEvaluation.current && ( - { - clearRuleValidationErrors(); - triggerEvaluation.current?.(); - }} - onClose={() => clearRuleValidationErrors()} - /> - )} - {children} - - + + {errorModalEnabled && pathNotInCacheValidationError && triggerEvaluation.current && ( + { + clearRuleValidationErrors(); + triggerEvaluation.current?.(); + }} + onClose={() => clearRuleValidationErrors()} + /> + )} + {children} + + + ); }; diff --git a/workspace/src/app/views/taskViews/linking/referenceLinks/LinkingRuleReferenceLinks.tsx b/workspace/src/app/views/taskViews/linking/referenceLinks/LinkingRuleReferenceLinks.tsx index 5265c4c806..e448fec56f 100644 --- a/workspace/src/app/views/taskViews/linking/referenceLinks/LinkingRuleReferenceLinks.tsx +++ b/workspace/src/app/views/taskViews/linking/referenceLinks/LinkingRuleReferenceLinks.tsx @@ -20,7 +20,9 @@ import { TableHeader, TableRow, Toolbar, - ToolbarSection, Tooltip, ConfidenceValue, + ToolbarSection, + Tooltip, + ConfidenceValue, } from "@eccenca/gui-elements"; import { usePagination } from "@eccenca/gui-elements/src/components/Pagination/Pagination"; import React from "react"; @@ -74,7 +76,7 @@ export const LinkingRuleReferenceLinks = ({ const [showConfirmedOnly, setShowConfirmedOnly] = React.useState(false); const [showDeclinedOnly, setShowDeclinedOnly] = React.useState(false); const [entityUrisToOpenInModal, setEntityUrisToOpenInModal] = React.useState( - undefined + undefined, ); const [pagination, paginationElement, onTotalChange] = usePagination({ initialPageSize: 10, @@ -82,7 +84,7 @@ export const LinkingRuleReferenceLinks = ({ presentation: { hideInfoText: true }, }); const [referenceLinksFiltered, setReferenceLinksFiltered] = React.useState( - undefined + undefined, ); const [t] = useTranslation(); const misMatches = (referenceLinksFiltered ?? []).filter((link) => link.misMatch).length; @@ -118,7 +120,7 @@ export const LinkingRuleReferenceLinks = ({ ); const misMatchFiltered = !showOnlyMismatches || link.misMatch; return typeFiltered && misMatchFiltered; - }) + }), ); setActiveTableRow(undefined); }, [referenceLinks, showOnlyMismatches, showConfirmedOnly, showDeclinedOnly]); @@ -200,9 +202,9 @@ export const LinkingRuleReferenceLinks = ({ disabled={misMatches <= 0} checked={showOnlyMismatches} onChange={() => setShowOnlyMismatches((prev) => !prev)} - style={{margin: "0px"}} + style={{ margin: "0px" }} > - {t("ReferenceLinks.mismatchCheckboxTitle", {nrMismatches: misMatches})} + {t("ReferenceLinks.mismatchCheckboxTitle", { nrMismatches: misMatches })} @@ -271,7 +273,7 @@ export const LinkingRuleReferenceLinks = ({ ? referenceLinksFiltered .slice( (pagination.current - 1) * pagination.limit, - pagination.current * pagination.limit + pagination.current * pagination.limit, ) .map((link, rowIdx) => { const [sourceLabel, targetLabel] = entityLabels(link); @@ -307,11 +309,7 @@ export const LinkingRuleReferenceLinks = ({ {sourceLabel} {targetLabel} - {link.score ? : - "N/A" - } + {link.score ? : "N/A"} @@ -336,7 +334,7 @@ export const LinkingRuleReferenceLinks = ({ data-test-id={`reference-link-more-menu-${rowIdx}`} togglerText={t( "common.action.moreOptions", - "Show more options" + "Show more options", )} > => { try { const [operatorNodeMap, rootNodes] = ruleUtils.convertToRuleOperatorNodeMap(ruleOperatorNodes, true); @@ -141,7 +141,7 @@ export const TransformRuleEditor = ({ })); return new RuleValidationError( t("taskViews.transformRulesEditor.errors.saveTransformRule.msg"), - nodeErrors + nodeErrors, ); } else { return { @@ -158,7 +158,7 @@ export const TransformRuleEditor = ({ /** Converts the linking task rule to the internal representation. */ const convertToRuleOperatorNodes = ( mappingRule: IComplexMappingRule, - ruleOperator: RuleOperatorFetchFnType + ruleOperator: RuleOperatorFetchFnType, ): IRuleOperatorNode[] => { const operatorNodes: IRuleOperatorNode[] = []; ruleUtils.extractOperatorNodeFromValueInput(mappingRule.operator, operatorNodes, false, ruleOperator); @@ -191,7 +191,7 @@ export const TransformRuleEditor = ({ ruleId, term, mappingEditorContext.taskContext, - limit + limit, ); let results = response.data.map((data) => ({ ...data, valueType: "" })); if (term.trim() === "") { @@ -205,7 +205,7 @@ export const TransformRuleEditor = ({ "LinkingRuleEditor_inputPathAutoCompletion", t("taskViews.linkRulesEditor.errors.inputPathAutoCompletion.msg"), err, - { errorNotificationInstanceId: RULE_EDITOR_NOTIFICATION_INSTANCE } + { errorNotificationInstanceId: RULE_EDITOR_NOTIFICATION_INSTANCE }, ); return []; } @@ -221,18 +221,18 @@ export const TransformRuleEditor = ({ containerRuleId, inputString, cursorPosition, - 200 + 200, ); return result.data; } catch (err) { registerError( "TransformRuleEditor_partialAutoCompletion", t("taskViews.transformRulesEditor.errors.partialPathAutoCompletion.msg"), - err + err, ); } }, - [] + [], ); const sourcePathInput = () => @@ -241,7 +241,7 @@ export const TransformRuleEditor = ({ "Source path", ["Source path"], "The value path of the input source of the transformation task.", - inputPathAutoCompletion + inputPathAutoCompletion, ); const fetchDatasetCharacteristics = async () => { @@ -258,7 +258,7 @@ export const TransformRuleEditor = ({ "TransformRuleEditor-fetchDatasetCharacteristics", "Dataset characteristics could not be fetched. UI-support for language filters will not be available.", ex, - { errorNotificationInstanceId: RULE_EDITOR_NOTIFICATION_INSTANCE } + { errorNotificationInstanceId: RULE_EDITOR_NOTIFICATION_INSTANCE }, ); } } @@ -278,9 +278,9 @@ export const TransformRuleEditor = ({ "linking-rule-editor-fetch-source-paths", t("taskViews.linkRulesEditor.errors.fetchLinkingPaths.msg"), ex, - { errorNotificationInstanceId: RULE_EDITOR_NOTIFICATION_INSTANCE } + { errorNotificationInstanceId: RULE_EDITOR_NOTIFICATION_INSTANCE }, ), - mappingEditorContext.taskContext + mappingEditorContext.taskContext, ), ruleUtils.sidebarTabs.transform, ]; diff --git a/workspace/src/app/views/taskViews/transform/evaluation/tabView/TransformEvaluationTabRow.tsx b/workspace/src/app/views/taskViews/transform/evaluation/tabView/TransformEvaluationTabRow.tsx index 1027eb0a3b..4f79b3e8c4 100644 --- a/workspace/src/app/views/taskViews/transform/evaluation/tabView/TransformEvaluationTabRow.tsx +++ b/workspace/src/app/views/taskViews/transform/evaluation/tabView/TransformEvaluationTabRow.tsx @@ -46,7 +46,7 @@ const TransformEvaluationTabRow: React.FC = Reac const handleTreeExpansion = React.useCallback( (rowId: number) => setTreeExpansionMap((prevExpansion) => new Map([...prevExpansion, [rowId, !prevExpansion.get(rowId)]])), - [] + [], ); const buildTree = React.useCallback(() => { @@ -78,7 +78,7 @@ const TransformEvaluationTabRow: React.FC = Reac const generateTree = ( rule: EvaluatedRuleOperator, entityValue: EvaluatedEntityOperator, - tree: TreeNodeInfo> + tree: TreeNodeInfo>, ) => { if (tree?.nodeData?.root && tree.nodeData.label) { tree.label = ( @@ -120,11 +120,11 @@ const TransformEvaluationTabRow: React.FC = Reac generateTree(matchingRuleType.operator!, evaluatedValue, treeNodeInfo); return treeNodeInfo; - }) + }), ); }, [treeExpansionMap, expandRowTrees]); - const existingError = entity.values.find(v => !!v.error)?.error + const existingError = entity.values.find((v) => !!v.error)?.error; return ( <> @@ -138,8 +138,18 @@ const TransformEvaluationTabRow: React.FC = Reac : t("linkingEvaluationTabView.table.expandRow") } > - {rowItem.uri} {existingError ? - : ""} + + {rowItem.uri}{" "} + {existingError ? ( + + ) : ( + "" + )} + {(rowIsExpanded && ( @@ -157,7 +167,7 @@ const TransformEvaluationTabRow: React.FC = Reac null} ); - } + }, ); export default TransformEvaluationTabRow; diff --git a/workspace/src/app/views/taskViews/transform/evaluation/tabView/TransformEvaluationTabViewUtils.tsx b/workspace/src/app/views/taskViews/transform/evaluation/tabView/TransformEvaluationTabViewUtils.tsx index 8b56d18ee0..bd61b35d3d 100644 --- a/workspace/src/app/views/taskViews/transform/evaluation/tabView/TransformEvaluationTabViewUtils.tsx +++ b/workspace/src/app/views/taskViews/transform/evaluation/tabView/TransformEvaluationTabViewUtils.tsx @@ -13,7 +13,7 @@ export const getEvaluatedEntities = async ( taskId: string, ruleId: string, limit: number, - showOnlyEntitiesWithUris: boolean + showOnlyEntitiesWithUris: boolean, ): Promise> => fetch({ method: "GET", @@ -65,7 +65,7 @@ export const NodeTagValues: React.FC = React.memo( {remainingNodes} ); - } + }, ); export const newNode = ({ diff --git a/workspace/src/app/views/taskViews/transform/transform.requests.ts b/workspace/src/app/views/taskViews/transform/transform.requests.ts index afea7b8df6..3ac7c3c469 100644 --- a/workspace/src/app/views/taskViews/transform/transform.requests.ts +++ b/workspace/src/app/views/taskViews/transform/transform.requests.ts @@ -1,7 +1,7 @@ import { FetchResponse } from "../../../services/fetch/responseInterceptor"; import fetch from "../../../services/fetch"; import { legacyTransformEndpoint } from "../../../utils/getApiEndpoint"; -import {IComplexMappingRule, ITransformRule, PartialBy} from "./transform.types"; +import { IComplexMappingRule, ITransformRule, PartialBy } from "./transform.types"; import { IAutocompleteDefaultResponse } from "@ducks/shared/typings"; import { TaskContext } from "../../shared/projectTaskTabView/projectTaskTabView.typing"; import { IPartialAutoCompleteResult } from "@eccenca/gui-elements/src/components/AutoSuggestion/AutoSuggestion"; @@ -11,11 +11,11 @@ export const requestTransformRule = async ( projectId: string, transformId: string, ruleId: string, - convertToComplex: boolean = true + convertToComplex: boolean = true, ): Promise> => { return fetch({ url: legacyTransformEndpoint( - `/tasks/${projectId}/${transformId}/rule/${ruleId}` + (convertToComplex ? "?convertToComplex=true" : "") + `/tasks/${projectId}/${transformId}/rule/${ruleId}` + (convertToComplex ? "?convertToComplex=true" : ""), ), }); }; @@ -38,11 +38,11 @@ export const partialAutoCompleteTransformInputPaths = ( rule: string, inputString: string, cursorPosition: number, - limit?: number + limit?: number, ): Promise> => { return fetch({ url: legacyTransformEndpoint( - `/tasks/${projectId}/${transformTaskId}/rule/${rule}/completions/partialSourcePaths` + `/tasks/${projectId}/${transformTaskId}/rule/${rule}/completions/partialSourcePaths`, ), method: "POST", body: { @@ -60,11 +60,11 @@ export const autoCompleteTransformSourcePath = ( ruleId: string, term = "", taskContext?: TaskContext, - limit = 100 + limit = 100, ): Promise> => { return fetch({ url: legacyTransformEndpoint( - `/tasks/${projectId}/${taskId}/rule/${ruleId}/completions/sourcePaths?maxResults=${limit}&term=${term}` + `/tasks/${projectId}/${taskId}/rule/${ruleId}/completions/sourcePaths?maxResults=${limit}&term=${term}`, ), method: "POST", body: { @@ -78,7 +78,7 @@ export const putTransformRule = async ( projectId: string, transformId: string, ruleId: string, - complexTransformRule: IComplexMappingRule + complexTransformRule: IComplexMappingRule, ): Promise> => { return fetch({ url: legacyTransformEndpoint(`/tasks/${projectId}/${transformId}/rule/${ruleId}`), @@ -93,7 +93,7 @@ export const evaluateTransformRule = async ( transformTaskId: string, containerRuleId: string, rule, - limit: number = 100 + limit: number = 100, ): Promise> => { return fetch({ url: legacyTransformEndpoint(`/tasks/${projectId}/${transformTaskId}/rule/${containerRuleId}/evaluateRule`), @@ -111,10 +111,13 @@ export const appendTransformRule = async ( transformId: string, containerRuleId: string, newRule: PartialBy, - afterRuleId?: string + afterRuleId?: string, ): Promise> => { return fetch({ - url: legacyTransformEndpoint(`/tasks/${projectId}/${transformId}/rule/${containerRuleId}/rules` + (afterRuleId ? `?afterRuleId=${afterRuleId}` : "")), + url: legacyTransformEndpoint( + `/tasks/${projectId}/${transformId}/rule/${containerRuleId}/rules` + + (afterRuleId ? `?afterRuleId=${afterRuleId}` : ""), + ), method: "POST", body: newRule, }); @@ -124,10 +127,10 @@ export const appendTransformRule = async ( export const removeTransformRule = async ( projectId: string, transformId: string, - ruleId: string + ruleId: string, ): Promise> => { return fetch({ url: legacyTransformEndpoint(`/tasks/${projectId}/${transformId}/rule/${ruleId}`), - method: "DELETE" + method: "DELETE", }); }; diff --git a/workspace/src/app/views/taskViews/transform/transform.types.ts b/workspace/src/app/views/taskViews/transform/transform.types.ts index c082c92a45..57781c42a8 100644 --- a/workspace/src/app/views/taskViews/transform/transform.types.ts +++ b/workspace/src/app/views/taskViews/transform/transform.types.ts @@ -4,7 +4,7 @@ import { IValueInput, RuleLayout } from "../shared/rules/rule.typings"; import { Stacktrace } from "../../shared/SampleError/SampleError"; import { StickyNote } from "@eccenca/gui-elements"; -export type PartialBy = Omit & Partial> +export type PartialBy = Omit & Partial>; /** Parameters of a transform task. */ export interface ITransformRule { diff --git a/workspace/test/integration/components/CreateArtefactModal/CreateArtefactModal.test.tsx b/workspace/test/integration/components/CreateArtefactModal/CreateArtefactModal.test.tsx index 3fad7f58c0..65a331ae52 100644 --- a/workspace/test/integration/components/CreateArtefactModal/CreateArtefactModal.test.tsx +++ b/workspace/test/integration/components/CreateArtefactModal/CreateArtefactModal.test.tsx @@ -58,7 +58,7 @@ describe("Task creation widget", () => { const createArtefactWrapper = ( currentUrl: string = `${SERVE_PATH}`, - existingTask?: RecursivePartial + existingTask?: RecursivePartial, ): IWrapper => { const history = createMemoryHistory(); history.push(currentUrl); @@ -104,7 +104,7 @@ describe("Task creation widget", () => { const pluginCreationDialogWrapper = async ( doubleClickToAdd: boolean = true, // The current data of a task that is being updated - existingTask?: RecursivePartial + existingTask?: RecursivePartial, ) => { const wrapper = await createMockedListWrapper(existingTask); const pluginA = selectionItems(wrapper.wrapper)[1]; @@ -120,13 +120,13 @@ describe("Task creation widget", () => { } mockAxios.mockResponseFor( { url: apiUrl("core/plugins/pluginA") }, - mockedAxiosResponse({ data: mockPluginDescription }) + mockedAxiosResponse({ data: mockPluginDescription }), ); } await waitFor(() => { const labels = findAll(wrapper.wrapper, ".eccgui-label .eccgui-label__text").map((e) => e.text()); Object.entries(mockPluginDescription.properties).forEach(([paramId, attributes]) => - expect(labels).toContain(attributes.title) + expect(labels).toContain(attributes.title), ); }); return wrapper; @@ -175,22 +175,22 @@ describe("Task creation widget", () => { resourceParam: atomicParamDescription({ title: "resource param", parameterType: INPUT_TYPES.RESOURCE }), enumerationParam: atomicParamDescription( { title: "enumeration param", parameterType: INPUT_TYPES.ENUMERATION }, - {} + {}, ), autoCompletionParamCustom: atomicParamDescription( { title: "auto-complete param that allows custom values", parameterType: INPUT_TYPES.STRING }, - { allowOnlyAutoCompletedValues: false } + { allowOnlyAutoCompletedValues: false }, ), optionalAutoCompletionParamCustom: atomicParamDescription( { title: "auto-complete param that allows resetting it's value", parameterType: INPUT_TYPES.STRING }, - {} + {}, ), objectParameter: objectParamDescription( "pluginX", { subProperty: atomicParamDescription( { title: "nested auto-complete param", parameterType: INPUT_TYPES.STRING }, - {} + {}, ), subStringParam: atomicParamDescription({ title: "string param", @@ -198,7 +198,7 @@ describe("Task creation widget", () => { }), }, ["subStringParam"], - {} + {}, ), }, }; @@ -291,7 +291,7 @@ describe("Task creation widget", () => { mockAxiosResponse(tasksUri, { data: { id: newTaskId } }); await waitFor(() => { expect(history.location.pathname).toEqual( - expect.stringMatching(new RegExp(`projects/${PROJECT_ID}/task/${newTaskId}$`)) + expect.stringMatching(new RegExp(`projects/${PROJECT_ID}/task/${newTaskId}$`)), ); }); }); @@ -307,7 +307,7 @@ describe("Task creation widget", () => { await waitFor(() => { mockAxiosResponse( legacyApiUrl("workspace/projects/projectId/tasks"), - mockedAxiosError(500, { title: "error", detail: expectedErrorMsg }) + mockedAxiosError(500, { title: "error", detail: expectedErrorMsg }), ); }); await waitFor(() => { @@ -353,7 +353,7 @@ describe("Task creation widget", () => { // Request is delayed by 200ms mockAutoCompleteResponse( { textQuery: "abc" }, - mockedAxiosResponse({ data: [{ value: "abc1" }, { value: "abc2" }] }) + mockedAxiosResponse({ data: [{ value: "abc1" }, { value: "abc2" }] }), ); }); await waitFor(() => { @@ -416,7 +416,7 @@ describe("Task creation widget", () => { Object.entries(expectedParams).forEach(([key, value]) => (expectedObject[key] = value.value)); const objectParameterObject: any = {}; Object.entries(expectedParams.objectParameter.value).forEach( - ([key, value]) => (objectParameterObject[key] = value.value) + ([key, value]) => (objectParameterObject[key] = value.value), ); expectedObject.objectParameter = objectParameterObject; expect(updateRequest.data.parameters).toEqual(expectedObject); @@ -434,11 +434,11 @@ describe("Task creation widget", () => { // Build expected request parameter object const expectedObject: any = {}; Object.entries(expectedParams).forEach( - ([key, value]) => key !== "stringParam" && (expectedObject[key] = value.value) + ([key, value]) => key !== "stringParam" && (expectedObject[key] = value.value), ); const objectParameterObject: any = {}; Object.entries(expectedParams.objectParameter.value).forEach( - ([key, value]) => (objectParameterObject[key] = value.value) + ([key, value]) => (objectParameterObject[key] = value.value), ); expectedObject.objectParameter = objectParameterObject; expect(updateRequest.data.parameters).toEqual(expectedObject);