@overmap-ai/core 1.0.63-form-submission-fix.4 → 1.0.63-org-projs-only.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.
@@ -2594,10 +2594,8 @@ const selectAttachedFormSubmissionsOfIssue = restructureCreateSelectorWithArgs(
2594
2594
  ],
2595
2595
  (issues, forms, formRevisions, submissions, issueId) => {
2596
2596
  const issue = issues[issueId];
2597
- if (!issue)
2597
+ if (!issue || !issue.issue_type) {
2598
2598
  return [];
2599
- if (!issue.issue_type) {
2600
- return Object.values(submissions).filter((submission) => submission.issue === issueId);
2601
2599
  }
2602
2600
  const issueTypeForms = new Set(
2603
2601
  Object.keys(forms).filter((formId) => forms[formId].issue_type === issue.issue_type)
@@ -2652,10 +2650,8 @@ const selectAttachedFormSubmissionsOfAsset = restructureCreateSelectorWithArgs(
2652
2650
  ],
2653
2651
  (assets, forms, formRevisions, submissions, assetId) => {
2654
2652
  const asset = assets[assetId];
2655
- if (!asset)
2653
+ if (!asset || !asset.asset_type) {
2656
2654
  return [];
2657
- if (!asset.asset_type) {
2658
- return Object.values(submissions).filter((submission) => submission.asset === assetId);
2659
2655
  }
2660
2656
  const issueTypeForms = new Set(
2661
2657
  Object.keys(forms).filter((formId) => forms[formId].asset_type === asset.asset_type)
@@ -5364,23 +5360,17 @@ class ProjectService extends BaseApiService {
5364
5360
  * @throws An APIError if the server returns an error, or any other error that may occur.
5365
5361
  */
5366
5362
  async add(project) {
5367
- if (!project.organization_owner && !project.user_owner) {
5368
- throw new Error("Project type was not chosen when trying to create a project");
5369
- }
5370
5363
  if (!project.bounds && !project.canvas_bounds) {
5371
5364
  throw new Error("Project must either have bounds or canvas_bounds set");
5372
5365
  }
5373
- const isOrganizationProject = !!project.organization_owner;
5374
- const url = isOrganizationProject ? `/organizations/${project.organization_owner}/projects/` : "/projects/";
5375
- const projectType = isOrganizationProject ? { organization_owner: project.organization_owner } : { user_owner: project.user_owner };
5376
5366
  return await this.enqueueRequest({
5377
5367
  description: "Create project",
5378
5368
  method: HttpMethod.POST,
5379
- url,
5369
+ url: "/projects/",
5380
5370
  payload: {
5381
5371
  name: project.name,
5382
5372
  bounds: project.bounds,
5383
- ...projectType
5373
+ organization_owner: project.organization_owner
5384
5374
  },
5385
5375
  blockers: [],
5386
5376
  blocks: []
@@ -5507,67 +5497,36 @@ const separateImageFromFields = async (fields) => {
5507
5497
  }
5508
5498
  return { fields: newFields, images };
5509
5499
  };
5510
- class FormService extends BaseUploadService {
5511
- async bulkAddRevisionAttachments(revisionId, files) {
5512
- const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
5513
- const createdBy = this.client.store.getState().userReducer.currentUser.id;
5514
- const filePayloads = {};
5515
- const offlineFormRevisionAttachments = [];
5516
- const attachmentPayloads = [];
5517
- for (const [fieldIdentifier, file] of Object.entries(files)) {
5518
- const sha1 = await hashFile(file);
5519
- if (!(sha1 in filePayloads)) {
5520
- filePayloads[sha1] = {
5521
- sha1,
5522
- file_type: file.type,
5523
- extension: file.name.split(".").pop(),
5524
- size: file.size
5500
+ class FormService extends BaseApiService {
5501
+ constructor() {
5502
+ super(...arguments);
5503
+ // Attach images to revision, after uploading them to S3
5504
+ __publicField(this, "getAttachImagePromises", (images, offlineRevisionId) => {
5505
+ return Object.entries(images).map(async ([key, image]) => {
5506
+ const sha1 = await hashFile(image);
5507
+ await this.client.files.addCache(image, sha1);
5508
+ const [fileProps] = await this.client.files.uploadFileToS3(sha1);
5509
+ const revisionAttachmentPayload = offline({
5510
+ ...fileProps,
5511
+ revision: offlineRevisionId,
5512
+ field_identifier: key
5513
+ });
5514
+ const attach = await this.enqueueRequest({
5515
+ description: "Attach image to form revision field",
5516
+ method: HttpMethod.POST,
5517
+ url: `/forms/revisions/${offlineRevisionId}/attachments/`,
5518
+ payload: revisionAttachmentPayload,
5519
+ blockers: [revisionAttachmentPayload.revision],
5520
+ blocks: [revisionAttachmentPayload.offline_id]
5521
+ });
5522
+ const offlinePayload = {
5523
+ ...revisionAttachmentPayload,
5524
+ file: URL.createObjectURL(image)
5525
5525
  };
5526
- await this.client.files.addCache(file, sha1);
5527
- }
5528
- const offlineFormRevisionAttachment = offline({
5529
- file: URL.createObjectURL(file),
5530
- file_type: file.type,
5531
- file_name: file.name,
5532
- file_sha1: sha1,
5533
- created_by: createdBy,
5534
- revision: revisionId,
5535
- submitted_at: submittedAt,
5536
- field_identifier: fieldIdentifier
5526
+ this.dispatch(addFormRevisionAttachment(offlinePayload));
5527
+ return attach;
5537
5528
  });
5538
- offlineFormRevisionAttachments.push(offlineFormRevisionAttachment);
5539
- const attachmentPayload = {
5540
- offline_id: offlineFormRevisionAttachment.offline_id,
5541
- name: file.name,
5542
- field_identifier: fieldIdentifier,
5543
- sha1
5544
- };
5545
- attachmentPayloads.push(attachmentPayload);
5546
- }
5547
- this.dispatch(addFormRevisionAttachments(offlineFormRevisionAttachments));
5548
- const promise = this.enqueueRequest({
5549
- description: "Attach files to form revision",
5550
- method: HttpMethod.POST,
5551
- url: `/forms/revisions/${revisionId}/attachments/bulk/`,
5552
- payload: {
5553
- submitted_at: submittedAt,
5554
- attachments: attachmentPayloads,
5555
- files: Object.values(filePayloads)
5556
- },
5557
- blockers: [revisionId],
5558
- blocks: offlineFormRevisionAttachments.map((attachment) => attachment.offline_id)
5559
5529
  });
5560
- promise.then((result) => {
5561
- this.processPresignedUrls(result.presigned_urls);
5562
- this.dispatch(updateFormRevisionAttachments(result.attachments));
5563
- }).catch(() => {
5564
- this.dispatch(
5565
- deleteFormRevisionAttachments(
5566
- offlineFormRevisionAttachments.map((attachment) => attachment.offline_id)
5567
- )
5568
- );
5569
- });
5570
- return [offlineFormRevisionAttachments, promise.then(({ attachments }) => attachments)];
5571
5530
  }
5572
5531
  async add(ownerId, form, initialRevision, urlPrefix) {
5573
5532
  const { fields, images } = await separateImageFromFields(initialRevision.fields);
@@ -5600,16 +5559,14 @@ class FormService extends BaseUploadService {
5600
5559
  blockers: [ownerId],
5601
5560
  blocks: [form.offline_id, offlineFormRevision.offline_id]
5602
5561
  });
5603
- const [offlineFormRevisionAttachments, attachmentsPromise] = await this.bulkAddRevisionAttachments(
5604
- offlineFormRevision.offline_id,
5605
- images
5606
- );
5562
+ const attachImagesPromises = this.getAttachImagePromises(images, offlineFormRevision.offline_id);
5607
5563
  void formPromise.catch((e) => {
5608
5564
  this.dispatch(deleteForm(form.offline_id));
5609
5565
  this.dispatch(deleteFormRevision(offlineFormRevision.offline_id));
5610
5566
  throw e;
5611
5567
  });
5612
- return [form, offlineFormRevision, offlineFormRevisionAttachments, formPromise, attachmentsPromise];
5568
+ const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
5569
+ return [form, offlineFormRevision, formPromise, settledPromise];
5613
5570
  }
5614
5571
  addForOrganization(organizationId, initialRevision) {
5615
5572
  const state = this.client.store.getState();
@@ -5691,16 +5648,14 @@ class FormService extends BaseUploadService {
5691
5648
  blockers: [formId],
5692
5649
  blocks: [offlineRevision.offline_id]
5693
5650
  });
5694
- const [offlineFormRevisionAttachments, attachmentsPromise] = await this.bulkAddRevisionAttachments(
5695
- fullRevision.offline_id,
5696
- images
5697
- );
5651
+ const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
5698
5652
  void promise.then((result) => {
5699
5653
  this.dispatch(setFormRevision(result));
5700
5654
  }).catch(() => {
5701
5655
  this.dispatch(deleteFormRevision(fullRevision.offline_id));
5702
5656
  });
5703
- return [fullRevision, offlineFormRevisionAttachments, promise, attachmentsPromise];
5657
+ const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
5658
+ return [fullRevision, settledPromise];
5704
5659
  }
5705
5660
  async favorite(formId) {
5706
5661
  const { store } = this.client;
@@ -5863,71 +5818,46 @@ const separateFilesFromValues = (values) => {
5863
5818
  return { values: newValues, files };
5864
5819
  };
5865
5820
  class FormSubmissionService extends BaseUploadService {
5866
- async bulkAddSubmissionAttachments(submissionId, files) {
5867
- const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
5868
- const createdBy = this.client.store.getState().userReducer.currentUser.id;
5869
- const filePayloads = {};
5870
- const offlineFormSubmissionAttachments = [];
5871
- const attachmentPayloads = [];
5872
- for (const [fieldIdentifier, filesArray] of Object.entries(files)) {
5873
- for (const file of filesArray) {
5874
- const sha1 = await hashFile(file);
5875
- if (!(sha1 in filePayloads)) {
5876
- filePayloads[sha1] = {
5877
- sha1,
5878
- file_type: file.type,
5879
- extension: file.name.split(".").pop(),
5880
- size: file.size
5881
- };
5821
+ constructor() {
5822
+ super(...arguments);
5823
+ // Attach files to submission, after uploading them to S3
5824
+ __publicField(this, "getAttachFilesPromises", (files, submission) => {
5825
+ return Object.entries(files).map(async ([key, fileArray]) => {
5826
+ const attachResults = [];
5827
+ for (const file of fileArray) {
5828
+ const sha1 = await hashFile(file);
5882
5829
  await this.client.files.addCache(file, sha1);
5830
+ const [fileProps] = await this.client.files.uploadFileToS3(sha1);
5831
+ const submissionAttachmentPayload = offline({
5832
+ ...fileProps,
5833
+ submission: submission.offline_id,
5834
+ field_identifier: key
5835
+ });
5836
+ const attach = await this.enqueueRequest({
5837
+ description: "Attach file to form submission",
5838
+ method: HttpMethod.POST,
5839
+ url: `/forms/submission/${submission.offline_id}/attachments/`,
5840
+ payload: submissionAttachmentPayload,
5841
+ blockers: [
5842
+ submission.asset,
5843
+ submission.asset_stage,
5844
+ submission.issue,
5845
+ submission.form_revision
5846
+ ].filter((x) => x !== void 0),
5847
+ blocks: [submissionAttachmentPayload.offline_id]
5848
+ });
5849
+ const offlinePayload = {
5850
+ ...submissionAttachmentPayload,
5851
+ file: URL.createObjectURL(file)
5852
+ };
5853
+ this.dispatch(addFormSubmissionAttachment(offlinePayload));
5854
+ attachResults.push(attach);
5883
5855
  }
5884
- const offlineFormSubmissionAttachment = offline({
5885
- file: URL.createObjectURL(file),
5886
- file_type: file.type,
5887
- file_name: file.name,
5888
- file_sha1: sha1,
5889
- created_by: createdBy,
5890
- submission: submissionId,
5891
- submitted_at: submittedAt,
5892
- field_identifier: fieldIdentifier
5893
- });
5894
- offlineFormSubmissionAttachments.push(offlineFormSubmissionAttachment);
5895
- const attachmentPayload = {
5896
- offline_id: offlineFormSubmissionAttachment.offline_id,
5897
- name: file.name,
5898
- sha1,
5899
- field_identifier: fieldIdentifier
5900
- };
5901
- attachmentPayloads.push(attachmentPayload);
5902
- }
5903
- }
5904
- this.dispatch(addFormSubmissionAttachments(offlineFormSubmissionAttachments));
5905
- const promise = this.enqueueRequest({
5906
- description: "Attach files to form submission",
5907
- method: HttpMethod.POST,
5908
- url: `/forms/submissions/${submissionId}/attachments/bulk/`,
5909
- payload: {
5910
- submitted_at: submittedAt,
5911
- attachments: attachmentPayloads,
5912
- files: Object.values(filePayloads)
5913
- },
5914
- blockers: [submissionId],
5915
- blocks: offlineFormSubmissionAttachments.map((attachment) => attachment.offline_id)
5916
- });
5917
- promise.then((result) => {
5918
- this.processPresignedUrls(result.presigned_urls);
5919
- this.dispatch(updateFormSubmissionAttachments(result.attachments));
5920
- }).catch(() => {
5921
- this.dispatch(
5922
- deleteFormSubmissionAttachments(
5923
- offlineFormSubmissionAttachments.map((attachment) => attachment.offline_id)
5924
- )
5925
- );
5856
+ return attachResults;
5857
+ });
5926
5858
  });
5927
- return [offlineFormSubmissionAttachments, promise.then(({ attachments }) => attachments)];
5928
5859
  }
5929
- // Outer promise is for hashing and caching files for submission attachments
5930
- async add(payload) {
5860
+ add(payload) {
5931
5861
  const { store } = this.client;
5932
5862
  const state = store.getState();
5933
5863
  const activeProjectId = state.projectReducer.activeProjectId;
@@ -5935,12 +5865,12 @@ class FormSubmissionService extends BaseUploadService {
5935
5865
  throw new Error("Expected an active project");
5936
5866
  }
5937
5867
  const { values, files } = separateFilesFromValues(payload.values);
5938
- const offlineSubmission = offline({
5868
+ const offlineSubmission = {
5939
5869
  ...payload,
5940
5870
  values,
5941
5871
  created_by: state.userReducer.currentUser.id,
5942
5872
  submitted_at: (/* @__PURE__ */ new Date()).toISOString()
5943
- });
5873
+ };
5944
5874
  const promise = this.enqueueRequest({
5945
5875
  description: "Respond to form",
5946
5876
  method: HttpMethod.POST,
@@ -5949,22 +5879,20 @@ class FormSubmissionService extends BaseUploadService {
5949
5879
  blockers: [payload.issue, payload.asset, payload.asset_stage, "add-form-entry"].filter(
5950
5880
  (x) => x !== void 0
5951
5881
  ),
5952
- blocks: [offlineSubmission.offline_id]
5882
+ blocks: [payload.offline_id]
5953
5883
  });
5884
+ const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
5954
5885
  this.dispatch(addFormSubmission(offlineSubmission));
5955
- const [offlineFormSubmissionAttachments, attachmentsPromise] = await this.bulkAddSubmissionAttachments(
5956
- offlineSubmission.offline_id,
5957
- files
5958
- );
5959
- promise.then((result) => {
5886
+ void promise.then((result) => {
5960
5887
  this.dispatch(addActiveProjectFormSubmissionsCount(1));
5961
5888
  this.dispatch(setFormSubmission(result));
5962
5889
  return result;
5963
5890
  }).catch(() => {
5964
- this.dispatch(deleteFormSubmission(offlineSubmission.offline_id));
5891
+ this.dispatch(deleteFormSubmission(payload.offline_id));
5965
5892
  this.dispatch(addActiveProjectFormSubmissionsCount(-1));
5966
5893
  });
5967
- return [offlineSubmission, offlineFormSubmissionAttachments, promise, attachmentsPromise];
5894
+ const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
5895
+ return [offlineSubmission, settledPromise];
5968
5896
  }
5969
5897
  // Note currently the bulkAdd method is specific to form submissions for assets
5970
5898
  // TODO: adapt the support bulk adding to any model type
@@ -6065,6 +5993,36 @@ class FormSubmissionService extends BaseUploadService {
6065
5993
  });
6066
5994
  return batchPromises;
6067
5995
  }
5996
+ update(submission) {
5997
+ const { store } = this.client;
5998
+ const { values, files } = separateFilesFromValues(submission.values);
5999
+ const attachFilesPromises = this.getAttachFilesPromises(files, submission);
6000
+ const offlineSubmission = {
6001
+ ...submission,
6002
+ values
6003
+ };
6004
+ const submissionToBeUpdated = selectFormSubmission(submission.offline_id)(store.getState());
6005
+ if (!submissionToBeUpdated) {
6006
+ throw new Error(`Expected submission with offline_id ${submission.offline_id} to exist`);
6007
+ }
6008
+ this.dispatch(updateFormSubmission(offlineSubmission));
6009
+ const promise = this.enqueueRequest({
6010
+ description: "Patch form submission",
6011
+ method: HttpMethod.PATCH,
6012
+ url: `/forms/submissions/${submission.offline_id}/`,
6013
+ payload: offlineSubmission,
6014
+ blockers: [offlineSubmission.issue, offlineSubmission.asset, offlineSubmission.asset_stage].filter(
6015
+ (x) => x !== void 0
6016
+ ),
6017
+ blocks: [offlineSubmission.offline_id]
6018
+ });
6019
+ promise.then((createdSubmission) => {
6020
+ this.dispatch(setFormSubmission(createdSubmission));
6021
+ }).catch(() => {
6022
+ this.dispatch(setFormSubmission(submissionToBeUpdated));
6023
+ });
6024
+ return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
6025
+ }
6068
6026
  async delete(submissionId) {
6069
6027
  const { store } = this.client;
6070
6028
  const state = store.getState();
@@ -6535,9 +6493,7 @@ class LicenseService extends BaseApiService {
6535
6493
  method: HttpMethod.GET,
6536
6494
  url: `/billing/${license.offline_id}/`,
6537
6495
  isAuthNeeded: true,
6538
- blockers: [
6539
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6540
- ],
6496
+ blockers: [license.organization_owner ? license.organization_owner.toString() : ""],
6541
6497
  blocks: []
6542
6498
  });
6543
6499
  this.dispatch(updateLicense(result));
@@ -6549,9 +6505,7 @@ class LicenseService extends BaseApiService {
6549
6505
  method: HttpMethod.DELETE,
6550
6506
  url: `/billing/${license.offline_id}/suspend/`,
6551
6507
  isAuthNeeded: true,
6552
- blockers: [
6553
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6554
- ],
6508
+ blockers: [license.organization_owner ? license.organization_owner.toString() : ""],
6555
6509
  blocks: []
6556
6510
  });
6557
6511
  this.dispatch(updateLicense(result));
@@ -6563,9 +6517,7 @@ class LicenseService extends BaseApiService {
6563
6517
  method: HttpMethod.PATCH,
6564
6518
  url: `/billing/${license.offline_id}/suspend/`,
6565
6519
  isAuthNeeded: true,
6566
- blockers: [
6567
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6568
- ],
6520
+ blockers: [license.organization_owner ? license.organization_owner.toString() : ""],
6569
6521
  blocks: []
6570
6522
  });
6571
6523
  this.dispatch(updateLicense(result));
@@ -6577,9 +6529,7 @@ class LicenseService extends BaseApiService {
6577
6529
  method: HttpMethod.DELETE,
6578
6530
  url: `/billing/${license.offline_id}/`,
6579
6531
  isAuthNeeded: true,
6580
- blockers: [
6581
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6582
- ],
6532
+ blockers: [license.organization_owner ? license.organization_owner.toString() : ""],
6583
6533
  blocks: []
6584
6534
  });
6585
6535
  this.dispatch(updateLicense(result));
@@ -6593,7 +6543,7 @@ class LicenseService extends BaseApiService {
6593
6543
  isAuthNeeded: true,
6594
6544
  payload: { project: project.id },
6595
6545
  blockers: [
6596
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : "",
6546
+ license.organization_owner ? license.organization_owner.toString() : "",
6597
6547
  project.id ? project.id.toString() : ""
6598
6548
  ],
6599
6549
  blocks: ["add-issue", "add-form-entry", "change-access-level", "add-workspace"]
@@ -6607,9 +6557,7 @@ class LicenseService extends BaseApiService {
6607
6557
  method: HttpMethod.DELETE,
6608
6558
  url: `/billing/${license.offline_id}/project/`,
6609
6559
  isAuthNeeded: true,
6610
- blockers: [
6611
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6612
- ],
6560
+ blockers: [license.organization_owner ? license.organization_owner.toString() : ""],
6613
6561
  blocks: ["add-issue", "add-form-entry", "change-access-level", "add-workspace"]
6614
6562
  });
6615
6563
  this.dispatch(updateLicense(result));