diff --git a/documentation/src/utils/schemas.ts b/documentation/src/utils/schemas.ts index 2e4210c5a..8e8464296 100644 --- a/documentation/src/utils/schemas.ts +++ b/documentation/src/utils/schemas.ts @@ -200,11 +200,18 @@ export const CreatePricingTaskOptionsSchema = z.object({ methodology: z.string().optional(), }); +export const CreateWheelAnalysisTaskOptionsSchema = z.object({ + name: z.literal(TaskName.WHEEL_ANALYSIS), + useLongShots: z.boolean(), + callbacks: z.array(TaskCallbackOptionsSchema).optional(), +}); + export const InspectionCreateTaskSchema = z .nativeEnum(TaskName) .or(CreateDamageDetectionTaskOptionsSchema) .or(CreateHinlTaskOptionsSchema) - .or(CreatePricingTaskOptionsSchema); + .or(CreatePricingTaskOptionsSchema) + .or(CreateWheelAnalysisTaskOptionsSchema); export const AdditionalDataSchema = z.record(z.string(), z.unknown()); diff --git a/documentation/src/utils/schemas/createInspection.schema.ts b/documentation/src/utils/schemas/createInspection.schema.ts index 59ecf6a78..074dfc633 100644 --- a/documentation/src/utils/schemas/createInspection.schema.ts +++ b/documentation/src/utils/schemas/createInspection.schema.ts @@ -28,11 +28,18 @@ export const CreatePricingTaskOptionsSchema = z.object({ methodology: z.string().optional(), }); +export const CreateWheelAnalysisTaskOptionsSchema = z.object({ + name: z.literal(TaskName.WHEEL_ANALYSIS), + useLongShots: z.boolean(), + callbacks: z.array(TaskCallbackOptionsSchema).optional(), +}); + export const InspectionCreateTaskSchema = z .nativeEnum(TaskName) .or(CreateDamageDetectionTaskOptionsSchema) .or(CreateHinlTaskOptionsSchema) - .or(CreatePricingTaskOptionsSchema); + .or(CreatePricingTaskOptionsSchema) + .or(CreateWheelAnalysisTaskOptionsSchema); export const AdditionalDataSchema = z.record(z.string(), z.unknown()); diff --git a/packages/inspection-capture-web/src/hooks/useUploadQueue.ts b/packages/inspection-capture-web/src/hooks/useUploadQueue.ts index 26a58d1d0..ff033d8a7 100644 --- a/packages/inspection-capture-web/src/hooks/useUploadQueue.ts +++ b/packages/inspection-capture-web/src/hooks/useUploadQueue.ts @@ -1,4 +1,4 @@ -import { Queue, uniq, useQueue } from '@monkvision/common'; +import { Queue, uniq, useMonkState, useQueue } from '@monkvision/common'; import { AddImageOptions, ImageUploadType, MonkApiConfig, useMonkApi } from '@monkvision/network'; import { PhotoCaptureAppConfig, @@ -133,6 +133,7 @@ function createAddImageOptions( enableThumbnail: boolean, additionalTasks?: PhotoCaptureAppConfig['additionalTasks'], compliance?: ComplianceOptions, + wheelAnalysisCloseUp?: boolean, ): AddImageOptions { if (upload.mode === CaptureMode.SIGHT) { return { @@ -143,6 +144,7 @@ function createAddImageOptions( inspectionId, compliance, useThumbnailCaching: enableThumbnail, + wheelAnalysisCloseUp, }; } if (upload.mode === CaptureMode.ADD_DAMAGE_PART_SELECT_SHOT) { @@ -179,6 +181,11 @@ export function useUploadQueue({ const { handleError } = useMonitoring(); const siblingIdRef = useRef(0); const { addImage } = useMonkApi(apiConfig); + const { state } = useMonkState(); + + const wheelAnalysisCloseUp = state.tasks.find( + (task) => task.name === TaskName.WHEEL_ANALYSIS && task.wheelAnalysisCloseUp, + )?.wheelAnalysisCloseUp; return useQueue(async (upload: PictureUpload) => { if (upload.mode === CaptureMode.ADD_DAMAGE_1ST_SHOT) { @@ -194,6 +201,7 @@ export function useUploadQueue({ true, additionalTasks, complianceOptions, + wheelAnalysisCloseUp, ), ); const uploadDurationMs = Date.now() - startTs; diff --git a/packages/network/src/api/image/requests.ts b/packages/network/src/api/image/requests.ts index 4d3cdb2ee..4d30f256d 100644 --- a/packages/network/src/api/image/requests.ts +++ b/packages/network/src/api/image/requests.ts @@ -86,6 +86,8 @@ export interface AddBeautyShotImageOptions { * Additional options used to configure the compliance locally. */ compliance?: ComplianceOptions; + + wheelAnalysisCloseUp?: boolean; } /** @@ -291,6 +293,7 @@ function createBeautyShotImageData( TaskName.IMAGES_OCR, TaskName.ODOMETER, TaskName.WARNING_LIGHTS, + TaskName.WHEEL_ANALYSIS, ].includes(task), ) as ApiImagePostTask[]; tasks.push({ @@ -323,6 +326,25 @@ function createBeautyShotImageData( wait_for_result: true, }); } + if (options.tasks.includes(TaskName.WHEEL_ANALYSIS)) { + const sightName = sights[options.sightId].wheelName; + if (options.wheelAnalysisCloseUp && !sightName) { + throw new Error('Wheel analysis task close-up requires a sight name.'); + } + if (!options.wheelAnalysisCloseUp && sightName) { + throw new Error( + "Wheel analysis task long shoot can't be run on sight that contains sightName.", + ); + } + if (options.wheelAnalysisCloseUp && sightName) { + tasks.push({ + name: TaskName.WHEEL_ANALYSIS, + image_details: { wheel_name: sightName }, + }); + } else { + tasks.push(TaskName.WHEEL_ANALYSIS); + } + } const body: ApiImagePost = { acquisition: { diff --git a/packages/network/src/api/inspection/mappers.ts b/packages/network/src/api/inspection/mappers.ts index e7637ed0c..770455376 100644 --- a/packages/network/src/api/inspection/mappers.ts +++ b/packages/network/src/api/inspection/mappers.ts @@ -5,6 +5,7 @@ import { CreateHinlTaskOptions, CreateInspectionOptions, CreatePricingTaskOptions, + CreateWheelAnalysisTaskOptions, CurrencyCode, CustomSeverityValue, Damage, @@ -326,6 +327,11 @@ function mapTasks(response: ApiInspectionGet): { tasks: Task[]; taskIds: string[ name: task.name as TaskName, status: task.status as ProgressStatus, images: task.images?.map((image) => image.image_id) ?? [], + ...(task.arguments?.['use_longshots'] !== undefined + ? { + wheelAnalysisCloseUp: !task.arguments['use_longshots'] as boolean, + } + : {}), }); }); @@ -563,10 +569,20 @@ function getDamageDetectionOptions( function getWheelAnalysisOptions( options: CreateInspectionOptions, ): ApiWheelAnalysisTaskPostComponent | undefined { - return options.tasks.includes(TaskName.WHEEL_ANALYSIS) + if (options.tasks.includes(TaskName.WHEEL_ANALYSIS)) { + return { + status: ProgressStatus.NOT_STARTED, + use_longshots: true, + }; + } + const taskOptions = options.tasks.find( + (task) => typeof task === 'object' && task.name === TaskName.WHEEL_ANALYSIS, + ) as CreateWheelAnalysisTaskOptions | undefined; + return taskOptions ? { status: ProgressStatus.NOT_STARTED, - use_longshots: true, + use_longshots: taskOptions.useLongShots, + callbacks: taskOptions.callbacks, } : undefined; } diff --git a/packages/network/src/api/models/image.ts b/packages/network/src/api/models/image.ts index 7405ade90..01c1e6fb6 100644 --- a/packages/network/src/api/models/image.ts +++ b/packages/network/src/api/models/image.ts @@ -10,6 +10,7 @@ import { ApiImagesOCRTaskPost, ApiImagesOdometerTaskPost, ApiImagesWarningLightsTaskPost, + ApiImagesWheelAnalysisTaskPost, } from './task'; export type ApiImageType = 'unknown' | 'beauty_shot' | 'close_up'; @@ -111,7 +112,8 @@ export type ApiImagePostTask = | ApiHinlTaskPost | ApiImagesOCRTaskPost | ApiImagesOdometerTaskPost - | ApiImagesWarningLightsTaskPost; + | ApiImagesWarningLightsTaskPost + | ApiImagesWheelAnalysisTaskPost; export interface ApiImagePost { acquisition: ApiAcquisition; diff --git a/packages/network/src/api/models/task.ts b/packages/network/src/api/models/task.ts index 1f4c031a0..11c312899 100644 --- a/packages/network/src/api/models/task.ts +++ b/packages/network/src/api/models/task.ts @@ -1,4 +1,5 @@ import { ApiPricingMethodology } from './pricingV2'; +import { ApiWheelType } from './wheelAnalysis'; export interface ApiImageInTask { image_id: string; @@ -57,6 +58,15 @@ export interface ApiImagesWarningLightsTaskPost { wait_for_result?: boolean; } +export interface ApiWheelAnalysisImageDetails { + wheel_name: ApiWheelType; +} + +export interface ApiImagesWheelAnalysisTaskPost { + name: 'wheel_analysis'; + image_details: ApiWheelAnalysisImageDetails; +} + export type ApiTaskProgressStatus = | 'NOT_STARTED' | 'TODO' @@ -71,6 +81,7 @@ export interface ApiTaskGet { images: ApiImageInTask[]; name: ApiBusinessTaskName; status: ApiTaskProgressStatus; + arguments?: Record; } export type ApiTasks = ApiTaskGet[]; diff --git a/packages/network/test/api/image/requests.test.ts b/packages/network/test/api/image/requests.test.ts index c0e451f3c..040af18eb 100644 --- a/packages/network/test/api/image/requests.test.ts +++ b/packages/network/test/api/image/requests.test.ts @@ -306,6 +306,7 @@ describe('Image requests', () => { TaskName.IMAGES_OCR, TaskName.ODOMETER, TaskName.WARNING_LIGHTS, + TaskName.WHEEL_ANALYSIS, ].includes(task), ), { @@ -328,6 +329,7 @@ describe('Image requests', () => { name: TaskName.WARNING_LIGHTS, wait_for_result: true, }, + TaskName.WHEEL_ANALYSIS, ], additional_data: { sight_id: options.sightId, diff --git a/packages/network/test/api/inspection/data/apiInspectionGet.data.ts b/packages/network/test/api/inspection/data/apiInspectionGet.data.ts index d489e27f3..c8f1e759f 100644 --- a/packages/network/test/api/inspection/data/apiInspectionGet.data.ts +++ b/packages/network/test/api/inspection/data/apiInspectionGet.data.ts @@ -946,6 +946,7 @@ export default { name: 'wheel_analysis', status: 'DONE', images: ['6a5e9a4c-8752-c1e6-6a34-38338074eda1'], + wheelAnalysisCloseUp: false, }, ], vehicles: [ diff --git a/packages/sights/research/data/fesc20/fesc20.json b/packages/sights/research/data/fesc20/fesc20.json index 2f46514d3..5b23c4c3e 100644 --- a/packages/sights/research/data/fesc20/fesc20.json +++ b/packages/sights/research/data/fesc20/fesc20.json @@ -70,6 +70,7 @@ "vehicle": "fesc20", "mirror_sight": "fesc20-raHPDUNm", "dev": true, + "wheel_name": "wheel_back_left", "tasks": ["wheel_analysis"] }, "fesc20-5Ts1UkPT": { @@ -96,6 +97,7 @@ "vehicle": "fesc20", "mirror_sight": "fesc20-Tlu3sz8A", "dev": true, + "wheel_name": "wheel_back_right", "tasks": ["wheel_analysis"] }, "fesc20-6GPUkfYn": { @@ -335,6 +337,7 @@ "vehicle": "fesc20", "mirror_sight": "fesc20-W6XrryMO", "dev": true, + "wheel_name": "wheel_front_left", "tasks": ["wheel_analysis"] }, "fesc20-WMUaKDp1": { @@ -419,6 +422,7 @@ "vehicle": "fesc20", "mirror_sight": "fesc20-YPcJPAZE", "dev": true, + "wheel_name": "wheel_front_right", "tasks": ["wheel_analysis"] }, "fesc20-dfICsfSV": { diff --git a/packages/sights/research/data/ff150/ff150.json b/packages/sights/research/data/ff150/ff150.json index ab4434708..db0827083 100644 --- a/packages/sights/research/data/ff150/ff150.json +++ b/packages/sights/research/data/ff150/ff150.json @@ -114,6 +114,7 @@ "vehicle": "ff150", "mirror_sight": "ff150-7vyfzrVQ", "dev": true, + "wheel_name": "wheel_back_right", "tasks": ["wheel_analysis"] }, "ff150-7UI3m9B3": { @@ -155,6 +156,7 @@ "vehicle": "ff150", "mirror_sight": "ff150-pNO26q4D", "dev": true, + "wheel_name": "wheel_front_right", "tasks": ["wheel_analysis"] }, "ff150-BmXfb-qD": { @@ -197,6 +199,7 @@ "vehicle": "ff150", "mirror_sight": "ff150-jUBEKij0", "dev": true, + "wheel_name": "wheel_front_left", "tasks": ["wheel_analysis"] }, "ff150-GOx2s_9L": { @@ -419,6 +422,7 @@ "vehicle": "ff150", "mirror_sight": "ff150-H3MCPESJ", "dev": true, + "wheel_name": "wheel_back_right", "tasks": ["wheel_analysis"] }, "ff150-phbX7Bef": { diff --git a/packages/sights/research/data/ffocus18/ffocus18.json b/packages/sights/research/data/ffocus18/ffocus18.json index fecd044e9..ccebf1e0d 100644 --- a/packages/sights/research/data/ffocus18/ffocus18.json +++ b/packages/sights/research/data/ffocus18/ffocus18.json @@ -175,6 +175,7 @@ "vehicle": "ffocus18", "mirror_sight": "ffocus18-Eo0jqD_a", "dev": true, + "wheel_name": "wheel_front_right", "tasks": ["wheel_analysis"] }, "ffocus18-L2UM_68Q": { @@ -230,6 +231,7 @@ "vehicle": "ffocus18", "mirror_sight": "ffocus18-JFX8WF9P", "dev": true, + "wheel_name": "wheel_back_right", "tasks": ["wheel_analysis"] }, "ffocus18-QKfhXU7o": { @@ -272,6 +274,7 @@ "vehicle": "ffocus18", "mirror_sight": "ffocus18-tufa4FoL", "dev": true, + "wheel_name": "wheel_back_left", "tasks": ["wheel_analysis"] }, "ffocus18-U3Bcfc2Q": { @@ -543,6 +546,7 @@ "vehicle": "ffocus18", "mirror_sight": "ffocus18-jkSlWpql", "dev": true, + "wheel_name": "wheel_front_left", "tasks": ["wheel_analysis"] }, "ffocus18-yo9eBDW6": { diff --git a/packages/sights/research/data/ftransit18/ftransit18.json b/packages/sights/research/data/ftransit18/ftransit18.json index a6a97db24..4618c0ff0 100644 --- a/packages/sights/research/data/ftransit18/ftransit18.json +++ b/packages/sights/research/data/ftransit18/ftransit18.json @@ -39,6 +39,7 @@ "vehicle": "ftransit18", "mirror_sight": "ftransit18-AuCXxG5o", "dev": true, + "wheel_name": "wheel_back_left", "tasks": ["wheel_analysis"] }, "ftransit18-3dkU10af": { @@ -96,6 +97,7 @@ "vehicle": "ftransit18", "mirror_sight": "ftransit18-mGSvkRHz", "dev": true, + "wheel_name": "wheel_front_right", "tasks": ["wheel_analysis"] }, "ftransit18-5SiNC94w": { @@ -243,6 +245,7 @@ "vehicle": "ftransit18", "mirror_sight": "ftransit18-yxw9gmyL", "dev": true, + "wheel_name": "wheel_back_right", "tasks": ["wheel_analysis"] }, "ftransit18-TkXihCj4": { @@ -299,6 +302,7 @@ "vehicle": "ftransit18", "mirror_sight": "ftransit18-7qLSCnFP", "dev": true, + "wheel_name": "wheel_front_left", "tasks": ["wheel_analysis"] }, "ftransit18-aA2K898S": { diff --git a/packages/sights/research/data/haccord/haccord.json b/packages/sights/research/data/haccord/haccord.json index 4f72c7525..8bf2cb625 100644 --- a/packages/sights/research/data/haccord/haccord.json +++ b/packages/sights/research/data/haccord/haccord.json @@ -112,6 +112,7 @@ "vehicle": "haccord", "mirror_sight": "haccord-boMeNVsC", "dev": true, + "wheel_name": "wheel_front_left", "tasks": ["wheel_analysis"] }, "haccord-GdWvsqrm": { @@ -184,6 +185,7 @@ "vehicle": "haccord", "mirror_sight": "haccord-2v-2_QD5", "dev": true, + "wheel_name": "wheel_front_right", "tasks": ["wheel_analysis"] }, "haccord-KvP-pm8L": { @@ -226,6 +228,7 @@ "vehicle": "haccord", "mirror_sight": "haccord-H_eRrLBl", "dev": true, + "wheel_name": "wheel_back_right", "tasks": ["wheel_analysis"] }, "haccord-PGr3RzzP": { @@ -299,6 +302,7 @@ "vehicle": "haccord", "mirror_sight": "haccord-9fxMGSs6", "dev": true, + "wheel_name": "wheel_back_left", "tasks": ["wheel_analysis"] }, "haccord-Z84erkMb": { diff --git a/packages/sights/research/data/jgc21/jgc21.json b/packages/sights/research/data/jgc21/jgc21.json index 58815352b..b77ab22d0 100644 --- a/packages/sights/research/data/jgc21/jgc21.json +++ b/packages/sights/research/data/jgc21/jgc21.json @@ -84,6 +84,7 @@ "vehicle": "jgc21", "mirror_sight": "jgc21-xwYV3_Hz", "dev": true, + "wheel_name": "wheel_back_left", "tasks": ["wheel_analysis"] }, "jgc21-5lovhZgA": { @@ -259,6 +260,7 @@ "vehicle": "jgc21", "mirror_sight": "jgc21-2bGeRS3I", "dev": true, + "wheel_name": "wheel_back_right", "tasks": ["wheel_analysis"] }, "jgc21-RE3li6rE": { @@ -470,6 +472,7 @@ "vehicle": "jgc21", "mirror_sight": "jgc21-nVbhsBaQ", "dev": true, + "wheel_name": "wheel_front_right", "tasks": ["wheel_analysis"] }, "jgc21-tbF2Ax8v": { @@ -510,6 +513,7 @@ "vehicle": "jgc21", "mirror_sight": "jgc21-S8sE69on", "dev": true, + "wheel_name": "wheel_front_left", "tasks": ["wheel_analysis"] }, "jgc21-zCrDwYWE": { diff --git a/packages/sights/research/data/tsienna20/tsienna20.json b/packages/sights/research/data/tsienna20/tsienna20.json index 7a6c62f18..01379a02d 100644 --- a/packages/sights/research/data/tsienna20/tsienna20.json +++ b/packages/sights/research/data/tsienna20/tsienna20.json @@ -85,6 +85,7 @@ "vehicle": "tsienna20", "mirror_sight": "tsienna20-K0ThKmue", "dev": true, + "wheel_name": "wheel_front_left", "tasks": ["wheel_analysis"] }, "tsienna20-670P2H2V": { @@ -111,6 +112,7 @@ "vehicle": "tsienna20", "mirror_sight": "tsienna20-RP6TzN4w", "dev": true, + "wheel_name": "wheel_back_left", "tasks": ["wheel_analysis"] }, "tsienna20-D6pPBrXx": { @@ -258,6 +260,7 @@ "vehicle": "tsienna20", "mirror_sight": "tsienna20-2Zz6SEaI", "dev": true, + "wheel_name": "wheel_back_right", "tasks": ["wheel_analysis"] }, "tsienna20-TI4TVvT9": { @@ -376,6 +379,7 @@ "vehicle": "tsienna20", "mirror_sight": "tsienna20-uz29ILgw", "dev": true, + "wheel_name": "wheel_front_right", "tasks": ["wheel_analysis"] }, "tsienna20-g2uWI1l8": { diff --git a/packages/sights/research/schemas/sight.schema.json b/packages/sights/research/schemas/sight.schema.json index 10ac6e52c..aae3beab9 100644 --- a/packages/sights/research/schemas/sight.schema.json +++ b/packages/sights/research/schemas/sight.schema.json @@ -13,6 +13,9 @@ }, "Task": { "$ref": "subschemas/task.schema" + }, + "WheelName": { + "$ref": "subschemas/wheelName.schema" } }, "type": "object", @@ -41,6 +44,9 @@ "vehicle": { "$ref": "#/definitions/Vehicle" }, + "wheel_name": { + "$ref": "#/definitions/WheelName" + }, "tasks": { "$ref": "#/definitions/Task" } diff --git a/packages/sights/research/schemas/subschemas/wheelName.schema.json b/packages/sights/research/schemas/subschemas/wheelName.schema.json new file mode 100644 index 000000000..44950eaeb --- /dev/null +++ b/packages/sights/research/schemas/subschemas/wheelName.schema.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "subschemas/wheelName.schema", + "type": "string", + "enum": ["wheel_front_left", "wheel_front_right", "wheel_back_left", "wheel_back_right"] +} diff --git a/packages/sights/src/build/buildJSONs.ts b/packages/sights/src/build/buildJSONs.ts index af252f245..f40482185 100644 --- a/packages/sights/src/build/buildJSONs.ts +++ b/packages/sights/src/build/buildJSONs.ts @@ -2,9 +2,12 @@ import { LabelDictionary, PartSelectionOrientation, PartSelectionWireframes, + Sight, SightDictionary, + VehicleDetails, VehicleDictionary, VehicleModel, + WheelName, WireframeDictionary, } from '@monkvision/types'; import { existsSync, readFileSync } from 'fs'; @@ -31,16 +34,20 @@ function mapLabels(labels: LabelDictionary): LabelDictionary { function mapVehicles(vehicles: VehicleDictionary): VehicleDictionary { return Object.entries(vehicles).reduce( - (prev: Partial, [model, vehicleDetails]) => ({ - ...prev, - [model]: { - id: model, - make: vehicleDetails.make, - model: vehicleDetails.model, - type: vehicleDetails.type, - dimensionsXYZ: vehicleDetails.dimensionsXYZ, - }, - }), + (prev: Partial, [model, vehicleDetails]) => { + const apiVehicleDetails = vehicleDetails as VehicleDetails & { dimensions_xyz?: number[] }; + + return { + ...prev, + [model]: { + id: model, + make: vehicleDetails.make, + model: vehicleDetails.model, + type: vehicleDetails.type, + dimensionsXYZ: apiVehicleDetails.dimensions_xyz, + }, + }; + }, {}, ) as VehicleDictionary; } @@ -54,8 +61,9 @@ function mapSights( vehicle: VehicleModel, overlaysPath: string, ): SightDictionary { - return Object.entries(sights).reduce( - (prev: SightDictionary, [id, sight]) => ({ + return Object.entries(sights).reduce((prev: SightDictionary, [id, sight]) => { + const apiSight = sight as Sight & { wheel_name?: WheelName }; + return { ...prev, [id]: { id, @@ -64,10 +72,10 @@ function mapSights( overlay: readOverlay(join(overlaysPath, sight.overlay)), tasks: sight.tasks, vehicle, + wheelName: apiSight.wheel_name, }, - }), - {}, - ); + }; + }, {}); } function mapWireframes(vehicles: VehicleDictionary): WireframeDictionary { diff --git a/packages/sights/test/build/buildJSON.test.ts b/packages/sights/test/build/buildJSON.test.ts index b4da0bb4c..9ee90fcd4 100644 --- a/packages/sights/test/build/buildJSON.test.ts +++ b/packages/sights/test/build/buildJSON.test.ts @@ -3,10 +3,12 @@ jest.mock('../../src/io'); import { PartSelectionOrientation, + Sight, SightCategory, SightDictionary, TaskName, VehicleModel, + WheelName, } from '@monkvision/types'; import fs from 'fs'; import { join, resolve } from 'path'; @@ -24,13 +26,13 @@ describe('JSON builder module', () => { make: 'make', model: 'model', type: 'type', - dimensionsXYZ: [1, 2, 3], + dimensions_xyz: [1, 2, 3], }, 'vehicle-key-2': { make: 'make 2', model: 'model 2', type: 'type 2', - dimensionsXYZ: [4, 5, 6], + dimensions_xyz: [4, 5, 6], extra: 'extra', }, }; @@ -44,6 +46,7 @@ describe('JSON builder module', () => { overlay: 'overlay1.svg', tasks: [TaskName.DAMAGE_DETECTION], vehicle, + wheel_name: WheelName.FRONT_LEFT, }, [`${vehicle}-dos`]: { id: `${vehicle}-dos`, @@ -151,7 +154,7 @@ describe('JSON builder module', () => { make: value.make, model: value.model, type: value.type, - dimensionsXYZ: value.dimensionsXYZ, + dimensionsXYZ: value.dimensions_xyz, }, }), {}, @@ -173,19 +176,24 @@ describe('JSON builder module', () => { it('should properly map the sights and write them in the lib directory', () => { const saveLibJSONSpy = jest.spyOn(io, 'saveLibJSON'); const properlyMappedSights = Object.entries(sights).reduce( - (prev: SightDictionary, [id, value]) => ({ - ...prev, - [id]: { - id, - category: value.category, - label: value.label, - tasks: value.tasks, - overlay: resolve( - join(__dirname, `../../research/data/${value.vehicle}/overlays/${value.overlay}`), - ), - vehicle: value.vehicle, - }, - }), + (prev: SightDictionary, [id, value]) => { + const apiSight = value as Sight & { wheel_name?: WheelName }; + + return { + ...prev, + [id]: { + id, + category: value.category, + label: value.label, + tasks: value.tasks, + overlay: resolve( + join(__dirname, `../../research/data/${value.vehicle}/overlays/${value.overlay}`), + ), + vehicle: value.vehicle, + wheelName: apiSight.wheel_name, + }, + }; + }, {} as SightDictionary, ); diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index a1138aecc..642f691e6 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -97,6 +97,27 @@ export interface CreateHinlTaskOptions { callbacks?: TaskCallbackOptions[]; } +/** + * Additional options that you can specify when adding the wheel analysis task to an inspection. + */ +export interface CreateWheelAnalysisTaskOptions { + /** + * The name of the task : `TaskName.WHEEL_ANALYSIS`. + */ + name: TaskName.WHEEL_ANALYSIS; + /** + * A boolean flag that determines whether wheel analysis should be performed on long shots. + * - When true: The system will generate cropped images of wheels to perform the analysis. + * - When false: The analysis will only run on sights that have the 'wheelName' field specified; + * otherwise, wheel analysis will be skipped for that sight. + */ + useLongShots: boolean; + /** + * The callbacks called at the end of the wheel analysis task. + */ + callbacks?: TaskCallbackOptions[]; +} + /** * The different methodologies that can be used to calculate pricing values. */ @@ -146,7 +167,8 @@ export type InspectionCreateTask = | TaskName | CreateDamageDetectionTaskOptions | CreateHinlTaskOptions - | CreatePricingTaskOptions; + | CreatePricingTaskOptions + | CreateWheelAnalysisTaskOptions; /** * Options that can be specified when creating a new inspection. diff --git a/packages/types/src/sights.ts b/packages/types/src/sights.ts index a31aba86d..88be8fe7e 100644 --- a/packages/types/src/sights.ts +++ b/packages/types/src/sights.ts @@ -1,4 +1,4 @@ -import { TaskName } from './state'; +import { TaskName, WheelName } from './state'; import { TranslationObject } from './i18n'; /** @@ -202,6 +202,10 @@ export interface Sight { * The list of tasks that must be run on this sight. */ tasks: TaskName[]; + /** + * The name of the wheel used for wheel analysis task. + */ + wheelName?: WheelName; } /** diff --git a/packages/types/src/state/task.ts b/packages/types/src/state/task.ts index bab38e181..d18fbd0e1 100644 --- a/packages/types/src/state/task.ts +++ b/packages/types/src/state/task.ts @@ -84,4 +84,10 @@ export interface Task extends MonkEntity { * The IDs of the images on which the task is being performed. */ images: string[]; + /** + * Boolean indicing if the wheel analysis task should be run on: + * - True: Close up mode ( only on sight that have wheelName field ) + * - False: Long shot mode ( only on sight that have wheel present and doesn't have wheelName field) + */ + wheelAnalysisCloseUp?: boolean; }