Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: shape file date fields wrong format ( MAPCO-5495 ) #526

Merged
merged 4 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/common/components/error/error-presentor.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ body[dir='rtl'] .errorsList {
direction: rtl;
}

/* body[dir='rtl'] .errorContainer {
body[dir='rtl'] .errorContainer {
flex-direction: row-reverse;
} */
}

.error {
color: var(--mdc-theme-gc-error-high) !important;
Expand Down
36 changes: 4 additions & 32 deletions src/discrete-layer/components/layer-details/entity.dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ import {
getFlatEntityDescriptors,
getPartialRecord,
getRecordForUpdate,
getValidationType
getValidationType,
getYupFieldConfig
} from './utils';
import suite from './validate';

Expand Down Expand Up @@ -303,35 +304,6 @@ export const EntityDialog: React.FC<EntityDialogProps> = observer(
store.discreteLayersStore.entityDescriptors as EntityDescriptorModelType[]
);

const getYupFieldConfig = (
field: FieldConfigModelType
): MixedSchema => {
return !field.dateGranularity ?
Yup.mixed().required(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
):
Yup.date().nullable().max(
new Date(),
intl.formatMessage(
{ id: 'validation-general.date.future' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
).typeError(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
).required(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
);
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const yupSchema: Record<string, any> = {};
[
Expand All @@ -343,12 +315,12 @@ export const EntityDialog: React.FC<EntityDialogProps> = observer(
case Mode.NEW:
case Mode.UPDATE:
if ((field.isRequired as boolean) && field.isAutoGenerated !== true) {
yupSchema[fieldName] = getYupFieldConfig(field);
yupSchema[fieldName] = getYupFieldConfig(field, intl);
}
break;
case Mode.EDIT:
if ((field.isRequired as boolean) && field.isManuallyEditable === true) {
yupSchema[fieldName] = getYupFieldConfig(field);
yupSchema[fieldName] = getYupFieldConfig(field, intl);
}
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,13 @@ export const DateValuePresentorComponent: React.FC<DateValuePresentorProps> = ({
};

const isReadOnlyMode = mode === Mode.VIEW || (mode === Mode.EDIT && fieldInfo.isManuallyEditable !== true) || mode === Mode.EXPORT;
const isDataError = fieldInfo.isRequired && !value;
const isDataError = fieldInfo.isRequired && isInvalidDate();

// Render empty field for null dates
if(isReadOnlyMode && isInvalidDate()) {
return <></>;
}

if (isReadOnlyMode) {
return (
<TooltippedValue className={`detailsFieldValue ${isDataError ? 'detailFieldDataError' : ''}`}>
{dateFormatter(value, shouldShowTime)}
{isDataError ? <></> : dateFormatter(value, shouldShowTime) }
</TooltippedValue>
);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import {
getFlatEntityDescriptors,
getPartialRecord,
getRecordForUpdate,
getValidationType
getValidationType,
getYupFieldConfig
} from '../utils';
import suite from '../validate';
import { getUIIngestionFieldDescriptors } from './ingestion.utils';
Expand Down Expand Up @@ -131,10 +132,7 @@ export const EntityRasterDialog: React.FC<EntityRasterDialogProps> = observer(
const dialogContainerRef = useRef<HTMLDivElement>(null);

const decideMode = useCallback(() => {
if (props.isSelectedLayerUpdateMode === true && props.layerRecord) {
return Mode.UPDATE;
}
return !props.layerRecord ? Mode.NEW : Mode.EDIT;
return (props.isSelectedLayerUpdateMode === true && props.layerRecord) ? Mode.UPDATE : Mode.NEW;
}, []);

const { isOpen, onSetOpen } = props;
Expand Down Expand Up @@ -275,18 +273,6 @@ export const EntityRasterDialog: React.FC<EntityRasterDialogProps> = observer(
}
};

const handleEditQueries = (): void => {
mutationQuery.setQuery(
store.mutateUpdateMetadata({
data: {
id: inputValues.id as string,
type: inputValues.type as RecordType,
partialRecordData: getPartialRecord(inputValues as Record<string, unknown> as Partial<ILayerImage>, descriptors as FieldConfigModelType[], IS_EDITABLE),
},
})
);
};

const handleUpdateQueries = (): void => {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { directory, fileNames, __typename, ...metadata } = inputValues;
Expand Down Expand Up @@ -362,35 +348,6 @@ export const EntityRasterDialog: React.FC<EntityRasterDialogProps> = observer(
},
];

const getYupFieldConfig = (
field: FieldConfigModelType
): MixedSchema => {
return !field.dateGranularity ?
Yup.mixed().required(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
):
Yup.date().nullable().max(
new Date(),
intl.formatMessage(
{ id: 'validation-general.date.future' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
).typeError(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
).required(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
);
};

const schemaUpdater = (partsNumber: number, startIndex = 0)=>{
const nestedFormdescriptors = getFlatEntityDescriptors(
'PolygonPartRecord',
Expand All @@ -405,12 +362,7 @@ export const EntityRasterDialog: React.FC<EntityRasterDialogProps> = observer(
case Mode.NEW:
case Mode.UPDATE:
if ((field.isRequired as boolean) && field.isAutoGenerated !== true) {
nestedYupSchema[fieldName] = getYupFieldConfig(field);
}
break;
case Mode.EDIT:
if ((field.isRequired as boolean) && field.isManuallyEditable === true) {
nestedYupSchema[fieldName] = getYupFieldConfig(field);
nestedYupSchema[fieldName] = getYupFieldConfig(field, intl);
}
break;
default:
Expand Down Expand Up @@ -450,12 +402,7 @@ export const EntityRasterDialog: React.FC<EntityRasterDialogProps> = observer(
case Mode.NEW:
case Mode.UPDATE:
if ((field.isRequired as boolean) && field.isAutoGenerated !== true) {
yupSchema[fieldName] = getYupFieldConfig(field);
}
break;
case Mode.EDIT:
if ((field.isRequired as boolean) && field.isManuallyEditable === true) {
yupSchema[fieldName] = getYupFieldConfig(field);
yupSchema[fieldName] = getYupFieldConfig(field, intl);
}
break;
default:
Expand Down Expand Up @@ -496,9 +443,6 @@ export const EntityRasterDialog: React.FC<EntityRasterDialogProps> = observer(
case Mode.NEW:
handleIngestQueries();
break;
case Mode.EDIT:
handleEditQueries();
break;
case Mode.UPDATE:
handleUpdateQueries();
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
FieldConfigModelType,
LayerMetadataMixedUnion,
ParsedPolygonPart,
ParsedPolygonPartError,
PolygonPartRecordModelType,
RecordType,
SourceValidationModelType
Expand Down Expand Up @@ -318,10 +319,11 @@ export const InnerRasterForm = (
const stattusErrors = parsingErrors.reduce(
(acc,curr) => {
Object.keys(curr).forEach(key=>{
let errObj = curr[key] as Record<string, string[]>;
let errObj = curr[key] as Record<string, ParsedPolygonPartError>;
Object.keys(errObj).forEach(fieldKey => {
errObj[fieldKey] = errObj[fieldKey].map(
errText => intl.formatMessage({id: errText}, {fieldName: emphasizeByHTML(fieldKey)})
// @ts-ignore
errObj[fieldKey] = errObj[fieldKey].codes.map(
errText => intl.formatMessage({id: errText}, {fieldName: emphasizeByHTML(`${intl.formatMessage({ id: errObj[fieldKey].label })}`)})
);
});
});
Expand All @@ -347,11 +349,17 @@ export const InnerRasterForm = (
});
}, [parsingErrors]);

useEffect(() => {
useEffect(() => {
if(ppCollisionCheckInProgress !== undefined) {
setShowCurtain(ppCollisionCheckInProgress);
}
}, [ppCollisionCheckInProgress]);
}, [ppCollisionCheckInProgress]);

useEffect(() => {
if (sourceExtent && outlinedPerimeter && !isPolygonContainsPolygon(sourceExtent as Feature<any>, outlinedPerimeter as Feature<any>)){
setClientCustomValidationError(intl.formatMessage({ id: shapeFilePerimeterVSGpkgExtentError.message }));
}
}, [sourceExtent, outlinedPerimeter]);

const excidedFeaturesNumberError = useMemo(() => new Error(`validation-general.shapeFile.too-many-features`), []);
const shapeFileGenericError = useMemo(() => new Error(`validation-general.shapeFile.generic`), []);
Expand Down Expand Up @@ -551,11 +559,6 @@ export const InnerRasterForm = (
type: 'Point'
},
});


if (!isPolygonContainsPolygon(sourceExtent as Feature<any>, outlinedPolygon as Feature<any>)){
setClientCustomValidationError(intl.formatMessage({ id: shapeFilePerimeterVSGpkgExtentError.message }));
}

return resolve(parsedPolygonParts);
})
Expand Down
55 changes: 53 additions & 2 deletions src/discrete-layer/components/layer-details/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import { get, isEmpty, omit } from 'lodash';
import moment, { unitOfTime } from 'moment';
import { IntlShape } from 'react-intl';
import * as Yup from 'yup';
import { MixedSchema } from 'yup/lib/mixed';
import { $enum } from 'ts-enum-util';
import { Feature } from 'geojson';
import rewind from '@turf/rewind';
Expand All @@ -10,6 +12,7 @@ import { sessionStore } from '../../../common/helpers/storage';
import { ValidationTypeName } from '../../../common/models/validation.enum';
import { SYNC_QUERY, syncQueries } from '../../../syncHttpClientGql';
import { Mode } from '../../../common/models/mode.enum';
import { emphasizeByHTML } from '../../../common/helpers/formatters';
import {
CategoryConfigModelType,
EntityDescriptorModelType,
Expand All @@ -23,6 +26,7 @@ import {
LinkModelType,
OperationType,
ParsedPolygonPart,
ParsedPolygonPartError,
PolygonPartRecordModel,
PolygonPartRecordModelType,
ProductType,
Expand Down Expand Up @@ -243,21 +247,68 @@ export const removeEmptyObjFields = (
return removeObjFields(obj, (val) => typeof val === 'object' && isEmpty(val));
};

export const getYupFieldConfig = (
field: FieldConfigModelType,
intl: IntlShape
): MixedSchema => {
return !field.dateGranularity ?
Yup.mixed().required(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
):
Yup.date().nullable().max(
new Date(),
intl.formatMessage(
{ id: 'validation-general.date.future' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
).typeError(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
).required(
intl.formatMessage(
{ id: 'validation-general.required' },
{ fieldName: emphasizeByHTML(`${intl.formatMessage({ id: field.label })}`) }
)
);
};

export const transformSynergyShapeFeatureToEntity = (desciptors: FieldConfigModelType[], feature: Feature): ParsedPolygonPart => {
const poygonPartData: Record<string,unknown> = {"__typename": "PolygonPartRecord"};
const errors: Record<string,string[]> = {};
const errors: Record<string,ParsedPolygonPartError> = {};
desciptors.forEach((desc) => {
const shapeFieldValue = get(feature, desc.shapeFileMapping as string);

// This logic mimics basic YUP schema:
// 1. required fields
// 2. no future dates
if(!shapeFieldValue && desc.isRequired){
errors[desc.fieldName as string] = ['validation-general.required'];
errors[desc.fieldName as string] = {
codes: ['validation-general.required'],
label: desc.label as string
};
}

if(desc.shapeFileMapping) {
switch(desc.fieldName){
case 'imagingTimeBeginUTC':
case 'imagingTimeEndUTC':
poygonPartData[desc.fieldName as string] = moment(shapeFieldValue, "DD/MM/YYYY");
if(poygonPartData[desc.fieldName as string] as moment.Moment > moment()){
if(errors[desc.fieldName as string]){
errors[desc.fieldName as string].codes.push('validation-general.date.future');
}
else{
errors[desc.fieldName as string] = {
codes: ['validation-general.date.future'],
label: desc.label as string
};
}
}
break;
case 'footprint':
poygonPartData[desc.fieldName as string] = rewind(shapeFieldValue);
Expand Down
6 changes: 5 additions & 1 deletion src/discrete-layer/models/PolygonPartRecordModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import { RecordTypeEnumType } from "./RecordTypeEnum";
/* The TypeScript type of an instance of PolygonPartRecordModel */
export interface PolygonPartRecordModelType extends Instance<typeof PolygonPartRecordModel.Type> {}

export interface ParsedPolygonPartError {
codes: string[];
label: string
}
export interface ParsedPolygonPart {
polygonPart: PolygonPartRecordModelType;
errors: Record<string,string[]>;
errors: Record<string,ParsedPolygonPartError>;
}
/* A graphql query fragment builders for PolygonPartRecordModel */
export { selectFromPolygonPartRecord, polygonPartRecordModelPrimitives, PolygonPartRecordModelSelector } from "./PolygonPartRecordModel.base"
Expand Down
Loading