@topconsultnpm/sdkui-react-beta 6.7.132 → 6.7.134

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,23 +1,21 @@
1
- import { ValidationItem, LayoutModes } from '@topconsultnpm/sdk-ts-beta';
1
+ import { ValidationItem, LayoutModes, QueryOperators } from '@topconsultnpm/sdk-ts-beta';
2
2
  import { DynDataListsToBeRefreshed } from '../choosers/TMDynDataListItemChooser';
3
3
  interface ITMMetadataEditorProps {
4
4
  tid: number | undefined;
5
5
  mid?: number;
6
6
  value: string | undefined;
7
7
  queryParamsDynDataList?: string[];
8
- allowMultipleSelection: boolean;
9
8
  autoFocus: boolean;
10
- showAsText?: boolean;
11
- showAsNumber?: boolean;
12
9
  containerElement: Element | undefined;
13
10
  disabled?: boolean;
14
11
  validationItems?: ValidationItem[];
15
12
  isLexProt?: number;
16
13
  layoutMode?: LayoutModes;
14
+ queryOperator?: QueryOperators;
17
15
  isModifiedWhen?: boolean;
18
16
  onValueChanged?: (value: any) => void;
19
17
  onValueChange?: (value: any) => void;
20
18
  onCascadeRefreshDynDataLists?: (dynDataListsToBeRefreshed: DynDataListsToBeRefreshed[]) => void;
21
19
  }
22
- declare const TMMetadataEditor: ({ isLexProt, layoutMode, isModifiedWhen, tid, mid, value, queryParamsDynDataList, containerElement, allowMultipleSelection, autoFocus, showAsText, showAsNumber, validationItems, disabled, onValueChanged, onValueChange, onCascadeRefreshDynDataLists }: ITMMetadataEditorProps) => import("react/jsx-runtime").JSX.Element;
20
+ declare const TMMetadataEditor: ({ isLexProt, layoutMode, queryOperator, isModifiedWhen, tid, mid, value, queryParamsDynDataList, containerElement, autoFocus, validationItems, disabled, onValueChanged, onValueChange, onCascadeRefreshDynDataLists }: ITMMetadataEditorProps) => import("react/jsx-runtime").JSX.Element;
23
21
  export default TMMetadataEditor;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
- import { MetadataDataDomains, MetadataDataTypes, DcmtTypeListCacheService, LayoutModes, AccessLevels } from '@topconsultnpm/sdk-ts-beta';
3
+ import { MetadataDataDomains, MetadataDataTypes, DcmtTypeListCacheService, LayoutModes, AccessLevels, PlatformObjectValidator } from '@topconsultnpm/sdk-ts-beta';
4
4
  import { IconLayerGroup } from '../../helper';
5
5
  import { TMColors } from '../../utils/theme';
6
6
  import ShowAlert from '../base/TMAlert';
@@ -11,7 +11,7 @@ import TMDateBox from './TMDateBox';
11
11
  import TMTextBox from './TMTextBox';
12
12
  import { TMMetadataIcon } from '../viewers/TMMidViewer';
13
13
  import TMTextArea from './TMTextArea';
14
- const TMMetadataEditor = ({ isLexProt, layoutMode, isModifiedWhen = false, tid, mid, value, queryParamsDynDataList, containerElement, allowMultipleSelection, autoFocus, showAsText, showAsNumber, validationItems = [], disabled = false, onValueChanged, onValueChange, onCascadeRefreshDynDataLists }) => {
14
+ const TMMetadataEditor = ({ isLexProt, layoutMode, queryOperator, isModifiedWhen = false, tid, mid, value, queryParamsDynDataList, containerElement, autoFocus, validationItems = [], disabled = false, onValueChanged, onValueChange, onCascadeRefreshDynDataLists }) => {
15
15
  const [md, setMd] = useState();
16
16
  useEffect(() => {
17
17
  DcmtTypeListCacheService.GetAsync(tid).then((dtd) => {
@@ -26,49 +26,55 @@ const TMMetadataEditor = ({ isLexProt, layoutMode, isModifiedWhen = false, tid,
26
26
  default: return false;
27
27
  }
28
28
  };
29
- const isModifiedWhenInternal = () => {
30
- return isModifiedWhen && !md?.isSystem;
31
- };
29
+ const isModifiedWhenInternal = () => { return isModifiedWhen && !md?.isSystem; };
30
+ let operands = PlatformObjectValidator.GetNumberOfOperands(queryOperator);
32
31
  const showLabelTop = (layoutMode === LayoutModes.Update) || (layoutMode === LayoutModes.Ark);
33
- const showByTextarea = md && md.length && md?.dataType === MetadataDataTypes.Varchar && md.length > 80;
32
+ const showByTextarea = showLabelTop && md && md.length && md?.dataType === MetadataDataTypes.Varchar && md.length > 80;
33
+ const showAsText = operands == 11 || operands == 99;
34
+ const showAsNumber = operands == 12;
35
+ const multipleSelectionIsenabled = operands == 11;
36
+ let maxLength = md?.length;
37
+ if (layoutMode === LayoutModes.None && showAsText)
38
+ maxLength = 1000;
34
39
  let btnDistincValues = { text: 'Valori distinti', icon: _jsx(IconLayerGroup, { fontSize: 16 }), onClick: () => { ShowAlert({ message: "TODO Valori distinti", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } };
35
40
  let isReadOnlyResult = isReadOnlyInternal();
36
41
  if (value?.startsWith("{@QueryParam") || value == "{@UserName}" || value == "{@UserID}")
37
- return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', maxLength: md?.length, autoFocus: autoFocus, value: value || '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
42
+ return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', maxLength: maxLength, autoFocus: autoFocus, value: value || '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
38
43
  if (md?.dataDomain == MetadataDataDomains.DynamicDataList)
39
- return _jsx(TMDynDataListItemChooser, { readOnly: isReadOnlyResult, isModifiedWhen: isModifiedWhenInternal(), label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, md: md, tid: tid, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, queryParamsDynDataList: queryParamsDynDataList, onCascadeRefreshDynDataLists: onCascadeRefreshDynDataLists, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, allowMultipleSelection: allowMultipleSelection, values: value ? [value] : [], showClearButton: !isReadOnlyResult, onValueChanged: (IDs) => {
44
+ return _jsx(TMDynDataListItemChooser, { readOnly: isReadOnlyResult, isModifiedWhen: isModifiedWhenInternal(), label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, md: md, tid: tid, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, queryParamsDynDataList: queryParamsDynDataList, onCascadeRefreshDynDataLists: onCascadeRefreshDynDataLists, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, allowMultipleSelection: multipleSelectionIsenabled, values: value ? [value] : [], showClearButton: !isReadOnlyResult, onValueChanged: (IDs) => {
40
45
  if (!IDs || IDs.length <= 0)
41
46
  onValueChanged?.(undefined);
42
47
  else
43
48
  onValueChanged?.(IDs[0]);
44
49
  } });
45
50
  if (md?.dataDomain == MetadataDataDomains.DataList)
46
- return _jsx(TMDataListItemChooser, { readOnly: isReadOnlyResult, isModifiedWhen: isModifiedWhenInternal(), label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, dataListId: md.dataListID, allowMultipleSelection: allowMultipleSelection, values: value?.split(',').map((item) => !item.startsWith("'") ? item : item.slice(1, -1)) ?? [], showClearButton: !isReadOnlyResult, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, onValueChanged: (IDs) => {
51
+ return _jsx(TMDataListItemChooser, { readOnly: isReadOnlyResult, isModifiedWhen: isModifiedWhenInternal(), label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, dataListId: md.dataListID, allowMultipleSelection: multipleSelectionIsenabled, values: value?.split(',').map((item) => !item.startsWith("'") ? item : item.slice(1, -1)) ?? [], showClearButton: !isReadOnlyResult, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, onValueChanged: (IDs) => {
47
52
  if (!IDs || IDs.length <= 0)
48
53
  onValueChanged?.(undefined);
49
54
  else
50
55
  onValueChanged?.(IDs.join(","));
51
56
  } });
52
57
  if (md?.dataDomain == MetadataDataDomains.UserID)
53
- return _jsx(TMUserChooser, { readOnly: isReadOnlyResult, isModifiedWhen: isModifiedWhenInternal(), label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, placeHolder: " ", showClearButton: !isReadOnlyResult, allowMultipleSelection: allowMultipleSelection, values: value?.split(',').map((item) => !item.startsWith("'") ? Number(item) : Number(item.slice(1, -1))) ?? [], buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, onValueChanged: (IDs) => {
58
+ return _jsx(TMUserChooser, { readOnly: isReadOnlyResult, isModifiedWhen: isModifiedWhenInternal(), label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, placeHolder: " ", showClearButton: !isReadOnlyResult, allowMultipleSelection: multipleSelectionIsenabled, values: value?.split(',').map((item) => !item.startsWith("'") ? Number(item) : Number(item.slice(1, -1))) ?? [], buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, onValueChanged: (IDs) => {
54
59
  if (!IDs || IDs.length <= 0)
55
60
  onValueChanged?.(undefined);
56
61
  else
57
62
  onValueChanged?.(IDs.join(","));
58
63
  } });
59
64
  if (showAsText)
60
- return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, showClearButton: !isReadOnlyResult, maxLength: md?.length, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
65
+ return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, showClearButton: !isReadOnlyResult, maxLength: maxLength, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
61
66
  if (showAsNumber)
62
67
  return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', showClearButton: !isReadOnlyResult, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
68
+ console.log('md?.dataType', md?.dataType);
63
69
  switch (md?.dataType) {
64
70
  case MetadataDataTypes.DateTime: return _jsx(TMDateBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, label: showLabelTop ? md?.nameLoc : undefined, validationItems: validationItems, disabled: disabled, width: '100%', value: value, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, showClearButton: !isReadOnlyResult, useDateSerializationFormat: true, containerElement: containerElement, onValueChange: (newValue) => { onValueChange?.(newValue ? newValue.toString() : undefined); onValueChanged?.(newValue ? newValue.toString() : undefined); } });
65
71
  case MetadataDataTypes.Number: return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, showClearButton: !isReadOnlyResult, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
66
72
  default:
67
73
  if (showByTextarea) {
68
- return _jsx(TMTextArea, { rows: 1, readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, isModifiedWhen: isModifiedWhenInternal(), validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, showClearButton: !isReadOnlyResult, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, autoFocus: autoFocus, maxLength: md?.length, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); } });
74
+ return _jsx(TMTextArea, { rows: 1, readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, isModifiedWhen: isModifiedWhenInternal(), validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, showClearButton: !isReadOnlyResult, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, autoFocus: autoFocus, maxLength: maxLength, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); } });
69
75
  }
70
76
  else {
71
- return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, disabled: disabled, validationItems: validationItems, type: 'text', elementStyle: { width: '100%' }, showClearButton: !isReadOnlyResult, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, autoFocus: autoFocus, maxLength: md?.length, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); } });
77
+ return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: showLabelTop ? md?.nameLoc : undefined, icon: showLabelTop ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, disabled: disabled, validationItems: validationItems, type: 'text', elementStyle: { width: '100%' }, showClearButton: !isReadOnlyResult, buttons: !isReadOnlyResult ? [btnDistincValues] : undefined, autoFocus: autoFocus, maxLength: maxLength, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); } });
72
78
  }
73
79
  }
74
80
  };
@@ -952,7 +952,7 @@ const TMQdWhereItemValue = ({ whereItem, index, queryParamsDynDataList, onlyEdit
952
952
  };
953
953
  const mdValueEmptyDescr = `<${SDKUI_Localizator.Search_EnterValue}...>`;
954
954
  return (_jsxs("div", { ref: ref, id: containerId, style: { width: isEditing && whereItem.operator == QueryOperators.Custom && !onlyEditing ? "100%" : undefined }, children: [(isEditing || onlyEditing) &&
955
- _jsxs(StyledRowItem, { children: [showValue1 && _jsx(TMMetadataEditor, { tid: whereItem.tid, mid: whereItem.mid, value: whereItem.value1, allowMultipleSelection: whereItem.operator == QueryOperators.In || whereItem.operator == QueryOperators.NotIn, autoFocus: !onlyEditing, containerElement: containerElement, showAsText: numberOfOperands == 11 || numberOfOperands == 99, showAsNumber: numberOfOperands == 12, onValueChange: (value) => setCurrentValue1(value), onValueChanged: (value) => { normalizeValue(value, true); } }), showValue2 && _jsx(TMMetadataEditor, { tid: whereItem.tid, mid: whereItem.mid, value: whereItem.value2, allowMultipleSelection: whereItem.operator == QueryOperators.In || whereItem.operator == QueryOperators.NotIn, autoFocus: !onlyEditing, containerElement: containerElement, showAsText: numberOfOperands == 11 || numberOfOperands == 99, showAsNumber: numberOfOperands == 12, onValueChange: (value) => setCurrentValue2(value), onValueChanged: (value) => { normalizeValue(value, false); } })] }), !isEditing && !onlyEditing && (showValue1 || showValue2) &&
955
+ _jsxs(StyledRowItem, { children: [showValue1 && _jsx(TMMetadataEditor, { tid: whereItem.tid, mid: whereItem.mid, layoutMode: LayoutModes.None, value: whereItem.value1, queryOperator: whereItem.operator, autoFocus: !onlyEditing, containerElement: containerElement, onValueChange: (value) => setCurrentValue1(value), onValueChanged: (value) => { normalizeValue(value, true); } }), showValue2 && _jsx(TMMetadataEditor, { tid: whereItem.tid, mid: whereItem.mid, layoutMode: LayoutModes.None, value: whereItem.value1, queryOperator: whereItem.operator, autoFocus: !onlyEditing, containerElement: containerElement, onValueChange: (value) => setCurrentValue2(value), onValueChanged: (value) => { normalizeValue(value, false); } })] }), !isEditing && !onlyEditing && (showValue1 || showValue2) &&
956
956
  _jsxs(StyledDivHorizontal, { children: [editingMode == EditingModes.Chooser &&
957
957
  _jsxs(_Fragment, { children: [showDataListChooseForm &&
958
958
  _jsx(TMDataListItemChooserForm, { height: '500px', width: '450px', allowMultipleSelection: whereItem.operator == QueryOperators.In || whereItem.operator == QueryOperators.NotIn, dataListId: md?.dataListID, selectedIDs: whereItem.value1?.split(',').map((item) => !item.startsWith("'") ? item : item.slice(1, -1)) ?? [], onClose: () => setShowDataListChooseForm(false), onChoose: (IDs) => { IDs && normalizeValue(IDs.length == 1 ? IDs[0] : IDs.map((item) => `${item}`).join(","), true); } }), showDynDataListChooseForm &&
@@ -980,20 +980,6 @@ const TMQdWhereItemValue = ({ whereItem, index, queryParamsDynDataList, onlyEdit
980
980
  toBeRefreshed.push({ mid: mid, queryParams: queryParams, midStarter: md?.id });
981
981
  }
982
982
  onCascadeRefreshDynDataLists?.(toBeRefreshed);
983
- // // onCascade
984
- // let newDynDataListsToBeRefreshed = [];
985
- // for (const item of dynDataListsToBeRefreshed) {
986
- // let index = toBeRefreshed.findIndex(o => o.mid == item.mid || (o.mid == -1 && o.midStarter == item.midStarter));
987
- // if (index >= 0) continue;
988
- // newDynDataListsToBeRefreshed.push(item);
989
- // }
990
- // for (const item of toBeRefreshed) {
991
- // if (item.queryParams.length <= 0) continue;
992
- // if (!item.mid) continue;
993
- // if (item.mid <= 0) continue;
994
- // newDynDataListsToBeRefreshed.push(item);
995
- // }
996
- // setDynDataListsToBeRefreshed(newDynDataListsToBeRefreshed);
997
983
  } }), showUserChooseForm &&
998
984
  _jsx(TMUserChooserForm, { height: '550px', width: '600px', allowMultipleSelection: whereItem.operator == QueryOperators.In || whereItem.operator == QueryOperators.NotIn, dataSource: users, selectedIDs: whereItem.value1?.split(',').map((item) => !item.startsWith("'") ? Number(item) : Number(item.slice(1, -1))) ?? [], onClose: () => setShowUserChooseForm(false), onChoose: (IDs) => { IDs && normalizeValue(IDs.length == 1 ? IDs[0].toString() : IDs.map((item) => item).join(","), true); } })] }), _jsx(StyledItemWrapper, { onClick: () => { (editingMode == EditingModes.Editing) ? setIsEditing(true) : chooseValue(); }, style: { backgroundColor: colorValue, cursor: 'pointer', width: '100%' }, children: numberOfOperands == 11 || numberOfOperands == 12 || numberOfOperands == 99
999
985
  ? _jsx(_Fragment, { children: whereItem.value1 ?? mdValueEmptyDescr })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react-beta",
3
- "version": "6.7.132",
3
+ "version": "6.7.134",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",