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

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,65 @@ 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
+ },
5551
+ blockers: [revisionId],
5552
+ blocks: offlineFormRevisionAttachments.map((attachment) => attachment.offline_id)
5535
5553
  });
5554
+ promise.then((result) => {
5555
+ this.processPresignedUrls(result.presigned_urls);
5556
+ this.dispatch(updateFormRevisionAttachments(result.attachments));
5557
+ }).catch(() => {
5558
+ this.dispatch(
5559
+ deleteFormRevisionAttachments(
5560
+ offlineFormRevisionAttachments.map((attachment) => attachment.offline_id)
5561
+ )
5562
+ );
5563
+ });
5564
+ return [offlineFormRevisionAttachments, promise.then(({ attachments }) => attachments)];
5536
5565
  }
5537
5566
  async add(ownerId, form, initialRevision, urlPrefix) {
5538
5567
  const { fields, images } = await separateImageFromFields(initialRevision.fields);
@@ -5565,14 +5594,16 @@ class FormService extends BaseApiService {
5565
5594
  blockers: [ownerId],
5566
5595
  blocks: [form.offline_id, offlineFormRevision.offline_id]
5567
5596
  });
5568
- const attachImagesPromises = this.getAttachImagePromises(images, offlineFormRevision.offline_id);
5597
+ const [offlineFormRevisionAttachments, attachmentsPromise] = await this.bulkAddRevisionAttachments(
5598
+ offlineFormRevision.offline_id,
5599
+ images
5600
+ );
5569
5601
  void formPromise.catch((e) => {
5570
5602
  this.dispatch(deleteForm(form.offline_id));
5571
5603
  this.dispatch(deleteFormRevision(offlineFormRevision.offline_id));
5572
5604
  throw e;
5573
5605
  });
5574
- const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
5575
- return [form, offlineFormRevision, formPromise, settledPromise];
5606
+ return [form, offlineFormRevision, offlineFormRevisionAttachments, formPromise, attachmentsPromise];
5576
5607
  }
5577
5608
  addForOrganization(organizationId, initialRevision) {
5578
5609
  const state = this.client.store.getState();
@@ -5654,14 +5685,16 @@ class FormService extends BaseApiService {
5654
5685
  blockers: [formId],
5655
5686
  blocks: [offlineRevision.offline_id]
5656
5687
  });
5657
- const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
5688
+ const [offlineFormRevisionAttachments, attachmentsPromise] = await this.bulkAddRevisionAttachments(
5689
+ fullRevision.offline_id,
5690
+ images
5691
+ );
5658
5692
  void promise.then((result) => {
5659
5693
  this.dispatch(setFormRevision(result));
5660
5694
  }).catch(() => {
5661
5695
  this.dispatch(deleteFormRevision(fullRevision.offline_id));
5662
5696
  });
5663
- const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
5664
- return [fullRevision, settledPromise];
5697
+ return [fullRevision, offlineFormRevisionAttachments, promise, attachmentsPromise];
5665
5698
  }
5666
5699
  async favorite(formId) {
5667
5700
  const { store } = this.client;
@@ -5824,46 +5857,69 @@ const separateFilesFromValues = (values) => {
5824
5857
  return { values: newValues, files };
5825
5858
  };
5826
5859
  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)
5860
+ async bulkAddSubmissionAttachments(submissionId, files) {
5861
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
5862
+ const createdBy = this.client.store.getState().userReducer.currentUser.id;
5863
+ const filePayloads = {};
5864
+ const offlineFormSubmissionAttachments = [];
5865
+ const attachmentPayloads = [];
5866
+ for (const [fieldIdentifier, filesArray] of Object.entries(files)) {
5867
+ for (const file of filesArray) {
5868
+ const sha1 = await hashFile(file);
5869
+ if (!(sha1 in filePayloads)) {
5870
+ filePayloads[sha1] = {
5871
+ sha1,
5872
+ file_type: file.type,
5873
+ extension: file.name.split(".").pop(),
5874
+ size: file.size
5858
5875
  };
5859
- this.dispatch(addFormSubmissionAttachment(offlinePayload));
5860
- attachResults.push(attach);
5876
+ await this.client.files.addCache(file, sha1);
5861
5877
  }
5862
- return attachResults;
5863
- });
5878
+ const offlineFormSubmissionAttachment = offline({
5879
+ file: URL.createObjectURL(file),
5880
+ file_type: file.type,
5881
+ file_name: file.name,
5882
+ file_sha1: sha1,
5883
+ created_by: createdBy,
5884
+ submission: submissionId,
5885
+ submitted_at: submittedAt,
5886
+ field_identifier: fieldIdentifier
5887
+ });
5888
+ offlineFormSubmissionAttachments.push(offlineFormSubmissionAttachment);
5889
+ const attachmentPayload = {
5890
+ offline_id: offlineFormSubmissionAttachment.offline_id,
5891
+ name: file.name,
5892
+ sha1
5893
+ };
5894
+ attachmentPayloads.push(attachmentPayload);
5895
+ }
5896
+ }
5897
+ this.dispatch(addFormSubmissionAttachments(offlineFormSubmissionAttachments));
5898
+ const promise = this.enqueueRequest({
5899
+ description: "Attach files to form submission",
5900
+ method: HttpMethod.POST,
5901
+ url: `/forms/submissions/${submissionId}/attachments/bulk/`,
5902
+ payload: {
5903
+ submitted_at: submittedAt,
5904
+ attachments: attachmentPayloads
5905
+ },
5906
+ blockers: [submissionId],
5907
+ blocks: offlineFormSubmissionAttachments.map((attachment) => attachment.offline_id)
5908
+ });
5909
+ promise.then((result) => {
5910
+ this.processPresignedUrls(result.presigned_urls);
5911
+ this.dispatch(updateFormSubmissionAttachments(result.attachments));
5912
+ }).catch(() => {
5913
+ this.dispatch(
5914
+ deleteFormSubmissionAttachments(
5915
+ offlineFormSubmissionAttachments.map((attachment) => attachment.offline_id)
5916
+ )
5917
+ );
5864
5918
  });
5919
+ return [offlineFormSubmissionAttachments, promise.then(({ attachments }) => attachments)];
5865
5920
  }
5866
- add(payload) {
5921
+ // Outer promise is for hashing and caching files for submission attachments
5922
+ async add(payload) {
5867
5923
  const { store } = this.client;
5868
5924
  const state = store.getState();
5869
5925
  const activeProjectId = state.projectReducer.activeProjectId;
@@ -5887,9 +5943,12 @@ class FormSubmissionService extends BaseUploadService {
5887
5943
  ),
5888
5944
  blocks: [offlineSubmission.offline_id]
5889
5945
  });
5890
- const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
5891
5946
  this.dispatch(addFormSubmission(offlineSubmission));
5892
- void promise.then((result) => {
5947
+ const [offlineFormSubmissionAttachments, attachmentsPromise] = await this.bulkAddSubmissionAttachments(
5948
+ offlineSubmission.offline_id,
5949
+ files
5950
+ );
5951
+ promise.then((result) => {
5893
5952
  this.dispatch(addActiveProjectFormSubmissionsCount(1));
5894
5953
  this.dispatch(setFormSubmission(result));
5895
5954
  return result;
@@ -5897,8 +5956,7 @@ class FormSubmissionService extends BaseUploadService {
5897
5956
  this.dispatch(deleteFormSubmission(offlineSubmission.offline_id));
5898
5957
  this.dispatch(addActiveProjectFormSubmissionsCount(-1));
5899
5958
  });
5900
- const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
5901
- return [offlineSubmission, settledPromise];
5959
+ return [offlineSubmission, offlineFormSubmissionAttachments, promise, attachmentsPromise];
5902
5960
  }
5903
5961
  // Note currently the bulkAdd method is specific to form submissions for assets
5904
5962
  // TODO: adapt the support bulk adding to any model type
@@ -5999,36 +6057,6 @@ class FormSubmissionService extends BaseUploadService {
5999
6057
  });
6000
6058
  return batchPromises;
6001
6059
  }
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
6060
  async delete(submissionId) {
6033
6061
  const { store } = this.client;
6034
6062
  const state = store.getState();