@overmap-ai/core 1.0.63-form-submission-fix.0 → 1.0.63-form-submission-fix.2

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.
@@ -5503,36 +5503,66 @@ const separateImageFromFields = async (fields) => {
5503
5503
  }
5504
5504
  return { fields: newFields, images };
5505
5505
  };
5506
- class FormService extends BaseApiService {
5507
- constructor() {
5508
- super(...arguments);
5509
- // Attach images to revision, after uploading them to S3
5510
- __publicField(this, "getAttachImagePromises", (images, offlineRevisionId) => {
5511
- return Object.entries(images).map(async ([key, image]) => {
5512
- const sha1 = await hashFile(image);
5513
- await this.client.files.addCache(image, sha1);
5514
- const [fileProps] = await this.client.files.uploadFileToS3(sha1);
5515
- const revisionAttachmentPayload = offline({
5516
- ...fileProps,
5517
- revision: offlineRevisionId,
5518
- field_identifier: key
5519
- });
5520
- const attach = await this.enqueueRequest({
5521
- description: "Attach image to form revision field",
5522
- method: HttpMethod.POST,
5523
- url: `/forms/revisions/${offlineRevisionId}/attachments/`,
5524
- payload: revisionAttachmentPayload,
5525
- blockers: [revisionAttachmentPayload.revision],
5526
- blocks: [revisionAttachmentPayload.offline_id]
5527
- });
5528
- const offlinePayload = {
5529
- ...revisionAttachmentPayload,
5530
- file: URL.createObjectURL(image)
5506
+ class FormService extends BaseUploadService {
5507
+ async bulkAddRevisionAttachments(revisionId, files) {
5508
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
5509
+ const createdBy = this.client.store.getState().userReducer.currentUser.id;
5510
+ const filePayloads = {};
5511
+ const offlineFormRevisionAttachments = [];
5512
+ const attachmentPayloads = [];
5513
+ for (const [fieldIdentifier, file] of Object.entries(files)) {
5514
+ const sha1 = await hashFile(file);
5515
+ if (!(sha1 in filePayloads)) {
5516
+ filePayloads[sha1] = {
5517
+ sha1,
5518
+ file_type: file.type,
5519
+ extension: file.name.split(".").pop(),
5520
+ size: file.size
5531
5521
  };
5532
- this.dispatch(addFormRevisionAttachment(offlinePayload));
5533
- return attach;
5522
+ await this.client.files.addCache(file, sha1);
5523
+ }
5524
+ const offlineFormRevisionAttachment = offline({
5525
+ file: URL.createObjectURL(file),
5526
+ file_type: file.type,
5527
+ file_name: file.name,
5528
+ file_sha1: sha1,
5529
+ created_by: createdBy,
5530
+ revision: revisionId,
5531
+ submitted_at: submittedAt,
5532
+ field_identifier: fieldIdentifier
5534
5533
  });
5534
+ offlineFormRevisionAttachments.push(offlineFormRevisionAttachment);
5535
+ const attachmentPayload = {
5536
+ offline_id: offlineFormRevisionAttachment.offline_id,
5537
+ name: file.name,
5538
+ sha1
5539
+ };
5540
+ attachmentPayloads.push(attachmentPayload);
5541
+ }
5542
+ this.dispatch(addFormRevisionAttachments(offlineFormRevisionAttachments));
5543
+ const promise = this.enqueueRequest({
5544
+ description: "Attach files to form revision",
5545
+ method: HttpMethod.POST,
5546
+ url: `/forms/revisions/${revisionId}/attachments/bulk/`,
5547
+ payload: {
5548
+ submitted_at: submittedAt,
5549
+ attachments: attachmentPayloads,
5550
+ files: Object.values(filePayloads)
5551
+ },
5552
+ blockers: [revisionId],
5553
+ blocks: offlineFormRevisionAttachments.map((attachment) => attachment.offline_id)
5554
+ });
5555
+ promise.then((result) => {
5556
+ this.processPresignedUrls(result.presigned_urls);
5557
+ this.dispatch(updateFormRevisionAttachments(result.attachments));
5558
+ }).catch(() => {
5559
+ this.dispatch(
5560
+ deleteFormRevisionAttachments(
5561
+ offlineFormRevisionAttachments.map((attachment) => attachment.offline_id)
5562
+ )
5563
+ );
5535
5564
  });
5565
+ return [offlineFormRevisionAttachments, promise.then(({ attachments }) => attachments)];
5536
5566
  }
5537
5567
  async add(ownerId, form, initialRevision, urlPrefix) {
5538
5568
  const { fields, images } = await separateImageFromFields(initialRevision.fields);
@@ -5565,14 +5595,16 @@ class FormService extends BaseApiService {
5565
5595
  blockers: [ownerId],
5566
5596
  blocks: [form.offline_id, offlineFormRevision.offline_id]
5567
5597
  });
5568
- const attachImagesPromises = this.getAttachImagePromises(images, offlineFormRevision.offline_id);
5598
+ const [offlineFormRevisionAttachments, attachmentsPromise] = await this.bulkAddRevisionAttachments(
5599
+ offlineFormRevision.offline_id,
5600
+ images
5601
+ );
5569
5602
  void formPromise.catch((e) => {
5570
5603
  this.dispatch(deleteForm(form.offline_id));
5571
5604
  this.dispatch(deleteFormRevision(offlineFormRevision.offline_id));
5572
5605
  throw e;
5573
5606
  });
5574
- const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
5575
- return [form, offlineFormRevision, formPromise, settledPromise];
5607
+ return [form, offlineFormRevision, offlineFormRevisionAttachments, formPromise, attachmentsPromise];
5576
5608
  }
5577
5609
  addForOrganization(organizationId, initialRevision) {
5578
5610
  const state = this.client.store.getState();
@@ -5654,14 +5686,16 @@ class FormService extends BaseApiService {
5654
5686
  blockers: [formId],
5655
5687
  blocks: [offlineRevision.offline_id]
5656
5688
  });
5657
- const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
5689
+ const [offlineFormRevisionAttachments, attachmentsPromise] = await this.bulkAddRevisionAttachments(
5690
+ fullRevision.offline_id,
5691
+ images
5692
+ );
5658
5693
  void promise.then((result) => {
5659
5694
  this.dispatch(setFormRevision(result));
5660
5695
  }).catch(() => {
5661
5696
  this.dispatch(deleteFormRevision(fullRevision.offline_id));
5662
5697
  });
5663
- const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
5664
- return [fullRevision, settledPromise];
5698
+ return [fullRevision, offlineFormRevisionAttachments, promise, attachmentsPromise];
5665
5699
  }
5666
5700
  async favorite(formId) {
5667
5701
  const { store } = this.client;
@@ -5824,46 +5858,70 @@ const separateFilesFromValues = (values) => {
5824
5858
  return { values: newValues, files };
5825
5859
  };
5826
5860
  class FormSubmissionService extends BaseUploadService {
5827
- constructor() {
5828
- super(...arguments);
5829
- // Attach files to submission, after uploading them to S3
5830
- __publicField(this, "getAttachFilesPromises", (files, submission) => {
5831
- return Object.entries(files).map(async ([key, fileArray]) => {
5832
- const attachResults = [];
5833
- for (const file of fileArray) {
5834
- const sha1 = await hashFile(file);
5835
- await this.client.files.addCache(file, sha1);
5836
- const [fileProps] = await this.client.files.uploadFileToS3(sha1);
5837
- const submissionAttachmentPayload = offline({
5838
- ...fileProps,
5839
- submission: submission.offline_id,
5840
- field_identifier: key
5841
- });
5842
- const attach = await this.enqueueRequest({
5843
- description: "Attach file to form submission",
5844
- method: HttpMethod.POST,
5845
- url: `/forms/submission/${submission.offline_id}/attachments/`,
5846
- payload: submissionAttachmentPayload,
5847
- blockers: [
5848
- submission.asset,
5849
- submission.asset_stage,
5850
- submission.issue,
5851
- submission.form_revision
5852
- ].filter((x) => x !== void 0),
5853
- blocks: [submissionAttachmentPayload.offline_id]
5854
- });
5855
- const offlinePayload = {
5856
- ...submissionAttachmentPayload,
5857
- file: URL.createObjectURL(file)
5861
+ async bulkAddSubmissionAttachments(submissionId, files) {
5862
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
5863
+ const createdBy = this.client.store.getState().userReducer.currentUser.id;
5864
+ const filePayloads = {};
5865
+ const offlineFormSubmissionAttachments = [];
5866
+ const attachmentPayloads = [];
5867
+ for (const [fieldIdentifier, filesArray] of Object.entries(files)) {
5868
+ for (const file of filesArray) {
5869
+ const sha1 = await hashFile(file);
5870
+ if (!(sha1 in filePayloads)) {
5871
+ filePayloads[sha1] = {
5872
+ sha1,
5873
+ file_type: file.type,
5874
+ extension: file.name.split(".").pop(),
5875
+ size: file.size
5858
5876
  };
5859
- this.dispatch(addFormSubmissionAttachment(offlinePayload));
5860
- attachResults.push(attach);
5877
+ await this.client.files.addCache(file, sha1);
5861
5878
  }
5862
- return attachResults;
5863
- });
5879
+ const offlineFormSubmissionAttachment = offline({
5880
+ file: URL.createObjectURL(file),
5881
+ file_type: file.type,
5882
+ file_name: file.name,
5883
+ file_sha1: sha1,
5884
+ created_by: createdBy,
5885
+ submission: submissionId,
5886
+ submitted_at: submittedAt,
5887
+ field_identifier: fieldIdentifier
5888
+ });
5889
+ offlineFormSubmissionAttachments.push(offlineFormSubmissionAttachment);
5890
+ const attachmentPayload = {
5891
+ offline_id: offlineFormSubmissionAttachment.offline_id,
5892
+ name: file.name,
5893
+ sha1
5894
+ };
5895
+ attachmentPayloads.push(attachmentPayload);
5896
+ }
5897
+ }
5898
+ this.dispatch(addFormSubmissionAttachments(offlineFormSubmissionAttachments));
5899
+ const promise = this.enqueueRequest({
5900
+ description: "Attach files to form submission",
5901
+ method: HttpMethod.POST,
5902
+ url: `/forms/submissions/${submissionId}/attachments/bulk/`,
5903
+ payload: {
5904
+ submitted_at: submittedAt,
5905
+ attachments: attachmentPayloads,
5906
+ files: Object.values(filePayloads)
5907
+ },
5908
+ blockers: [submissionId],
5909
+ blocks: offlineFormSubmissionAttachments.map((attachment) => attachment.offline_id)
5910
+ });
5911
+ promise.then((result) => {
5912
+ this.processPresignedUrls(result.presigned_urls);
5913
+ this.dispatch(updateFormSubmissionAttachments(result.attachments));
5914
+ }).catch(() => {
5915
+ this.dispatch(
5916
+ deleteFormSubmissionAttachments(
5917
+ offlineFormSubmissionAttachments.map((attachment) => attachment.offline_id)
5918
+ )
5919
+ );
5864
5920
  });
5921
+ return [offlineFormSubmissionAttachments, promise.then(({ attachments }) => attachments)];
5865
5922
  }
5866
- add(payload) {
5923
+ // Outer promise is for hashing and caching files for submission attachments
5924
+ async add(payload) {
5867
5925
  const { store } = this.client;
5868
5926
  const state = store.getState();
5869
5927
  const activeProjectId = state.projectReducer.activeProjectId;
@@ -5887,9 +5945,12 @@ class FormSubmissionService extends BaseUploadService {
5887
5945
  ),
5888
5946
  blocks: [offlineSubmission.offline_id]
5889
5947
  });
5890
- const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
5891
5948
  this.dispatch(addFormSubmission(offlineSubmission));
5892
- void promise.then((result) => {
5949
+ const [offlineFormSubmissionAttachments, attachmentsPromise] = await this.bulkAddSubmissionAttachments(
5950
+ offlineSubmission.offline_id,
5951
+ files
5952
+ );
5953
+ promise.then((result) => {
5893
5954
  this.dispatch(addActiveProjectFormSubmissionsCount(1));
5894
5955
  this.dispatch(setFormSubmission(result));
5895
5956
  return result;
@@ -5897,8 +5958,7 @@ class FormSubmissionService extends BaseUploadService {
5897
5958
  this.dispatch(deleteFormSubmission(offlineSubmission.offline_id));
5898
5959
  this.dispatch(addActiveProjectFormSubmissionsCount(-1));
5899
5960
  });
5900
- const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
5901
- return [offlineSubmission, settledPromise];
5961
+ return [offlineSubmission, offlineFormSubmissionAttachments, promise, attachmentsPromise];
5902
5962
  }
5903
5963
  // Note currently the bulkAdd method is specific to form submissions for assets
5904
5964
  // TODO: adapt the support bulk adding to any model type
@@ -5999,36 +6059,6 @@ class FormSubmissionService extends BaseUploadService {
5999
6059
  });
6000
6060
  return batchPromises;
6001
6061
  }
6002
- update(submission) {
6003
- const { store } = this.client;
6004
- const { values, files } = separateFilesFromValues(submission.values);
6005
- const attachFilesPromises = this.getAttachFilesPromises(files, submission);
6006
- const offlineSubmission = {
6007
- ...submission,
6008
- values
6009
- };
6010
- const submissionToBeUpdated = selectFormSubmission(submission.offline_id)(store.getState());
6011
- if (!submissionToBeUpdated) {
6012
- throw new Error(`Expected submission with offline_id ${submission.offline_id} to exist`);
6013
- }
6014
- this.dispatch(updateFormSubmission(offlineSubmission));
6015
- const promise = this.enqueueRequest({
6016
- description: "Patch form submission",
6017
- method: HttpMethod.PATCH,
6018
- url: `/forms/submissions/${submission.offline_id}/`,
6019
- payload: offlineSubmission,
6020
- blockers: [offlineSubmission.issue, offlineSubmission.asset, offlineSubmission.asset_stage].filter(
6021
- (x) => x !== void 0
6022
- ),
6023
- blocks: [offlineSubmission.offline_id]
6024
- });
6025
- promise.then((createdSubmission) => {
6026
- this.dispatch(setFormSubmission(createdSubmission));
6027
- }).catch(() => {
6028
- this.dispatch(setFormSubmission(submissionToBeUpdated));
6029
- });
6030
- return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
6031
- }
6032
6062
  async delete(submissionId) {
6033
6063
  const { store } = this.client;
6034
6064
  const state = store.getState();