@overmap-ai/core 1.0.53-add-agent-sdk.1 → 1.0.53-attachment-creation-flows.0

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.
@@ -1577,6 +1577,9 @@ const selectIssueCountOfCategory = (categoryId) => (state) => {
1577
1577
  return Object.values(state.issueReducer.issues).filter((issue) => issue.category === categoryId).length;
1578
1578
  };
1579
1579
  const categoryReducer = categorySlice.reducer;
1580
+ function setAttachment(state, action) {
1581
+ state.attachments[action.payload.offline_id] = action.payload;
1582
+ }
1580
1583
  function setAttachments(state, action) {
1581
1584
  state.attachments = {};
1582
1585
  for (const attachment of action.payload) {
@@ -1601,6 +1604,15 @@ function updateAttachment(state, action) {
1601
1604
  throw new Error(`Attachment ${action.payload.offline_id} does not exist.`);
1602
1605
  }
1603
1606
  }
1607
+ function updateAttachments(state, action) {
1608
+ for (const attachment of action.payload) {
1609
+ if (attachment.offline_id in state.attachments) {
1610
+ state.attachments[attachment.offline_id] = attachment;
1611
+ } else {
1612
+ throw new Error(`Attachment ${attachment.offline_id} does not exist.`);
1613
+ }
1614
+ }
1615
+ }
1604
1616
  function removeAttachment(state, action) {
1605
1617
  if (action.payload in state.attachments) {
1606
1618
  delete state.attachments[action.payload];
@@ -1634,12 +1646,6 @@ const componentSlice = createSlice({
1634
1646
  state.components = toOfflineIdRecord(action.payload);
1635
1647
  prevComponents = null;
1636
1648
  },
1637
- setComponentAttachments: setAttachments,
1638
- addComponentAttachment: addAttachment,
1639
- addComponentAttachments: addAttachments,
1640
- updateComponentAttachment: updateAttachment,
1641
- removeComponentAttachment: removeAttachment,
1642
- removeComponentAttachments: removeAttachments,
1643
1649
  updateComponent: (state, action) => {
1644
1650
  if (action.payload.offline_id in state.components) {
1645
1651
  state.components[action.payload.offline_id] = action.payload;
@@ -1664,9 +1670,35 @@ const componentSlice = createSlice({
1664
1670
  }
1665
1671
  }
1666
1672
  prevComponents = null;
1667
- }
1673
+ },
1674
+ // Attachments
1675
+ setComponentAttachment: setAttachment,
1676
+ setComponentAttachments: setAttachments,
1677
+ addComponentAttachment: addAttachment,
1678
+ addComponentAttachments: addAttachments,
1679
+ updateComponentAttachment: updateAttachment,
1680
+ updateComponentAttachments: updateAttachments,
1681
+ removeComponentAttachment: removeAttachment,
1682
+ removeComponentAttachments: removeAttachments
1668
1683
  }
1669
1684
  });
1685
+ const {
1686
+ addComponent,
1687
+ updateComponent,
1688
+ removeComponent,
1689
+ addComponentsInBatches,
1690
+ setComponents,
1691
+ removeAllComponentsOfType,
1692
+ // Attachments
1693
+ setComponentAttachment,
1694
+ setComponentAttachments,
1695
+ addComponentAttachment,
1696
+ addComponentAttachments,
1697
+ updateComponentAttachment,
1698
+ updateComponentAttachments,
1699
+ removeComponentAttachment,
1700
+ removeComponentAttachments
1701
+ } = componentSlice.actions;
1670
1702
  let prevComponents = null;
1671
1703
  const selectComponents = (state) => {
1672
1704
  if (!prevComponents) {
@@ -1761,20 +1793,6 @@ const selectAttachmentsOfComponentByType = restructureCreateSelectorWithArgs(
1761
1793
  }
1762
1794
  )
1763
1795
  );
1764
- const {
1765
- addComponent,
1766
- updateComponent,
1767
- removeComponent,
1768
- addComponentsInBatches,
1769
- setComponents,
1770
- setComponentAttachments,
1771
- addComponentAttachment,
1772
- addComponentAttachments,
1773
- updateComponentAttachment,
1774
- removeComponentAttachment,
1775
- removeComponentAttachments,
1776
- removeAllComponentsOfType
1777
- } = componentSlice.actions;
1778
1796
  const componentReducer = componentSlice.reducer;
1779
1797
  const initialState$o = {
1780
1798
  completionsByComponentId: {}
@@ -1965,20 +1983,38 @@ const componentTypeSlice = createSlice({
1965
1983
  setComponentTypes: (state, action) => {
1966
1984
  state.componentTypes = toOfflineIdRecord(action.payload);
1967
1985
  },
1968
- setComponentTypeAttachments: setAttachments,
1969
- addComponentTypeAttachment: addAttachment,
1970
- addComponentTypeAttachments: addAttachments,
1971
- updateComponentTypeAttachment: updateAttachment,
1972
- removeComponentTypeAttachment: removeAttachment,
1973
- removeComponentTypeAttachments: removeAttachments,
1974
1986
  toggleComponentTypeVisibility: (state, action) => {
1975
1987
  state.hiddenComponentTypeIds[action.payload] = !state.hiddenComponentTypeIds[action.payload];
1976
1988
  },
1977
1989
  deleteComponentType: (state, action) => {
1978
1990
  delete state.componentTypes[action.payload];
1979
- }
1991
+ },
1992
+ // Attachments
1993
+ setComponentTypeAttachment: setAttachment,
1994
+ setComponentTypeAttachments: setAttachments,
1995
+ addComponentTypeAttachment: addAttachment,
1996
+ addComponentTypeAttachments: addAttachments,
1997
+ updateComponentTypeAttachment: updateAttachment,
1998
+ updateComponentTypeAttachments: updateAttachments,
1999
+ removeComponentTypeAttachment: removeAttachment,
2000
+ removeComponentTypeAttachments: removeAttachments
1980
2001
  }
1981
2002
  });
2003
+ const {
2004
+ addComponentType,
2005
+ setComponentTypes,
2006
+ toggleComponentTypeVisibility,
2007
+ deleteComponentType,
2008
+ // Attachmet
2009
+ setComponentTypeAttachment,
2010
+ setComponentTypeAttachments,
2011
+ addComponentTypeAttachment,
2012
+ addComponentTypeAttachments,
2013
+ updateComponentTypeAttachment,
2014
+ updateComponentTypeAttachments,
2015
+ removeComponentTypeAttachment,
2016
+ removeComponentTypeAttachments
2017
+ } = componentTypeSlice.actions;
1982
2018
  const selectComponentTypesMapping = (state) => state.componentTypeReducer.componentTypes;
1983
2019
  const selectComponentTypes = createSelector(
1984
2020
  [selectComponentTypesMapping],
@@ -2055,18 +2091,6 @@ const selectAttachmentsOfComponentTypeByType = restructureCreateSelectorWithArgs
2055
2091
  }
2056
2092
  )
2057
2093
  );
2058
- const {
2059
- addComponentType,
2060
- setComponentTypes,
2061
- setComponentTypeAttachments,
2062
- addComponentTypeAttachment,
2063
- addComponentTypeAttachments,
2064
- updateComponentTypeAttachment,
2065
- removeComponentTypeAttachment,
2066
- removeComponentTypeAttachments,
2067
- toggleComponentTypeVisibility,
2068
- deleteComponentType
2069
- } = componentTypeSlice.actions;
2070
2094
  const componentTypeReducer = componentTypeSlice.reducer;
2071
2095
  const initialState$l = {
2072
2096
  workspaces: {},
@@ -2156,7 +2180,6 @@ const issueSlice = createSlice({
2156
2180
  state.issues[issue.offline_id] = issue;
2157
2181
  });
2158
2182
  },
2159
- setIssueAttachments: setAttachments,
2160
2183
  setIssueUpdates: (state, action) => {
2161
2184
  if (action.payload.filter(onlyUniqueOfflineIds).length !== action.payload.length) {
2162
2185
  throw new Error("Tried to use setIssues reducer with duplicate ID's");
@@ -2186,8 +2209,6 @@ const issueSlice = createSlice({
2186
2209
  state.issues[issue.offline_id] = issue;
2187
2210
  }
2188
2211
  },
2189
- addIssueAttachment: addAttachment,
2190
- addIssueAttachments: addAttachments,
2191
2212
  addIssueUpdate: (state, action) => {
2192
2213
  if (action.payload.offline_id in state.updates) {
2193
2214
  throw new Error(`Tried to add duplicate issue update with offline_id: ${action.payload.offline_id}`);
@@ -2209,7 +2230,6 @@ const issueSlice = createSlice({
2209
2230
  throw new Error(`Tried to update issue with ID that doesn't exist: ${action.payload.offline_id}`);
2210
2231
  }
2211
2232
  },
2212
- updateIssueAttachment: updateAttachment,
2213
2233
  removeIssue: (state, action) => {
2214
2234
  if (action.payload in state.issues) {
2215
2235
  delete state.issues[action.payload];
@@ -2222,7 +2242,6 @@ const issueSlice = createSlice({
2222
2242
  delete state.issues[issueId];
2223
2243
  }
2224
2244
  },
2225
- removeIssueAttachment: removeAttachment,
2226
2245
  removeIssueUpdate: (state, action) => {
2227
2246
  if (action.payload in state.updates) {
2228
2247
  delete state.updates[action.payload];
@@ -2319,12 +2338,19 @@ const issueSlice = createSlice({
2319
2338
  if (indexToRemove !== -1) {
2320
2339
  state.recentIssueIds.splice(indexToRemove, 1);
2321
2340
  }
2322
- }
2341
+ },
2342
+ // Attachments
2343
+ setIssueAttachment: setAttachment,
2344
+ setIssueAttachments: setAttachments,
2345
+ addIssueAttachment: addAttachment,
2346
+ addIssueAttachments: addAttachments,
2347
+ updateIssueAttachment: updateAttachment,
2348
+ updateIssueAttachments: updateAttachments,
2349
+ removeIssueAttachment: removeAttachment,
2350
+ removeIssueAttachments: removeAttachments
2323
2351
  }
2324
2352
  });
2325
2353
  const {
2326
- addIssueAttachment,
2327
- addIssueAttachments,
2328
2354
  addIssue,
2329
2355
  addIssues,
2330
2356
  addIssueUpdate,
@@ -2332,7 +2358,6 @@ const {
2332
2358
  addOrReplaceIssueComment,
2333
2359
  addToRecentIssues,
2334
2360
  cleanRecentIssues,
2335
- removeIssueAttachment,
2336
2361
  removeAttachmentsOfIssue,
2337
2362
  removeIssue,
2338
2363
  removeIssues,
@@ -2341,13 +2366,20 @@ const {
2341
2366
  removeRecentIssue,
2342
2367
  resetRecentIssues,
2343
2368
  setActiveIssueId,
2344
- setIssueAttachments,
2345
2369
  setIssueUpdates,
2346
2370
  setIssues,
2347
2371
  setVisibleStatuses,
2348
2372
  setVisibleUserIds,
2349
- updateIssueAttachment,
2350
2373
  updateIssue,
2374
+ // Attachments
2375
+ setIssueAttachment,
2376
+ setIssueAttachments,
2377
+ addIssueAttachment,
2378
+ addIssueAttachments,
2379
+ updateIssueAttachment,
2380
+ updateIssueAttachments,
2381
+ removeIssueAttachment,
2382
+ removeIssueAttachments,
2351
2383
  // Commments
2352
2384
  addIssueComment,
2353
2385
  addIssueComments,
@@ -2716,6 +2748,14 @@ var OrganizationAccessLevel = /* @__PURE__ */ ((OrganizationAccessLevel2) => {
2716
2748
  OrganizationAccessLevel2[OrganizationAccessLevel2["ADMIN"] = 2] = "ADMIN";
2717
2749
  return OrganizationAccessLevel2;
2718
2750
  })(OrganizationAccessLevel || {});
2751
+ var AttachmentModel = /* @__PURE__ */ ((AttachmentModel2) => {
2752
+ AttachmentModel2["Issue"] = "issue";
2753
+ AttachmentModel2["Component"] = "component";
2754
+ AttachmentModel2["ComponentType"] = "component_type";
2755
+ AttachmentModel2["Project"] = "project";
2756
+ AttachmentModel2["Document"] = "document";
2757
+ return AttachmentModel2;
2758
+ })(AttachmentModel || {});
2719
2759
  var IssueUpdateChange = /* @__PURE__ */ ((IssueUpdateChange2) => {
2720
2760
  IssueUpdateChange2["STATUS"] = "status";
2721
2761
  IssueUpdateChange2["PRIORITY"] = "priority";
@@ -3103,11 +3143,13 @@ const projectSlice = createSlice({
3103
3143
  throw new Error("Update form submissions count: no active project");
3104
3144
  }
3105
3145
  },
3106
- // Attachment related
3146
+ // Attachments
3147
+ setProjectAttachment: setAttachment,
3107
3148
  setProjectAttachments: setAttachments,
3108
3149
  addProjectAttachment: addAttachment,
3109
3150
  addProjectAttachments: addAttachments,
3110
3151
  updateProjectAttachment: updateAttachment,
3152
+ updateProjectAttachments: updateAttachments,
3111
3153
  removeProjectAttachment: removeAttachment,
3112
3154
  removeProjectAttachments: removeAttachments
3113
3155
  }
@@ -3122,11 +3164,13 @@ const {
3122
3164
  acceptProjectInvite,
3123
3165
  addActiveProjectIssuesCount,
3124
3166
  addActiveProjectFormSubmissionsCount,
3125
- // Attachment related
3167
+ // Attachments
3168
+ setProjectAttachment,
3126
3169
  setProjectAttachments,
3127
3170
  addProjectAttachment,
3128
3171
  addProjectAttachments,
3129
3172
  updateProjectAttachment,
3173
+ updateProjectAttachments,
3130
3174
  removeProjectAttachment,
3131
3175
  removeProjectAttachments
3132
3176
  } = projectSlice.actions;
@@ -3197,6 +3241,9 @@ const selectAllProjectAttachments = createSelector(
3197
3241
  [selectProjectAttachmentMapping],
3198
3242
  (mapping) => Object.values(mapping)
3199
3243
  );
3244
+ const selectProjectAttachment = (attachmentId) => (state) => {
3245
+ return state.projectReducer.attachments[attachmentId];
3246
+ };
3200
3247
  const selectAttachmentsOfProject = restructureCreateSelectorWithArgs(
3201
3248
  createSelector(
3202
3249
  [selectAllProjectAttachments, (_state, projectId) => projectId],
@@ -4312,10 +4359,13 @@ const documentSlice = createSlice({
4312
4359
  delete state.documents[documentId];
4313
4360
  }
4314
4361
  },
4362
+ // Attachments
4363
+ setDocumentAttachment: setAttachment,
4315
4364
  setDocumentAttachments: setAttachments,
4316
4365
  addDocumentAttachment: addAttachment,
4317
4366
  addDocumentAttachments: addAttachments,
4318
4367
  updateDocumentAttachment: updateAttachment,
4368
+ updateDocumentAttachments: updateAttachments,
4319
4369
  removeDocumentAttachment: removeAttachment,
4320
4370
  removeDocumentAttachments: removeAttachments
4321
4371
  }
@@ -4326,10 +4376,13 @@ const {
4326
4376
  updateDocuments,
4327
4377
  moveDocument,
4328
4378
  removeDocuments,
4379
+ // Attachments
4380
+ setDocumentAttachment,
4329
4381
  setDocumentAttachments,
4330
4382
  addDocumentAttachment,
4331
4383
  addDocumentAttachments,
4332
4384
  updateDocumentAttachment,
4385
+ updateDocumentAttachments,
4333
4386
  removeDocumentAttachment,
4334
4387
  removeDocumentAttachments
4335
4388
  } = documentSlice.actions;
@@ -5019,553 +5072,6 @@ class BaseApiService {
5019
5072
  return promise;
5020
5073
  }
5021
5074
  }
5022
- class AttachmentService extends BaseApiService {
5023
- fetchAll(projectId) {
5024
- const promise = this.enqueueRequest({
5025
- description: "Fetch attachments",
5026
- method: HttpMethod.GET,
5027
- url: `/attachments/${projectId}/`,
5028
- blocks: [],
5029
- blockers: []
5030
- });
5031
- const state = this.client.store.getState();
5032
- const allAttachments = {
5033
- issue_attachments: Object.values(state.issueReducer.attachments),
5034
- component_attachments: Object.values(state.componentReducer.attachments),
5035
- component_type_attachments: Object.values(state.componentTypeReducer.attachments),
5036
- project_attachments: Object.values(state.projectReducer.attachments),
5037
- document_attachments: Object.values(state.documentsReducer.attachments)
5038
- };
5039
- return [allAttachments, promise];
5040
- }
5041
- // Attachments aren't models, so we use the OptimisticGenericResult type instead
5042
- async addIssueAttachment(attachmentPayload) {
5043
- const { issue, file_sha1, offline_id } = attachmentPayload;
5044
- if (!attachmentPayload.file.objectURL) {
5045
- throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
5046
- }
5047
- const offlineAttachment = {
5048
- ...attachmentPayload,
5049
- file: attachmentPayload.file.objectURL,
5050
- file_name: attachmentPayload.file.name,
5051
- file_type: attachmentPayload.file.type,
5052
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5053
- created_by: this.client.store.getState().userReducer.currentUser.id
5054
- };
5055
- await this.client.files.addCache(attachmentPayload.file, file_sha1);
5056
- this.client.store.dispatch(addIssueAttachment(offlineAttachment));
5057
- const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
5058
- const promise = this.enqueueRequest({
5059
- description: "Create attachment",
5060
- method: HttpMethod.POST,
5061
- url: `/issues/${issue}/attach/`,
5062
- blocks: [offline_id, issue],
5063
- blockers: [file_sha1],
5064
- payload: {
5065
- ...offlineAttachment,
5066
- ...fileProps
5067
- }
5068
- });
5069
- promise.catch((error2) => {
5070
- this.client.store.dispatch(removeIssueAttachment(offlineAttachment.offline_id));
5071
- throw error2;
5072
- });
5073
- return [offlineAttachment, promise];
5074
- }
5075
- async addComponentAttachment(attachmentPayload) {
5076
- const { component, file_sha1, offline_id } = attachmentPayload;
5077
- if (!attachmentPayload.file.objectURL) {
5078
- throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
5079
- }
5080
- const offlineAttachment = {
5081
- ...attachmentPayload,
5082
- file: attachmentPayload.file.objectURL,
5083
- file_name: attachmentPayload.file.name,
5084
- file_type: attachmentPayload.file.type,
5085
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5086
- created_by: this.client.store.getState().userReducer.currentUser.id
5087
- };
5088
- await this.client.files.addCache(attachmentPayload.file, file_sha1);
5089
- this.client.store.dispatch(addComponentAttachment(offlineAttachment));
5090
- const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
5091
- const promise = this.enqueueRequest({
5092
- description: "Create attachment",
5093
- method: HttpMethod.POST,
5094
- url: `/components/${component}/attach/`,
5095
- blocks: [offline_id, component],
5096
- blockers: [file_sha1],
5097
- payload: {
5098
- ...offlineAttachment,
5099
- ...fileProps
5100
- }
5101
- });
5102
- promise.catch((error2) => {
5103
- this.client.store.dispatch(removeComponentAttachment(offlineAttachment.offline_id));
5104
- throw error2;
5105
- });
5106
- return [offlineAttachment, promise];
5107
- }
5108
- async addComponentTypeAttachment(attachmentPayload) {
5109
- const { component_type, file_sha1, offline_id } = attachmentPayload;
5110
- if (!attachmentPayload.file.objectURL) {
5111
- throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
5112
- }
5113
- const offlineAttachment = {
5114
- ...attachmentPayload,
5115
- file: attachmentPayload.file.objectURL,
5116
- file_name: attachmentPayload.file.name,
5117
- file_type: attachmentPayload.file.type,
5118
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5119
- created_by: this.client.store.getState().userReducer.currentUser.id
5120
- };
5121
- await this.client.files.addCache(attachmentPayload.file, file_sha1);
5122
- this.client.store.dispatch(addComponentTypeAttachment(offlineAttachment));
5123
- const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
5124
- const promise = this.enqueueRequest({
5125
- description: "Create attachment",
5126
- method: HttpMethod.POST,
5127
- url: `/components/types/${component_type}/attach/`,
5128
- blocks: [offline_id, component_type],
5129
- blockers: [file_sha1],
5130
- payload: {
5131
- ...offlineAttachment,
5132
- ...fileProps
5133
- }
5134
- });
5135
- promise.catch((error2) => {
5136
- this.client.store.dispatch(removeComponentTypeAttachment(offlineAttachment.offline_id));
5137
- throw error2;
5138
- });
5139
- return [offlineAttachment, promise];
5140
- }
5141
- async addDocumentAttachment(attachmentPayload) {
5142
- const { description: description2, document: document2, file_sha1, offline_id } = attachmentPayload;
5143
- if (!attachmentPayload.file.objectURL) {
5144
- throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
5145
- }
5146
- const offlineAttachment = {
5147
- ...attachmentPayload,
5148
- file: attachmentPayload.file.objectURL,
5149
- file_name: attachmentPayload.file.name,
5150
- file_type: attachmentPayload.file.type,
5151
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5152
- created_by: this.client.store.getState().userReducer.currentUser.id
5153
- };
5154
- await this.client.files.addCache(attachmentPayload.file, file_sha1);
5155
- this.client.store.dispatch(addDocumentAttachment(offlineAttachment));
5156
- const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
5157
- const promise = this.enqueueRequest({
5158
- description: "Create attachment",
5159
- method: HttpMethod.POST,
5160
- url: `/documents/${document2}/attach/`,
5161
- blocks: [offline_id, document2],
5162
- blockers: [file_sha1],
5163
- payload: {
5164
- offline_id,
5165
- document: document2,
5166
- description: description2 ?? "",
5167
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5168
- ...fileProps
5169
- }
5170
- });
5171
- promise.catch((error2) => {
5172
- this.client.store.dispatch(removeDocumentAttachment(offlineAttachment.offline_id));
5173
- throw error2;
5174
- });
5175
- return [offlineAttachment, promise];
5176
- }
5177
- /** the outer Promise is needed to await the hashing of each file, which is required before offline use. If wanting to
5178
- * attach promise handlers to the request to add the attachment in the backend, apply it on the promise returned from the
5179
- * OptimisticModelResult. */
5180
- attachFilesToIssue(filesToSubmit, issueId) {
5181
- return filesToSubmit.map((file) => {
5182
- if (!(file instanceof File)) {
5183
- throw new Error("Expected a File instance.");
5184
- }
5185
- const photoAttachmentPromise = async (file2) => {
5186
- const hash = await hashFile(file2);
5187
- const attachment = offline({
5188
- file: file2,
5189
- file_name: file2.name,
5190
- file_type: file2.type,
5191
- issue: issueId,
5192
- file_sha1: hash,
5193
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5194
- created_by: this.client.store.getState().userReducer.currentUser.id
5195
- });
5196
- return this.addIssueAttachment(attachment);
5197
- };
5198
- return photoAttachmentPromise(file);
5199
- });
5200
- }
5201
- attachFilesToComponent(filesToSubmit, componentId) {
5202
- return filesToSubmit.map((file) => {
5203
- if (!(file instanceof File)) {
5204
- throw new Error("Expected a File instance.");
5205
- }
5206
- const photoAttachmentPromise = async (file2) => {
5207
- const hash = await hashFile(file2);
5208
- const attachment = offline({
5209
- file: file2,
5210
- file_name: file2.name,
5211
- file_type: file2.type,
5212
- component: componentId,
5213
- file_sha1: hash,
5214
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5215
- created_by: this.client.store.getState().userReducer.currentUser.id
5216
- });
5217
- return this.addComponentAttachment(attachment);
5218
- };
5219
- return photoAttachmentPromise(file);
5220
- });
5221
- }
5222
- attachFilesToComponentType(filesToSubmit, componentTypeId) {
5223
- return filesToSubmit.map((file) => {
5224
- if (!(file instanceof File)) {
5225
- throw new Error("Expected a File instance.");
5226
- }
5227
- const photoAttachmentPromise = async (file2) => {
5228
- const hash = await hashFile(file2);
5229
- const attachment = offline({
5230
- file: file2,
5231
- file_name: file2.name,
5232
- file_type: file2.type,
5233
- component_type: componentTypeId,
5234
- file_sha1: hash,
5235
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5236
- created_by: this.client.store.getState().userReducer.currentUser.id
5237
- });
5238
- return this.addComponentTypeAttachment(attachment);
5239
- };
5240
- return photoAttachmentPromise(file);
5241
- });
5242
- }
5243
- attachFilesToDocument(filesToSubmit, documentId) {
5244
- return filesToSubmit.map((file) => {
5245
- if (!(file instanceof File)) {
5246
- throw new Error("Expected a File instance.");
5247
- }
5248
- const photoAttachmentPromise = async (file2) => {
5249
- const hash = await hashFile(file2);
5250
- const attachment = offline({
5251
- file: file2,
5252
- file_name: file2.name,
5253
- file_type: file2.type,
5254
- document: documentId,
5255
- file_sha1: hash,
5256
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
5257
- created_by: this.client.store.getState().userReducer.currentUser.id
5258
- });
5259
- return this.addDocumentAttachment(attachment);
5260
- };
5261
- return photoAttachmentPromise(file);
5262
- });
5263
- }
5264
- async replaceIssueAttachmentFile(attachmentId, newFile) {
5265
- const { store } = this.client;
5266
- const attachment = store.getState().issueReducer.attachments[attachmentId];
5267
- if (!attachment)
5268
- throw new Error(`Attachment ${attachmentId} not found`);
5269
- let oldFile = void 0;
5270
- const newSha1 = await hashFile(newFile);
5271
- const performRequest2 = async () => {
5272
- oldFile = await this.client.files.fetchCache(attachment.file_sha1);
5273
- if (!oldFile) {
5274
- console.error(`Failed to fetch old file from cache for sha1 ${attachment.file_sha1}.`);
5275
- }
5276
- if (!newFile.objectURL) {
5277
- throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
5278
- }
5279
- store.dispatch(
5280
- updateIssueAttachment({ ...attachment, file_sha1: newSha1, file: URL.createObjectURL(newFile) })
5281
- );
5282
- await this.client.files.addCache(newFile, newSha1);
5283
- const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
5284
- store.dispatch(updateIssueAttachment(attachment));
5285
- throw e;
5286
- });
5287
- const promise2 = this.enqueueRequest({
5288
- description: "Edit attachment",
5289
- method: HttpMethod.PATCH,
5290
- url: `/attachments/issues/${attachment.offline_id}/`,
5291
- isResponseBlob: false,
5292
- payload: fileProps,
5293
- blockers: [attachmentId, newSha1],
5294
- blocks: [attachmentId, newSha1]
5295
- });
5296
- try {
5297
- const result = await promise2;
5298
- void this.client.files.removeCache(attachment.file_sha1);
5299
- return result;
5300
- } catch (e) {
5301
- if (oldFile) {
5302
- store.dispatch(
5303
- updateIssueAttachment({
5304
- ...attachment,
5305
- file_sha1: attachment.file_sha1,
5306
- file: URL.createObjectURL(oldFile)
5307
- })
5308
- );
5309
- }
5310
- throw e;
5311
- }
5312
- };
5313
- const offlineAttachment = {
5314
- ...attachment,
5315
- file_sha1: newSha1,
5316
- file: URL.createObjectURL(newFile)
5317
- };
5318
- const promise = performRequest2();
5319
- return [offlineAttachment, promise];
5320
- }
5321
- async replaceComponentAttachmentFile(attachmentId, newFile) {
5322
- const { store } = this.client;
5323
- const attachment = store.getState().componentReducer.attachments[attachmentId];
5324
- if (!attachment)
5325
- throw new Error(`Attachment ${attachmentId} not found`);
5326
- let oldFile = void 0;
5327
- const newSha1 = await hashFile(newFile);
5328
- const performRequest2 = async () => {
5329
- oldFile = await this.client.files.fetchCache(attachment.file_sha1);
5330
- if (!oldFile) {
5331
- console.error(`Failed to fetch old file from cache for sha1 ${attachment.file_sha1}.`);
5332
- }
5333
- if (!newFile.objectURL) {
5334
- throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
5335
- }
5336
- store.dispatch(
5337
- updateComponentAttachment({ ...attachment, file_sha1: newSha1, file: URL.createObjectURL(newFile) })
5338
- );
5339
- await this.client.files.addCache(newFile, newSha1);
5340
- const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
5341
- store.dispatch(updateComponentAttachment(attachment));
5342
- throw e;
5343
- });
5344
- const promise2 = this.enqueueRequest({
5345
- description: "Edit attachment",
5346
- method: HttpMethod.PATCH,
5347
- url: `/attachments/components/${attachment.offline_id}/`,
5348
- isResponseBlob: false,
5349
- payload: fileProps,
5350
- blockers: [attachmentId, newSha1],
5351
- blocks: [attachmentId, newSha1]
5352
- });
5353
- try {
5354
- const result = await promise2;
5355
- void this.client.files.removeCache(attachment.file_sha1);
5356
- return result;
5357
- } catch (e) {
5358
- if (oldFile) {
5359
- store.dispatch(
5360
- updateComponentAttachment({
5361
- ...attachment,
5362
- file_sha1: attachment.file_sha1,
5363
- file: URL.createObjectURL(oldFile)
5364
- })
5365
- );
5366
- }
5367
- throw e;
5368
- }
5369
- };
5370
- const offlineAttachment = {
5371
- ...attachment,
5372
- file_sha1: newSha1,
5373
- file: URL.createObjectURL(newFile)
5374
- };
5375
- const promise = performRequest2();
5376
- return [offlineAttachment, promise];
5377
- }
5378
- async replaceComponentTypeAttachmentFile(attachmentId, newFile) {
5379
- const { store } = this.client;
5380
- const attachment = store.getState().componentTypeReducer.attachments[attachmentId];
5381
- if (!attachment)
5382
- throw new Error(`Attachment ${attachmentId} not found`);
5383
- let oldFile = void 0;
5384
- const newSha1 = await hashFile(newFile);
5385
- const performRequest2 = async () => {
5386
- oldFile = await this.client.files.fetchCache(attachment.file_sha1);
5387
- if (!oldFile) {
5388
- console.error(`Failed to fetch old file from cache for sha1 ${attachment.file_sha1}.`);
5389
- }
5390
- if (!newFile.objectURL) {
5391
- throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
5392
- }
5393
- store.dispatch(
5394
- updateComponentTypeAttachment({
5395
- ...attachment,
5396
- file_sha1: newSha1,
5397
- file: URL.createObjectURL(newFile)
5398
- })
5399
- );
5400
- await this.client.files.addCache(newFile, newSha1);
5401
- const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
5402
- store.dispatch(updateComponentTypeAttachment(attachment));
5403
- throw e;
5404
- });
5405
- const promise2 = this.enqueueRequest({
5406
- description: "Edit attachment",
5407
- method: HttpMethod.PATCH,
5408
- url: `/attachments/component_types/${attachment.offline_id}/`,
5409
- isResponseBlob: false,
5410
- payload: fileProps,
5411
- blockers: [attachmentId, newSha1],
5412
- blocks: [attachmentId, newSha1]
5413
- });
5414
- try {
5415
- const result = await promise2;
5416
- void this.client.files.removeCache(attachment.file_sha1);
5417
- return result;
5418
- } catch (e) {
5419
- if (oldFile) {
5420
- store.dispatch(
5421
- updateComponentTypeAttachment({
5422
- ...attachment,
5423
- file_sha1: attachment.file_sha1,
5424
- file: URL.createObjectURL(oldFile)
5425
- })
5426
- );
5427
- }
5428
- throw e;
5429
- }
5430
- };
5431
- const offlineAttachment = {
5432
- ...attachment,
5433
- file_sha1: newSha1,
5434
- file: URL.createObjectURL(newFile)
5435
- };
5436
- const promise = performRequest2();
5437
- return [offlineAttachment, promise];
5438
- }
5439
- async replaceDocumentAttachmentFile(attachmentId, newFile) {
5440
- const { store } = this.client;
5441
- const attachment = store.getState().documentsReducer.attachments[attachmentId];
5442
- if (!attachment)
5443
- throw new Error(`Attachment ${attachmentId} not found`);
5444
- let oldFile = void 0;
5445
- const newSha1 = await hashFile(newFile);
5446
- const performRequest2 = async () => {
5447
- oldFile = await this.client.files.fetchCache(attachment.file_sha1);
5448
- if (!oldFile) {
5449
- console.error(`Failed to fetch old file from cache for sha1 ${attachment.file_sha1}.`);
5450
- }
5451
- if (!newFile.objectURL) {
5452
- throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
5453
- }
5454
- store.dispatch(
5455
- updateDocumentAttachment({
5456
- ...attachment,
5457
- file_sha1: newSha1,
5458
- file: URL.createObjectURL(newFile)
5459
- })
5460
- );
5461
- await this.client.files.addCache(newFile, newSha1);
5462
- const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
5463
- store.dispatch(updateDocumentAttachment(attachment));
5464
- throw e;
5465
- });
5466
- const promise2 = this.enqueueRequest({
5467
- description: "Edit attachment",
5468
- method: HttpMethod.PATCH,
5469
- url: `/attachments/documents/${attachment.offline_id}/`,
5470
- isResponseBlob: false,
5471
- payload: fileProps,
5472
- blockers: [attachmentId, newSha1],
5473
- blocks: [attachmentId, newSha1]
5474
- });
5475
- try {
5476
- const result = await promise2;
5477
- void this.client.files.removeCache(attachment.file_sha1);
5478
- return result;
5479
- } catch (e) {
5480
- if (oldFile) {
5481
- store.dispatch(
5482
- updateDocumentAttachment({
5483
- ...attachment,
5484
- file_sha1: attachment.file_sha1,
5485
- file: URL.createObjectURL(oldFile)
5486
- })
5487
- );
5488
- }
5489
- throw e;
5490
- }
5491
- };
5492
- const offlineAttachment = {
5493
- ...attachment,
5494
- file_sha1: newSha1,
5495
- file: URL.createObjectURL(newFile)
5496
- };
5497
- const promise = performRequest2();
5498
- return [offlineAttachment, promise];
5499
- }
5500
- /**
5501
- * Deletes an attachment and associated data in the cloud, in the Redux store and the cache.
5502
- * @param issueAttachmentId
5503
- */
5504
- deleteIssueAttachment(issueAttachmentId) {
5505
- const { store } = this.client;
5506
- const attachment = selectIssueAttachmentMapping(store.getState())[issueAttachmentId];
5507
- if (!attachment) {
5508
- throw new Error(`Attachment ${issueAttachmentId} not found`);
5509
- }
5510
- store.dispatch(removeIssueAttachment(issueAttachmentId));
5511
- void this.client.files.removeCache(attachment.file_sha1);
5512
- return this.enqueueRequest({
5513
- description: "Delete attachment",
5514
- method: HttpMethod.DELETE,
5515
- url: `/attachments/issues/${issueAttachmentId}/`,
5516
- blockers: [issueAttachmentId],
5517
- blocks: [issueAttachmentId]
5518
- });
5519
- }
5520
- deleteComponentAttachment(componentAttachmentId) {
5521
- const { store } = this.client;
5522
- const attachment = selectComponentAttachmentMapping(store.getState())[componentAttachmentId];
5523
- if (!attachment) {
5524
- throw new Error(`Attachment ${componentAttachmentId} not found`);
5525
- }
5526
- store.dispatch(removeComponentAttachment(componentAttachmentId));
5527
- void this.client.files.removeCache(attachment.file_sha1);
5528
- return this.enqueueRequest({
5529
- description: "Delete attachment",
5530
- method: HttpMethod.DELETE,
5531
- url: `/attachments/components/${componentAttachmentId}/`,
5532
- blockers: [componentAttachmentId],
5533
- blocks: [componentAttachmentId]
5534
- });
5535
- }
5536
- deleteComponentTypeAttachment(componentTypeAttachmentId) {
5537
- const { store } = this.client;
5538
- const attachment = selectComponentTypeAttachmentMapping(store.getState())[componentTypeAttachmentId];
5539
- if (!attachment) {
5540
- throw new Error(`Attachment ${componentTypeAttachmentId} not found`);
5541
- }
5542
- store.dispatch(removeComponentTypeAttachment(componentTypeAttachmentId));
5543
- void this.client.files.removeCache(attachment.file_sha1);
5544
- return this.enqueueRequest({
5545
- description: "Delete attachment",
5546
- method: HttpMethod.DELETE,
5547
- url: `/attachments/component_types/${componentTypeAttachmentId}/`,
5548
- blockers: [componentTypeAttachmentId],
5549
- blocks: [componentTypeAttachmentId]
5550
- });
5551
- }
5552
- deleteDocumentAttachment(documentAttachmentId) {
5553
- const { store } = this.client;
5554
- const attachment = store.getState().documentsReducer.attachments[documentAttachmentId];
5555
- if (!attachment) {
5556
- throw new Error(`Attachment ${documentAttachmentId} not found`);
5557
- }
5558
- store.dispatch(removeDocumentAttachment(documentAttachmentId));
5559
- void this.client.files.removeCache(attachment.file_sha1);
5560
- return this.enqueueRequest({
5561
- description: "Delete document attachment",
5562
- method: HttpMethod.DELETE,
5563
- url: `/attachments/documents/${documentAttachmentId}/`,
5564
- blockers: [documentAttachmentId],
5565
- blocks: [documentAttachmentId]
5566
- });
5567
- }
5568
- }
5569
5075
  const EXPIRING_SOON_THRESHOLD = 1800;
5570
5076
  function parseTokens(response) {
5571
5077
  if (!response.access)
@@ -6257,6 +5763,221 @@ class ComponentStageService extends BaseApiService {
6257
5763
  store.dispatch(addStages(result));
6258
5764
  }
6259
5765
  }
5766
+ const AttachmentModelMeta = {
5767
+ [AttachmentModel.Issue]: {
5768
+ name: "issue",
5769
+ attachUrlPrefix: "/issues",
5770
+ deleteUrlPrefix: "/issues",
5771
+ fetchUrlPostfix: "/issue-attachments"
5772
+ },
5773
+ [AttachmentModel.Component]: {
5774
+ name: "component",
5775
+ attachUrlPrefix: "/components",
5776
+ deleteUrlPrefix: "/components",
5777
+ fetchUrlPostfix: "/component-attachments"
5778
+ },
5779
+ [AttachmentModel.ComponentType]: {
5780
+ name: "component type",
5781
+ attachUrlPrefix: "/components/types",
5782
+ deleteUrlPrefix: "/components/types",
5783
+ fetchUrlPostfix: "/component-type-attachments"
5784
+ },
5785
+ [AttachmentModel.Project]: {
5786
+ name: "component project",
5787
+ attachUrlPrefix: "/projects",
5788
+ deleteUrlPrefix: "/projects",
5789
+ fetchUrlPostfix: "/attachments"
5790
+ },
5791
+ [AttachmentModel.Document]: {
5792
+ name: "document",
5793
+ attachUrlPrefix: "/documents",
5794
+ deleteUrlPrefix: "/documents",
5795
+ fetchUrlPostfix: "/document-attachments"
5796
+ }
5797
+ };
5798
+ class BaseAttachmentService extends BaseApiService {
5799
+ getNumberOfAttachmentsWithSha1(sha1) {
5800
+ const {
5801
+ issueReducer: issueReducer2,
5802
+ componentReducer: componentReducer2,
5803
+ componentTypeReducer: componentTypeReducer2,
5804
+ documentsReducer: documentsReducer2,
5805
+ projectReducer: projectReducer2,
5806
+ formSubmissionReducer: formSubmissionReducer2,
5807
+ formRevisionReducer: formRevisionReducer2
5808
+ } = this.client.store.getState();
5809
+ const objectsWithSha1 = [].concat(
5810
+ Object.values(issueReducer2.attachments),
5811
+ Object.values(componentReducer2.attachments),
5812
+ Object.values(componentTypeReducer2.attachments),
5813
+ Object.values(documentsReducer2.attachments),
5814
+ Object.values(projectReducer2.attachments),
5815
+ Object.values(formRevisionReducer2.attachments),
5816
+ Object.values(formSubmissionReducer2.attachments)
5817
+ );
5818
+ return objectsWithSha1.filter((object) => object.file_sha1 === sha1).length;
5819
+ }
5820
+ processPresignedUrls(presignedUrls) {
5821
+ for (const [sha1, presignedUrl] of Object.entries(presignedUrls)) {
5822
+ void this.enqueueRequest({
5823
+ url: presignedUrl.url,
5824
+ description: "Upload file to S3",
5825
+ method: HttpMethod.POST,
5826
+ isExternalUrl: true,
5827
+ isAuthNeeded: false,
5828
+ attachmentHash: sha1,
5829
+ // TODO: can we use the sha1 as the blocker?
5830
+ blockers: [`s3-${presignedUrl.fields.key}`],
5831
+ blocks: [sha1],
5832
+ s3url: presignedUrl
5833
+ });
5834
+ }
5835
+ }
5836
+ // Note that currently the fetching of attachments for all models dependds on the active projectId. This may change in the future. And
5837
+ // so for some attachment model services, this method will have to be overridden.
5838
+ async getAttachments(actions) {
5839
+ const { store } = this.client;
5840
+ const activeProjectId = store.getState().projectReducer.activeProjectId;
5841
+ const meta = AttachmentModelMeta[this.attachmentModel];
5842
+ const result = await this.enqueueRequest({
5843
+ description: `Get ${meta.name} attachments`,
5844
+ method: HttpMethod.GET,
5845
+ url: `/projects/${activeProjectId}${meta.fetchUrlPostfix}/`,
5846
+ blocks: [],
5847
+ blockers: []
5848
+ });
5849
+ store.dispatch(actions.setAttachments(result));
5850
+ }
5851
+ async attachFiles(files, modelId, buildOfflineAttachment, actions) {
5852
+ const { store } = this.client;
5853
+ const currentUser = store.getState().userReducer.currentUser;
5854
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
5855
+ const offlineAttachments = [];
5856
+ const attachmentPayloads = [];
5857
+ const filePayloads = {};
5858
+ for (const file of files) {
5859
+ const sha1 = await hashFile(file);
5860
+ if (!(sha1 in filePayloads)) {
5861
+ filePayloads[sha1] = {
5862
+ sha1,
5863
+ file_type: file.type,
5864
+ extension: file.name.split(".").pop(),
5865
+ size: file.size
5866
+ };
5867
+ await this.client.files.addCache(file, sha1);
5868
+ }
5869
+ const offlineAttachment = buildOfflineAttachment({
5870
+ file,
5871
+ sha1,
5872
+ submittedAt,
5873
+ createdBy: currentUser.id,
5874
+ description: "",
5875
+ modelId
5876
+ });
5877
+ offlineAttachments.push(offlineAttachment);
5878
+ attachmentPayloads.push({
5879
+ offline_id: offlineAttachment.offline_id,
5880
+ name: offlineAttachment.file_name,
5881
+ sha1: offlineAttachment.file_sha1,
5882
+ description: offlineAttachment.description
5883
+ });
5884
+ }
5885
+ store.dispatch(actions.addAttachments(offlineAttachments));
5886
+ const meta = AttachmentModelMeta[this.attachmentModel];
5887
+ const promise = this.enqueueRequest({
5888
+ description: `Attach files to ${meta.name}`,
5889
+ method: HttpMethod.POST,
5890
+ url: `${meta.attachUrlPrefix}/${modelId}/attach/`,
5891
+ payload: {
5892
+ submitted_at: submittedAt,
5893
+ attachments: attachmentPayloads,
5894
+ files: Object.values(filePayloads)
5895
+ },
5896
+ blocks: offlineAttachments.map((attachment) => attachment.offline_id),
5897
+ blockers: offlineAttachments.map((attachment) => attachment.file_sha1)
5898
+ });
5899
+ promise.then(({ attachments, presigned_urls }) => {
5900
+ store.dispatch(actions.updateAttachments(attachments));
5901
+ this.processPresignedUrls(presigned_urls);
5902
+ }).catch(() => {
5903
+ store.dispatch(actions.removeAttachments(offlineAttachments.map((attachment) => attachment.offline_id)));
5904
+ });
5905
+ return [offlineAttachments, promise.then(({ attachments }) => attachments)];
5906
+ }
5907
+ async deleteAttachment(attachmendId, actions, selectors) {
5908
+ const { store } = this.client;
5909
+ const attachment = selectors.selectAttachment(attachmendId)(store.getState());
5910
+ if (!attachment) {
5911
+ throw new Error(
5912
+ `Attempting to delete attachment with offline_id ${attachmendId} that does not exist in the store`
5913
+ );
5914
+ }
5915
+ store.dispatch(actions.removeAttachment(attachment.offline_id));
5916
+ const meta = AttachmentModelMeta[this.attachmentModel];
5917
+ const promise = this.enqueueRequest({
5918
+ description: "Delete attachment",
5919
+ method: HttpMethod.DELETE,
5920
+ url: `${meta.deleteUrlPrefix}/attachments/${attachmendId}/`,
5921
+ blockers: [attachmendId],
5922
+ blocks: []
5923
+ });
5924
+ promise.then(() => {
5925
+ if (this.getNumberOfAttachmentsWithSha1(attachment.file_sha1) === 0) {
5926
+ void this.client.files.removeCache(attachment.file_sha1);
5927
+ }
5928
+ }).catch(() => {
5929
+ store.dispatch(actions.setAttachment(attachment));
5930
+ });
5931
+ return promise;
5932
+ }
5933
+ }
5934
+ class ComponentAttachmentService extends BaseAttachmentService {
5935
+ constructor() {
5936
+ super(...arguments);
5937
+ __publicField(this, "attachmentModel", AttachmentModel.Component);
5938
+ }
5939
+ buildOfflineAttachment(data) {
5940
+ return offline({
5941
+ file: URL.createObjectURL(data.file),
5942
+ file_sha1: data.sha1,
5943
+ created_by: data.createdBy,
5944
+ file_name: data.file.name,
5945
+ file_type: data.file.type,
5946
+ submitted_at: data.submittedAt,
5947
+ description: data.description,
5948
+ component: data.modelId
5949
+ });
5950
+ }
5951
+ async attachFilesToComponent(files, componentId) {
5952
+ return this.attachFiles(
5953
+ files,
5954
+ componentId,
5955
+ this.buildOfflineAttachment.bind(this),
5956
+ {
5957
+ addAttachments: addComponentAttachments,
5958
+ updateAttachments: updateComponentAttachments,
5959
+ removeAttachments: removeComponentAttachments
5960
+ }
5961
+ );
5962
+ }
5963
+ deleteComponentAttachment(attachmentId) {
5964
+ return this.deleteAttachment(
5965
+ attachmentId,
5966
+ {
5967
+ setAttachment: setComponentAttachment,
5968
+ removeAttachment: removeComponentAttachment
5969
+ },
5970
+ {
5971
+ selectAttachment: selectComponentAttachment
5972
+ }
5973
+ );
5974
+ }
5975
+ async refreshStore() {
5976
+ return this.getAttachments({
5977
+ setAttachments: setComponentAttachments
5978
+ });
5979
+ }
5980
+ }
6260
5981
  class ComponentTypeService extends BaseApiService {
6261
5982
  add(componentType) {
6262
5983
  const offlineComponentType = offline(componentType);
@@ -6329,6 +6050,53 @@ class ComponentTypeService extends BaseApiService {
6329
6050
  store.dispatch(setComponentTypes(result));
6330
6051
  }
6331
6052
  }
6053
+ class ComponentTypeAttachmentService extends BaseAttachmentService {
6054
+ constructor() {
6055
+ super(...arguments);
6056
+ __publicField(this, "attachmentModel", AttachmentModel.ComponentType);
6057
+ }
6058
+ buildOfflineAttachment(data) {
6059
+ return offline({
6060
+ file: URL.createObjectURL(data.file),
6061
+ file_sha1: data.sha1,
6062
+ created_by: data.createdBy,
6063
+ file_name: data.file.name,
6064
+ file_type: data.file.type,
6065
+ submitted_at: data.submittedAt,
6066
+ description: data.description,
6067
+ component_type: data.modelId
6068
+ });
6069
+ }
6070
+ async attachFilesToComponentType(files, componentTypeId) {
6071
+ return this.attachFiles(
6072
+ files,
6073
+ componentTypeId,
6074
+ this.buildOfflineAttachment.bind(this),
6075
+ {
6076
+ addAttachments: addComponentTypeAttachments,
6077
+ updateAttachments: updateComponentTypeAttachments,
6078
+ removeAttachments: removeComponentTypeAttachments
6079
+ }
6080
+ );
6081
+ }
6082
+ deleteComponentTypeAttachment(attachmentId) {
6083
+ return this.deleteAttachment(
6084
+ attachmentId,
6085
+ {
6086
+ setAttachment: setComponentTypeAttachment,
6087
+ removeAttachment: removeComponentTypeAttachment
6088
+ },
6089
+ {
6090
+ selectAttachment: selectComponentTypeAttachment
6091
+ }
6092
+ );
6093
+ }
6094
+ async refreshStore() {
6095
+ return this.getAttachments({
6096
+ setAttachments: setComponentTypeAttachments
6097
+ });
6098
+ }
6099
+ }
6332
6100
  class IssueCommentService extends BaseApiService {
6333
6101
  // Omit author and submitted_at since these will always be set internally
6334
6102
  add(comment) {
@@ -6425,6 +6193,48 @@ class IssueUpdateService extends BaseApiService {
6425
6193
  store.dispatch(setIssueUpdates(filteredResult));
6426
6194
  }
6427
6195
  }
6196
+ class IssueAttachmentService extends BaseAttachmentService {
6197
+ constructor() {
6198
+ super(...arguments);
6199
+ __publicField(this, "attachmentModel", AttachmentModel.Issue);
6200
+ }
6201
+ buildOfflineAttachment(data) {
6202
+ return offline({
6203
+ file: URL.createObjectURL(data.file),
6204
+ file_sha1: data.sha1,
6205
+ created_by: data.createdBy,
6206
+ file_name: data.file.name,
6207
+ file_type: data.file.type,
6208
+ submitted_at: data.submittedAt,
6209
+ description: data.description,
6210
+ issue: data.modelId
6211
+ });
6212
+ }
6213
+ async attachFilesToIssue(files, issueId) {
6214
+ return this.attachFiles(files, issueId, this.buildOfflineAttachment.bind(this), {
6215
+ addAttachments: addIssueAttachments,
6216
+ updateAttachments: updateIssueAttachments,
6217
+ removeAttachments: removeIssueAttachments
6218
+ });
6219
+ }
6220
+ deleteIssueAttachment(attachmentId) {
6221
+ return this.deleteAttachment(
6222
+ attachmentId,
6223
+ {
6224
+ setAttachment: setIssueAttachment,
6225
+ removeAttachment: removeIssueAttachment
6226
+ },
6227
+ {
6228
+ selectAttachment: selectIssueAttachment
6229
+ }
6230
+ );
6231
+ }
6232
+ async refreshStore() {
6233
+ return this.getAttachments({
6234
+ setAttachments: setIssueAttachments
6235
+ });
6236
+ }
6237
+ }
6428
6238
  class IssueService extends BaseApiService {
6429
6239
  // Basic CRUD functions
6430
6240
  // TODO: Once all models are represented in `Created<TModel>`, use `Created` in `OptimisticModelResult`, so we don't
@@ -6869,6 +6679,7 @@ class MainService extends BaseApiService {
6869
6679
  const usersResult = await usersResultPromise;
6870
6680
  await projectAccessRefreshPromise;
6871
6681
  store.dispatch(addUsers(usersResult));
6682
+ void this.client.projectAttachments.refreshStore();
6872
6683
  }
6873
6684
  let currentWorkspaceId;
6874
6685
  const oldWorkspaceId = this.client.store.getState().workspaceReducer.activeWorkspaceId;
@@ -6881,35 +6692,29 @@ class MainService extends BaseApiService {
6881
6692
  store.dispatch(setActiveWorkspaceId(currentWorkspaceId));
6882
6693
  void this.client.categories.refreshStore().then(() => {
6883
6694
  void this.client.issues.refreshStore().then(() => {
6695
+ void this.client.issueAttachments.refreshStore().then();
6884
6696
  void this.client.issueComments.refreshStore().then();
6697
+ void this.client.issueUpdates.refreshStore().then();
6885
6698
  });
6886
6699
  });
6887
6700
  void this.client.projectFiles.refreshStore().then();
6888
6701
  void this.client.componentTypes.refreshStore().then(() => {
6889
- void this.client.componentStages.refreshStore().then(() => {
6890
- void this.client.components.refreshStore(overwrite).then();
6702
+ void this.client.componentTypeAttachments.refreshStore().then(() => {
6703
+ void this.client.componentStages.refreshStore().then(() => {
6704
+ void this.client.components.refreshStore(overwrite).then(() => {
6705
+ void this.client.componentAttachments.refreshStore().then();
6706
+ });
6707
+ });
6708
+ void this.client.componentStageCompletions.refreshStore().then();
6891
6709
  });
6892
- void this.client.componentStageCompletions.refreshStore().then();
6893
6710
  });
6894
6711
  void this.client.userForms.refreshStore().then(() => {
6895
6712
  void this.client.userFormSubmissions.refreshStore().then();
6896
6713
  });
6897
6714
  }
6898
6715
  if (currentProjectId) {
6899
- const [_offlineAttachments, promise] = this.client.attachments.fetchAll(currentProjectId);
6900
- void promise.then((result) => {
6901
- const {
6902
- issue_attachments,
6903
- component_type_attachments,
6904
- component_attachments,
6905
- project_attachments,
6906
- document_attachments
6907
- } = result;
6908
- store.dispatch(setIssueAttachments(issue_attachments));
6909
- store.dispatch(setComponentAttachments(component_attachments));
6910
- store.dispatch(setComponentTypeAttachments(component_type_attachments));
6911
- store.dispatch(setProjectAttachments(project_attachments));
6912
- store.dispatch(setDocumentAttachments(document_attachments));
6716
+ void this.client.documents.refreshStore().then(() => {
6717
+ void this.client.documentAttachments.refreshStore().then();
6913
6718
  });
6914
6719
  void this.client.documents.refreshStore();
6915
6720
  void this.client.issueUpdates.refreshStore();
@@ -7012,6 +6817,7 @@ class ProjectFileService extends BaseApiService {
7012
6817
  });
7013
6818
  return promise;
7014
6819
  }
6820
+ // TODO: This needs to be seperated into a update and create method
7015
6821
  saveActive() {
7016
6822
  const { store } = this.client;
7017
6823
  const state = store.getState();
@@ -7077,6 +6883,48 @@ class ProjectFileService extends BaseApiService {
7077
6883
  });
7078
6884
  }
7079
6885
  }
6886
+ class ProjectAttachmentService extends BaseAttachmentService {
6887
+ constructor() {
6888
+ super(...arguments);
6889
+ __publicField(this, "attachmentModel", AttachmentModel.Project);
6890
+ }
6891
+ buildOfflineAttachment(data) {
6892
+ return offline({
6893
+ file: URL.createObjectURL(data.file),
6894
+ file_sha1: data.sha1,
6895
+ created_by: data.createdBy,
6896
+ file_name: data.file.name,
6897
+ file_type: data.file.type,
6898
+ submitted_at: data.submittedAt,
6899
+ description: data.description,
6900
+ project: data.modelId
6901
+ });
6902
+ }
6903
+ async attachFilesToProject(files, projectId) {
6904
+ return this.attachFiles(files, projectId, this.buildOfflineAttachment.bind(this), {
6905
+ addAttachments: addProjectAttachments,
6906
+ updateAttachments: updateProjectAttachments,
6907
+ removeAttachments: removeProjectAttachments
6908
+ });
6909
+ }
6910
+ deleteProjectAttachment(attachmentId) {
6911
+ return this.deleteAttachment(
6912
+ attachmentId,
6913
+ {
6914
+ setAttachment: setProjectAttachment,
6915
+ removeAttachment: removeProjectAttachment
6916
+ },
6917
+ {
6918
+ selectAttachment: selectProjectAttachment
6919
+ }
6920
+ );
6921
+ }
6922
+ async refreshStore() {
6923
+ return this.getAttachments({
6924
+ setAttachments: setProjectAttachments
6925
+ });
6926
+ }
6927
+ }
7080
6928
  class ProjectService extends BaseApiService {
7081
6929
  /**
7082
6930
  * Creates a new project. Due to the nature of project creation,
@@ -8468,6 +8316,48 @@ class DocumentService extends BaseApiService {
8468
8316
  store.dispatch(addDocuments(await organizationDocumentsPromise));
8469
8317
  }
8470
8318
  }
8319
+ class DocumentAttachmentService extends BaseAttachmentService {
8320
+ constructor() {
8321
+ super(...arguments);
8322
+ __publicField(this, "attachmentModel", AttachmentModel.Document);
8323
+ }
8324
+ buildOfflineAttachment(data) {
8325
+ return offline({
8326
+ file: URL.createObjectURL(data.file),
8327
+ file_sha1: data.sha1,
8328
+ created_by: data.createdBy,
8329
+ file_name: data.file.name,
8330
+ file_type: data.file.type,
8331
+ submitted_at: data.submittedAt,
8332
+ description: data.description,
8333
+ document: data.modelId
8334
+ });
8335
+ }
8336
+ async attachFilesToDocument(files, documentId) {
8337
+ return this.attachFiles(files, documentId, this.buildOfflineAttachment.bind(this), {
8338
+ addAttachments: addDocumentAttachments,
8339
+ updateAttachments: updateDocumentAttachments,
8340
+ removeAttachments: removeDocumentAttachments
8341
+ });
8342
+ }
8343
+ deleteDocumentAttachment(attachmentId) {
8344
+ return this.deleteAttachment(
8345
+ attachmentId,
8346
+ {
8347
+ setAttachment: setDocumentAttachment,
8348
+ removeAttachment: removeDocumentAttachment
8349
+ },
8350
+ {
8351
+ selectAttachment: selectDocumentAttachment
8352
+ }
8353
+ );
8354
+ }
8355
+ async refreshStore() {
8356
+ return this.getAttachments({
8357
+ setAttachments: setDocumentAttachments
8358
+ });
8359
+ }
8360
+ }
8471
8361
  class AgentService extends BaseApiService {
8472
8362
  /**
8473
8363
  * Prompt the agent with a message.
@@ -8489,16 +8379,6 @@ class AgentService extends BaseApiService {
8489
8379
  queryParams: conversationId ? { conversation_id: conversationId } : {}
8490
8380
  });
8491
8381
  }
8492
- async fetchAll() {
8493
- const activeProjectId = this.client.store.getState().projectReducer.activeProjectId;
8494
- return this.enqueueRequest({
8495
- description: "Fetch agent conversations",
8496
- method: HttpMethod.GET,
8497
- url: `/projects/${activeProjectId}/agents-conversations/`,
8498
- blockers: ["fetch-agent-conversations"],
8499
- blocks: ["fetch-agent-conversations"]
8500
- });
8501
- }
8502
8382
  async rate(responseId, rating) {
8503
8383
  return this.enqueueRequest({
8504
8384
  description: "Rate agent response",
@@ -8652,7 +8532,6 @@ class OvermapSDK {
8652
8532
  __publicField(this, "store");
8653
8533
  __publicField(this, "agent", new AgentService(this));
8654
8534
  __publicField(this, "files", new FileService(this));
8655
- __publicField(this, "attachments", new AttachmentService(this));
8656
8535
  __publicField(this, "auth", new AuthService(this));
8657
8536
  __publicField(this, "categories", new CategoryService(this));
8658
8537
  __publicField(this, "projectAccesses", new ProjectAccessService(this));
@@ -8662,21 +8541,26 @@ class OvermapSDK {
8662
8541
  __publicField(this, "issueTypes", new IssueTypeService(this));
8663
8542
  __publicField(this, "issueComments", new IssueCommentService(this));
8664
8543
  __publicField(this, "issueUpdates", new IssueUpdateService(this));
8544
+ __publicField(this, "issueAttachments", new IssueAttachmentService(this));
8665
8545
  __publicField(this, "workspaces", new WorkspaceService(this));
8666
8546
  __publicField(this, "main", new MainService(this));
8667
8547
  __publicField(this, "components", new ComponentService(this));
8548
+ __publicField(this, "componentAttachments", new ComponentAttachmentService(this));
8668
8549
  __publicField(this, "componentTypes", new ComponentTypeService(this));
8550
+ __publicField(this, "componentTypeAttachments", new ComponentTypeAttachmentService(this));
8669
8551
  __publicField(this, "componentStages", new ComponentStageService(this));
8670
8552
  __publicField(this, "componentStageCompletions", new ComponentStageCompletionService(this));
8671
8553
  __publicField(this, "userForms", new UserFormService(this));
8672
8554
  __publicField(this, "userFormSubmissions", new UserFormSubmissionService(this));
8673
8555
  __publicField(this, "projects", new ProjectService(this));
8674
8556
  __publicField(this, "projectFiles", new ProjectFileService(this));
8557
+ __publicField(this, "projectAttachments", new ProjectAttachmentService(this));
8675
8558
  __publicField(this, "emailVerification", new EmailVerificationService(this));
8676
8559
  __publicField(this, "emailDomains", new EmailDomainsService(this));
8677
8560
  __publicField(this, "licenses", new LicenseService(this));
8678
8561
  __publicField(this, "documents", new DocumentService(this));
8679
8562
  __publicField(this, "teams", new TeamService(this));
8563
+ __publicField(this, "documentAttachments", new DocumentAttachmentService(this));
8680
8564
  this.API_URL = apiUrl;
8681
8565
  this.store = store;
8682
8566
  }
@@ -16509,7 +16393,7 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
16509
16393
  export {
16510
16394
  APIError,
16511
16395
  AgentService,
16512
- AttachmentService,
16396
+ AttachmentModel,
16513
16397
  AuthService,
16514
16398
  BaseApiService,
16515
16399
  BaseField,
@@ -16520,15 +16404,18 @@ export {
16520
16404
  ColorPicker,
16521
16405
  Colors,
16522
16406
  ColorsToString,
16407
+ ComponentAttachmentService,
16523
16408
  ComponentService,
16524
16409
  ComponentStageColors,
16525
16410
  ComponentStageCompletionService,
16526
16411
  ComponentStageService,
16412
+ ComponentTypeAttachmentService,
16527
16413
  ComponentTypeService,
16528
16414
  DEFAULT_ISSUE_PRIORITY,
16529
16415
  DEFAULT_ISSUE_STATUS,
16530
16416
  DateField,
16531
16417
  DateInput,
16418
+ DocumentAttachmentService,
16532
16419
  DocumentService,
16533
16420
  EmailDomainsService,
16534
16421
  EmailVerificationService,
@@ -16552,6 +16439,7 @@ export {
16552
16439
  InputWithHelpText,
16553
16440
  InputWithLabel,
16554
16441
  InputWithLabelAndHelpText,
16442
+ IssueAttachmentService,
16555
16443
  IssueCommentService,
16556
16444
  IssuePriority,
16557
16445
  IssueService,
@@ -16584,6 +16472,7 @@ export {
16584
16472
  PatchFormProvider,
16585
16473
  ProjectAccessLevel,
16586
16474
  ProjectAccessService,
16475
+ ProjectAttachmentService,
16587
16476
  ProjectFileService,
16588
16477
  ProjectService,
16589
16478
  ProjectType,
@@ -16814,6 +16703,7 @@ export {
16814
16703
  removeFavouriteProjectId,
16815
16704
  removeIssue,
16816
16705
  removeIssueAttachment,
16706
+ removeIssueAttachments,
16817
16707
  removeIssueComment,
16818
16708
  removeIssueComments,
16819
16709
  removeIssueType,
@@ -16988,6 +16878,7 @@ export {
16988
16878
  selectProjectAccessForUser,
16989
16879
  selectProjectAccessUserMapping,
16990
16880
  selectProjectAccesses,
16881
+ selectProjectAttachment,
16991
16882
  selectProjectAttachmentMapping,
16992
16883
  selectProjectFileVisibility,
16993
16884
  selectProjectFiles,
@@ -17037,12 +16928,15 @@ export {
17037
16928
  setAppearance,
17038
16929
  setCategories,
17039
16930
  setCenterMapToProject,
16931
+ setComponentAttachment,
17040
16932
  setComponentAttachments,
16933
+ setComponentTypeAttachment,
17041
16934
  setComponentTypeAttachments,
17042
16935
  setComponentTypes,
17043
16936
  setComponents,
17044
16937
  setCreateProjectType,
17045
16938
  setCurrentUser,
16939
+ setDocumentAttachment,
17046
16940
  setDocumentAttachments,
17047
16941
  setDocuments,
17048
16942
  setEmailDomains,
@@ -17059,6 +16953,7 @@ export {
17059
16953
  setIsFetchingInitialData,
17060
16954
  setIsImportingProjectFile,
17061
16955
  setIsLoading,
16956
+ setIssueAttachment,
17062
16957
  setIssueAttachments,
17063
16958
  setIssueComment,
17064
16959
  setIssueComments,
@@ -17073,6 +16968,7 @@ export {
17073
16968
  setOrganizations,
17074
16969
  setProfilePicture,
17075
16970
  setProjectAccesses,
16971
+ setProjectAttachment,
17076
16972
  setProjectAttachments,
17077
16973
  setProjectFileVisible,
17078
16974
  setProjects,
@@ -17107,20 +17003,25 @@ export {
17107
17003
  updateActiveOrganization,
17108
17004
  updateComponent,
17109
17005
  updateComponentAttachment,
17006
+ updateComponentAttachments,
17110
17007
  updateComponentTypeAttachment,
17008
+ updateComponentTypeAttachments,
17111
17009
  updateDocumentAttachment,
17010
+ updateDocumentAttachments,
17112
17011
  updateDocuments,
17113
17012
  updateFormSubmission,
17114
17013
  updateFormSubmissionAttachments,
17115
17014
  updateFormSubmissions,
17116
17015
  updateIssue,
17117
17016
  updateIssueAttachment,
17017
+ updateIssueAttachments,
17118
17018
  updateIssueType,
17119
17019
  updateLicense,
17120
17020
  updateOrCreateProject,
17121
17021
  updateOrganizationAccess,
17122
17022
  updateProjectAccess,
17123
17023
  updateProjectAttachment,
17024
+ updateProjectAttachments,
17124
17025
  updateStages,
17125
17026
  updateTeam,
17126
17027
  useAppDispatch,