@overmap-ai/core 1.0.43-projects-licensing.3 → 1.0.44-tiptap.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.
@@ -632,15 +632,15 @@ const wrapMigration = (migrator) => (state) => {
632
632
  };
633
633
  const migrations = [initialVersioning, signOut, signOut, createOutboxState];
634
634
  const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
635
- const initialState$m = {
635
+ const initialState$l = {
636
636
  accessToken: "",
637
637
  refreshToken: "",
638
638
  isLoggedIn: false
639
639
  };
640
640
  const authSlice = createSlice({
641
641
  name: "auth",
642
- initialState: initialState$m,
643
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
642
+ initialState: initialState$l,
643
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
644
644
  reducers: {
645
645
  setTokens: (state, action) => {
646
646
  state.accessToken = action.payload.accessToken;
@@ -1371,7 +1371,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
1371
1371
  return getLocalDateString(date);
1372
1372
  return relative.format(days, "days");
1373
1373
  });
1374
- const initialState$l = {
1374
+ const initialState$k = {
1375
1375
  categories: {},
1376
1376
  usedCategoryColors: [],
1377
1377
  categoryVisibility: {
@@ -1381,8 +1381,8 @@ const initialState$l = {
1381
1381
  };
1382
1382
  const categorySlice = createSlice({
1383
1383
  name: "categories",
1384
- initialState: initialState$l,
1385
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1384
+ initialState: initialState$k,
1385
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1386
1386
  reducers: {
1387
1387
  setCategories: (state, action) => {
1388
1388
  if (!Array.isArray(action.payload))
@@ -1515,13 +1515,49 @@ const selectHiddenCategoryCount = (state) => {
1515
1515
  return hiddenCategoryCount;
1516
1516
  };
1517
1517
  const categoryReducer = categorySlice.reducer;
1518
- const initialState$k = {
1519
- components: {}
1518
+ function setAttachments(state, action) {
1519
+ for (const attachment of action.payload) {
1520
+ state.attachments[attachment.offline_id] = attachment;
1521
+ }
1522
+ }
1523
+ function addAttachment(state, action) {
1524
+ if (action.payload.offline_id in state.attachments) {
1525
+ throw new Error(`Attachment ${action.payload.offline_id} already exists.`);
1526
+ }
1527
+ state.attachments[action.payload.offline_id] = action.payload;
1528
+ }
1529
+ function addAttachments(state, action) {
1530
+ for (const attachment of action.payload) {
1531
+ state.attachments[attachment.offline_id] = attachment;
1532
+ }
1533
+ }
1534
+ function updateAttachment(state, action) {
1535
+ if (action.payload.offline_id in state.attachments) {
1536
+ state.attachments[action.payload.offline_id] = action.payload;
1537
+ } else {
1538
+ throw new Error(`Attachment ${action.payload.offline_id} does not exist.`);
1539
+ }
1540
+ }
1541
+ function removeAttachment(state, action) {
1542
+ if (action.payload in state.attachments) {
1543
+ delete state.attachments[action.payload];
1544
+ } else {
1545
+ throw new Error(`Attachment ${action.payload} does not exist.`);
1546
+ }
1547
+ }
1548
+ function removeAttachments(state, action) {
1549
+ for (const attachmentId of action.payload) {
1550
+ delete state.attachments[attachmentId];
1551
+ }
1552
+ }
1553
+ const initialState$j = {
1554
+ components: {},
1555
+ attachments: {}
1520
1556
  };
1521
1557
  const componentSlice = createSlice({
1522
1558
  name: "components",
1523
- initialState: initialState$k,
1524
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1559
+ initialState: initialState$j,
1560
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1525
1561
  reducers: {
1526
1562
  addComponent: (state, action) => {
1527
1563
  state.components[action.payload.offline_id] = action.payload;
@@ -1535,6 +1571,12 @@ const componentSlice = createSlice({
1535
1571
  state.components = toOfflineIdRecord(action.payload);
1536
1572
  prevComponents = null;
1537
1573
  },
1574
+ setComponentAttachments: setAttachments,
1575
+ addComponentAttachment: addAttachment,
1576
+ addComponentAttachments: addAttachments,
1577
+ updateComponentAttachment: updateAttachment,
1578
+ removeComponentAttachment: removeAttachment,
1579
+ removeComponentAttachments: removeAttachments,
1538
1580
  updateComponent: (state, action) => {
1539
1581
  if (action.payload.offline_id in state.components) {
1540
1582
  state.components[action.payload.offline_id] = action.payload;
@@ -1624,22 +1666,41 @@ const selectComponentTypesFromIds = (componentTypeIds) => (state) => {
1624
1666
  return acc;
1625
1667
  }, []);
1626
1668
  };
1669
+ const selectComponentAttachmentMapping = (state) => state.componentReducer.attachments;
1670
+ const selectAllComponentAttachments = createSelector(
1671
+ [selectComponentAttachmentMapping],
1672
+ (mapping) => Object.values(mapping)
1673
+ );
1674
+ const selectAttachmentsOfComponent = restructureCreateSelectorWithArgs(
1675
+ createSelector(
1676
+ [selectAllComponentAttachments, (_state, componentId) => componentId],
1677
+ (attachments, componentId) => {
1678
+ return attachments.filter(({ component_id }) => componentId === component_id);
1679
+ }
1680
+ )
1681
+ );
1627
1682
  const {
1628
1683
  addComponent,
1629
1684
  updateComponent,
1630
1685
  removeComponent,
1631
1686
  addComponentsInBatches,
1632
1687
  setComponents,
1688
+ setComponentAttachments,
1689
+ addComponentAttachment,
1690
+ addComponentAttachments,
1691
+ updateComponentAttachment,
1692
+ removeComponentAttachment,
1693
+ removeComponentAttachments,
1633
1694
  removeAllComponentsOfType
1634
1695
  } = componentSlice.actions;
1635
1696
  const componentReducer = componentSlice.reducer;
1636
- const initialState$j = {
1697
+ const initialState$i = {
1637
1698
  completionsByComponentId: {}
1638
1699
  };
1639
1700
  const componentStageCompletionSlice = createSlice({
1640
1701
  name: "componentStageCompletions",
1641
- initialState: initialState$j,
1642
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1702
+ initialState: initialState$i,
1703
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1643
1704
  reducers: {
1644
1705
  addStageCompletion: (state, action) => {
1645
1706
  let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
@@ -1690,13 +1751,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
1690
1751
  return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
1691
1752
  };
1692
1753
  const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
1693
- const initialState$i = {
1754
+ const initialState$h = {
1694
1755
  stages: {}
1695
1756
  };
1696
1757
  const componentStageSlice = createSlice({
1697
1758
  name: "componentStages",
1698
- initialState: initialState$i,
1699
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1759
+ initialState: initialState$h,
1760
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
1700
1761
  reducers: {
1701
1762
  addStages: (state, action) => {
1702
1763
  Object.assign(state.stages, toOfflineIdRecord(action.payload));
@@ -1787,14 +1848,15 @@ const selectStageFormIdsFromStageIds = restructureCreateSelectorWithArgs(
1787
1848
  );
1788
1849
  const { addStages, updateStages, removeStages, linkStageToForm, unlinkStageToForm } = componentStageSlice.actions;
1789
1850
  const componentStageReducer = componentStageSlice.reducer;
1790
- const initialState$h = {
1851
+ const initialState$g = {
1791
1852
  componentTypes: {},
1792
- hiddenComponentTypeIds: {}
1853
+ hiddenComponentTypeIds: {},
1854
+ attachments: {}
1793
1855
  };
1794
1856
  const componentTypeSlice = createSlice({
1795
1857
  name: "componentTypes",
1796
- initialState: initialState$h,
1797
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
1858
+ initialState: initialState$g,
1859
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
1798
1860
  reducers: {
1799
1861
  addComponentType: (state, action) => {
1800
1862
  state.componentTypes[action.payload.offline_id] = action.payload;
@@ -1802,6 +1864,12 @@ const componentTypeSlice = createSlice({
1802
1864
  setComponentTypes: (state, action) => {
1803
1865
  state.componentTypes = toOfflineIdRecord(action.payload);
1804
1866
  },
1867
+ setComponentTypeAttachments: setAttachments,
1868
+ addComponentTypeAttachment: addAttachment,
1869
+ addComponentTypeAttachments: addAttachments,
1870
+ updateComponentTypeAttachment: updateAttachment,
1871
+ removeComponentTypeAttachment: removeAttachment,
1872
+ removeComponentTypeAttachments: removeAttachments,
1805
1873
  toggleComponentTypeVisibility: (state, action) => {
1806
1874
  state.hiddenComponentTypeIds[action.payload] = !state.hiddenComponentTypeIds[action.payload];
1807
1875
  },
@@ -1851,15 +1919,39 @@ const selectComponentTypesByName = restructureCreateSelectorWithArgs(
1851
1919
  )
1852
1920
  );
1853
1921
  const selectHiddenComponentTypeIds = (state) => state.componentTypeReducer.hiddenComponentTypeIds;
1854
- const { addComponentType, setComponentTypes, toggleComponentTypeVisibility, deleteComponentType } = componentTypeSlice.actions;
1922
+ const selectComponentTypeAttachmentMapping = (state) => state.componentTypeReducer.attachments;
1923
+ const selectAllComponentTypeAttachments = createSelector(
1924
+ [selectComponentTypeAttachmentMapping],
1925
+ (mapping) => Object.values(mapping)
1926
+ );
1927
+ const selectAttachmentsOfComponentType = restructureCreateSelectorWithArgs(
1928
+ createSelector(
1929
+ [selectAllComponentTypeAttachments, (_state, componentTypeId) => componentTypeId],
1930
+ (attachments, componentTypeId) => {
1931
+ return attachments.filter(({ component_type_id }) => componentTypeId === component_type_id);
1932
+ }
1933
+ )
1934
+ );
1935
+ const {
1936
+ addComponentType,
1937
+ setComponentTypes,
1938
+ setComponentTypeAttachments,
1939
+ addComponentTypeAttachment,
1940
+ addComponentTypeAttachments,
1941
+ updateComponentTypeAttachment,
1942
+ removeComponentTypeAttachment,
1943
+ removeComponentTypeAttachments,
1944
+ toggleComponentTypeVisibility,
1945
+ deleteComponentType
1946
+ } = componentTypeSlice.actions;
1855
1947
  const componentTypeReducer = componentTypeSlice.reducer;
1856
- const initialState$g = {
1948
+ const initialState$f = {
1857
1949
  workspaces: {},
1858
1950
  activeWorkspaceId: null
1859
1951
  };
1860
1952
  const workspaceSlice = createSlice({
1861
1953
  name: "workspace",
1862
- initialState: initialState$g,
1954
+ initialState: initialState$f,
1863
1955
  // The `reducers` field lets us define reducers and generate associated actions
1864
1956
  reducers: {
1865
1957
  setWorkspaces: (state, action) => {
@@ -1916,20 +2008,21 @@ const selectPermittedWorkspaceIds = createSelector(
1916
2008
  );
1917
2009
  const workspaceReducer = workspaceSlice.reducer;
1918
2010
  const maxRecentIssues = 10;
1919
- const initialState$f = {
2011
+ const initialState$e = {
1920
2012
  issues: {},
1921
2013
  attachments: {},
1922
2014
  comments: {},
1923
2015
  visibleStatuses: [IssueStatus.BACKLOG, IssueStatus.SELECTED],
2016
+ isFetchingInitialData: false,
1924
2017
  visibleUserIds: null,
1925
2018
  recentIssueIds: [],
1926
2019
  activeIssueId: null
1927
2020
  };
1928
2021
  const issueSlice = createSlice({
1929
2022
  name: "issues",
1930
- initialState: initialState$f,
2023
+ initialState: initialState$e,
1931
2024
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
1932
- Object.assign(state, initialState$f);
2025
+ Object.assign(state, initialState$e);
1933
2026
  }),
1934
2027
  reducers: {
1935
2028
  setIssues: (state, action) => {
@@ -1941,11 +2034,7 @@ const issueSlice = createSlice({
1941
2034
  });
1942
2035
  },
1943
2036
  // TODO: Reusable function
1944
- setAttachments: (state, action) => {
1945
- for (const attachment of action.payload) {
1946
- state.attachments[attachment.offline_id] = attachment;
1947
- }
1948
- },
2037
+ setIssueAttachments: setAttachments,
1949
2038
  setActiveIssueId: (state, action) => {
1950
2039
  state.activeIssueId = action.payload;
1951
2040
  },
@@ -1956,17 +2045,8 @@ const issueSlice = createSlice({
1956
2045
  state.issues[action.payload.offline_id] = action.payload;
1957
2046
  },
1958
2047
  // TODO: Reusable function
1959
- addAttachment: (state, action) => {
1960
- if (action.payload.offline_id in state.attachments) {
1961
- throw new Error(`Attachment ${action.payload.offline_id} already exists.`);
1962
- }
1963
- state.attachments[action.payload.offline_id] = action.payload;
1964
- },
1965
- addAttachments: (state, action) => {
1966
- for (const attachment of action.payload) {
1967
- state.attachments[attachment.offline_id] = attachment;
1968
- }
1969
- },
2048
+ addIssueAttachment: addAttachment,
2049
+ addIssueAttachments: addAttachments,
1970
2050
  updateIssue: (state, action) => {
1971
2051
  if (action.payload.offline_id in state.issues) {
1972
2052
  state.issues[action.payload.offline_id] = {
@@ -1978,13 +2058,7 @@ const issueSlice = createSlice({
1978
2058
  }
1979
2059
  },
1980
2060
  // TODO: Reusable function
1981
- updateAttachment: (state, action) => {
1982
- if (action.payload.offline_id in state.attachments) {
1983
- state.attachments[action.payload.offline_id] = action.payload;
1984
- } else {
1985
- throw new Error(`Attachment ${action.payload.offline_id} does not exist.`);
1986
- }
1987
- },
2061
+ updateIssueAttachment: updateAttachment,
1988
2062
  removeIssue: (state, action) => {
1989
2063
  if (action.payload in state.issues) {
1990
2064
  delete state.issues[action.payload];
@@ -1992,13 +2066,7 @@ const issueSlice = createSlice({
1992
2066
  throw new Error(`Failed to remove issue because ID doesn't exist: ${action.payload}`);
1993
2067
  }
1994
2068
  },
1995
- removeAttachment: (state, action) => {
1996
- if (action.payload in state.attachments) {
1997
- delete state.attachments[action.payload];
1998
- } else {
1999
- throw new Error(`Attachment ${action.payload} does not exist.`);
2000
- }
2001
- },
2069
+ removeIssueAttachment: removeAttachment,
2002
2070
  removeAttachmentsOfIssue: (state, action) => {
2003
2071
  const attachments = Object.values(state.attachments).filter((a) => a.issue_id === action.payload);
2004
2072
  for (const attachment of attachments) {
@@ -2008,6 +2076,9 @@ const issueSlice = createSlice({
2008
2076
  setVisibleStatuses: (state, action) => {
2009
2077
  state.visibleStatuses = action.payload;
2010
2078
  },
2079
+ setIsFetchingInitialData: (state, action) => {
2080
+ state.isFetchingInitialData = action.payload;
2081
+ },
2011
2082
  setVisibleUserIds: (state, action) => {
2012
2083
  state.visibleUserIds = [...new Set(action.payload)];
2013
2084
  },
@@ -2052,25 +2123,26 @@ const issueSlice = createSlice({
2052
2123
  }
2053
2124
  });
2054
2125
  const {
2055
- addAttachment,
2056
- addAttachments,
2126
+ addIssueAttachment,
2127
+ addIssueAttachments,
2057
2128
  addIssue,
2058
2129
  addOrReplaceIssueComment,
2059
2130
  addToRecentIssues,
2060
2131
  cleanRecentIssues,
2061
- removeAttachment,
2132
+ removeIssueAttachment,
2062
2133
  removeAttachmentsOfIssue,
2063
2134
  removeIssue,
2064
2135
  removeIssueComment,
2065
2136
  removeRecentIssue,
2066
2137
  resetRecentIssues,
2067
2138
  setActiveIssueId,
2068
- setAttachments,
2139
+ setIssueAttachments,
2140
+ setIsFetchingInitialData,
2069
2141
  setIssueComments,
2070
2142
  setIssues,
2071
2143
  setVisibleStatuses,
2072
2144
  setVisibleUserIds,
2073
- updateAttachment,
2145
+ updateIssueAttachment,
2074
2146
  updateIssue
2075
2147
  } = issueSlice.actions;
2076
2148
  const selectIssueMapping = (state) => state.issueReducer.issues;
@@ -2130,8 +2202,6 @@ const selectPhotoAttachmentsOfIssue = restructureCreateSelectorWithArgs(
2130
2202
  createSelector(
2131
2203
  [selectIssueAttachmentMapping, (_state, issueId) => issueId],
2132
2204
  (attachmentMapping, issueId) => {
2133
- if (!issueId)
2134
- return void 0;
2135
2205
  return Object.values(attachmentMapping).filter(
2136
2206
  (attachment) => attachment.issue_id === issueId && attachment.file_type && attachment.file_type.startsWith("image/")
2137
2207
  );
@@ -2164,6 +2234,7 @@ const selectIssue = restructureCreateSelectorWithArgs(
2164
2234
  return mapping[id];
2165
2235
  })
2166
2236
  );
2237
+ const selectIsFetchingInitialData = (state) => state.issueReducer.isFetchingInitialData;
2167
2238
  const selectAllAttachments = createSelector([selectIssueAttachmentMapping], (mapping) => Object.values(mapping));
2168
2239
  const searchIssues = restructureCreateSelectorWithArgs(
2169
2240
  createSelector(
@@ -2255,15 +2326,15 @@ const selectRecentIssuesAsSearchResults = createSelector(
2255
2326
  }
2256
2327
  );
2257
2328
  const issueReducer = issueSlice.reducer;
2258
- const initialState$e = {
2329
+ const initialState$d = {
2259
2330
  s3Urls: {}
2260
2331
  };
2261
2332
  const msPerHour = 1e3 * 60 * 60;
2262
2333
  const msPerWeek = msPerHour * 24 * 7;
2263
2334
  const fileSlice = createSlice({
2264
2335
  name: "file",
2265
- initialState: initialState$e,
2266
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2336
+ initialState: initialState$d,
2337
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2267
2338
  reducers: {
2268
2339
  setUploadUrl: (state, action) => {
2269
2340
  const { url, fields, sha1 } = action.payload;
@@ -2290,7 +2361,7 @@ const selectUploadUrl = (sha1) => (state) => {
2290
2361
  return url;
2291
2362
  };
2292
2363
  const fileReducer = fileSlice.reducer;
2293
- const initialState$d = {
2364
+ const initialState$c = {
2294
2365
  // TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
2295
2366
  mapStyle: MapStyle.SATELLITE,
2296
2367
  showTooltips: false,
@@ -2298,8 +2369,8 @@ const initialState$d = {
2298
2369
  };
2299
2370
  const mapSlice = createSlice({
2300
2371
  name: "map",
2301
- initialState: initialState$d,
2302
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2372
+ initialState: initialState$c,
2373
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2303
2374
  reducers: {
2304
2375
  setMapStyle: (state, action) => {
2305
2376
  state.mapStyle = action.payload;
@@ -2341,24 +2412,7 @@ var VerificationCodeType = /* @__PURE__ */ ((VerificationCodeType2) => {
2341
2412
  VerificationCodeType2[VerificationCodeType2["RESET_PASSWORD"] = 10] = "RESET_PASSWORD";
2342
2413
  return VerificationCodeType2;
2343
2414
  })(VerificationCodeType || {});
2344
- var PaddleCheckoutEvent = /* @__PURE__ */ ((PaddleCheckoutEvent2) => {
2345
- PaddleCheckoutEvent2["COMPLETED"] = "checkout.completed";
2346
- PaddleCheckoutEvent2["CLOSED"] = "checkout.closed";
2347
- return PaddleCheckoutEvent2;
2348
- })(PaddleCheckoutEvent || {});
2349
- var LicenseLevel = /* @__PURE__ */ ((LicenseLevel2) => {
2350
- LicenseLevel2[LicenseLevel2["PRO"] = 0] = "PRO";
2351
- return LicenseLevel2;
2352
- })(LicenseLevel || {});
2353
- var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
2354
- LicenseStatus2[LicenseStatus2["ACTIVE"] = 0] = "ACTIVE";
2355
- LicenseStatus2[LicenseStatus2["PAUSED"] = 2] = "PAUSED";
2356
- LicenseStatus2[LicenseStatus2["CANCELLED"] = 4] = "CANCELLED";
2357
- LicenseStatus2[LicenseStatus2["INACTIVE"] = 6] = "INACTIVE";
2358
- LicenseStatus2[LicenseStatus2["PAST_DUE"] = 8] = "PAST_DUE";
2359
- return LicenseStatus2;
2360
- })(LicenseStatus || {});
2361
- const initialState$c = {
2415
+ const initialState$b = {
2362
2416
  users: {},
2363
2417
  currentUser: {
2364
2418
  id: 0,
@@ -2369,8 +2423,8 @@ const initialState$c = {
2369
2423
  };
2370
2424
  const userSlice = createSlice({
2371
2425
  name: "users",
2372
- initialState: initialState$c,
2373
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2426
+ initialState: initialState$b,
2427
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2374
2428
  reducers: {
2375
2429
  setUsers: (state, action) => {
2376
2430
  const usersMapping = {};
@@ -2432,13 +2486,13 @@ const selectUser = (userId) => (state) => {
2432
2486
  const selectUsersAsMapping = (state) => state.userReducer.users;
2433
2487
  const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
2434
2488
  const userReducer = userSlice.reducer;
2435
- const initialState$b = {
2489
+ const initialState$a = {
2436
2490
  organizationAccesses: {}
2437
2491
  };
2438
2492
  const organizationAccessSlice = createSlice({
2439
2493
  name: "organizationAccess",
2440
- initialState: initialState$b,
2441
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2494
+ initialState: initialState$a,
2495
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2442
2496
  reducers: {
2443
2497
  setOrganizationAccesses: (state, action) => {
2444
2498
  if (!Array.isArray(action.payload))
@@ -2501,64 +2555,151 @@ const selectOrganizationAccessUserMapping = (state) => {
2501
2555
  return organizationAccesses;
2502
2556
  };
2503
2557
  const organizationAccessReducer = organizationAccessSlice.reducer;
2504
- const initialState$a = {
2505
- licenses: {}
2558
+ const initialState$9 = {
2559
+ organizations: {},
2560
+ activeOrganizationId: null
2506
2561
  };
2507
- const licenseSlice = createSlice({
2508
- name: "license",
2509
- initialState: initialState$a,
2510
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2562
+ const organizationSlice = createSlice({
2563
+ name: "organizations",
2564
+ initialState: initialState$9,
2565
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
2511
2566
  reducers: {
2512
- setLicenses: (state, action) => {
2513
- if (!Array.isArray(action.payload))
2514
- throw new Error("Expected an array of Licenses");
2515
- if (action.payload.filter(onlyUniqueOfflineIds).length !== action.payload.length) {
2516
- throw new Error("Tried to use setLicenses reducer with duplicate ID's");
2517
- }
2518
- const licenses = {};
2519
- for (const license of action.payload) {
2520
- licenses[license.offline_id] = license;
2567
+ setOrganizations: (state, action) => {
2568
+ for (const org of action.payload) {
2569
+ state.organizations[org.id] = org;
2521
2570
  }
2522
- state.licenses = licenses;
2523
2571
  },
2524
- addLicenses: (state, action) => {
2525
- for (const license of action.payload) {
2526
- state.licenses[license.offline_id] = license;
2572
+ updateActiveOrganization: (state, action) => {
2573
+ if (!state.activeOrganizationId) {
2574
+ throw new Error("Cannot update name of active organization. Active organization ID does not exist");
2527
2575
  }
2528
- },
2529
- updateLicense: (state, action) => {
2530
- if (!(action.payload.offline_id in state.licenses)) {
2531
- throw new Error("Tried to update license that does not exist.");
2576
+ if (state.activeOrganizationId !== action.payload.id) {
2577
+ throw new Error("Tried updating active organization with different organization");
2532
2578
  }
2533
- state.licenses[action.payload.offline_id] = action.payload;
2579
+ state.organizations[state.activeOrganizationId] = action.payload;
2580
+ },
2581
+ setActiveOrganizationId: (state, action) => {
2582
+ state.activeOrganizationId = action.payload;
2534
2583
  }
2535
2584
  }
2536
2585
  });
2537
- const { setLicenses, addLicenses, updateLicense } = licenseSlice.actions;
2538
- const selectLicenses = (state) => {
2539
- return state.licenseReducer.licenses;
2586
+ const { setOrganizations, setActiveOrganizationId, updateActiveOrganization } = organizationSlice.actions;
2587
+ const selectActiveOrganizationId = (state) => {
2588
+ return state.organizationReducer.activeOrganizationId;
2589
+ };
2590
+ const selectOrganizations = (state) => {
2591
+ return Object.values(state.organizationReducer.organizations);
2540
2592
  };
2541
- const selectLicense = (licenseId) => (state) => state.licenseReducer.licenses[licenseId];
2542
- const selectActiveLicense = (state) => Object.values(state.licenseReducer.licenses).find(
2543
- (license) => license.project === state.projectReducer.activeProjectId
2544
- ) ?? null;
2545
- const selectLicenseForProject = (projectId) => (state) => Object.values(state.licenseReducer.licenses).find((license) => license.project === projectId);
2546
- const selectActiveStatusLicenses = createSelector(
2547
- [selectLicenses],
2548
- (licenses) => Object.values(licenses).filter((license) => license.is_active)
2593
+ const selectOrganizationsWithAccess = createSelector(
2594
+ [selectOrganizations],
2595
+ (organizations) => Object.values(organizations).filter((organization) => organization.has_access)
2549
2596
  );
2550
- const selectLicensesForProjectsMapping = createSelector(
2551
- [selectLicenses],
2552
- (licenses) => Object.values(licenses).filter((license) => license.project).reduce((accum, license) => ({ ...accum, [license.project]: license }), {})
2597
+ const selectActiveOrganization = (state) => {
2598
+ const id = selectActiveOrganizationId(state);
2599
+ if (!id) {
2600
+ return null;
2601
+ }
2602
+ const organization = state.organizationReducer.organizations[id];
2603
+ if (!organization) {
2604
+ return null;
2605
+ }
2606
+ return organization;
2607
+ };
2608
+ const selectOrganizationUsersIds = createSelector(
2609
+ [selectOrganizationAccesses],
2610
+ (organizationAccesses) => Object.values(organizationAccesses).map((organizationAccess) => organizationAccess.user)
2553
2611
  );
2554
- const licenseReducer = licenseSlice.reducer;
2555
- const initialState$9 = {
2612
+ const selectOrganizationUsersAsMapping = createSelector(
2613
+ [selectOrganizationUsersIds, selectUsersAsMapping],
2614
+ (organizationUserIds, users) => organizationUserIds.reduce((accum, userId) => ({ ...accum, [userId]: users[userId] }), {})
2615
+ );
2616
+ const selectSortedOrganizationUsers = createSelector(
2617
+ [selectCurrentUser, selectOrganizationUsersAsMapping, selectOrganizationAccessUserMapping],
2618
+ (currentUser, userMapping, organizationAccessMapping) => {
2619
+ return Object.values(userMapping).sort((userA, userB) => {
2620
+ if (userA.id === currentUser.id) {
2621
+ return -1;
2622
+ } else if (userB.id === currentUser.id) {
2623
+ return 1;
2624
+ }
2625
+ const organizationAccessesA = organizationAccessMapping[userA.id];
2626
+ const organizationAccessesB = organizationAccessMapping[userB.id];
2627
+ if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === (organizationAccessesB == null ? void 0 : organizationAccessesB.access_level)) {
2628
+ return userA.username.localeCompare(userB.username);
2629
+ }
2630
+ if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === OrganizationAccessLevel.ADMIN) {
2631
+ return -1;
2632
+ }
2633
+ return 1;
2634
+ });
2635
+ }
2636
+ );
2637
+ const selectOrganization = (id) => (state) => {
2638
+ return state.organizationReducer.organizations[id];
2639
+ };
2640
+ const organizationReducer = organizationSlice.reducer;
2641
+ const createOfflineAction = (request2, baseUrl) => {
2642
+ const requestWithUuid = request2.uuid ? request2 : { ...request2, uuid: v4() };
2643
+ return {
2644
+ payload: requestWithUuid,
2645
+ type: "",
2646
+ meta: {
2647
+ offline: {
2648
+ effect: {
2649
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2650
+ request: requestWithUuid,
2651
+ BASE_URL: baseUrl
2652
+ }
2653
+ }
2654
+ }
2655
+ };
2656
+ };
2657
+ const initialState$8 = {
2658
+ deletedRequests: [],
2659
+ latestRetryTime: 0
2660
+ };
2661
+ const outboxSlice = createSlice({
2662
+ name: "outbox",
2663
+ initialState: initialState$8,
2664
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
2665
+ reducers: {
2666
+ // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
2667
+ // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
2668
+ // Then this reducer enqueueRequest() is responsible for adding the actual request data to the outbox
2669
+ enqueueRequest: {
2670
+ reducer: (state, _action) => {
2671
+ return state;
2672
+ },
2673
+ prepare: (payload) => {
2674
+ console.debug("Preparing to enqueue request", payload);
2675
+ const { BASE_URL, ...rest } = payload;
2676
+ return createOfflineAction(rest, BASE_URL);
2677
+ }
2678
+ },
2679
+ markForDeletion(state, action) {
2680
+ state.deletedRequests.push(action.payload);
2681
+ },
2682
+ markAsDeleted(state, action) {
2683
+ const index2 = state.deletedRequests.indexOf(action.payload);
2684
+ if (index2 !== -1)
2685
+ state.deletedRequests.splice(index2, 1);
2686
+ },
2687
+ _setLatestRetryTime: (state, action) => {
2688
+ state.latestRetryTime = action.payload;
2689
+ }
2690
+ }
2691
+ });
2692
+ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
2693
+ const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
2694
+ const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
2695
+ const outboxReducer = outboxSlice.reducer;
2696
+ const initialState$7 = {
2556
2697
  projectAccesses: {}
2557
2698
  };
2558
2699
  const projectAccessSlice = createSlice({
2559
2700
  name: "projectAccess",
2560
- initialState: initialState$9,
2561
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
2701
+ initialState: initialState$7,
2702
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
2562
2703
  reducers: {
2563
2704
  setProjectAccesses: (state, action) => {
2564
2705
  if (!Array.isArray(action.payload))
@@ -2626,7 +2767,7 @@ const selectProjectAccessUserMapping = (state) => {
2626
2767
  return projectAccesses;
2627
2768
  };
2628
2769
  const projectAccessReducer = projectAccessSlice.reducer;
2629
- const initialState$8 = {
2770
+ const initialState$6 = {
2630
2771
  projects: {},
2631
2772
  activeProjectId: null,
2632
2773
  recentProjectIds: [],
@@ -2635,7 +2776,7 @@ const initialState$8 = {
2635
2776
  };
2636
2777
  const projectSlice = createSlice({
2637
2778
  name: "projects",
2638
- initialState: initialState$8,
2779
+ initialState: initialState$6,
2639
2780
  reducers: {
2640
2781
  setProjects: (state, action) => {
2641
2782
  const projectsMap = {};
@@ -2681,27 +2822,6 @@ const projectSlice = createSlice({
2681
2822
  } else {
2682
2823
  throw new Error("Accept project invite: user is not in this project");
2683
2824
  }
2684
- },
2685
- addActiveProjectIssuesCount: (state, action) => {
2686
- if (!state.activeProjectId || !(state.activeProjectId in state.projects)) {
2687
- throw new Error("Update issues count: no active project");
2688
- }
2689
- if (!state.projects[state.activeProjectId].issues_count) {
2690
- state.projects[state.activeProjectId].issues_count = action.payload;
2691
- } else {
2692
- state.projects[state.activeProjectId].issues_count += action.payload;
2693
- }
2694
- },
2695
- addActiveProjectFormSubmissionsCount: (state, action) => {
2696
- if (state.activeProjectId && state.activeProjectId in state.projects) {
2697
- if (!state.projects[state.activeProjectId].form_submissions_count) {
2698
- state.projects[state.activeProjectId].form_submissions_count = action.payload;
2699
- } else {
2700
- state.projects[state.activeProjectId].form_submissions_count += action.payload;
2701
- }
2702
- } else {
2703
- throw new Error("Update form submissions count: no active project");
2704
- }
2705
2825
  }
2706
2826
  }
2707
2827
  });
@@ -2712,9 +2832,7 @@ const {
2712
2832
  setActiveProjectId,
2713
2833
  setCreateProjectType,
2714
2834
  deleteProject,
2715
- acceptProjectInvite,
2716
- addActiveProjectIssuesCount,
2717
- addActiveProjectFormSubmissionsCount
2835
+ acceptProjectInvite
2718
2836
  } = projectSlice.actions;
2719
2837
  const selectProjects = (state) => state.projectReducer.projects;
2720
2838
  const selectActiveProjectId = (state) => state.projectReducer.activeProjectId;
@@ -2778,171 +2896,6 @@ const selectSortedProjectUsers = createSelector(
2778
2896
  });
2779
2897
  }
2780
2898
  );
2781
- const initialState$7 = {
2782
- organizations: {},
2783
- activeOrganizationId: null
2784
- };
2785
- const organizationSlice = createSlice({
2786
- name: "organizations",
2787
- initialState: initialState$7,
2788
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
2789
- reducers: {
2790
- setOrganizations: (state, action) => {
2791
- for (const org of action.payload) {
2792
- state.organizations[org.id] = org;
2793
- }
2794
- },
2795
- updateActiveOrganization: (state, action) => {
2796
- if (!state.activeOrganizationId) {
2797
- throw new Error("Cannot update name of active organization. Active organization ID does not exist");
2798
- }
2799
- if (state.activeOrganizationId !== action.payload.id) {
2800
- throw new Error("Tried updating active organization with different organization");
2801
- }
2802
- state.organizations[state.activeOrganizationId] = action.payload;
2803
- },
2804
- setActiveOrganizationId: (state, action) => {
2805
- state.activeOrganizationId = action.payload;
2806
- }
2807
- }
2808
- });
2809
- const { setOrganizations, setActiveOrganizationId, updateActiveOrganization } = organizationSlice.actions;
2810
- const selectActiveOrganizationId = (state) => {
2811
- return state.organizationReducer.activeOrganizationId;
2812
- };
2813
- const selectOrganizations = (state) => {
2814
- return Object.values(state.organizationReducer.organizations);
2815
- };
2816
- const selectOrganizationsMapping = (state) => {
2817
- return state.organizationReducer.organizations;
2818
- };
2819
- const selectOrganizationsWithAccess = createSelector(
2820
- [selectOrganizations],
2821
- (organizations) => Object.values(organizations).filter((organization) => organization.has_access)
2822
- );
2823
- const selectActiveOrganization = (state) => {
2824
- const id = selectActiveOrganizationId(state);
2825
- if (!id) {
2826
- return null;
2827
- }
2828
- const organization = state.organizationReducer.organizations[id];
2829
- if (!organization) {
2830
- return null;
2831
- }
2832
- return organization;
2833
- };
2834
- const selectOrganizationUsersIds = createSelector(
2835
- [selectOrganizationAccesses],
2836
- (organizationAccesses) => Object.values(organizationAccesses).map((organizationAccess) => organizationAccess.user)
2837
- );
2838
- const selectActiveOrganizationProjects = createSelector(
2839
- [selectProjects, selectActiveOrganizationId],
2840
- (projects, activeOrganizationId) => activeOrganizationId ? Object.values(projects).filter((project) => project.owner_organization === activeOrganizationId) : []
2841
- );
2842
- const selectActiveOrganizationLicenses = createSelector(
2843
- [selectActiveOrganizationId, selectLicenses],
2844
- (activeOrganizationId, licenses) => !activeOrganizationId ? [] : Object.values(licenses).filter((license) => license.organization_owner === activeOrganizationId)
2845
- );
2846
- const selectSortedOrganizationLicenses = createSelector(
2847
- [selectActiveOrganizationLicenses, selectProjects],
2848
- (licences, projects) => licences.sort((licenseA, licenseB) => {
2849
- if (!licenseA.project) {
2850
- return 1;
2851
- }
2852
- if (!licenseB.project) {
2853
- return -1;
2854
- }
2855
- return projects[licenseA.project].name.toLowerCase().localeCompare(
2856
- projects[licenseB.project].name.toLowerCase(),
2857
- void 0,
2858
- { numeric: true }
2859
- );
2860
- })
2861
- );
2862
- const selectOrganizationUsersAsMapping = createSelector(
2863
- [selectOrganizationUsersIds, selectUsersAsMapping],
2864
- (organizationUserIds, users) => organizationUserIds.reduce((accum, userId) => ({ ...accum, [userId]: users[userId] }), {})
2865
- );
2866
- const selectSortedOrganizationUsers = createSelector(
2867
- [selectCurrentUser, selectOrganizationUsersAsMapping, selectOrganizationAccessUserMapping],
2868
- (currentUser, userMapping, organizationAccessMapping) => {
2869
- return Object.values(userMapping).sort((userA, userB) => {
2870
- if (userA.id === currentUser.id) {
2871
- return -1;
2872
- } else if (userB.id === currentUser.id) {
2873
- return 1;
2874
- }
2875
- const organizationAccessesA = organizationAccessMapping[userA.id];
2876
- const organizationAccessesB = organizationAccessMapping[userB.id];
2877
- if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === (organizationAccessesB == null ? void 0 : organizationAccessesB.access_level)) {
2878
- return userA.username.localeCompare(userB.username);
2879
- }
2880
- if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === OrganizationAccessLevel.ADMIN) {
2881
- return -1;
2882
- }
2883
- return 1;
2884
- });
2885
- }
2886
- );
2887
- const selectOrganization = (id) => (state) => {
2888
- return state.organizationReducer.organizations[id];
2889
- };
2890
- const organizationReducer = organizationSlice.reducer;
2891
- const createOfflineAction = (request2, baseUrl) => {
2892
- const requestWithUuid = request2.uuid ? request2 : { ...request2, uuid: v4() };
2893
- return {
2894
- payload: requestWithUuid,
2895
- type: "",
2896
- meta: {
2897
- offline: {
2898
- effect: {
2899
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2900
- request: requestWithUuid,
2901
- BASE_URL: baseUrl
2902
- }
2903
- }
2904
- }
2905
- };
2906
- };
2907
- const initialState$6 = {
2908
- deletedRequests: [],
2909
- latestRetryTime: 0
2910
- };
2911
- const outboxSlice = createSlice({
2912
- name: "outbox",
2913
- initialState: initialState$6,
2914
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
2915
- reducers: {
2916
- // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
2917
- // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
2918
- // Then this reducer enqueueRequest() is responsible for adding the actual request data to the outbox
2919
- enqueueRequest: {
2920
- reducer: (state, _action) => {
2921
- return state;
2922
- },
2923
- prepare: (payload) => {
2924
- console.debug("Preparing to enqueue request", payload);
2925
- const { BASE_URL, ...rest } = payload;
2926
- return createOfflineAction(rest, BASE_URL);
2927
- }
2928
- },
2929
- markForDeletion(state, action) {
2930
- state.deletedRequests.push(action.payload);
2931
- },
2932
- markAsDeleted(state, action) {
2933
- const index2 = state.deletedRequests.indexOf(action.payload);
2934
- if (index2 !== -1)
2935
- state.deletedRequests.splice(index2, 1);
2936
- },
2937
- _setLatestRetryTime: (state, action) => {
2938
- state.latestRetryTime = action.payload;
2939
- }
2940
- }
2941
- });
2942
- const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
2943
- const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
2944
- const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
2945
- const outboxReducer = outboxSlice.reducer;
2946
2899
  const initialState$5 = {
2947
2900
  projectFiles: {},
2948
2901
  activeProjectFileId: null,
@@ -3079,9 +3032,7 @@ const initialState$3 = {
3079
3032
  Components: false,
3080
3033
  Experimental: false
3081
3034
  },
3082
- appearance: "dark",
3083
- isFetchingInitialData: false,
3084
- isLoading: false
3035
+ appearance: "dark"
3085
3036
  };
3086
3037
  const settingSlice = createSlice({
3087
3038
  name: "settings",
@@ -3105,12 +3056,6 @@ const settingSlice = createSlice({
3105
3056
  },
3106
3057
  setAppearance: (state, action) => {
3107
3058
  state.appearance = action.payload;
3108
- },
3109
- setIsFetchingInitialData: (state, action) => {
3110
- state.isFetchingInitialData = action.payload;
3111
- },
3112
- setIsLoading: (state, action) => {
3113
- state.isLoading = action.payload;
3114
3059
  }
3115
3060
  }
3116
3061
  });
@@ -3119,9 +3064,7 @@ const {
3119
3064
  setEnablePlacementMode,
3120
3065
  setSectionExpanded,
3121
3066
  setEnableClustering,
3122
- setAppearance,
3123
- setIsFetchingInitialData,
3124
- setIsLoading
3067
+ setAppearance
3125
3068
  } = settingSlice.actions;
3126
3069
  const selectEnablePlacementMode = (state) => state.settingReducer.placementMode;
3127
3070
  const selectEnableDuplicateIssues = (state) => state.settingReducer.useIssueTemplate;
@@ -3130,8 +3073,6 @@ const selectExpandedSections = (state) => state.settingReducer.expandedSections;
3130
3073
  const selectEnableClustering = (state) => state.settingReducer.enableClustering;
3131
3074
  const selectAppearance = (state) => state.settingReducer.appearance;
3132
3075
  const settingReducer = settingSlice.reducer;
3133
- const selectIsFetchingInitialData = (state) => state.settingReducer.isFetchingInitialData;
3134
- const selectIsLoading = (state) => state.settingReducer.isLoading;
3135
3076
  const LATEST_REVISION_CACHE = {};
3136
3077
  function considerCachingRevision(revision, formId2, preferPending = false) {
3137
3078
  var _a2;
@@ -3550,8 +3491,7 @@ const overmapReducers = {
3550
3491
  userFormReducer,
3551
3492
  userReducer,
3552
3493
  workspaceReducer,
3553
- emailDomainsReducer,
3554
- licenseReducer
3494
+ emailDomainsReducer
3555
3495
  };
3556
3496
  const overmapReducer = combineReducers(overmapReducers);
3557
3497
  const resetStore = "RESET";
@@ -4072,22 +4012,86 @@ class BaseApiService {
4072
4012
  }
4073
4013
  return promise;
4074
4014
  }
4075
- }
4076
- class AttachmentService extends BaseApiService {
4077
- fetchAll(projectId) {
4015
+ }
4016
+ class AttachmentService extends BaseApiService {
4017
+ fetchAll(projectId) {
4018
+ const promise = this.enqueueRequest({
4019
+ description: "Fetch attachments",
4020
+ method: HttpMethod.GET,
4021
+ url: `/attachments/${projectId}/`,
4022
+ blocks: [],
4023
+ blockers: []
4024
+ });
4025
+ const allAttachments = {
4026
+ issue_attachments: Object.values(this.client.store.getState().issueReducer.attachments),
4027
+ component_attachments: Object.values(this.client.store.getState().componentReducer.attachments),
4028
+ component_type_attachments: Object.values(this.client.store.getState().componentTypeReducer.attachments)
4029
+ };
4030
+ return [allAttachments, promise];
4031
+ }
4032
+ // Attachments aren't models, so we use the OptimisticGenericResult type instead
4033
+ async addIssueAttachment(attachmentPayload) {
4034
+ const { description: description2, issue_id, file_sha1, offline_id } = attachmentPayload;
4035
+ if (!attachmentPayload.file.objectURL) {
4036
+ throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
4037
+ }
4038
+ const offlineAttachment = {
4039
+ ...attachmentPayload,
4040
+ file: attachmentPayload.file.objectURL,
4041
+ file_name: attachmentPayload.file.name,
4042
+ file_type: attachmentPayload.file.type
4043
+ };
4044
+ await this.client.files.addCache(attachmentPayload.file, file_sha1);
4045
+ this.client.store.dispatch(addIssueAttachment(offlineAttachment));
4046
+ const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
4047
+ const promise = this.enqueueRequest({
4048
+ description: "Create attachment",
4049
+ method: HttpMethod.POST,
4050
+ url: `/issues/${issue_id}/attach/`,
4051
+ blocks: [offline_id, issue_id],
4052
+ blockers: [file_sha1],
4053
+ payload: {
4054
+ offline_id,
4055
+ issue: issue_id,
4056
+ description: description2 ?? "",
4057
+ submitted_at: (/* @__PURE__ */ new Date()).getTime() / 1e3,
4058
+ ...fileProps
4059
+ }
4060
+ });
4061
+ return [offlineAttachment, promise];
4062
+ }
4063
+ async addComponentAttachment(attachmentPayload) {
4064
+ const { description: description2, component_id, file_sha1, offline_id } = attachmentPayload;
4065
+ if (!attachmentPayload.file.objectURL) {
4066
+ throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
4067
+ }
4068
+ const offlineAttachment = {
4069
+ ...attachmentPayload,
4070
+ file: attachmentPayload.file.objectURL,
4071
+ file_name: attachmentPayload.file.name,
4072
+ file_type: attachmentPayload.file.type
4073
+ };
4074
+ await this.client.files.addCache(attachmentPayload.file, file_sha1);
4075
+ this.client.store.dispatch(addComponentAttachment(offlineAttachment));
4076
+ const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
4078
4077
  const promise = this.enqueueRequest({
4079
- description: "Fetch attachments",
4080
- method: HttpMethod.GET,
4081
- url: `/attachments/${projectId}/`,
4082
- blocks: [],
4083
- blockers: []
4078
+ description: "Create attachment",
4079
+ method: HttpMethod.POST,
4080
+ url: `/components/${component_id}/attach/`,
4081
+ blocks: [offline_id, component_id],
4082
+ blockers: [file_sha1],
4083
+ payload: {
4084
+ offline_id,
4085
+ component: component_id,
4086
+ description: description2 ?? "",
4087
+ submitted_at: (/* @__PURE__ */ new Date()).getTime() / 1e3,
4088
+ ...fileProps
4089
+ }
4084
4090
  });
4085
- const allAttachments = Object.values(this.client.store.getState().issueReducer.attachments);
4086
- return [allAttachments, promise];
4091
+ return [offlineAttachment, promise];
4087
4092
  }
4088
- // Attachments aren't models, so we use the OptimisticGenericResult type instead
4089
- async add(attachmentPayload) {
4090
- const { description: description2, issue_id, file_sha1, offline_id } = attachmentPayload;
4093
+ async addComponentTypeAttachment(attachmentPayload) {
4094
+ const { description: description2, component_type_id, file_sha1, offline_id } = attachmentPayload;
4091
4095
  if (!attachmentPayload.file.objectURL) {
4092
4096
  throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
4093
4097
  }
@@ -4098,17 +4102,17 @@ class AttachmentService extends BaseApiService {
4098
4102
  file_type: attachmentPayload.file.type
4099
4103
  };
4100
4104
  await this.client.files.addCache(attachmentPayload.file, file_sha1);
4101
- this.client.store.dispatch(addAttachment(offlineAttachment));
4105
+ this.client.store.dispatch(addComponentTypeAttachment(offlineAttachment));
4102
4106
  const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
4103
4107
  const promise = this.enqueueRequest({
4104
4108
  description: "Create attachment",
4105
4109
  method: HttpMethod.POST,
4106
- url: `/issues/${issue_id}/attach/`,
4107
- blocks: [offline_id, issue_id],
4110
+ url: `/component_types/${component_type_id}/attach/`,
4111
+ blocks: [offline_id, component_type_id],
4108
4112
  blockers: [file_sha1],
4109
4113
  payload: {
4110
4114
  offline_id,
4111
- issue: issue_id,
4115
+ component_type: component_type_id,
4112
4116
  description: description2 ?? "",
4113
4117
  submitted_at: (/* @__PURE__ */ new Date()).getTime() / 1e3,
4114
4118
  ...fileProps
@@ -4116,27 +4120,67 @@ class AttachmentService extends BaseApiService {
4116
4120
  });
4117
4121
  return [offlineAttachment, promise];
4118
4122
  }
4119
- async attachFilesToIssue(filesToSubmit, issueId) {
4120
- return Promise.allSettled(
4121
- filesToSubmit.map((file) => {
4122
- if (!(file instanceof File)) {
4123
- throw new Error("Expected a File instance.");
4124
- }
4125
- const photoAttachmentPromise = async (file2) => {
4126
- const hash = await hashFile(file2);
4127
- const attachment = offline({
4128
- file: file2,
4129
- // No description for now
4130
- issue_id: issueId,
4131
- file_sha1: hash
4132
- });
4133
- return await this.add(attachment);
4134
- };
4135
- return photoAttachmentPromise(file);
4136
- })
4137
- );
4123
+ /** the outer Promise is needed to await the hashing of each file, which is required before offline use. If wanting to
4124
+ * attach promise handlers to the request to add the attachment in the backend, apply it on the promise returned from the
4125
+ * OptimisticModelResult. */
4126
+ attachFilesToIssue(filesToSubmit, issueId) {
4127
+ return filesToSubmit.map((file) => {
4128
+ if (!(file instanceof File)) {
4129
+ throw new Error("Expected a File instance.");
4130
+ }
4131
+ const photoAttachmentPromise = async (file2) => {
4132
+ const hash = await hashFile(file2);
4133
+ const attachment = offline({
4134
+ file: file2,
4135
+ file_name: file2.name,
4136
+ file_type: file2.type,
4137
+ issue_id: issueId,
4138
+ file_sha1: hash
4139
+ });
4140
+ return this.addIssueAttachment(attachment);
4141
+ };
4142
+ return photoAttachmentPromise(file);
4143
+ });
4144
+ }
4145
+ attachFilesToComponent(filesToSubmit, componentId) {
4146
+ return filesToSubmit.map((file) => {
4147
+ if (!(file instanceof File)) {
4148
+ throw new Error("Expected a File instance.");
4149
+ }
4150
+ const photoAttachmentPromise = async (file2) => {
4151
+ const hash = await hashFile(file2);
4152
+ const attachment = offline({
4153
+ file: file2,
4154
+ file_name: file2.name,
4155
+ file_type: file2.type,
4156
+ component_id: componentId,
4157
+ file_sha1: hash
4158
+ });
4159
+ return this.addComponentAttachment(attachment);
4160
+ };
4161
+ return photoAttachmentPromise(file);
4162
+ });
4163
+ }
4164
+ attachFilesToComponentType(filesToSubmit, componentTypeId) {
4165
+ return filesToSubmit.map((file) => {
4166
+ if (!(file instanceof File)) {
4167
+ throw new Error("Expected a File instance.");
4168
+ }
4169
+ const photoAttachmentPromise = async (file2) => {
4170
+ const hash = await hashFile(file2);
4171
+ const attachment = offline({
4172
+ file: file2,
4173
+ file_name: file2.name,
4174
+ file_type: file2.type,
4175
+ component_type_id: componentTypeId,
4176
+ file_sha1: hash
4177
+ });
4178
+ return this.addComponentTypeAttachment(attachment);
4179
+ };
4180
+ return photoAttachmentPromise(file);
4181
+ });
4138
4182
  }
4139
- async replaceFile(attachmentId, newFile) {
4183
+ async replaceIssueAttachmentFile(attachmentId, newFile) {
4140
4184
  const { store } = this.client;
4141
4185
  const attachment = store.getState().issueReducer.attachments[attachmentId];
4142
4186
  if (!attachment)
@@ -4151,16 +4195,136 @@ class AttachmentService extends BaseApiService {
4151
4195
  if (!newFile.objectURL) {
4152
4196
  throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
4153
4197
  }
4154
- store.dispatch(updateAttachment({ ...attachment, file_sha1: newSha1, file: URL.createObjectURL(newFile) }));
4198
+ store.dispatch(
4199
+ updateIssueAttachment({ ...attachment, file_sha1: newSha1, file: URL.createObjectURL(newFile) })
4200
+ );
4201
+ await this.client.files.addCache(newFile, newSha1);
4202
+ const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
4203
+ store.dispatch(updateIssueAttachment(attachment));
4204
+ throw e;
4205
+ });
4206
+ const promise2 = this.enqueueRequest({
4207
+ description: "Edit attachment",
4208
+ method: HttpMethod.PATCH,
4209
+ url: `/attachments/issues/${attachment.offline_id}/`,
4210
+ isResponseBlob: false,
4211
+ payload: fileProps,
4212
+ blockers: [attachmentId, newSha1],
4213
+ blocks: [attachmentId, newSha1]
4214
+ });
4215
+ try {
4216
+ const result = await promise2;
4217
+ void this.client.files.removeCache(attachment.file_sha1);
4218
+ return result;
4219
+ } catch (e) {
4220
+ if (oldFile) {
4221
+ store.dispatch(
4222
+ updateIssueAttachment({
4223
+ ...attachment,
4224
+ file_sha1: attachment.file_sha1,
4225
+ file: URL.createObjectURL(oldFile)
4226
+ })
4227
+ );
4228
+ }
4229
+ throw e;
4230
+ }
4231
+ };
4232
+ const offlineAttachment = {
4233
+ ...attachment,
4234
+ file_sha1: newSha1,
4235
+ file: URL.createObjectURL(newFile)
4236
+ };
4237
+ const promise = performRequest2();
4238
+ return [offlineAttachment, promise];
4239
+ }
4240
+ async replaceComponentAttachmentFile(attachmentId, newFile) {
4241
+ const { store } = this.client;
4242
+ const attachment = store.getState().componentReducer.attachments[attachmentId];
4243
+ if (!attachment)
4244
+ throw new Error(`Attachment ${attachmentId} not found`);
4245
+ let oldFile = void 0;
4246
+ const newSha1 = await hashFile(newFile);
4247
+ const performRequest2 = async () => {
4248
+ oldFile = await this.client.files.fetchCache(attachment.file_sha1);
4249
+ if (!oldFile) {
4250
+ console.error(`Failed to fetch old file from cache for sha1 ${attachment.file_sha1}.`);
4251
+ }
4252
+ if (!newFile.objectURL) {
4253
+ throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
4254
+ }
4255
+ store.dispatch(
4256
+ updateComponentAttachment({ ...attachment, file_sha1: newSha1, file: URL.createObjectURL(newFile) })
4257
+ );
4258
+ await this.client.files.addCache(newFile, newSha1);
4259
+ const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
4260
+ store.dispatch(updateComponentAttachment(attachment));
4261
+ throw e;
4262
+ });
4263
+ const promise2 = this.enqueueRequest({
4264
+ description: "Edit attachment",
4265
+ method: HttpMethod.PATCH,
4266
+ url: `/attachments/components/${attachment.offline_id}/`,
4267
+ isResponseBlob: false,
4268
+ payload: fileProps,
4269
+ blockers: [attachmentId, newSha1],
4270
+ blocks: [attachmentId, newSha1]
4271
+ });
4272
+ try {
4273
+ const result = await promise2;
4274
+ void this.client.files.removeCache(attachment.file_sha1);
4275
+ return result;
4276
+ } catch (e) {
4277
+ if (oldFile) {
4278
+ store.dispatch(
4279
+ updateComponentAttachment({
4280
+ ...attachment,
4281
+ file_sha1: attachment.file_sha1,
4282
+ file: URL.createObjectURL(oldFile)
4283
+ })
4284
+ );
4285
+ }
4286
+ throw e;
4287
+ }
4288
+ };
4289
+ const offlineAttachment = {
4290
+ ...attachment,
4291
+ file_sha1: newSha1,
4292
+ file: URL.createObjectURL(newFile)
4293
+ };
4294
+ const promise = performRequest2();
4295
+ return [offlineAttachment, promise];
4296
+ }
4297
+ async replaceComponentTypeAttachmentFile(attachmentId, newFile) {
4298
+ const { store } = this.client;
4299
+ const attachment = store.getState().componentTypeReducer.attachments[attachmentId];
4300
+ if (!attachment)
4301
+ throw new Error(`Attachment ${attachmentId} not found`);
4302
+ let oldFile = void 0;
4303
+ const newSha1 = await hashFile(newFile);
4304
+ const performRequest2 = async () => {
4305
+ oldFile = await this.client.files.fetchCache(attachment.file_sha1);
4306
+ if (!oldFile) {
4307
+ console.error(`Failed to fetch old file from cache for sha1 ${attachment.file_sha1}.`);
4308
+ }
4309
+ if (!newFile.objectURL) {
4310
+ throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
4311
+ }
4312
+ store.dispatch(
4313
+ updateComponentTypeAttachment({
4314
+ ...attachment,
4315
+ file_sha1: newSha1,
4316
+ file: URL.createObjectURL(newFile)
4317
+ })
4318
+ );
4155
4319
  await this.client.files.addCache(newFile, newSha1);
4156
4320
  const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
4157
- store.dispatch(updateAttachment(attachment));
4321
+ store.dispatch(updateComponentTypeAttachment(attachment));
4158
4322
  throw e;
4159
4323
  });
4160
4324
  const promise2 = this.enqueueRequest({
4161
4325
  description: "Edit attachment",
4162
4326
  method: HttpMethod.PATCH,
4163
- url: `/attachments/${attachment.offline_id}/`,
4327
+ url: `/attachments/component_types/${attachment.offline_id}/`,
4164
4328
  isResponseBlob: false,
4165
4329
  payload: fileProps,
4166
4330
  blockers: [attachmentId, newSha1],
@@ -4173,7 +4337,7 @@ class AttachmentService extends BaseApiService {
4173
4337
  } catch (e) {
4174
4338
  if (oldFile) {
4175
4339
  store.dispatch(
4176
- updateAttachment({
4340
+ updateComponentTypeAttachment({
4177
4341
  ...attachment,
4178
4342
  file_sha1: attachment.file_sha1,
4179
4343
  file: URL.createObjectURL(oldFile)
@@ -4193,23 +4357,54 @@ class AttachmentService extends BaseApiService {
4193
4357
  }
4194
4358
  /**
4195
4359
  * Deletes an attachment and associated data in the cloud, in the Redux store and the cache.
4196
- * @param attachmentId
4360
+ * @param issueAttachmentId
4197
4361
  */
4198
- delete(attachmentId) {
4362
+ deleteIssueAttachment(issueAttachmentId) {
4199
4363
  const { store } = this.client;
4200
- const storeStateIssueReducer = store.getState().issueReducer;
4201
- const attachment = storeStateIssueReducer.attachments[attachmentId];
4364
+ const attachment = selectIssueAttachmentMapping(store.getState())[issueAttachmentId];
4202
4365
  if (!attachment) {
4203
- throw new Error(`Attachment ${attachmentId} not found`);
4366
+ throw new Error(`Attachment ${issueAttachmentId} not found`);
4367
+ }
4368
+ store.dispatch(removeIssueAttachment(issueAttachmentId));
4369
+ void this.client.files.removeCache(attachment.file_sha1);
4370
+ return this.enqueueRequest({
4371
+ description: "Delete attachment",
4372
+ method: HttpMethod.DELETE,
4373
+ url: `/attachments/issues/${issueAttachmentId}/`,
4374
+ blockers: [issueAttachmentId],
4375
+ blocks: [issueAttachmentId]
4376
+ });
4377
+ }
4378
+ deleteComponentAttachment(componentAttachmentId) {
4379
+ const { store } = this.client;
4380
+ const attachment = selectComponentAttachmentMapping(store.getState())[componentAttachmentId];
4381
+ if (!attachment) {
4382
+ throw new Error(`Attachment ${componentAttachmentId} not found`);
4383
+ }
4384
+ store.dispatch(removeIssueAttachment(componentAttachmentId));
4385
+ void this.client.files.removeCache(attachment.file_sha1);
4386
+ return this.enqueueRequest({
4387
+ description: "Delete attachment",
4388
+ method: HttpMethod.DELETE,
4389
+ url: `/attachments/components/${componentAttachmentId}/`,
4390
+ blockers: [componentAttachmentId],
4391
+ blocks: [componentAttachmentId]
4392
+ });
4393
+ }
4394
+ deleteComponentTypeAttachment(componentTypeAttachmentId) {
4395
+ const { store } = this.client;
4396
+ const attachment = selectComponentTypeAttachmentMapping(store.getState())[componentTypeAttachmentId];
4397
+ if (!attachment) {
4398
+ throw new Error(`Attachment ${componentTypeAttachmentId} not found`);
4204
4399
  }
4205
- store.dispatch(removeAttachment(attachmentId));
4400
+ store.dispatch(removeIssueAttachment(componentTypeAttachmentId));
4206
4401
  void this.client.files.removeCache(attachment.file_sha1);
4207
4402
  return this.enqueueRequest({
4208
4403
  description: "Delete attachment",
4209
4404
  method: HttpMethod.DELETE,
4210
- url: `/attachments/${attachmentId}/`,
4211
- blockers: [attachmentId],
4212
- blocks: [attachmentId]
4405
+ url: `/attachments/component_types/${componentTypeAttachmentId}/`,
4406
+ blockers: [componentTypeAttachmentId],
4407
+ blocks: [componentTypeAttachmentId]
4213
4408
  });
4214
4409
  }
4215
4410
  }
@@ -4601,13 +4796,26 @@ class ComponentService extends BaseApiService {
4601
4796
  return [component, promise];
4602
4797
  }
4603
4798
  async remove(id) {
4604
- this.client.store.dispatch(removeComponent(id));
4799
+ const { store } = this.client;
4800
+ const backupComponent = selectComponent(id)(store.getState());
4801
+ if (!backupComponent)
4802
+ throw new Error(`No component with id ${id} found in the store`);
4803
+ const attachmentsOfComponent = selectAttachmentsOfComponent(id)(store.getState());
4804
+ store.dispatch(removeComponent(id));
4805
+ if (attachmentsOfComponent.length > 0) {
4806
+ const attachmentsOfComponentIds = attachmentsOfComponent.map(({ offline_id }) => offline_id);
4807
+ store.dispatch(removeComponentAttachments(attachmentsOfComponentIds));
4808
+ }
4605
4809
  return this.enqueueRequest({
4606
4810
  description: "Delete issue",
4607
4811
  method: HttpMethod.DELETE,
4608
4812
  url: `/components/${id}/`,
4609
4813
  blockers: [id],
4610
4814
  blocks: []
4815
+ }).catch((err) => {
4816
+ store.dispatch(addComponent(backupComponent));
4817
+ store.dispatch(addComponentAttachments(attachmentsOfComponent));
4818
+ throw err;
4611
4819
  });
4612
4820
  }
4613
4821
  async deleteAllByComponentType(componentTypeId) {
@@ -4918,13 +5126,19 @@ class ComponentTypeService extends BaseApiService {
4918
5126
  if (!componentType) {
4919
5127
  throw new Error("Expected componentType to exist");
4920
5128
  }
4921
- const componentTypeStages = selectStagesFromComponentType(componentTypeId)(state) ?? [];
4922
- store.dispatch(
4923
- removeStages(
4924
- componentTypeStages.map((componentTypeStage) => componentTypeStage.offline_id)
4925
- )
4926
- );
5129
+ const stagesOfComponentType = selectStagesFromComponentType(componentTypeId)(state) ?? [];
5130
+ const attachmentsOfComponentType = selectAttachmentsOfComponentType(componentTypeId)(state);
4927
5131
  store.dispatch(deleteComponentType(componentTypeId));
5132
+ if (stagesOfComponentType.length > 0) {
5133
+ const stagesOfComponentTypeIds = stagesOfComponentType.map(
5134
+ (componentTypeStage) => componentTypeStage.offline_id
5135
+ );
5136
+ store.dispatch(removeStages(stagesOfComponentTypeIds));
5137
+ }
5138
+ if (attachmentsOfComponentType.length > 0) {
5139
+ const attachmentsOfComponentTypeIds = attachmentsOfComponentType.map(({ offline_id }) => offline_id);
5140
+ store.dispatch(removeComponentTypeAttachments(attachmentsOfComponentTypeIds));
5141
+ }
4928
5142
  return this.enqueueRequest({
4929
5143
  description: "Delete ComponentType",
4930
5144
  method: HttpMethod.DELETE,
@@ -4933,7 +5147,8 @@ class ComponentTypeService extends BaseApiService {
4933
5147
  blocks: []
4934
5148
  }).catch((e) => {
4935
5149
  store.dispatch(addComponentType(componentType));
4936
- store.dispatch(addStages(componentTypeStages));
5150
+ store.dispatch(addStages(stagesOfComponentType));
5151
+ store.dispatch(addComponentTypeAttachments(attachmentsOfComponentType));
4937
5152
  throw e;
4938
5153
  });
4939
5154
  }
@@ -5038,7 +5253,6 @@ class IssueService extends BaseApiService {
5038
5253
  });
5039
5254
  store.dispatch(addIssue(issuePayload));
5040
5255
  store.dispatch(addToRecentIssues(issuePayload.offline_id));
5041
- store.dispatch(addActiveProjectIssuesCount(1));
5042
5256
  const promise = this.enqueueRequest({
5043
5257
  description: "Create issue",
5044
5258
  method: HttpMethod.POST,
@@ -5048,7 +5262,6 @@ class IssueService extends BaseApiService {
5048
5262
  },
5049
5263
  payload: issuePayload,
5050
5264
  blockers: [
5051
- "add-issue",
5052
5265
  ...issuePayload.index_workspace ? [issuePayload.index_workspace] : [],
5053
5266
  ...issuePayload.visible_in_workspaces
5054
5267
  ],
@@ -5066,7 +5279,6 @@ class IssueService extends BaseApiService {
5066
5279
  });
5067
5280
  }
5068
5281
  store.dispatch(removeIssue(issuePayload.offline_id));
5069
- store.dispatch(addActiveProjectIssuesCount(-1));
5070
5282
  throw error2;
5071
5283
  });
5072
5284
  return [issuePayload, promise];
@@ -5105,18 +5317,16 @@ class IssueService extends BaseApiService {
5105
5317
  return [fullIssue, promise];
5106
5318
  }
5107
5319
  async remove(id) {
5108
- const { store } = this.client;
5109
- const state = store.getState();
5320
+ const state = this.client.store.getState();
5110
5321
  const backup = state.issueReducer.issues[id];
5111
5322
  if (!backup) {
5112
5323
  throw new Error(`No issue with id ${id} found in the store`);
5113
5324
  }
5114
5325
  const attachments = Object.values(state.issueReducer.attachments).filter((a) => a.issue_id === id);
5115
5326
  const attachmentsOfIssue = selectPhotoAttachmentsOfIssue(id)(state);
5116
- store.dispatch(removeIssue(id));
5117
- store.dispatch(addActiveProjectIssuesCount(-1));
5327
+ this.client.store.dispatch(removeIssue(id));
5118
5328
  if (attachmentsOfIssue) {
5119
- store.dispatch(removeAttachmentsOfIssue(id));
5329
+ this.client.store.dispatch(removeAttachmentsOfIssue(id));
5120
5330
  }
5121
5331
  try {
5122
5332
  return await this.enqueueRequest({
@@ -5127,9 +5337,8 @@ class IssueService extends BaseApiService {
5127
5337
  blocks: []
5128
5338
  });
5129
5339
  } catch (e) {
5130
- store.dispatch(addIssue(backup));
5131
- store.dispatch(addAttachments(attachments));
5132
- store.dispatch(addActiveProjectIssuesCount(1));
5340
+ this.client.store.dispatch(addIssue(backup));
5341
+ this.client.store.dispatch(addIssueAttachments(attachments));
5133
5342
  throw e;
5134
5343
  }
5135
5344
  }
@@ -5205,9 +5414,7 @@ class MainService extends BaseApiService {
5205
5414
  owner_organization: projectData.organization_owner,
5206
5415
  owner_user: projectData.user_owner,
5207
5416
  bounds: projectData.bounds,
5208
- invited: projectData.invited || false,
5209
- issues_count: projectData.issues_count,
5210
- form_submissions_count: projectData.form_submissions_count
5417
+ invited: projectData.invited || false
5211
5418
  });
5212
5419
  if (currentProjectId === projectData.id && !projectData.invited) {
5213
5420
  isProjectIdValid = true;
@@ -5225,7 +5432,6 @@ class MainService extends BaseApiService {
5225
5432
  }
5226
5433
  store.dispatch(setCurrentUser(data.user));
5227
5434
  store.dispatch(addUsers(data.project_owners));
5228
- store.dispatch(setLicenses(data.licenses));
5229
5435
  const organizationsData = data.organizations;
5230
5436
  store.dispatch(setOrganizations(organizationsData));
5231
5437
  const validProjects = projects.filter((project) => !project.invited);
@@ -5304,7 +5510,10 @@ class MainService extends BaseApiService {
5304
5510
  if (currentProjectId) {
5305
5511
  const [_offlineAttachments, promise] = this.client.attachments.fetchAll(currentProjectId);
5306
5512
  void promise.then((result) => {
5307
- store.dispatch(setAttachments(result));
5513
+ const { issue_attachments, component_type_attachments, component_attachments } = result;
5514
+ store.dispatch(setIssueAttachments(issue_attachments));
5515
+ store.dispatch(setComponentAttachments(component_attachments));
5516
+ store.dispatch(setComponentTypeAttachments(component_type_attachments));
5308
5517
  });
5309
5518
  }
5310
5519
  store.dispatch(setIsFetchingInitialData(false));
@@ -5339,7 +5548,7 @@ class ProjectAccessService extends BaseApiService {
5339
5548
  method: HttpMethod.PATCH,
5340
5549
  url: `/access/${projectAccess.offline_id}/`,
5341
5550
  payload: projectAccess,
5342
- blockers: [projectAccess.offline_id, "change-access-level"],
5551
+ blockers: [projectAccess.offline_id],
5343
5552
  blocks: [projectAccess.offline_id]
5344
5553
  });
5345
5554
  }
@@ -5548,11 +5757,6 @@ class ProjectService extends BaseApiService {
5548
5757
  store.dispatch(removeProjectAccessesOfProject(project.id));
5549
5758
  store.dispatch({ type: "rehydrated/setRehydrated", payload: false });
5550
5759
  store.dispatch(deleteProject(project));
5551
- const licenseSelector = selectLicenseForProject(project.id);
5552
- const license = licenseSelector(state);
5553
- if (license) {
5554
- store.dispatch(updateLicense({ ...license, project: null }));
5555
- }
5556
5760
  try {
5557
5761
  await this.enqueueRequest({
5558
5762
  description: "Delete project",
@@ -5568,9 +5772,6 @@ class ProjectService extends BaseApiService {
5568
5772
  store.dispatch(addOrReplaceProjectFiles(filesToDelete));
5569
5773
  store.dispatch(setActiveProjectId(activeProjectId));
5570
5774
  store.dispatch({ type: "rehydrated/setRehydrated", payload: true });
5571
- if (license) {
5572
- store.dispatch(updateLicense({ ...license, project: project.id }));
5573
- }
5574
5775
  throw e;
5575
5776
  }
5576
5777
  }
@@ -5945,7 +6146,7 @@ class UserFormSubmissionService extends BaseApiService {
5945
6146
  method: HttpMethod.POST,
5946
6147
  url: `/forms/revisions/${payload.form_revision}/respond/`,
5947
6148
  payload: { ...payloadWithoutFiles, project: activeProjectId },
5948
- blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
6149
+ blockers: [payload.issue, payload.component, payload.component_stage].filter(
5949
6150
  (x) => x !== void 0
5950
6151
  ),
5951
6152
  blocks: [payload.offline_id]
@@ -5964,12 +6165,10 @@ class UserFormSubmissionService extends BaseApiService {
5964
6165
  };
5965
6166
  store.dispatch(updateOrCreateUserFormSubmission(offlineResultWithoutFiles));
5966
6167
  void promise.then((result) => {
5967
- store.dispatch(addActiveProjectFormSubmissionsCount(1));
5968
6168
  store.dispatch(updateOrCreateUserFormSubmission(result));
5969
6169
  return result;
5970
6170
  }).catch(() => {
5971
6171
  store.dispatch(deleteUserFormSubmission(payload.offline_id));
5972
- store.dispatch(addActiveProjectFormSubmissionsCount(-1));
5973
6172
  });
5974
6173
  const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
5975
6174
  return [fullOfflineResult, settledPromise];
@@ -6003,7 +6202,6 @@ class UserFormSubmissionService extends BaseApiService {
6003
6202
  const state = store.getState();
6004
6203
  const submission = state.userFormReducer.submissions[submissionId];
6005
6204
  store.dispatch(deleteUserFormSubmission(submissionId));
6006
- store.dispatch(addActiveProjectFormSubmissionsCount(-1));
6007
6205
  try {
6008
6206
  return await this.enqueueRequest({
6009
6207
  description: "Delete user form submissions",
@@ -6014,7 +6212,6 @@ class UserFormSubmissionService extends BaseApiService {
6014
6212
  });
6015
6213
  } catch (e) {
6016
6214
  if (submission) {
6017
- store.dispatch(addActiveProjectFormSubmissionsCount(1));
6018
6215
  store.dispatch(updateOrCreateUserFormSubmission(submission));
6019
6216
  }
6020
6217
  throw e;
@@ -6051,7 +6248,7 @@ class WorkspaceService extends BaseApiService {
6051
6248
  method: HttpMethod.POST,
6052
6249
  url: `/projects/${store.getState().projectReducer.activeProjectId}/workspaces/`,
6053
6250
  payload: offlineWorkspace,
6054
- blockers: ["add-workspace"],
6251
+ blockers: [],
6055
6252
  blocks: [offlineWorkspace.offline_id]
6056
6253
  });
6057
6254
  void promise.then((result) => {
@@ -6472,121 +6669,6 @@ class OrganizationService extends BaseApiService {
6472
6669
  });
6473
6670
  }
6474
6671
  }
6475
- class LicenseService extends BaseApiService {
6476
- async fetchLicensesForOrganization(organizationId, showLoading = false) {
6477
- if (showLoading) {
6478
- this.client.store.dispatch(setIsFetchingInitialData(true));
6479
- }
6480
- const result = await this.enqueueRequest({
6481
- description: "Get licenses",
6482
- method: HttpMethod.GET,
6483
- url: `/organizations/${organizationId}/licenses/`,
6484
- isAuthNeeded: true,
6485
- blockers: [organizationId.toString()],
6486
- blocks: ["add-issue", "add-form-entry", "change-access-level", "add-workspace"]
6487
- });
6488
- if (showLoading) {
6489
- this.client.store.dispatch(setIsFetchingInitialData(false));
6490
- }
6491
- return result;
6492
- }
6493
- async getLicense(license) {
6494
- const result = await this.enqueueRequest({
6495
- description: "Get license",
6496
- method: HttpMethod.GET,
6497
- url: `/billing/${license.offline_id}/`,
6498
- isAuthNeeded: true,
6499
- blockers: [
6500
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6501
- ],
6502
- blocks: []
6503
- });
6504
- this.client.store.dispatch(updateLicense(result));
6505
- return result;
6506
- }
6507
- async pauseLicense(license) {
6508
- const result = await this.enqueueRequest({
6509
- description: "Pause license",
6510
- method: HttpMethod.DELETE,
6511
- url: `/billing/${license.offline_id}/suspend/`,
6512
- isAuthNeeded: true,
6513
- blockers: [
6514
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6515
- ],
6516
- blocks: []
6517
- });
6518
- this.client.store.dispatch(updateLicense(result));
6519
- return result;
6520
- }
6521
- async resumeLicense(license) {
6522
- const result = await this.enqueueRequest({
6523
- description: "Resume license",
6524
- method: HttpMethod.PATCH,
6525
- url: `/billing/${license.offline_id}/suspend/`,
6526
- isAuthNeeded: true,
6527
- blockers: [
6528
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6529
- ],
6530
- blocks: []
6531
- });
6532
- this.client.store.dispatch(updateLicense(result));
6533
- return result;
6534
- }
6535
- async cancelLicense(license) {
6536
- const result = await this.enqueueRequest({
6537
- description: "Cancel license",
6538
- method: HttpMethod.DELETE,
6539
- url: `/billing/${license.offline_id}/`,
6540
- isAuthNeeded: true,
6541
- blockers: [
6542
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6543
- ],
6544
- blocks: []
6545
- });
6546
- this.client.store.dispatch(updateLicense(result));
6547
- return result;
6548
- }
6549
- async attachLicenseToProject(license, project) {
6550
- const result = await this.enqueueRequest({
6551
- description: "Attach license",
6552
- method: HttpMethod.PATCH,
6553
- url: `/billing/${license.offline_id}/project/`,
6554
- isAuthNeeded: true,
6555
- payload: { project: project.id },
6556
- blockers: [
6557
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : "",
6558
- project.id ? project.id.toString() : ""
6559
- ],
6560
- blocks: ["add-issue", "add-form-entry", "change-access-level", "add-workspace"]
6561
- });
6562
- this.client.store.dispatch(updateLicense(result));
6563
- return result;
6564
- }
6565
- async detachLicenseFromProject(license) {
6566
- const result = await this.enqueueRequest({
6567
- description: "Detach license",
6568
- method: HttpMethod.DELETE,
6569
- url: `/billing/${license.offline_id}/project/`,
6570
- isAuthNeeded: true,
6571
- blockers: [
6572
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6573
- ],
6574
- blocks: ["add-issue", "add-form-entry", "change-access-level", "add-workspace"]
6575
- });
6576
- this.client.store.dispatch(updateLicense(result));
6577
- return result;
6578
- }
6579
- async getLatestTransaction(license) {
6580
- return await this.enqueueRequest({
6581
- description: "Get latest transaction",
6582
- method: HttpMethod.GET,
6583
- url: `/billing/${license.offline_id}/transaction/`,
6584
- isAuthNeeded: true,
6585
- blockers: [license.offline_id],
6586
- blocks: [license.offline_id]
6587
- });
6588
- }
6589
- }
6590
6672
  class OvermapSDK {
6591
6673
  constructor(apiUrl, store) {
6592
6674
  __publicField(this, "API_URL");
@@ -6612,7 +6694,6 @@ class OvermapSDK {
6612
6694
  __publicField(this, "projectFiles", new ProjectFileService(this));
6613
6695
  __publicField(this, "emailVerification", new EmailVerificationService(this));
6614
6696
  __publicField(this, "emailDomains", new EmailDomainsService(this));
6615
- __publicField(this, "licenses", new LicenseService(this));
6616
6697
  this.API_URL = apiUrl;
6617
6698
  this.store = store;
6618
6699
  }
@@ -14626,9 +14707,6 @@ export {
14626
14707
  IssuePriority,
14627
14708
  IssueService,
14628
14709
  IssueStatus,
14629
- LicenseLevel,
14630
- LicenseService,
14631
- LicenseStatus,
14632
14710
  MainService,
14633
14711
  MapStyle,
14634
14712
  MultiSelectField,
@@ -14646,7 +14724,6 @@ export {
14646
14724
  OvermapProvider,
14647
14725
  OvermapSDK,
14648
14726
  PDFViewer,
14649
- PaddleCheckoutEvent,
14650
14727
  PatchField,
14651
14728
  PatchFormProvider,
14652
14729
  ProjectAccessLevel,
@@ -14673,18 +14750,19 @@ export {
14673
14750
  YELLOW,
14674
14751
  _setLatestRetryTime,
14675
14752
  acceptProjectInvite,
14676
- addActiveProjectFormSubmissionsCount,
14677
- addActiveProjectIssuesCount,
14678
- addAttachment,
14679
- addAttachments,
14680
14753
  addCategory,
14681
14754
  addComponent,
14755
+ addComponentAttachment,
14756
+ addComponentAttachments,
14682
14757
  addComponentType,
14758
+ addComponentTypeAttachment,
14759
+ addComponentTypeAttachments,
14683
14760
  addComponentsInBatches,
14684
14761
  addEmailDomain,
14685
14762
  addFavouriteProjectId,
14686
14763
  addIssue,
14687
- addLicenses,
14764
+ addIssueAttachment,
14765
+ addIssueAttachments,
14688
14766
  addOrReplaceCategories,
14689
14767
  addOrReplaceIssueComment,
14690
14768
  addOrReplaceProjectFile,
@@ -14784,8 +14862,6 @@ export {
14784
14862
  issueReducer,
14785
14863
  issueSlice,
14786
14864
  issueToSearchResult,
14787
- licenseReducer,
14788
- licenseSlice,
14789
14865
  linkStageToForm,
14790
14866
  literalToCoordinates,
14791
14867
  logOnlyOnce,
@@ -14824,14 +14900,18 @@ export {
14824
14900
  rehydratedReducer,
14825
14901
  rehydratedSlice,
14826
14902
  removeAllComponentsOfType,
14827
- removeAttachment,
14828
14903
  removeAttachmentsOfIssue,
14829
14904
  removeCategory,
14830
14905
  removeColor,
14831
14906
  removeComponent,
14907
+ removeComponentAttachment,
14908
+ removeComponentAttachments,
14909
+ removeComponentTypeAttachment,
14910
+ removeComponentTypeAttachments,
14832
14911
  removeEmailDomain,
14833
14912
  removeFavouriteProjectId,
14834
14913
  removeIssue,
14914
+ removeIssueAttachment,
14835
14915
  removeIssueComment,
14836
14916
  removeOrganizationAccess,
14837
14917
  removeProjectAccess,
@@ -14853,21 +14933,21 @@ export {
14853
14933
  searchIssues,
14854
14934
  selectAccessToken,
14855
14935
  selectActiveIssueId,
14856
- selectActiveLicense,
14857
14936
  selectActiveOrganization,
14858
14937
  selectActiveOrganizationAccess,
14859
14938
  selectActiveOrganizationId,
14860
- selectActiveOrganizationLicenses,
14861
- selectActiveOrganizationProjects,
14862
14939
  selectActiveProject,
14863
14940
  selectActiveProjectAccess,
14864
14941
  selectActiveProjectFileId,
14865
14942
  selectActiveProjectId,
14866
- selectActiveStatusLicenses,
14867
14943
  selectActiveWorkspace,
14868
14944
  selectActiveWorkspaceId,
14869
14945
  selectAllAttachments,
14946
+ selectAllComponentAttachments,
14947
+ selectAllComponentTypeAttachments,
14870
14948
  selectAppearance,
14949
+ selectAttachmentsOfComponent,
14950
+ selectAttachmentsOfComponentType,
14871
14951
  selectCategories,
14872
14952
  selectCategoriesOfWorkspace,
14873
14953
  selectCategory,
@@ -14879,7 +14959,9 @@ export {
14879
14959
  selectCompletedStageIdsForComponent,
14880
14960
  selectCompletedStages,
14881
14961
  selectComponent,
14962
+ selectComponentAttachmentMapping,
14882
14963
  selectComponentType,
14964
+ selectComponentTypeAttachmentMapping,
14883
14965
  selectComponentTypeForm,
14884
14966
  selectComponentTypeFromComponent,
14885
14967
  selectComponentTypeFromComponents,
@@ -14909,7 +14991,6 @@ export {
14909
14991
  selectHiddenComponentTypeIds,
14910
14992
  selectIsFetchingInitialData,
14911
14993
  selectIsImportingProjectFile,
14912
- selectIsLoading,
14913
14994
  selectIsLoggedIn,
14914
14995
  selectIssue,
14915
14996
  selectIssueAttachmentMapping,
@@ -14920,10 +15001,6 @@ export {
14920
15001
  selectLatestRetryTime,
14921
15002
  selectLatestRevisionByFormId,
14922
15003
  selectLatestRevisionsFromComponentTypeIds,
14923
- selectLicense,
14924
- selectLicenseForProject,
14925
- selectLicenses,
14926
- selectLicensesForProjectsMapping,
14927
15004
  selectMainWorkspace,
14928
15005
  selectMapStyle,
14929
15006
  selectNumberOfComponentTypesMatchingCaseInsensitiveName,
@@ -14938,7 +15015,6 @@ export {
14938
15015
  selectOrganizationUsersAsMapping,
14939
15016
  selectOrganizationUsersIds,
14940
15017
  selectOrganizations,
14941
- selectOrganizationsMapping,
14942
15018
  selectOrganizationsWithAccess,
14943
15019
  selectPermittedWorkspaceIds,
14944
15020
  selectPhotoAttachmentsOfIssue,
@@ -14960,7 +15036,6 @@ export {
14960
15036
  selectRevisionsForForm,
14961
15037
  selectShowTooltips,
14962
15038
  selectSortedEmailDomains,
14963
- selectSortedOrganizationLicenses,
14964
15039
  selectSortedOrganizationUsers,
14965
15040
  selectSortedProjectUsers,
14966
15041
  selectSortedProjects,
@@ -14991,9 +15066,10 @@ export {
14991
15066
  setActiveProjectId,
14992
15067
  setActiveWorkspaceId,
14993
15068
  setAppearance,
14994
- setAttachments,
14995
15069
  setCategories,
14996
15070
  setCenterMapToProject,
15071
+ setComponentAttachments,
15072
+ setComponentTypeAttachments,
14997
15073
  setComponentTypes,
14998
15074
  setComponents,
14999
15075
  setCreateProjectType,
@@ -15004,10 +15080,9 @@ export {
15004
15080
  setEnablePlacementMode,
15005
15081
  setIsFetchingInitialData,
15006
15082
  setIsImportingProjectFile,
15007
- setIsLoading,
15083
+ setIssueAttachments,
15008
15084
  setIssueComments,
15009
15085
  setIssues,
15010
- setLicenses,
15011
15086
  setLoggedIn,
15012
15087
  setMapStyle,
15013
15088
  setOrganizationAccesses,
@@ -15044,10 +15119,11 @@ export {
15044
15119
  unhideCategory,
15045
15120
  unlinkStageToForm,
15046
15121
  updateActiveOrganization,
15047
- updateAttachment,
15048
15122
  updateComponent,
15123
+ updateComponentAttachment,
15124
+ updateComponentTypeAttachment,
15049
15125
  updateIssue,
15050
- updateLicense,
15126
+ updateIssueAttachment,
15051
15127
  updateOrCreateProject,
15052
15128
  updateOrCreateUserFormSubmission,
15053
15129
  updateOrganizationAccess,