@overmap-ai/core 1.0.58-qr-code-field-fix.0 → 1.0.58-sign-up-hotfix.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.
@@ -1738,6 +1738,16 @@ const assetSlice = createSlice({
1738
1738
  }
1739
1739
  prevAssets = null;
1740
1740
  },
1741
+ updateAssets: (state, action) => {
1742
+ for (const asset of action.payload) {
1743
+ if (asset.offline_id in state.assets) {
1744
+ state.assets[asset.offline_id] = asset;
1745
+ } else {
1746
+ throw new Error(`Tried to update asset with ID that doesn't exist: ${asset.offline_id}`);
1747
+ }
1748
+ }
1749
+ prevAssets = null;
1750
+ },
1741
1751
  removeAsset: (state, action) => {
1742
1752
  if (action.payload in state.assets) {
1743
1753
  delete state.assets[action.payload];
@@ -1746,6 +1756,16 @@ const assetSlice = createSlice({
1746
1756
  }
1747
1757
  prevAssets = null;
1748
1758
  },
1759
+ removeAssets: (state, action) => {
1760
+ for (const assetId of action.payload) {
1761
+ if (assetId in state.assets) {
1762
+ delete state.assets[assetId];
1763
+ } else {
1764
+ throw new Error(`Failed to remove asset because ID doesn't exist: ${assetId}`);
1765
+ }
1766
+ }
1767
+ prevAssets = null;
1768
+ },
1749
1769
  removeAllAssetsOfType: (state, action) => {
1750
1770
  var _a2;
1751
1771
  for (const componentId in state.assets) {
@@ -1769,7 +1789,9 @@ const assetSlice = createSlice({
1769
1789
  const {
1770
1790
  addAsset,
1771
1791
  updateAsset,
1792
+ updateAssets,
1772
1793
  removeAsset,
1794
+ removeAssets,
1773
1795
  addAssetsInBatches,
1774
1796
  setAssets,
1775
1797
  removeAllAssetsOfType,
@@ -3810,17 +3832,15 @@ const selectFilteredForms = restructureCreateSelectorWithArgs(
3810
3832
  (_state, search) => search
3811
3833
  ],
3812
3834
  (userForms, revisions, search) => {
3813
- const { searchTerm, maxResults, favorites, owner_organization, owner_user } = search;
3835
+ const { searchTerm, maxResults, favorites, organization } = search;
3814
3836
  const favoriteMatches = [];
3815
3837
  const regularMatches = [];
3816
3838
  for (const [userFormId, userForm] of Object.entries(userForms)) {
3817
3839
  if (favorites !== void 0 && userForm.favorite != favorites)
3818
3840
  continue;
3819
- if (Number.isInteger(owner_organization) && owner_organization !== userForm.owner_organization) {
3841
+ if (Number.isInteger(organization) && organization !== userForm.organization) {
3820
3842
  continue;
3821
3843
  }
3822
- if (Number.isInteger(owner_user) && owner_user !== userForm.owner_user)
3823
- continue;
3824
3844
  const latestRevision = _selectLatestFormRevision(revisions, userFormId);
3825
3845
  if (latestRevision.title.toLowerCase().includes(searchTerm.toLowerCase())) {
3826
3846
  if (userForm.favorite) {
@@ -4605,10 +4625,6 @@ function handleWorkspaceRemoval(draft, action) {
4605
4625
  throw new Error(`Failed to update index_workspace of issue ${issue.offline_id} to main workspace`);
4606
4626
  }
4607
4627
  }
4608
- const indexedForms = Object.values(draft.formReducer.forms).filter((form) => form.index_workspace === workspaceId);
4609
- for (const form of indexedForms) {
4610
- form.index_workspace = mainWorkspace.offline_id;
4611
- }
4612
4628
  }
4613
4629
  const rootReducer = (state, action) => {
4614
4630
  if (action.type === "auth/setLoggedIn" && !action.payload) {
@@ -5108,12 +5124,8 @@ class AuthService extends BaseApiService {
5108
5124
  const initialDataUuid = v4();
5109
5125
  const timeout = 5;
5110
5126
  let timedOut = false;
5111
- let initialDataRequestFinished = false;
5112
5127
  const timeoutPromise = new Promise((_, reject) => {
5113
5128
  setTimeout(() => {
5114
- if (initialDataRequestFinished) {
5115
- return void 0;
5116
- }
5117
5129
  timedOut = true;
5118
5130
  store.dispatch(markForDeletion(uuid));
5119
5131
  store.dispatch(markForDeletion(initialDataUuid));
@@ -5125,15 +5137,8 @@ class AuthService extends BaseApiService {
5125
5137
  return void 0;
5126
5138
  }
5127
5139
  store.dispatch(setTokens(tokens));
5128
- return this.client.main.fetchInitialData(true, initialDataUuid).then(() => {
5129
- if (timedOut) {
5130
- return void 0;
5131
- }
5132
- initialDataRequestFinished = true;
5133
- store.dispatch(setLoggedIn(true));
5134
- store.dispatch({ type: "rehydrated/setRehydrated", payload: true });
5135
- return void 0;
5136
- });
5140
+ store.dispatch(setLoggedIn(true));
5141
+ store.dispatch({ type: "rehydrated/setRehydrated", payload: true });
5137
5142
  });
5138
5143
  return Promise.race([timeoutPromise, successPromise]);
5139
5144
  }
@@ -5378,6 +5383,15 @@ class CategoryService extends BaseApiService {
5378
5383
  store.dispatch(setCategories(result));
5379
5384
  }
5380
5385
  }
5386
+ function chunkArray(arr, chunkSize) {
5387
+ const chunks = [];
5388
+ let index2 = 0;
5389
+ const arrLength = arr.length;
5390
+ while (index2 < arrLength) {
5391
+ chunks.push(arr.slice(index2, index2 += chunkSize));
5392
+ }
5393
+ return chunks;
5394
+ }
5381
5395
  class AssetService extends BaseApiService {
5382
5396
  // Basic CRUD functions
5383
5397
  add(asset, workspaceId) {
@@ -5454,36 +5468,55 @@ class AssetService extends BaseApiService {
5454
5468
  throw err;
5455
5469
  });
5456
5470
  }
5457
- async addBatch(assetsToCreate, workspaceId, assetTypeId) {
5458
- const fullAssets = assetsToCreate.map((asset) => {
5459
- return { ...offline(asset), submitted_at: (/* @__PURE__ */ new Date()).toISOString() };
5460
- });
5471
+ // TODO: payload does not require asset_type
5472
+ bulkAdd(assetsToCreate, workspaceId, assetTypeId, batchSize) {
5461
5473
  const { store } = this.client;
5462
- store.dispatch(addAssetsInBatches(fullAssets));
5463
- const promise = this.client.enqueueRequest({
5464
- description: "Batch create assets",
5465
- method: HttpMethod.POST,
5466
- url: `/assets/types/${assetTypeId}/add-assets/`,
5467
- queryParams: {
5468
- workspace_id: workspaceId.toString()
5469
- },
5470
- payload: {
5471
- assets: fullAssets
5472
- },
5473
- blockers: [assetTypeId],
5474
- blocks: fullAssets.map((c) => c.offline_id)
5474
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
5475
+ const transactionId = v4();
5476
+ const assetBatches = chunkArray(assetsToCreate, batchSize).map((assetBatch) => {
5477
+ const assetPayloads = assetBatch.map((assetPayload) => {
5478
+ return offline({
5479
+ ...assetPayload,
5480
+ submitted_at: submittedAt
5481
+ });
5482
+ });
5483
+ return {
5484
+ batchId: v4(),
5485
+ payload: {
5486
+ transaction_id: transactionId,
5487
+ assets: assetPayloads
5488
+ }
5489
+ };
5475
5490
  });
5476
- void promise.then((result) => {
5477
- for (const assets of Object.values(result)) {
5478
- store.dispatch(updateAsset(assets));
5479
- }
5480
- }).catch((e) => {
5481
- for (const asset of fullAssets) {
5482
- store.dispatch(removeAsset(asset.offline_id));
5483
- }
5484
- throw e;
5491
+ const batchPromises = [];
5492
+ let prevBatchId = null;
5493
+ for (const assetBatch of assetBatches) {
5494
+ const { batchId, payload } = assetBatch;
5495
+ const batchAssetOfflineIds = payload.assets.map((c) => c.offline_id);
5496
+ const blockers = [assetTypeId];
5497
+ if (prevBatchId)
5498
+ blockers.push(prevBatchId);
5499
+ const blocks = batchAssetOfflineIds;
5500
+ blocks.push(batchId);
5501
+ const promise = this.client.enqueueRequest({
5502
+ description: "Batch create assets",
5503
+ method: HttpMethod.POST,
5504
+ url: `/assets/types/${assetTypeId}/add-assets/`,
5505
+ queryParams: {
5506
+ workspace_id: workspaceId.toString()
5507
+ },
5508
+ payload,
5509
+ blockers,
5510
+ blocks
5511
+ });
5512
+ prevBatchId = assetBatch.batchId;
5513
+ batchPromises.push(promise);
5514
+ }
5515
+ void Promise.all(batchPromises).then((result) => {
5516
+ const allCreatedAssets = result.flat();
5517
+ store.dispatch(addAssetsInBatches(allCreatedAssets));
5485
5518
  });
5486
- return promise;
5519
+ return batchPromises;
5487
5520
  }
5488
5521
  async refreshStore() {
5489
5522
  const { store } = this.client;
@@ -6617,6 +6650,7 @@ class MainService extends BaseApiService {
6617
6650
  store.dispatch(addOrReplaceProjects(projects));
6618
6651
  store.dispatch(addOrReplaceWorkspaces(workspaces));
6619
6652
  }
6653
+ console.debug("currentProjectId", currentProjectId);
6620
6654
  if (!currentProjectId) {
6621
6655
  store.dispatch(setIsFetchingInitialData(false));
6622
6656
  } else {
@@ -6975,8 +7009,7 @@ class ProjectService extends BaseApiService {
6975
7009
  });
6976
7010
  }
6977
7011
  }
6978
- const separateImageFromFields = async (payload) => {
6979
- const { fields } = payload;
7012
+ const separateImageFromFields = async (fields) => {
6980
7013
  const images = {};
6981
7014
  const newFields = [];
6982
7015
  for (const section of fields) {
@@ -7002,11 +7035,7 @@ const separateImageFromFields = async (payload) => {
7002
7035
  }
7003
7036
  newFields.push({ ...section, fields: newSectionFields });
7004
7037
  }
7005
- const payloadWithoutImage = {
7006
- ...payload,
7007
- fields: newFields
7008
- };
7009
- return { payloadWithoutImage, images };
7038
+ return { fields: newFields, images };
7010
7039
  };
7011
7040
  class UserFormService extends BaseApiService {
7012
7041
  constructor() {
@@ -7040,93 +7069,90 @@ class UserFormService extends BaseApiService {
7040
7069
  });
7041
7070
  });
7042
7071
  }
7043
- async add(state, initialRevision, url, ownerUser, ownerOrganization, assetTypeId, issueTypeId) {
7044
- if (!!ownerUser === !!ownerOrganization) {
7045
- throw new Error("Exactly one of ownerUser and ownerOrganization must be defined.");
7046
- }
7047
- const ownerAttrs = {
7048
- owner_user: ownerUser,
7049
- owner_organization: ownerOrganization
7050
- };
7051
- const currentUser = state.userReducer.currentUser;
7052
- const activeWorkspaceId = state.workspaceReducer.activeWorkspaceId;
7053
- const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
7054
- const offlineFormPayload = offline({ ...ownerAttrs });
7055
- const offlineRevisionPayload = offline({ ...initialRevision, submitted_at: submittedAt });
7056
- const retForm = {
7057
- ...offlineFormPayload,
7058
- index_workspace: activeWorkspaceId,
7059
- favorite: true,
7060
- submitted_at: submittedAt,
7061
- created_by: currentUser.id,
7062
- ...assetTypeId && { asset_type: assetTypeId },
7063
- ...issueTypeId && { issue_type: issueTypeId },
7064
- ...ownerAttrs
7065
- };
7066
- const { payloadWithoutImage, images } = await separateImageFromFields(offlineRevisionPayload);
7067
- const retRevision = {
7068
- ...payloadWithoutImage,
7069
- created_by: currentUser.id,
7070
- form: retForm.offline_id,
7071
- revision: 0,
7072
- submitted_at: submittedAt
7073
- };
7072
+ async add(ownerId, form, initialRevision, urlPrefix) {
7074
7073
  const { store } = this.client;
7075
- store.dispatch(addForm(retForm));
7076
- store.dispatch(addFormRevision(retRevision));
7074
+ const { fields, images } = await separateImageFromFields(initialRevision.fields);
7075
+ const offlineFormRevision = offline({
7076
+ ...initialRevision,
7077
+ fields,
7078
+ created_by: form.created_by,
7079
+ form: form.offline_id,
7080
+ submitted_at: form.submitted_at,
7081
+ revision: "Pending"
7082
+ });
7083
+ store.dispatch(addForm(form));
7084
+ store.dispatch(addFormRevision(offlineFormRevision));
7077
7085
  const formPromise = this.client.enqueueRequest({
7078
7086
  description: "Create form",
7079
7087
  method: HttpMethod.POST,
7080
- url,
7081
- queryParams: activeWorkspaceId ? {
7082
- workspace_id: activeWorkspaceId
7083
- } : void 0,
7088
+ url: urlPrefix,
7084
7089
  payload: {
7085
- ...offlineFormPayload,
7086
- ...assetTypeId && { asset_type: assetTypeId },
7087
- ...issueTypeId && { issue_type: issueTypeId },
7088
- initial_revision: payloadWithoutImage
7090
+ // Sending exactly what is currently needed for the endpoint
7091
+ offline_id: form.offline_id,
7092
+ initial_revision: {
7093
+ offline_id: offlineFormRevision.offline_id,
7094
+ submitted_at: offlineFormRevision.submitted_at,
7095
+ title: offlineFormRevision.title,
7096
+ description: offlineFormRevision.description,
7097
+ fields: offlineFormRevision.fields
7098
+ }
7089
7099
  },
7090
- blockers: assetTypeId ? [assetTypeId] : issueTypeId ? [issueTypeId] : [],
7091
- blocks: [offlineFormPayload.offline_id, payloadWithoutImage.offline_id]
7100
+ blockers: [ownerId],
7101
+ blocks: [form.offline_id, offlineFormRevision.offline_id]
7092
7102
  });
7093
- const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
7103
+ const attachImagesPromises = this.getAttachImagePromises(images, offlineFormRevision.offline_id);
7094
7104
  void formPromise.catch((e) => {
7095
- store.dispatch(deleteForm(retForm.offline_id));
7096
- store.dispatch(deleteFormRevision(retRevision.offline_id));
7105
+ store.dispatch(deleteForm(form.offline_id));
7106
+ store.dispatch(deleteFormRevision(offlineFormRevision.offline_id));
7097
7107
  throw e;
7098
7108
  });
7099
7109
  const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
7100
- return [retForm, retRevision, formPromise, settledPromise];
7110
+ return [form, offlineFormRevision, formPromise, settledPromise];
7101
7111
  }
7102
- async addForOrganization(initialRevision, attachedTo) {
7112
+ addForOrganization(organizationId, initialRevision) {
7103
7113
  const state = this.client.store.getState();
7104
- const activeOrganizationId = state.organizationReducer.activeOrganizationId;
7105
- if (!activeOrganizationId) {
7106
- throw new Error("Cannot add forms for organization when there is no active organization.");
7107
- }
7108
- return await this.add(
7109
- state,
7114
+ const offlineForm = offline({
7115
+ favorite: false,
7116
+ created_by: state.userReducer.currentUser.id,
7117
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
7118
+ organization: organizationId
7119
+ });
7120
+ return this.add(
7121
+ organizationId.toString(),
7122
+ offlineForm,
7110
7123
  initialRevision,
7111
- `/forms/in-organization/${activeOrganizationId}/`,
7112
- void 0,
7113
- activeOrganizationId,
7114
- attachedTo && "assetTypeId" in attachedTo ? attachedTo.assetTypeId : void 0,
7115
- attachedTo && "issueTypeId" in attachedTo ? attachedTo.issueTypeId : void 0
7124
+ `/organizations/${organizationId}/create-form/`
7116
7125
  );
7117
7126
  }
7118
- async addForCurrentUser(initialRevision, attachedTo) {
7127
+ addForProject(projectId, initialRevision) {
7119
7128
  const state = this.client.store.getState();
7120
- const currentUser = state.userReducer.currentUser;
7121
- return await this.add(
7122
- state,
7123
- initialRevision,
7124
- "/forms/my-forms/",
7125
- currentUser.id,
7126
- void 0,
7127
- attachedTo && "assetTypeId" in attachedTo ? attachedTo.assetTypeId : void 0,
7128
- attachedTo && "issueTypeId" in attachedTo ? attachedTo.issueTypeId : void 0
7129
- );
7129
+ const offlineForm = offline({
7130
+ favorite: false,
7131
+ created_by: state.userReducer.currentUser.id,
7132
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
7133
+ project: projectId
7134
+ });
7135
+ return this.add(projectId.toString(), offlineForm, initialRevision, `/projects/${projectId}/create-form/`);
7136
+ }
7137
+ addForIssueType(issueTypeId, initialRevision) {
7138
+ const state = this.client.store.getState();
7139
+ const offlineForm = offline({
7140
+ favorite: false,
7141
+ created_by: state.userReducer.currentUser.id,
7142
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
7143
+ issue_type: issueTypeId
7144
+ });
7145
+ return this.add(issueTypeId, offlineForm, initialRevision, `/issues/types/${issueTypeId}/create-form/`);
7146
+ }
7147
+ addForAssetType(assetTypeId, initialRevision) {
7148
+ const state = this.client.store.getState();
7149
+ const offlineForm = offline({
7150
+ favorite: false,
7151
+ created_by: state.userReducer.currentUser.id,
7152
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
7153
+ asset_type: assetTypeId
7154
+ });
7155
+ return this.add(assetTypeId, offlineForm, initialRevision, `/assets/types/${assetTypeId}/create-form/`);
7130
7156
  }
7131
7157
  async createRevision(formId2, revision) {
7132
7158
  const offlineRevision = offline(revision);
@@ -7137,9 +7163,10 @@ class UserFormService extends BaseApiService {
7137
7163
  throw new Error("Cannot create form revision when there is no active project.");
7138
7164
  }
7139
7165
  const currentUserId = state.userReducer.currentUser.id;
7140
- const { payloadWithoutImage, images } = await separateImageFromFields(offlineRevision);
7166
+ const { fields, images } = await separateImageFromFields(offlineRevision.fields);
7141
7167
  const fullRevision = {
7142
- ...payloadWithoutImage,
7168
+ ...offlineRevision,
7169
+ fields,
7143
7170
  created_by: currentUserId,
7144
7171
  revision: "Pending",
7145
7172
  form: formId2,
@@ -7150,9 +7177,14 @@ class UserFormService extends BaseApiService {
7150
7177
  description: "Create form revision",
7151
7178
  method: HttpMethod.PATCH,
7152
7179
  url: `/forms/${formId2}/`,
7153
- payload: { initial_revision: payloadWithoutImage },
7154
- queryParams: {
7155
- project_id: activeProjectId.toString()
7180
+ payload: {
7181
+ initial_revision: {
7182
+ offline_id: fullRevision.offline_id,
7183
+ submitted_at: fullRevision.submitted_at,
7184
+ title: fullRevision.title,
7185
+ description: fullRevision.description,
7186
+ fields: fullRevision.fields
7187
+ }
7156
7188
  },
7157
7189
  blockers: [formId2],
7158
7190
  blocks: [offlineRevision.offline_id]
@@ -7237,16 +7269,68 @@ class UserFormService extends BaseApiService {
7237
7269
  }
7238
7270
  async refreshStore() {
7239
7271
  const { store } = this.client;
7240
- const result = await this.client.enqueueRequest({
7241
- description: "Fetch user forms",
7272
+ const activeProjectId = store.getState().projectReducer.activeProjectId;
7273
+ if (!activeProjectId) {
7274
+ throw new Error("No active project");
7275
+ }
7276
+ const forms = [];
7277
+ const revisions = [];
7278
+ const attachments = [];
7279
+ const projectFormsResult = await this.client.enqueueRequest({
7280
+ description: "Fetch project forms",
7242
7281
  method: HttpMethod.GET,
7243
- url: `/forms/in-project/${store.getState().projectReducer.activeProjectId}/forms/`,
7244
- blockers: [],
7282
+ url: `/projects/${activeProjectId}/forms/`,
7283
+ blockers: [activeProjectId.toString()],
7284
+ blocks: []
7285
+ });
7286
+ for (const form of projectFormsResult.forms)
7287
+ forms.push(form);
7288
+ for (const revision of projectFormsResult.revisions)
7289
+ revisions.push(revision);
7290
+ for (const attachment of projectFormsResult.attachments)
7291
+ attachments.push(attachment);
7292
+ const organizationFormsResult = await this.client.enqueueRequest({
7293
+ description: "Fetch organization forms",
7294
+ method: HttpMethod.GET,
7295
+ url: `/projects/${activeProjectId}/organizations/forms/`,
7296
+ blockers: [activeProjectId.toString()],
7297
+ blocks: []
7298
+ });
7299
+ for (const form of organizationFormsResult.forms)
7300
+ forms.push(form);
7301
+ for (const revision of organizationFormsResult.revisions)
7302
+ revisions.push(revision);
7303
+ for (const attachment of organizationFormsResult.attachments)
7304
+ attachments.push(attachment);
7305
+ const assetTypeFormsResult = await this.client.enqueueRequest({
7306
+ description: "Fetch asset type forms",
7307
+ method: HttpMethod.GET,
7308
+ url: `/projects/${activeProjectId}/asset-types/forms/`,
7309
+ blockers: [activeProjectId.toString()],
7245
7310
  blocks: []
7246
7311
  });
7247
- store.dispatch(setForms(Object.values(result.forms)));
7248
- store.dispatch(setFormRevisions(Object.values(result.revisions)));
7249
- store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
7312
+ for (const form of assetTypeFormsResult.forms)
7313
+ forms.push(form);
7314
+ for (const revision of assetTypeFormsResult.latest_revisions)
7315
+ revisions.push(revision);
7316
+ for (const attachment of assetTypeFormsResult.attachments)
7317
+ attachments.push(attachment);
7318
+ const issueTypeFormsResult = await this.client.enqueueRequest({
7319
+ description: "Fetch issue type forms",
7320
+ method: HttpMethod.GET,
7321
+ url: `/projects/${activeProjectId}/issue-types/forms/`,
7322
+ blockers: [activeProjectId.toString()],
7323
+ blocks: []
7324
+ });
7325
+ for (const form of issueTypeFormsResult.forms)
7326
+ forms.push(form);
7327
+ for (const revision of issueTypeFormsResult.latest_revisions)
7328
+ revisions.push(revision);
7329
+ for (const attachment of issueTypeFormsResult.attachments)
7330
+ attachments.push(attachment);
7331
+ store.dispatch(setForms(forms));
7332
+ store.dispatch(setFormRevisions(revisions));
7333
+ store.dispatch(setFormRevisionAttachments(attachments));
7250
7334
  }
7251
7335
  }
7252
7336
  const isArrayOfFiles = (value) => {
@@ -7349,100 +7433,120 @@ class UserFormSubmissionService extends BaseApiService {
7349
7433
  }
7350
7434
  // Note currently the bulkAdd method is specific to form submissions for assets
7351
7435
  // TODO: adapt the support bulk adding to any model type
7352
- async bulkAdd(args) {
7353
- const { formRevision, values: argsValues, assetOfflineIds } = args;
7436
+ async bulkAdd(args, batchSize) {
7354
7437
  const { store } = this.client;
7355
- const offlineSubmissions = [];
7356
- const offlineAttachments = [];
7357
- const submissionOfflineIds = [];
7358
- const submissionsPayload = [];
7359
- const attachmentsPayload = [];
7360
- const { values, files } = separateFilesFromValues(argsValues);
7438
+ const { formRevision, commonFieldValues, fieldValuesByAsset } = args;
7439
+ const allFilesRecord = {};
7440
+ const { values: fileSeperatedCommonFieldValues, files: commonFiles } = separateFilesFromValues(commonFieldValues);
7361
7441
  const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
7362
- const createdBy = store.getState().userReducer.currentUser.id;
7363
- for (const assetId of assetOfflineIds) {
7364
- const submission = offline({
7365
- form_revision: formRevision,
7366
- values,
7367
- created_by: createdBy,
7368
- submitted_at: submittedAt,
7369
- asset: assetId
7370
- });
7371
- submissionOfflineIds.push(submission.offline_id);
7372
- submissionsPayload.push({ offline_id: submission.offline_id, asset_id: assetId });
7373
- offlineSubmissions.push(submission);
7374
- for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
7375
- for (const file of fileArray) {
7376
- const sha1 = await hashFile(file);
7377
- await this.client.files.addCache(file, sha1);
7378
- const offlineAttachment = offline({
7379
- file_name: file.name,
7380
- file_sha1: sha1,
7381
- file: URL.createObjectURL(file),
7382
- submission: submission.offline_id,
7383
- field_identifier: fieldIdentifier
7442
+ const transactionId = v4();
7443
+ const assetIdBatches = chunkArray(Object.keys(fieldValuesByAsset), batchSize);
7444
+ const bulkAddBatches = await Promise.all(
7445
+ assetIdBatches.map(async (assetIdBatch) => {
7446
+ const batchId = v4();
7447
+ const submissionPayloads = [];
7448
+ const attachmentPayloads = [];
7449
+ const files = { ...commonFiles };
7450
+ for (const assetId of assetIdBatch) {
7451
+ const { values: fileSeperatedSubmissionSpecificValues, files: submissionSpecificFiles } = separateFilesFromValues(fieldValuesByAsset[assetId] ?? {});
7452
+ Object.assign(files, submissionSpecificFiles);
7453
+ const submissionPayload = offline({
7454
+ asset_id: assetId,
7455
+ form_data: fileSeperatedSubmissionSpecificValues
7384
7456
  });
7385
- offlineAttachments.push(offlineAttachment);
7386
- attachmentsPayload.push({
7387
- offline_id: offlineAttachment.offline_id,
7388
- submission_id: submission.offline_id,
7457
+ submissionPayloads.push(submissionPayload);
7458
+ for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
7459
+ for (const file of fileArray) {
7460
+ const sha1 = await hashFile(file);
7461
+ await this.client.files.addCache(file, sha1);
7462
+ const attachmentPayload = offline({
7463
+ submission_id: submissionPayload.offline_id,
7464
+ sha1,
7465
+ name: file.name,
7466
+ field_identifier: fieldIdentifier
7467
+ });
7468
+ attachmentPayloads.push(attachmentPayload);
7469
+ }
7470
+ }
7471
+ }
7472
+ const filePaylods = [];
7473
+ for (const file of Object.values(files).flat()) {
7474
+ const sha1 = await hashFile(file);
7475
+ const filePayload = {
7389
7476
  sha1,
7390
- name: file.name,
7391
- field_identifier: fieldIdentifier
7477
+ extension: file.name.split(".").pop() || "",
7478
+ file_type: file.type,
7479
+ size: file.size
7480
+ };
7481
+ allFilesRecord[sha1] = filePayload;
7482
+ filePaylods.push(filePayload);
7483
+ }
7484
+ return {
7485
+ batchId,
7486
+ payload: {
7487
+ transaction_id: transactionId,
7488
+ form_data: fileSeperatedCommonFieldValues,
7489
+ submitted_at: submittedAt,
7490
+ submissions: submissionPayloads,
7491
+ attachments: attachmentPayloads,
7492
+ files: filePaylods
7493
+ }
7494
+ };
7495
+ })
7496
+ );
7497
+ const batchPromises = [];
7498
+ let prevBatchId = null;
7499
+ for (const batch of bulkAddBatches) {
7500
+ const { payload, batchId } = batch;
7501
+ const batchAssetIds = payload.submissions.map((x) => x.asset_id);
7502
+ const batchSubmissionOfflineIds = payload.submissions.map((x) => x.offline_id);
7503
+ const batchAttachmentsOfflineIds = payload.attachments.map((x) => x.offline_id);
7504
+ const blockers = batchAssetIds;
7505
+ if (prevBatchId)
7506
+ blockers.push(prevBatchId);
7507
+ const blocks = [...batchSubmissionOfflineIds, ...batchAttachmentsOfflineIds, batchId];
7508
+ const promise = this.client.enqueueRequest({
7509
+ description: "Bulk add form submissions",
7510
+ method: HttpMethod.POST,
7511
+ url: `/forms/revisions/${formRevision}/bulk-respond/`,
7512
+ payload,
7513
+ blockers,
7514
+ blocks
7515
+ });
7516
+ void promise.then(({ presigned_urls }) => {
7517
+ for (const [sha1, presignedUrl] of Object.entries(presigned_urls)) {
7518
+ const file = allFilesRecord[sha1];
7519
+ if (!file)
7520
+ continue;
7521
+ void this.client.enqueueRequest({
7522
+ url: presignedUrl.url,
7523
+ description: "Upload file",
7524
+ method: HttpMethod.POST,
7525
+ isExternalUrl: true,
7526
+ isAuthNeeded: false,
7527
+ attachmentHash: sha1,
7528
+ blockers: [`s3-${file.sha1}.${file.extension}`],
7529
+ blocks: [sha1],
7530
+ s3url: presignedUrl
7392
7531
  });
7393
7532
  }
7394
- }
7395
- }
7396
- const filesRecord = {};
7397
- for (const file of Object.values(files).flat()) {
7398
- const sha1 = await hashFile(file);
7399
- filesRecord[sha1] = {
7400
- sha1,
7401
- extension: file.name.split(".").pop() || "",
7402
- file_type: file.type,
7403
- size: file.size
7404
- };
7405
- }
7406
- store.dispatch(addFormSubmissions(offlineSubmissions));
7407
- store.dispatch(addFormSubmissionAttachments(offlineAttachments));
7408
- const promise = this.client.enqueueRequest({
7409
- description: "Bulk add form submissions",
7410
- method: HttpMethod.POST,
7411
- url: `/forms/revisions/${formRevision}/bulk-respond/`,
7412
- payload: {
7413
- form_data: values,
7414
- submitted_at: submittedAt,
7415
- submissions: submissionsPayload,
7416
- attachments: attachmentsPayload,
7417
- files: Object.values(filesRecord)
7418
- },
7419
- blockers: assetOfflineIds,
7420
- blocks: submissionOfflineIds
7421
- });
7422
- promise.then(({ submissions, attachments, presigned_urls }) => {
7423
- store.dispatch(updateFormSubmissions(submissions));
7424
- store.dispatch(updateFormSubmissionAttachments(attachments));
7425
- for (const [sha1, presigned_url] of Object.entries(presigned_urls)) {
7426
- const file = filesRecord[sha1];
7427
- if (!file)
7428
- continue;
7429
- void this.client.enqueueRequest({
7430
- url: presigned_url.url,
7431
- description: "Upload file",
7432
- method: HttpMethod.POST,
7433
- isExternalUrl: true,
7434
- isAuthNeeded: false,
7435
- attachmentHash: sha1,
7436
- blockers: [`s3-${file.sha1}.${file.extension}`],
7437
- blocks: [sha1],
7438
- s3url: presigned_url
7439
- });
7440
- }
7441
- }).catch(() => {
7442
- store.dispatch(deleteFormSubmissions(submissionOfflineIds));
7443
- store.dispatch(deleteFormSubmissionAttachments(offlineAttachments.map((x) => x.offline_id)));
7533
+ });
7534
+ prevBatchId = batchId;
7535
+ batchPromises.push(promise);
7536
+ }
7537
+ void Promise.all(batchPromises).then((results) => {
7538
+ const createdSubmissions = [];
7539
+ const createdAttachments = [];
7540
+ for (const result of results) {
7541
+ for (const createdSubmission of result.submissions)
7542
+ createdSubmissions.push(createdSubmission);
7543
+ for (const createdAttachment of result.attachments)
7544
+ createdAttachments.push(createdAttachment);
7545
+ }
7546
+ store.dispatch(addFormSubmissions(createdSubmissions));
7547
+ store.dispatch(addFormSubmissionAttachments(createdAttachments));
7444
7548
  });
7445
- return [offlineSubmissions, promise.then(({ submissions }) => submissions)];
7549
+ return batchPromises;
7446
7550
  }
7447
7551
  update(submission) {
7448
7552
  const { store } = this.client;
@@ -8797,6 +8901,12 @@ class BaseField extends BaseFormElement {
8797
8901
  getFormValidators() {
8798
8902
  return [...this.formValidators];
8799
8903
  }
8904
+ encodeValueToJson(value) {
8905
+ return JSON.stringify(value);
8906
+ }
8907
+ decodeJsonToValue(json) {
8908
+ return JSON.parse(json);
8909
+ }
8800
8910
  }
8801
8911
  __publicField(BaseField, "fieldTypeName");
8802
8912
  __publicField(BaseField, "fieldTypeDescription");
@@ -13050,10 +13160,7 @@ const MultiStringInput = memo((props) => {
13050
13160
  helpText = showInputOnly ? null : helpText;
13051
13161
  label = showInputOnly ? "" : label;
13052
13162
  const color = useSeverityColor(severity);
13053
- const value = useMemo(
13054
- () => Array.isArray(fieldProps.value) ? fieldProps.value : [],
13055
- [fieldProps.value]
13056
- );
13163
+ const value = useMemo(() => Array.isArray(fieldProps.value) ? fieldProps.value : [], [fieldProps.value]);
13057
13164
  const { onChange, onBlur } = fieldProps;
13058
13165
  const droppableId = `${inputId}-droppable`;
13059
13166
  const { disabled } = rest;
@@ -13070,7 +13177,7 @@ const MultiStringInput = memo((props) => {
13070
13177
  );
13071
13178
  const handleChange = useCallback(
13072
13179
  (e) => {
13073
- if (value.findIndex((option) => option.value === e.target.value.trim()) >= 0) {
13180
+ if (value.findIndex((option) => option === e.target.value.trim()) >= 0) {
13074
13181
  setInternalError("All options must be unique");
13075
13182
  } else if (!e.target.value) {
13076
13183
  setInternalError("Option cannot be empty");
@@ -13089,7 +13196,7 @@ const MultiStringInput = memo((props) => {
13089
13196
  return;
13090
13197
  }
13091
13198
  const trimmedValue = intermediateValue.trim();
13092
- setValueAndTouched([...value, { value: trimmedValue, label: trimmedValue }]);
13199
+ setValueAndTouched([...value, trimmedValue]);
13093
13200
  setIntermediateValue("");
13094
13201
  }, [intermediateValue, internalError, setValueAndTouched, value]);
13095
13202
  const handleKeyDown = useCallback(
@@ -13159,7 +13266,7 @@ const MultiStringInput = memo((props) => {
13159
13266
  value.map((option, index2) => /* @__PURE__ */ jsx(
13160
13267
  Draggable,
13161
13268
  {
13162
- draggableId: `${option.value}-draggable`,
13269
+ draggableId: `${option}-draggable`,
13163
13270
  index: index2,
13164
13271
  isDragDisabled: disabled,
13165
13272
  children: ({ draggableProps, dragHandleProps, innerRef }) => /* @__PURE__ */ jsx(
@@ -13174,7 +13281,10 @@ const MultiStringInput = memo((props) => {
13174
13281
  mb: "1",
13175
13282
  asChild: true,
13176
13283
  children: /* @__PURE__ */ jsxs(Badge, { color: "gray", size: "2", children: [
13177
- /* @__PURE__ */ jsx("span", { children: option.label }),
13284
+ /* @__PURE__ */ jsx("span", {
13285
+ // TODO: remove this, its just a saftey check for old compatibility of what was acceptable as a value for multi string
13286
+ children: typeof option === "object" && "label" in option ? option.label : option
13287
+ }),
13178
13288
  /* @__PURE__ */ jsx(
13179
13289
  IconButton,
13180
13290
  {
@@ -13194,7 +13304,7 @@ const MultiStringInput = memo((props) => {
13194
13304
  }
13195
13305
  )
13196
13306
  },
13197
- option.value
13307
+ option
13198
13308
  )),
13199
13309
  droppableProvided.placeholder
13200
13310
  ] }) })
@@ -14869,6 +14979,44 @@ function formRevisionToSchema(formRevision, meta = {}) {
14869
14979
  meta: { readonly }
14870
14980
  };
14871
14981
  }
14982
+ function flattenFields(schema) {
14983
+ const allFields = [];
14984
+ for (const field of schema.fields) {
14985
+ if (field instanceof FieldSection) {
14986
+ for (const subField of field.fields) {
14987
+ allFields.push(subField);
14988
+ }
14989
+ } else {
14990
+ if (!(field instanceof BaseField)) {
14991
+ throw new Error(`Invalid field type: ${field.type}`);
14992
+ }
14993
+ allFields.push(field);
14994
+ }
14995
+ }
14996
+ return allFields;
14997
+ }
14998
+ function decodeFormValues(schema, values) {
14999
+ const allFields = flattenFields(schema);
15000
+ const result = {};
15001
+ for (const field of allFields) {
15002
+ const value = values[field.identifier] ?? null;
15003
+ if (value !== null) {
15004
+ result[field.identifier] = field.decodeJsonToValue(value);
15005
+ } else {
15006
+ result[field.identifier] = value;
15007
+ }
15008
+ }
15009
+ return result;
15010
+ }
15011
+ function encodeFormValues(schema, values) {
15012
+ const allFields = flattenFields(schema);
15013
+ const result = {};
15014
+ for (const field of allFields) {
15015
+ const value = values[field.identifier];
15016
+ result[field.identifier] = field.encodeValueToJson(value);
15017
+ }
15018
+ return result;
15019
+ }
14872
15020
  function valueIsFile(v) {
14873
15021
  return Array.isArray(v) && v.some((v2) => v2 instanceof File || v2 instanceof Promise);
14874
15022
  }
@@ -15245,7 +15393,6 @@ const styles$3 = {
15245
15393
  regularIcon
15246
15394
  };
15247
15395
  const orgOptionPrefix = "organization:";
15248
- const userOptionPrefix = "user:";
15249
15396
  const FormBrowser = memo(
15250
15397
  forwardRef((props, ref) => {
15251
15398
  const { maxResults = 20, ...entryProps } = props;
@@ -15256,9 +15403,7 @@ const FormBrowser = memo(
15256
15403
  const ret = { maxResults, searchTerm: filter };
15257
15404
  if (ownerFilter) {
15258
15405
  if (ownerFilter.startsWith(orgOptionPrefix)) {
15259
- ret.owner_organization = parseInt(ownerFilter.slice(orgOptionPrefix.length));
15260
- } else if (ownerFilter.startsWith(userOptionPrefix)) {
15261
- ret.owner_user = parseInt(ownerFilter.slice(userOptionPrefix.length));
15406
+ ret.organization = parseInt(ownerFilter.slice(orgOptionPrefix.length));
15262
15407
  }
15263
15408
  }
15264
15409
  return ret;
@@ -15283,14 +15428,10 @@ const FormBrowser = memo(
15283
15428
  const state = sdk.store.getState();
15284
15429
  const accumulator = {};
15285
15430
  for (const form of attachableUserFormMapping) {
15286
- const organization = selectOrganization(form.owner_organization || -1)(state);
15431
+ const organization = selectOrganization(form.organization || -1)(state);
15287
15432
  if (organization) {
15288
15433
  accumulator[`${orgOptionPrefix}${organization.id}`] = organization.name;
15289
15434
  }
15290
- const user = selectUser(form.owner_user || -1)(state);
15291
- if (user) {
15292
- accumulator[`${userOptionPrefix}${user.id}`] = user.username;
15293
- }
15294
15435
  }
15295
15436
  return Object.entries(accumulator).map(([value, label]) => ({ itemContent: label, value }));
15296
15437
  }, [sdk.store, attachableUserFormMapping]);
@@ -15332,11 +15473,7 @@ const FormBrowser = memo(
15332
15473
  const FormBrowserEntry = (props) => {
15333
15474
  var _a2;
15334
15475
  const { form, onSelectForm, isFavoriteEditable, handleToggleFavorite } = props;
15335
- const ownerOrganization = (_a2 = useAppSelector(selectOrganization(form.owner_organization || -1))) == null ? void 0 : _a2.name;
15336
- const ownerUser = useAppSelector(selectUser(form.owner_user || -1));
15337
- const currentUserId = useAppSelector(selectCurrentUser).id;
15338
- const ownedByCurrentUser = !!ownerUser && ownerUser.id === currentUserId;
15339
- const owner = ownerOrganization ?? (ownedByCurrentUser ? "You" : ownerUser == null ? void 0 : ownerUser.username) ?? "Unknown";
15476
+ const ownerOrganization = (_a2 = useAppSelector(selectOrganization(form.organization || -1))) == null ? void 0 : _a2.name;
15340
15477
  const handleFavoriteClick = useCallback(
15341
15478
  (e) => {
15342
15479
  e.stopPropagation();
@@ -15367,10 +15504,10 @@ const FormBrowserEntry = (props) => {
15367
15504
  /* @__PURE__ */ jsx(Text$1, { noWrap: true, children: form.latestRevision.title }),
15368
15505
  form.latestRevision.description && /* @__PURE__ */ jsx(RiIcon, { icon: "RiQuestionLine" })
15369
15506
  ] }),
15370
- owner && /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15507
+ ownerOrganization && /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15371
15508
  /* @__PURE__ */ jsx(RiIcon, { icon: "RiUserLine" }),
15372
15509
  " ",
15373
- owner
15510
+ ownerOrganization
15374
15511
  ] })
15375
15512
  ] })
15376
15513
  }
@@ -16650,6 +16787,7 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
16650
16787
  StringInput,
16651
16788
  TextField,
16652
16789
  TextInput,
16790
+ decodeFormValues,
16653
16791
  deserialize,
16654
16792
  deserializeField,
16655
16793
  emptyBaseField,
@@ -16662,11 +16800,15 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
16662
16800
  emptySelectField,
16663
16801
  emptyStringField,
16664
16802
  emptyTextField,
16803
+ encodeFormValues,
16804
+ flattenFields,
16665
16805
  formRevisionToSchema,
16806
+ initialFormValues,
16666
16807
  isConditionMet,
16667
16808
  useFieldInput,
16668
16809
  useFieldInputs,
16669
16810
  useFormikInput,
16811
+ validateForm,
16670
16812
  valueIsFile
16671
16813
  }, Symbol.toStringTag, { value: "Module" }));
16672
16814
  export {
@@ -16858,6 +17000,7 @@ export {
16858
17000
  coordinatesToUrlText,
16859
17001
  createOfflineAction,
16860
17002
  createPointMarker,
17003
+ decodeFormValues,
16861
17004
  defaultBadgeColor,
16862
17005
  defaultStore,
16863
17006
  deleteAssetType,
@@ -16893,6 +17036,7 @@ export {
16893
17036
  emptySelectField,
16894
17037
  emptyStringField,
16895
17038
  emptyTextField,
17039
+ encodeFormValues,
16896
17040
  enqueue,
16897
17041
  enqueueRequest,
16898
17042
  errorColor,
@@ -16900,6 +17044,7 @@ export {
16900
17044
  fileReducer,
16901
17045
  fileSlice,
16902
17046
  fileToBlob,
17047
+ flattenFields,
16903
17048
  flipCoordinates,
16904
17049
  formReducer,
16905
17050
  formRevisionReducer,
@@ -16923,6 +17068,7 @@ export {
16923
17068
  hashFile,
16924
17069
  hideAllCategories,
16925
17070
  hideCategory,
17071
+ initialFormValues,
16926
17072
  isConditionMet,
16927
17073
  isToday,
16928
17074
  issueReducer,
@@ -16976,6 +17122,7 @@ export {
16976
17122
  removeAssetAttachments,
16977
17123
  removeAssetTypeAttachment,
16978
17124
  removeAssetTypeAttachments,
17125
+ removeAssets,
16979
17126
  removeAttachmentsOfIssue,
16980
17127
  removeCategory,
16981
17128
  removeColor,
@@ -17293,6 +17440,7 @@ export {
17293
17440
  updateAssetAttachments,
17294
17441
  updateAssetTypeAttachment,
17295
17442
  updateAssetTypeAttachments,
17443
+ updateAssets,
17296
17444
  updateConversation,
17297
17445
  updateDocumentAttachment,
17298
17446
  updateDocumentAttachments,
@@ -17323,6 +17471,7 @@ export {
17323
17471
  useSDK,
17324
17472
  userReducer,
17325
17473
  userSlice,
17474
+ validateForm,
17326
17475
  valueIsFile,
17327
17476
  warningColor,
17328
17477
  workspaceReducer,