@overmap-ai/core 1.0.48-add-agent-response-rating.1 → 1.0.48-bulk-form-submission.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.
Files changed (32) hide show
  1. package/README.md +4 -4
  2. package/dist/components/ImageCard/ImageCard.d.ts +1 -1
  3. package/dist/forms/builder/hooks.d.ts +2 -1
  4. package/dist/forms/renderer/FormSubmissionBrowser/FormSubmissionBrowser.d.ts +5 -5
  5. package/dist/forms/renderer/FormSubmissionViewer/FormSubmissionViewer.d.ts +3 -3
  6. package/dist/overmap-core.js +1028 -533
  7. package/dist/overmap-core.js.map +1 -1
  8. package/dist/overmap-core.umd.cjs +1027 -532
  9. package/dist/overmap-core.umd.cjs.map +1 -1
  10. package/dist/sdk/sdk.d.ts +2 -1
  11. package/dist/sdk/services/IssueCommentService.d.ts +2 -2
  12. package/dist/sdk/services/IssueUpdateService.d.ts +4 -0
  13. package/dist/sdk/services/UserFormSubmissionService.d.ts +9 -2
  14. package/dist/sdk/services/index.d.ts +1 -0
  15. package/dist/store/slices/categorySlice.d.ts +3 -1
  16. package/dist/store/slices/componentSlice.d.ts +1 -0
  17. package/dist/store/slices/componentStageSlice.d.ts +2 -0
  18. package/dist/store/slices/documentSlice.d.ts +3 -1
  19. package/dist/store/slices/formRevisionSlice.d.ts +73 -0
  20. package/dist/store/slices/formSubmissionSlice.d.ts +46 -0
  21. package/dist/store/slices/index.d.ts +2 -0
  22. package/dist/store/slices/issueSlice.d.ts +24 -4
  23. package/dist/store/slices/projectFileSlice.d.ts +3 -1
  24. package/dist/store/slices/userFormSlice.d.ts +38 -63
  25. package/dist/store/slices/workspaceSlice.d.ts +3 -1
  26. package/dist/store/store.d.ts +10 -4
  27. package/dist/typings/models/access.d.ts +1 -1
  28. package/dist/typings/models/attachments.d.ts +3 -1
  29. package/dist/typings/models/base.d.ts +7 -0
  30. package/dist/typings/models/forms.d.ts +3 -6
  31. package/dist/typings/models/issues.d.ts +35 -1
  32. package/package.json +152 -152
@@ -8,7 +8,7 @@ var _a;
8
8
  import * as React from "react";
9
9
  import React__default, { useState, useEffect, useRef, memo, useMemo, useCallback, createContext, createElement, useContext, forwardRef, Children, isValidElement, cloneElement, Fragment as Fragment$1, useLayoutEffect, useReducer, lazy, Suspense } from "react";
10
10
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
11
- import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex as Flex$1, IconButton, RiIcon, Text as Text$1, useSeverityColor, Checkbox, TextArea, Select, useToast, Badge, MultiSelect, useViewportSize, Overlay, ButtonGroup, Spinner, IconColorUtility, Tooltip, Popover, useSize, ToggleButton, Separator, OvermapItem, Button, ButtonList, divButtonProps, DropdownItemMenu, Input, useAlertDialog } from "@overmap-ai/blocks";
11
+ import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex as Flex$1, IconButton, RiIcon, Text as Text$1, useSeverityColor, Checkbox, TextArea, Select, useToast, Badge, MultiSelect, useViewportSize, Overlay, ButtonGroup, Spinner, IconColorUtility, Tooltip, Popover, useSize, ToggleButton, Separator, OvermapItem, Button, ButtonList, divButtonProps, OvermapDropdownMenu, Input, useAlertDialog } from "@overmap-ai/blocks";
12
12
  import { DepGraph } from "dependency-graph";
13
13
  import { offline as offline$1 } from "@redux-offline/redux-offline";
14
14
  import offlineConfig from "@redux-offline/redux-offline/lib/defaults";
@@ -631,15 +631,15 @@ const wrapMigration = (migrator) => (state) => {
631
631
  };
632
632
  const migrations = [initialVersioning, signOut, signOut, createOutboxState];
633
633
  const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
634
- const initialState$n = {
634
+ const initialState$p = {
635
635
  accessToken: "",
636
636
  refreshToken: "",
637
637
  isLoggedIn: false
638
638
  };
639
639
  const authSlice = createSlice({
640
640
  name: "auth",
641
- initialState: initialState$n,
642
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
641
+ initialState: initialState$p,
642
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$p)),
643
643
  reducers: {
644
644
  setTokens: (state, action) => {
645
645
  state.accessToken = action.payload.accessToken;
@@ -1370,7 +1370,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
1370
1370
  return getLocalDateString(date);
1371
1371
  return relative.format(days, "days");
1372
1372
  });
1373
- const initialState$m = {
1373
+ const initialState$o = {
1374
1374
  categories: {},
1375
1375
  usedCategoryColors: [],
1376
1376
  categoryVisibility: {
@@ -1380,8 +1380,8 @@ const initialState$m = {
1380
1380
  };
1381
1381
  const categorySlice = createSlice({
1382
1382
  name: "categories",
1383
- initialState: initialState$m,
1384
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
1383
+ initialState: initialState$o,
1384
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$o)),
1385
1385
  reducers: {
1386
1386
  setCategories: (state, action) => {
1387
1387
  if (!Array.isArray(action.payload))
@@ -1549,14 +1549,14 @@ function removeAttachments(state, action) {
1549
1549
  delete state.attachments[attachmentId];
1550
1550
  }
1551
1551
  }
1552
- const initialState$l = {
1552
+ const initialState$n = {
1553
1553
  components: {},
1554
1554
  attachments: {}
1555
1555
  };
1556
1556
  const componentSlice = createSlice({
1557
1557
  name: "components",
1558
- initialState: initialState$l,
1559
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1558
+ initialState: initialState$n,
1559
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
1560
1560
  reducers: {
1561
1561
  addComponent: (state, action) => {
1562
1562
  state.components[action.payload.offline_id] = action.payload;
@@ -1610,6 +1610,7 @@ const selectComponents = (state) => {
1610
1610
  }
1611
1611
  return prevComponents;
1612
1612
  };
1613
+ const selectComponentsMapping = (state) => state.componentReducer.components;
1613
1614
  const selectComponentsFromComponentType = (componentTypeId) => (state) => {
1614
1615
  if (!componentTypeId)
1615
1616
  return [];
@@ -1640,16 +1641,14 @@ const selectComponentTypeFromComponents = (state) => {
1640
1641
  }
1641
1642
  return ret;
1642
1643
  };
1643
- const selectComponentsByType = (componentTypeId) => (state) => {
1644
- const components = state.componentReducer.components;
1645
- const componentsOfType = [];
1646
- for (const component of Object.values(components)) {
1647
- if (component.component_type === componentTypeId) {
1648
- componentsOfType.push(component);
1644
+ const selectComponentsByType = restructureCreateSelectorWithArgs(
1645
+ createSelector(
1646
+ [selectComponents, (_state, componentTypeId) => componentTypeId],
1647
+ (components, componentTypeId) => {
1648
+ return components.filter((component) => component.component_type === componentTypeId);
1649
1649
  }
1650
- }
1651
- return componentsOfType;
1652
- };
1650
+ )
1651
+ );
1653
1652
  const selectNumberOfComponentsOfComponentType = (componentTypeId) => (state) => {
1654
1653
  var _a2;
1655
1654
  if (!componentTypeId)
@@ -1710,13 +1709,13 @@ const {
1710
1709
  removeAllComponentsOfType
1711
1710
  } = componentSlice.actions;
1712
1711
  const componentReducer = componentSlice.reducer;
1713
- const initialState$k = {
1712
+ const initialState$m = {
1714
1713
  completionsByComponentId: {}
1715
1714
  };
1716
1715
  const componentStageCompletionSlice = createSlice({
1717
1716
  name: "componentStageCompletions",
1718
- initialState: initialState$k,
1719
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1717
+ initialState: initialState$m,
1718
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
1720
1719
  reducers: {
1721
1720
  addStageCompletion: (state, action) => {
1722
1721
  let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
@@ -1767,13 +1766,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
1767
1766
  return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
1768
1767
  };
1769
1768
  const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
1770
- const initialState$j = {
1769
+ const initialState$l = {
1771
1770
  stages: {}
1772
1771
  };
1773
1772
  const componentStageSlice = createSlice({
1774
1773
  name: "componentStages",
1775
- initialState: initialState$j,
1776
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1774
+ initialState: initialState$l,
1775
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1777
1776
  reducers: {
1778
1777
  addStages: (state, action) => {
1779
1778
  Object.assign(state.stages, toOfflineIdRecord(action.payload));
@@ -1807,6 +1806,11 @@ const componentStageSlice = createSlice({
1807
1806
  }
1808
1807
  });
1809
1808
  const selectStageMapping = (state) => state.componentStageReducer.stages;
1809
+ const selectStage = restructureCreateSelectorWithArgs(
1810
+ createSelector([selectStageMapping, (_state, stageId) => stageId], (stageMapping, stageId) => {
1811
+ return stageMapping[stageId];
1812
+ })
1813
+ );
1810
1814
  const selectStages = createSelector(
1811
1815
  [selectStageMapping],
1812
1816
  (stageMapping) => {
@@ -1834,6 +1838,20 @@ const selectStagesFromComponentTypeIds = restructureCreateSelectorWithArgs(
1834
1838
  }
1835
1839
  )
1836
1840
  );
1841
+ const selectComponentTypeStagesMapping = restructureCreateSelectorWithArgs(
1842
+ createSelector(
1843
+ [selectStageMapping, (_state, componentTypeId) => componentTypeId],
1844
+ (stagesMapping, componentTypeId) => {
1845
+ const componentTypeStagesMapping = {};
1846
+ for (const [stageId, stage] of Object.entries(stagesMapping)) {
1847
+ if (stage.component_type === componentTypeId) {
1848
+ componentTypeStagesMapping[stageId] = stage;
1849
+ }
1850
+ }
1851
+ return componentTypeStagesMapping;
1852
+ }
1853
+ )
1854
+ );
1837
1855
  const selectStagesFromComponentType = restructureCreateSelectorWithArgs(
1838
1856
  createSelector(
1839
1857
  [selectStages, (_state, componentTypeId) => componentTypeId],
@@ -1864,15 +1882,15 @@ const selectStageFormIdsFromStageIds = restructureCreateSelectorWithArgs(
1864
1882
  );
1865
1883
  const { addStages, updateStages, removeStages, linkStageToForm, unlinkStageToForm } = componentStageSlice.actions;
1866
1884
  const componentStageReducer = componentStageSlice.reducer;
1867
- const initialState$i = {
1885
+ const initialState$k = {
1868
1886
  componentTypes: {},
1869
1887
  hiddenComponentTypeIds: {},
1870
1888
  attachments: {}
1871
1889
  };
1872
1890
  const componentTypeSlice = createSlice({
1873
1891
  name: "componentTypes",
1874
- initialState: initialState$i,
1875
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1892
+ initialState: initialState$k,
1893
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1876
1894
  reducers: {
1877
1895
  addComponentType: (state, action) => {
1878
1896
  state.componentTypes[action.payload.offline_id] = action.payload;
@@ -1980,13 +1998,13 @@ const {
1980
1998
  deleteComponentType
1981
1999
  } = componentTypeSlice.actions;
1982
2000
  const componentTypeReducer = componentTypeSlice.reducer;
1983
- const initialState$h = {
2001
+ const initialState$j = {
1984
2002
  workspaces: {},
1985
2003
  activeWorkspaceId: null
1986
2004
  };
1987
2005
  const workspaceSlice = createSlice({
1988
2006
  name: "workspace",
1989
- initialState: initialState$h,
2007
+ initialState: initialState$j,
1990
2008
  // The `reducers` field lets us define reducers and generate associated actions
1991
2009
  reducers: {
1992
2010
  setWorkspaces: (state, action) => {
@@ -2043,10 +2061,11 @@ const selectPermittedWorkspaceIds = createSelector(
2043
2061
  );
2044
2062
  const workspaceReducer = workspaceSlice.reducer;
2045
2063
  const maxRecentIssues = 10;
2046
- const initialState$g = {
2064
+ const initialState$i = {
2047
2065
  issues: {},
2048
2066
  attachments: {},
2049
2067
  comments: {},
2068
+ updates: {},
2050
2069
  visibleStatuses: [IssueStatus.BACKLOG, IssueStatus.SELECTED],
2051
2070
  visibleUserIds: null,
2052
2071
  recentIssueIds: [],
@@ -2054,9 +2073,9 @@ const initialState$g = {
2054
2073
  };
2055
2074
  const issueSlice = createSlice({
2056
2075
  name: "issues",
2057
- initialState: initialState$g,
2076
+ initialState: initialState$i,
2058
2077
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
2059
- Object.assign(state, initialState$g);
2078
+ Object.assign(state, initialState$i);
2060
2079
  }),
2061
2080
  reducers: {
2062
2081
  setIssues: (state, action) => {
@@ -2068,6 +2087,16 @@ const issueSlice = createSlice({
2068
2087
  });
2069
2088
  },
2070
2089
  setIssueAttachments: setAttachments,
2090
+ setIssueUpdates: (state, action) => {
2091
+ if (action.payload.filter(onlyUniqueOfflineIds).length !== action.payload.length) {
2092
+ throw new Error("Tried to use setIssues reducer with duplicate ID's");
2093
+ }
2094
+ const newUpdates = {};
2095
+ for (const update of action.payload) {
2096
+ newUpdates[update.offline_id] = update;
2097
+ }
2098
+ state.updates = newUpdates;
2099
+ },
2071
2100
  setActiveIssueId: (state, action) => {
2072
2101
  state.activeIssueId = action.payload;
2073
2102
  },
@@ -2079,6 +2108,17 @@ const issueSlice = createSlice({
2079
2108
  },
2080
2109
  addIssueAttachment: addAttachment,
2081
2110
  addIssueAttachments: addAttachments,
2111
+ addIssueUpdate: (state, action) => {
2112
+ if (action.payload.offline_id in state.updates) {
2113
+ throw new Error(`Tried to add duplicate issue update with offline_id: ${action.payload.offline_id}`);
2114
+ }
2115
+ state.updates[action.payload.offline_id] = action.payload;
2116
+ },
2117
+ addIssueUpdates: (state, action) => {
2118
+ for (const update of action.payload) {
2119
+ state.updates[update.offline_id] = update;
2120
+ }
2121
+ },
2082
2122
  updateIssue: (state, action) => {
2083
2123
  if (action.payload.offline_id in state.issues) {
2084
2124
  state.issues[action.payload.offline_id] = {
@@ -2098,6 +2138,18 @@ const issueSlice = createSlice({
2098
2138
  }
2099
2139
  },
2100
2140
  removeIssueAttachment: removeAttachment,
2141
+ removeIssueUpdate: (state, action) => {
2142
+ if (action.payload in state.updates) {
2143
+ delete state.updates[action.payload];
2144
+ } else {
2145
+ throw new Error(`Failed to remove issue update because offline_id doesn't exist: ${action.payload}`);
2146
+ }
2147
+ },
2148
+ removeIssueUpdates: (state, action) => {
2149
+ for (const updateId of action.payload) {
2150
+ delete state.updates[updateId];
2151
+ }
2152
+ },
2101
2153
  removeAttachmentsOfIssue: (state, action) => {
2102
2154
  const attachments = Object.values(state.attachments).filter((a) => a.issue === action.payload);
2103
2155
  for (const attachment of attachments) {
@@ -2110,20 +2162,55 @@ const issueSlice = createSlice({
2110
2162
  setVisibleUserIds: (state, action) => {
2111
2163
  state.visibleUserIds = [...new Set(action.payload)];
2112
2164
  },
2113
- setIssueComments: (state, action) => {
2165
+ // Comments
2166
+ addIssueComment: (state, action) => {
2167
+ if (action.payload.offline_id in state.comments) {
2168
+ throw new Error(
2169
+ `Tried to add issue comment with offline_id: ${action.payload.offline_id} that already exists`
2170
+ );
2171
+ }
2172
+ state.comments[action.payload.offline_id] = action.payload;
2173
+ },
2174
+ addIssueComments: (state, action) => {
2175
+ for (const comment of action.payload) {
2176
+ if (comment.offline_id in state.comments) {
2177
+ throw new Error(
2178
+ `Tried to add issue comment with offline_id: ${comment.offline_id} that already exists`
2179
+ );
2180
+ }
2181
+ }
2114
2182
  for (const comment of action.payload) {
2115
2183
  state.comments[comment.offline_id] = comment;
2116
2184
  }
2117
2185
  },
2186
+ setIssueComment: (state, action) => {
2187
+ state.comments[action.payload.offline_id] = action.payload;
2188
+ },
2189
+ setIssueComments: (state, action) => {
2190
+ const newComments = {};
2191
+ for (const comment of action.payload) {
2192
+ newComments[comment.offline_id] = comment;
2193
+ }
2194
+ state.comments = newComments;
2195
+ },
2118
2196
  addOrReplaceIssueComment: (state, action) => {
2119
2197
  state.comments[action.payload.offline_id] = action.payload;
2120
2198
  },
2121
2199
  removeIssueComment: (state, action) => {
2122
- if (action.payload in state.comments) {
2123
- delete state.comments[action.payload];
2124
- } else {
2200
+ if (!(action.payload in state.comments)) {
2125
2201
  throw new Error(`Failed to remove issue comment because ID doesn't exist: ${action.payload}`);
2126
2202
  }
2203
+ delete state.comments[action.payload];
2204
+ },
2205
+ removeIssueComments: (state, action) => {
2206
+ for (const commentId of action.payload) {
2207
+ if (!(commentId in state.comments)) {
2208
+ throw new Error(`Failed to remove issue comment because ID doesn't exist: ${commentId}`);
2209
+ }
2210
+ }
2211
+ for (const commentId of action.payload) {
2212
+ delete state.comments[commentId];
2213
+ }
2127
2214
  },
2128
2215
  cleanRecentIssues: (state) => {
2129
2216
  state.recentIssueIds = state.recentIssueIds.filter((recentIssue) => state.issues[recentIssue.offlineId]);
@@ -2154,23 +2241,33 @@ const {
2154
2241
  addIssueAttachment,
2155
2242
  addIssueAttachments,
2156
2243
  addIssue,
2244
+ addIssueUpdate,
2245
+ addIssueUpdates,
2157
2246
  addOrReplaceIssueComment,
2158
2247
  addToRecentIssues,
2159
2248
  cleanRecentIssues,
2160
2249
  removeIssueAttachment,
2161
2250
  removeAttachmentsOfIssue,
2162
2251
  removeIssue,
2163
- removeIssueComment,
2252
+ removeIssueUpdate,
2253
+ removeIssueUpdates,
2164
2254
  removeRecentIssue,
2165
2255
  resetRecentIssues,
2166
2256
  setActiveIssueId,
2167
2257
  setIssueAttachments,
2168
- setIssueComments,
2258
+ setIssueUpdates,
2169
2259
  setIssues,
2170
2260
  setVisibleStatuses,
2171
2261
  setVisibleUserIds,
2172
2262
  updateIssueAttachment,
2173
- updateIssue
2263
+ updateIssue,
2264
+ // Commments
2265
+ addIssueComment,
2266
+ addIssueComments,
2267
+ setIssueComment,
2268
+ setIssueComments,
2269
+ removeIssueComment,
2270
+ removeIssueComments
2174
2271
  } = issueSlice.actions;
2175
2272
  const selectIssueMapping = (state) => state.issueReducer.issues;
2176
2273
  const selectRecentIssueIds = (state) => state.issueReducer.recentIssueIds;
@@ -2241,6 +2338,12 @@ const selectCommentsOfIssue = restructureCreateSelectorWithArgs(
2241
2338
  return Object.values(commentMapping).filter((comment) => comment.issue === issueId);
2242
2339
  })
2243
2340
  );
2341
+ const selectIssueUpdateMapping = (state) => state.issueReducer.updates;
2342
+ const selectIssueUpdatesOfIssue = restructureCreateSelectorWithArgs(
2343
+ createSelector([selectIssueUpdateMapping, (_state, issueId) => issueId], (updates, issueId) => {
2344
+ return Object.values(updates).filter((update) => update.issue === issueId);
2345
+ })
2346
+ );
2244
2347
  const selectAttachmentsOfIssue = restructureCreateSelectorWithArgs(
2245
2348
  createSelector(
2246
2349
  [selectIssueAttachments, (_state, issueId) => issueId],
@@ -2377,15 +2480,15 @@ const selectRecentIssuesAsSearchResults = createSelector(
2377
2480
  }
2378
2481
  );
2379
2482
  const issueReducer = issueSlice.reducer;
2380
- const initialState$f = {
2483
+ const initialState$h = {
2381
2484
  s3Urls: {}
2382
2485
  };
2383
2486
  const msPerHour = 1e3 * 60 * 60;
2384
2487
  const msPerWeek = msPerHour * 24 * 7;
2385
2488
  const fileSlice = createSlice({
2386
2489
  name: "file",
2387
- initialState: initialState$f,
2388
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
2490
+ initialState: initialState$h,
2491
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
2389
2492
  reducers: {
2390
2493
  setUploadUrl: (state, action) => {
2391
2494
  const { url, fields, sha1 } = action.payload;
@@ -2412,7 +2515,7 @@ const selectUploadUrl = (sha1) => (state) => {
2412
2515
  return url;
2413
2516
  };
2414
2517
  const fileReducer = fileSlice.reducer;
2415
- const initialState$e = {
2518
+ const initialState$g = {
2416
2519
  // TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
2417
2520
  mapStyle: MapStyle.SATELLITE,
2418
2521
  showTooltips: false,
@@ -2420,8 +2523,8 @@ const initialState$e = {
2420
2523
  };
2421
2524
  const mapSlice = createSlice({
2422
2525
  name: "map",
2423
- initialState: initialState$e,
2424
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2526
+ initialState: initialState$g,
2527
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
2425
2528
  reducers: {
2426
2529
  setMapStyle: (state, action) => {
2427
2530
  state.mapStyle = action.payload;
@@ -2449,6 +2552,16 @@ var OrganizationAccessLevel = /* @__PURE__ */ ((OrganizationAccessLevel2) => {
2449
2552
  OrganizationAccessLevel2[OrganizationAccessLevel2["ADMIN"] = 2] = "ADMIN";
2450
2553
  return OrganizationAccessLevel2;
2451
2554
  })(OrganizationAccessLevel || {});
2555
+ var IssueUpdateChange = /* @__PURE__ */ ((IssueUpdateChange2) => {
2556
+ IssueUpdateChange2["STATUS"] = "status";
2557
+ IssueUpdateChange2["PRIORITY"] = "priority";
2558
+ IssueUpdateChange2["CATEGORY"] = "category";
2559
+ IssueUpdateChange2["DESCRIPTION"] = "description";
2560
+ IssueUpdateChange2["TITLE"] = "title";
2561
+ IssueUpdateChange2["ASSIGNED_TO"] = "assigned_to";
2562
+ IssueUpdateChange2["DUE_DATE"] = "due_date";
2563
+ return IssueUpdateChange2;
2564
+ })(IssueUpdateChange || {});
2452
2565
  var ProjectType = /* @__PURE__ */ ((ProjectType2) => {
2453
2566
  ProjectType2[ProjectType2["PERSONAL"] = 0] = "PERSONAL";
2454
2567
  ProjectType2[ProjectType2["ORGANIZATION"] = 2] = "ORGANIZATION";
@@ -2480,7 +2593,7 @@ var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
2480
2593
  LicenseStatus2[LicenseStatus2["PAST_DUE"] = 8] = "PAST_DUE";
2481
2594
  return LicenseStatus2;
2482
2595
  })(LicenseStatus || {});
2483
- const initialState$d = {
2596
+ const initialState$f = {
2484
2597
  users: {},
2485
2598
  currentUser: {
2486
2599
  id: 0,
@@ -2491,8 +2604,8 @@ const initialState$d = {
2491
2604
  };
2492
2605
  const userSlice = createSlice({
2493
2606
  name: "users",
2494
- initialState: initialState$d,
2495
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2607
+ initialState: initialState$f,
2608
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
2496
2609
  reducers: {
2497
2610
  setUsers: (state, action) => {
2498
2611
  const usersMapping = {};
@@ -2554,13 +2667,13 @@ const selectUser = (userId) => (state) => {
2554
2667
  const selectUsersAsMapping = (state) => state.userReducer.users;
2555
2668
  const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
2556
2669
  const userReducer = userSlice.reducer;
2557
- const initialState$c = {
2670
+ const initialState$e = {
2558
2671
  organizationAccesses: {}
2559
2672
  };
2560
2673
  const organizationAccessSlice = createSlice({
2561
2674
  name: "organizationAccess",
2562
- initialState: initialState$c,
2563
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2675
+ initialState: initialState$e,
2676
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2564
2677
  reducers: {
2565
2678
  setOrganizationAccesses: (state, action) => {
2566
2679
  if (!Array.isArray(action.payload))
@@ -2623,13 +2736,13 @@ const selectOrganizationAccessUserMapping = (state) => {
2623
2736
  return organizationAccesses;
2624
2737
  };
2625
2738
  const organizationAccessReducer = organizationAccessSlice.reducer;
2626
- const initialState$b = {
2739
+ const initialState$d = {
2627
2740
  licenses: {}
2628
2741
  };
2629
2742
  const licenseSlice = createSlice({
2630
2743
  name: "license",
2631
- initialState: initialState$b,
2632
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2744
+ initialState: initialState$d,
2745
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2633
2746
  reducers: {
2634
2747
  setLicenses: (state, action) => {
2635
2748
  if (!Array.isArray(action.payload))
@@ -2674,13 +2787,13 @@ const selectLicensesForProjectsMapping = createSelector(
2674
2787
  (licenses) => Object.values(licenses).filter((license) => license.project).reduce((accum, license) => ({ ...accum, [license.project]: license }), {})
2675
2788
  );
2676
2789
  const licenseReducer = licenseSlice.reducer;
2677
- const initialState$a = {
2790
+ const initialState$c = {
2678
2791
  projectAccesses: {}
2679
2792
  };
2680
2793
  const projectAccessSlice = createSlice({
2681
2794
  name: "projectAccess",
2682
- initialState: initialState$a,
2683
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2795
+ initialState: initialState$c,
2796
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2684
2797
  reducers: {
2685
2798
  setProjectAccesses: (state, action) => {
2686
2799
  if (!Array.isArray(action.payload))
@@ -2748,7 +2861,7 @@ const selectProjectAccessUserMapping = (state) => {
2748
2861
  return projectAccesses;
2749
2862
  };
2750
2863
  const projectAccessReducer = projectAccessSlice.reducer;
2751
- const initialState$9 = {
2864
+ const initialState$b = {
2752
2865
  projects: {},
2753
2866
  activeProjectId: null,
2754
2867
  recentProjectIds: [],
@@ -2758,7 +2871,7 @@ const initialState$9 = {
2758
2871
  };
2759
2872
  const projectSlice = createSlice({
2760
2873
  name: "projects",
2761
- initialState: initialState$9,
2874
+ initialState: initialState$b,
2762
2875
  reducers: {
2763
2876
  setProjects: (state, action) => {
2764
2877
  const projectsMap = {};
@@ -2945,14 +3058,14 @@ const selectAttachmentsOfProjectByType = restructureCreateSelectorWithArgs(
2945
3058
  }
2946
3059
  )
2947
3060
  );
2948
- const initialState$8 = {
3061
+ const initialState$a = {
2949
3062
  organizations: {},
2950
3063
  activeOrganizationId: null
2951
3064
  };
2952
3065
  const organizationSlice = createSlice({
2953
3066
  name: "organizations",
2954
- initialState: initialState$8,
2955
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
3067
+ initialState: initialState$a,
3068
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2956
3069
  reducers: {
2957
3070
  setOrganizations: (state, action) => {
2958
3071
  for (const org of action.payload) {
@@ -3071,14 +3184,14 @@ const createOfflineAction = (request2, baseUrl) => {
3071
3184
  }
3072
3185
  };
3073
3186
  };
3074
- const initialState$7 = {
3187
+ const initialState$9 = {
3075
3188
  deletedRequests: [],
3076
3189
  latestRetryTime: 0
3077
3190
  };
3078
3191
  const outboxSlice = createSlice({
3079
3192
  name: "outbox",
3080
- initialState: initialState$7,
3081
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
3193
+ initialState: initialState$9,
3194
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
3082
3195
  reducers: {
3083
3196
  // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
3084
3197
  // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
@@ -3110,7 +3223,7 @@ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
3110
3223
  const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
3111
3224
  const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
3112
3225
  const outboxReducer = outboxSlice.reducer;
3113
- const initialState$6 = {
3226
+ const initialState$8 = {
3114
3227
  projectFiles: {},
3115
3228
  activeProjectFileId: null,
3116
3229
  isImportingProjectFile: false,
@@ -3118,8 +3231,8 @@ const initialState$6 = {
3118
3231
  };
3119
3232
  const projectFileSlice = createSlice({
3120
3233
  name: "projectFiles",
3121
- initialState: initialState$6,
3122
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
3234
+ initialState: initialState$8,
3235
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
3123
3236
  reducers: {
3124
3237
  addOrReplaceProjectFiles: (state, action) => {
3125
3238
  for (let fileObj of action.payload) {
@@ -3220,12 +3333,12 @@ const selectProjectFiles = createSelector(
3220
3333
  const selectActiveProjectFileId = (state) => state.projectFileReducer.activeProjectFileId;
3221
3334
  const selectIsImportingProjectFile = (state) => state.projectFileReducer.isImportingProjectFile;
3222
3335
  const projectFileReducer = projectFileSlice.reducer;
3223
- const initialState$5 = {
3336
+ const initialState$7 = {
3224
3337
  isRehydrated: false
3225
3338
  };
3226
3339
  const rehydratedSlice = createSlice({
3227
3340
  name: "rehydrated",
3228
- initialState: initialState$5,
3341
+ initialState: initialState$7,
3229
3342
  // The `reducers` field lets us define reducers and generate associated actions
3230
3343
  reducers: {
3231
3344
  setRehydrated: (state, action) => {
@@ -3235,7 +3348,7 @@ const rehydratedSlice = createSlice({
3235
3348
  });
3236
3349
  const selectRehydrated = (state) => state.rehydratedReducer.isRehydrated;
3237
3350
  const rehydratedReducer = rehydratedSlice.reducer;
3238
- const initialState$4 = {
3351
+ const initialState$6 = {
3239
3352
  useIssueTemplate: false,
3240
3353
  placementMode: false,
3241
3354
  enableClustering: false,
@@ -3252,8 +3365,8 @@ const initialState$4 = {
3252
3365
  };
3253
3366
  const settingSlice = createSlice({
3254
3367
  name: "settings",
3255
- initialState: initialState$4,
3256
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
3368
+ initialState: initialState$6,
3369
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
3257
3370
  reducers: {
3258
3371
  setEnableDuplicateIssues: (state, action) => {
3259
3372
  state.useIssueTemplate = action.payload;
@@ -3299,146 +3412,248 @@ const selectAppearance = (state) => state.settingReducer.appearance;
3299
3412
  const settingReducer = settingSlice.reducer;
3300
3413
  const selectIsFetchingInitialData = (state) => state.settingReducer.isFetchingInitialData;
3301
3414
  const selectIsLoading = (state) => state.settingReducer.isLoading;
3302
- const LATEST_REVISION_CACHE = {};
3303
- function considerCachingRevision(revision, formId2, preferPending = false) {
3415
+ const LATEST_FORM_REVISION_CACHE = {};
3416
+ function considerCachingFormRevision(formRevision, formId2, preferPending = false) {
3304
3417
  var _a2;
3305
- if (!revision) {
3418
+ if (!formRevision) {
3306
3419
  if (!formId2) {
3307
- throw new Error("If revision is null, formId is required.");
3420
+ throw new Error("If form revision is null, formId is required.");
3308
3421
  }
3309
- const currentLatestRevision = getLatestRevisionFromCache(formId2);
3310
- if (currentLatestRevision)
3422
+ const currentLatestFormRevision = getLatestFormRevisionFromCache(formId2);
3423
+ if (currentLatestFormRevision)
3311
3424
  return;
3312
- LATEST_REVISION_CACHE[formId2] = null;
3425
+ LATEST_FORM_REVISION_CACHE[formId2] = null;
3313
3426
  return;
3314
3427
  }
3315
- if (revision.revision === "Pending") {
3428
+ if (formRevision.revision === "Pending") {
3316
3429
  if (preferPending) {
3317
- LATEST_REVISION_CACHE[revision.form] = revision;
3430
+ LATEST_FORM_REVISION_CACHE[formRevision.form] = formRevision;
3318
3431
  }
3319
3432
  return;
3320
3433
  }
3321
- const cachedRevision = (_a2 = LATEST_REVISION_CACHE[revision.form]) == null ? void 0 : _a2.revision;
3322
- if (revision.revision > (typeof cachedRevision === "number" ? cachedRevision : -1)) {
3323
- LATEST_REVISION_CACHE[revision.form] = revision;
3434
+ const cachedFormRevision = (_a2 = LATEST_FORM_REVISION_CACHE[formRevision.form]) == null ? void 0 : _a2.revision;
3435
+ if (formRevision.revision > (typeof cachedFormRevision === "number" ? cachedFormRevision : -1)) {
3436
+ LATEST_FORM_REVISION_CACHE[formRevision.form] = formRevision;
3324
3437
  }
3325
3438
  }
3326
- function getLatestRevisionFromCache(formId2) {
3327
- return LATEST_REVISION_CACHE[formId2];
3439
+ function getLatestFormRevisionFromCache(formId2) {
3440
+ return LATEST_FORM_REVISION_CACHE[formId2];
3328
3441
  }
3329
- const initialState$3 = {
3330
- userForms: {},
3331
- revisions: {},
3332
- submissions: {},
3333
- submissionAttachments: {},
3334
- revisionAttachments: {}
3442
+ const initialState$5 = {
3443
+ formRevisions: {},
3444
+ attachments: {}
3335
3445
  };
3336
- const userFormSlice = createSlice({
3337
- name: "userForms",
3338
- initialState: initialState$3,
3339
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
3446
+ const formRevisionsSlice = createSlice({
3447
+ name: "formRevisions",
3448
+ initialState: initialState$5,
3449
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
3340
3450
  reducers: {
3341
- setUserForms: (state, action) => {
3342
- state.userForms = {};
3343
- action.payload.forEach((userForm) => {
3344
- state.userForms[userForm.offline_id] = userForm;
3345
- });
3451
+ // revision related actions
3452
+ setFormRevision: (state, action) => {
3453
+ state.formRevisions[action.payload.offline_id] = action.payload;
3454
+ considerCachingFormRevision(action.payload);
3346
3455
  },
3347
- addUserForm: (state, action) => {
3348
- state.userForms[action.payload.offline_id] = action.payload;
3349
- },
3350
- addUserForms: (state, action) => {
3351
- action.payload.forEach((userForm) => {
3352
- state.userForms[userForm.offline_id] = userForm;
3353
- });
3354
- },
3355
- addUserFormRevisions: (state, action) => {
3356
- action.payload.forEach((userFormRevision) => {
3357
- state.revisions[userFormRevision.offline_id] = userFormRevision;
3358
- considerCachingRevision(userFormRevision);
3359
- });
3360
- },
3361
- addUserFormRevision: (state, action) => {
3362
- state.revisions[action.payload.offline_id] = action.payload;
3363
- considerCachingRevision(action.payload);
3456
+ setFormRevisions: (state, action) => {
3457
+ state.formRevisions = {};
3458
+ for (const revision of action.payload) {
3459
+ state.formRevisions[revision.offline_id] = revision;
3460
+ considerCachingFormRevision(revision);
3461
+ }
3364
3462
  },
3365
- deleteUserFormRevision: (state, action) => {
3366
- delete state.revisions[action.payload];
3367
- delete LATEST_REVISION_CACHE[action.payload];
3463
+ addFormRevision: (state, action) => {
3464
+ if (state.formRevisions[action.payload.offline_id] !== void 0) {
3465
+ throw new Error(`Revision with offline_id ${action.payload.offline_id} already exists`);
3466
+ }
3467
+ state.formRevisions[action.payload.offline_id] = action.payload;
3468
+ considerCachingFormRevision(action.payload);
3368
3469
  },
3369
- deleteUserFormRevisions: (state, action) => {
3470
+ // TODO: @Audiopolis / Magnus - do we want to standardize using PayloadAction?
3471
+ addFormRevisions: (state, action) => {
3370
3472
  for (const userFormRevision of action.payload) {
3371
- delete state.revisions[userFormRevision.offline_id];
3372
- delete LATEST_REVISION_CACHE[userFormRevision.offline_id];
3473
+ if (state.formRevisions[userFormRevision.offline_id] !== void 0) {
3474
+ throw new Error(`Revision with offline_id ${userFormRevision.offline_id} already exists`);
3475
+ }
3476
+ }
3477
+ for (const userFormRevision of action.payload) {
3478
+ state.formRevisions[userFormRevision.offline_id] = userFormRevision;
3479
+ considerCachingFormRevision(userFormRevision);
3373
3480
  }
3374
3481
  },
3375
- updateOrCreateUserFormSubmission: (state, action) => {
3376
- state.submissions[action.payload.offline_id] = action.payload;
3377
- },
3378
- addUserFormSubmissionAttachment: (state, action) => {
3379
- const submissionId = action.payload.submission;
3380
- const submissionAttachments = state.submissionAttachments[submissionId];
3381
- if (submissionAttachments) {
3382
- submissionAttachments.push(action.payload);
3383
- } else {
3384
- state.submissionAttachments[submissionId] = [action.payload];
3482
+ // UserFormRevisions do not get updated
3483
+ deleteFormRevision: (state, action) => {
3484
+ if (state.formRevisions[action.payload] === void 0) {
3485
+ throw new Error(`Revision with offline_id ${action.payload} does not exist`);
3385
3486
  }
3487
+ delete state.formRevisions[action.payload];
3488
+ delete LATEST_FORM_REVISION_CACHE[action.payload];
3386
3489
  },
3387
- addUserFormRevisionAttachment: (state, action) => {
3388
- const revisionId = action.payload.revision;
3389
- const revisionAttachments = state.revisionAttachments[revisionId];
3390
- if (revisionAttachments) {
3391
- revisionAttachments.push(action.payload);
3392
- } else {
3393
- state.revisionAttachments[revisionId] = [action.payload];
3490
+ deleteFormRevisions: (state, action) => {
3491
+ for (const offlineId of action.payload) {
3492
+ if (state.formRevisions[offlineId] === void 0) {
3493
+ throw new Error(`Revision with offline_id ${offlineId} does not exist`);
3494
+ }
3495
+ }
3496
+ for (const offlineId of action.payload) {
3497
+ delete state.formRevisions[offlineId];
3498
+ delete LATEST_FORM_REVISION_CACHE[offlineId];
3394
3499
  }
3395
3500
  },
3396
- setUserFormSubmissionAttachments: (state, action) => {
3397
- state.submissionAttachments = {};
3501
+ // attachment related actions
3502
+ setFormRevisionAttachments: (state, action) => {
3503
+ state.attachments = {};
3398
3504
  for (const attachment of action.payload) {
3399
- const submissionId = attachment.submission;
3400
- const submissionAttachments = state.submissionAttachments[submissionId];
3401
- if (submissionAttachments) {
3402
- submissionAttachments.push(attachment);
3403
- } else {
3404
- state.submissionAttachments[submissionId] = [attachment];
3405
- }
3505
+ state.attachments[attachment.offline_id] = attachment;
3506
+ }
3507
+ },
3508
+ addFormRevisionAttachment: (state, action) => {
3509
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3510
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3406
3511
  }
3512
+ state.attachments[action.payload.offline_id] = action.payload;
3407
3513
  },
3408
- setUserFormRevisionAttachments: (state, action) => {
3409
- state.revisionAttachments = {};
3514
+ addFormRevisionAttachments: (state, action) => {
3410
3515
  for (const attachment of action.payload) {
3411
- const revisionId = attachment.revision;
3412
- const revisionAttachments = state.revisionAttachments[revisionId];
3413
- if (revisionAttachments) {
3414
- revisionAttachments.push(attachment);
3415
- } else {
3416
- state.revisionAttachments[revisionId] = [attachment];
3516
+ if (state.attachments[attachment.offline_id] !== void 0) {
3517
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3417
3518
  }
3418
3519
  }
3520
+ for (const attachment of action.payload) {
3521
+ state.attachments[attachment.offline_id] = attachment;
3522
+ }
3419
3523
  },
3420
- deleteUserFormSubmission: (state, action) => {
3421
- delete state.submissions[action.payload];
3422
- },
3423
- deleteUserFormSubmissions: (state, action) => {
3424
- for (const userFormSubmission of action.payload) {
3425
- delete state.submissions[userFormSubmission.offline_id];
3524
+ deleteFormRevisionAttachment: (state, action) => {
3525
+ if (state.attachments[action.payload] === void 0) {
3526
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3426
3527
  }
3528
+ delete state.attachments[action.payload];
3427
3529
  },
3428
- addUserFormSubmissions: (state, action) => {
3429
- for (const submission of action.payload) {
3430
- state.submissions[submission.offline_id] = submission;
3530
+ deleteFormRevisionAttachments: (state, action) => {
3531
+ for (const offlineId of action.payload) {
3532
+ if (state.attachments[offlineId] === void 0) {
3533
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3534
+ }
3535
+ }
3536
+ for (const offlineId of action.payload) {
3537
+ delete state.attachments[offlineId];
3431
3538
  }
3539
+ }
3540
+ }
3541
+ });
3542
+ const {
3543
+ setFormRevision,
3544
+ setFormRevisions,
3545
+ addFormRevision,
3546
+ addFormRevisions,
3547
+ deleteFormRevision,
3548
+ deleteFormRevisions,
3549
+ setFormRevisionAttachments,
3550
+ addFormRevisionAttachment,
3551
+ addFormRevisionAttachments,
3552
+ deleteFormRevisionAttachment,
3553
+ deleteFormRevisionAttachments
3554
+ } = formRevisionsSlice.actions;
3555
+ const selectFormRevisionMapping = (state) => state.formRevisionReducer.formRevisions;
3556
+ const selectFormRevisions = createSelector(
3557
+ [selectFormRevisionMapping],
3558
+ (formRevisions) => Object.values(formRevisions)
3559
+ );
3560
+ const selectUserFormRevision = (formRevisionId) => (state) => {
3561
+ return state.formRevisionReducer.formRevisions[formRevisionId];
3562
+ };
3563
+ const _selectLatestFormRevision = (formRevisions, formId2) => {
3564
+ let ret = null;
3565
+ for (const candidate of Object.values(formRevisions)) {
3566
+ if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
3567
+ ret = candidate;
3568
+ }
3569
+ }
3570
+ if (!ret) {
3571
+ throw new Error("No form revision found for form " + formId2);
3572
+ }
3573
+ return ret;
3574
+ };
3575
+ const selectLatestFormRevisionOfForm = restructureCreateSelectorWithArgs(
3576
+ createSelector([selectFormRevisionMapping, (_state, formId2) => formId2], (revisions, formId2) => {
3577
+ if (!formId2) {
3578
+ throw new Error("formId is required");
3579
+ }
3580
+ return _selectLatestFormRevision(revisions, formId2);
3581
+ })
3582
+ );
3583
+ const selectFormRevisionsOfForm = restructureCreateSelectorWithArgs(
3584
+ createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3585
+ return revisions.filter((revision) => {
3586
+ return revision.form === formId2;
3587
+ });
3588
+ })
3589
+ );
3590
+ const selectLatestFormRevisionsOfComponentTypes = restructureCreateSelectorWithArgs(
3591
+ createSelector(
3592
+ [
3593
+ selectUserFormMapping,
3594
+ selectFormRevisionMapping,
3595
+ (_state, componentTypeIds) => componentTypeIds
3596
+ ],
3597
+ (userForms, revisions, componentTypeIds) => {
3598
+ const componentTypeIdsSet = new Set(componentTypeIds);
3599
+ const ret = {};
3600
+ for (const form of Object.values(userForms)) {
3601
+ if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
3602
+ ret[form.component_type] = _selectLatestFormRevision(revisions, form.offline_id);
3603
+ }
3604
+ }
3605
+ return ret;
3606
+ }
3607
+ )
3608
+ );
3609
+ const selectLatestFormRevisionByForm = createSelector([selectFormRevisionMapping], (revisions) => {
3610
+ const latestRevisions = {};
3611
+ for (const revision of Object.values(revisions)) {
3612
+ const formId2 = revision.form;
3613
+ const currentLatestRevision = latestRevisions[formId2];
3614
+ if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
3615
+ latestRevisions[formId2] = revision;
3616
+ }
3617
+ }
3618
+ return latestRevisions;
3619
+ });
3620
+ const selectUserFormRevisionAttachmentsMapping = (state) => {
3621
+ return state.formRevisionReducer.attachments;
3622
+ };
3623
+ const selectAttachmentsOfFormRevision = restructureCreateSelectorWithArgs(
3624
+ createSelector(
3625
+ [selectUserFormRevisionAttachmentsMapping, (_state, revisionId) => revisionId],
3626
+ (attachments, revisionId) => {
3627
+ return Object.values(attachments).filter((attachment) => attachment.revision === revisionId);
3628
+ }
3629
+ )
3630
+ );
3631
+ const formRevisionReducer = formRevisionsSlice.reducer;
3632
+ const initialState$4 = {
3633
+ forms: {}
3634
+ };
3635
+ const userFormSlice = createSlice({
3636
+ name: "userForms",
3637
+ initialState: initialState$4,
3638
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
3639
+ reducers: {
3640
+ setForms: (state, action) => {
3641
+ state.forms = {};
3642
+ action.payload.forEach((userForm) => {
3643
+ state.forms[userForm.offline_id] = userForm;
3644
+ });
3645
+ },
3646
+ addForm: (state, action) => {
3647
+ state.forms[action.payload.offline_id] = action.payload;
3432
3648
  },
3433
- setUserFormSubmissions: (state, action) => {
3434
- state.submissions = {};
3435
- action.payload.forEach((submission) => {
3436
- state.submissions[submission.offline_id] = submission;
3649
+ addForms: (state, action) => {
3650
+ action.payload.forEach((userForm) => {
3651
+ state.forms[userForm.offline_id] = userForm;
3437
3652
  });
3438
3653
  },
3439
3654
  favoriteForm: (state, action) => {
3440
3655
  const { formId: formId2 } = action.payload;
3441
- const form = state.userForms[formId2];
3656
+ const form = state.forms[formId2];
3442
3657
  if (!form) {
3443
3658
  throw new Error("No form exists with the id " + formId2);
3444
3659
  }
@@ -3446,48 +3661,23 @@ const userFormSlice = createSlice({
3446
3661
  },
3447
3662
  unfavoriteForm: (state, action) => {
3448
3663
  const { formId: formId2 } = action.payload;
3449
- const form = state.userForms[formId2];
3664
+ const form = state.forms[formId2];
3450
3665
  if (!form) {
3451
3666
  throw new Error("No form exists with the id " + formId2);
3452
3667
  }
3453
3668
  form.favorite = false;
3454
3669
  },
3455
- deleteUserForm: (state, action) => {
3456
- delete state.userForms[action.payload];
3670
+ deleteForm: (state, action) => {
3671
+ delete state.forms[action.payload];
3457
3672
  }
3458
3673
  }
3459
3674
  });
3460
- const {
3461
- addUserForm,
3462
- addUserForms,
3463
- addUserFormRevisions,
3464
- updateOrCreateUserFormSubmission,
3465
- addUserFormSubmissions,
3466
- deleteUserFormSubmission,
3467
- deleteUserFormSubmissions,
3468
- favoriteForm,
3469
- unfavoriteForm,
3470
- deleteUserForm,
3471
- deleteUserFormRevision,
3472
- deleteUserFormRevisions,
3473
- setUserFormSubmissions,
3474
- addUserFormRevision,
3475
- addUserFormSubmissionAttachment,
3476
- addUserFormRevisionAttachment,
3477
- setUserFormSubmissionAttachments,
3478
- setUserFormRevisionAttachments
3479
- } = userFormSlice.actions;
3480
- const selectSubmissionAttachments = (submissionId) => (state) => {
3481
- return state.userFormReducer.submissionAttachments[submissionId] || [];
3482
- };
3483
- const selectRevisionAttachments = (revisionId) => (state) => {
3484
- return state.userFormReducer.revisionAttachments[revisionId] || [];
3485
- };
3675
+ const { setForms, addForm, addForms, favoriteForm, unfavoriteForm, deleteForm } = userFormSlice.actions;
3486
3676
  const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3487
3677
  createSelector(
3488
3678
  [
3489
- (state) => state.userFormReducer.userForms,
3490
- (state) => state.userFormReducer.revisions,
3679
+ (state) => state.userFormReducer.forms,
3680
+ (state) => state.formRevisionReducer.formRevisions,
3491
3681
  (_state, search) => search
3492
3682
  ],
3493
3683
  (userForms, revisions, search) => {
@@ -3514,67 +3704,184 @@ const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3514
3704
  break;
3515
3705
  }
3516
3706
  }
3517
- const maxRegularMatches = maxResults - favoriteMatches.length;
3518
- return [...favoriteMatches, ...regularMatches.slice(0, maxRegularMatches)];
3707
+ const maxRegularMatches = maxResults - favoriteMatches.length;
3708
+ return [...favoriteMatches, ...regularMatches.slice(0, maxRegularMatches)];
3709
+ },
3710
+ // as the argument is an object, we check the first level of properties for equality
3711
+ { memoizeOptions: { equalityCheck: shallowEqual$1 } }
3712
+ )
3713
+ );
3714
+ const selectUserForm = (formId2) => (state) => {
3715
+ return state.userFormReducer.forms[formId2];
3716
+ };
3717
+ const selectUserFormMapping = (state) => {
3718
+ return state.userFormReducer.forms;
3719
+ };
3720
+ const selectComponentTypeForm = restructureCreateSelectorWithArgs(
3721
+ createSelector(
3722
+ [selectUserFormMapping, (_state, componentTypeId) => componentTypeId],
3723
+ (userForms, componentTypeId) => {
3724
+ return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
3725
+ }
3726
+ )
3727
+ );
3728
+ const selectNumberOfUserForms = createSelector([selectUserFormMapping], (userForms) => {
3729
+ return Object.keys(userForms).length;
3730
+ });
3731
+ const selectNumberOfGeneralUserForms = createSelector([selectUserFormMapping], (userForms) => {
3732
+ return Object.values(userForms).filter((form) => !form.component_type).length;
3733
+ });
3734
+ const userFormReducer = userFormSlice.reducer;
3735
+ const initialState$3 = {
3736
+ formSubmissions: {},
3737
+ attachments: {}
3738
+ };
3739
+ const formSubmissionSlice = createSlice({
3740
+ name: "formSubmissions",
3741
+ initialState: initialState$3,
3742
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
3743
+ reducers: {
3744
+ setFormSubmission: (state, action) => {
3745
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3746
+ },
3747
+ setFormSubmissions: (state, action) => {
3748
+ state.formSubmissions = {};
3749
+ for (const submission of action.payload) {
3750
+ state.formSubmissions[submission.offline_id] = submission;
3751
+ }
3752
+ },
3753
+ addFormSubmission: (state, action) => {
3754
+ if (state.formSubmissions[action.payload.offline_id] !== void 0) {
3755
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} already exists`);
3756
+ }
3757
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3758
+ },
3759
+ addFormSubmissions: (state, action) => {
3760
+ for (const submission of action.payload) {
3761
+ if (state.formSubmissions[submission.offline_id] !== void 0) {
3762
+ throw new Error(`Submission with offline_id ${submission.offline_id} already exists`);
3763
+ }
3764
+ }
3765
+ for (const submission of action.payload) {
3766
+ state.formSubmissions[submission.offline_id] = submission;
3767
+ }
3768
+ },
3769
+ updateFormSubmission: (state, action) => {
3770
+ if (state.formSubmissions[action.payload.offline_id] === void 0) {
3771
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} does not exist`);
3772
+ }
3773
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3774
+ },
3775
+ updateFormSubmissions: (state, action) => {
3776
+ for (const submission of action.payload) {
3777
+ if (state.formSubmissions[submission.offline_id] === void 0) {
3778
+ throw new Error(`Submission with offline_id ${submission.offline_id} does not exist`);
3779
+ }
3780
+ }
3781
+ for (const submission of action.payload) {
3782
+ state.formSubmissions[submission.offline_id] = submission;
3783
+ }
3784
+ },
3785
+ deleteFormSubmission: (state, action) => {
3786
+ if (state.formSubmissions[action.payload] === void 0) {
3787
+ throw new Error(`Submission with offline_id ${action.payload} does not exist`);
3788
+ }
3789
+ delete state.formSubmissions[action.payload];
3790
+ },
3791
+ deleteFormSubmissions: (state, action) => {
3792
+ for (const offlineId of action.payload) {
3793
+ if (state.formSubmissions[offlineId] === void 0) {
3794
+ throw new Error(`Submission with offline_id ${offlineId} does not exist`);
3795
+ }
3796
+ delete state.formSubmissions[offlineId];
3797
+ }
3798
+ for (const offlineId of action.payload) {
3799
+ delete state.formSubmissions[offlineId];
3800
+ }
3801
+ },
3802
+ // Attachments
3803
+ addFormSubmissionAttachment: (state, action) => {
3804
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3805
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3806
+ }
3807
+ state.attachments[action.payload.offline_id] = action.payload;
3808
+ },
3809
+ addFormSubmissionAttachments: (state, action) => {
3810
+ for (const attachment of action.payload) {
3811
+ if (state.attachments[attachment.offline_id] !== void 0) {
3812
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3813
+ }
3814
+ }
3815
+ for (const attachment of action.payload) {
3816
+ state.attachments[attachment.offline_id] = attachment;
3817
+ }
3519
3818
  },
3520
- // as the argument is an object, we check the first level of properties for equality
3521
- { memoizeOptions: { equalityCheck: shallowEqual$1 } }
3522
- )
3523
- );
3524
- const selectFormRevision = (revisionId) => (state) => {
3525
- return state.userFormReducer.revisions[revisionId];
3526
- };
3527
- const _selectLatestFormRevision = (revisions, formId2) => {
3528
- let ret = null;
3529
- for (const candidate of Object.values(revisions)) {
3530
- if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
3531
- ret = candidate;
3819
+ // We only need a multi set for attachments because they are not updated, only added and deleted
3820
+ setFormSubmissionAttachments: (state, action) => {
3821
+ state.attachments = {};
3822
+ for (const attachment of action.payload) {
3823
+ state.attachments[attachment.offline_id] = attachment;
3824
+ }
3825
+ },
3826
+ // The delete actions for UserFormSubmissionAttachments are not used in the app, but are included for completeness
3827
+ // Could be used if editing a submission is ever supported, will be applicable for supporting tip tap content in submissions
3828
+ deleteFormSubmissionAttachment: (state, action) => {
3829
+ if (state.attachments[action.payload] === void 0) {
3830
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3831
+ }
3832
+ delete state.attachments[action.payload];
3833
+ },
3834
+ deleteFormSubmissionAttachments: (state, action) => {
3835
+ for (const offlineId of action.payload) {
3836
+ if (state.attachments[offlineId] === void 0) {
3837
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3838
+ }
3839
+ delete state.attachments[offlineId];
3840
+ }
3532
3841
  }
3533
3842
  }
3534
- if (!ret) {
3535
- throw new Error("No revision found for form " + formId2);
3843
+ });
3844
+ const {
3845
+ setFormSubmission,
3846
+ setFormSubmissions,
3847
+ addFormSubmission,
3848
+ addFormSubmissions,
3849
+ updateFormSubmission,
3850
+ updateFormSubmissions,
3851
+ deleteFormSubmission,
3852
+ deleteFormSubmissions,
3853
+ addFormSubmissionAttachment,
3854
+ addFormSubmissionAttachments,
3855
+ setFormSubmissionAttachments,
3856
+ deleteFormSubmissionAttachment,
3857
+ deleteFormSubmissionAttachments
3858
+ } = formSubmissionSlice.actions;
3859
+ const selectFormSubmissionsMapping = (state) => {
3860
+ return state.formSubmissionReducer.formSubmissions;
3861
+ };
3862
+ const selectFormSubmissions = createSelector(
3863
+ [selectFormSubmissionsMapping],
3864
+ (submissions) => {
3865
+ return Object.values(submissions);
3536
3866
  }
3537
- return ret;
3538
- };
3539
- const selectLatestFormRevision = restructureCreateSelectorWithArgs(
3540
- createSelector(
3541
- [(state) => state.userFormReducer.revisions, (_state, formId2) => formId2],
3542
- (revisions, formId2) => {
3543
- if (!formId2) {
3544
- throw new Error("formId is required");
3545
- }
3546
- return _selectLatestFormRevision(revisions, formId2);
3547
- }
3548
- )
3549
- );
3550
- const selectUserForm = (formId2) => (state) => {
3551
- return state.userFormReducer.userForms[formId2];
3552
- };
3553
- const selectSubmissionMapping = (state) => state.userFormReducer.submissions;
3554
- const selectSubmissions = createSelector([selectSubmissionMapping], (submissions) => Object.values(submissions));
3555
- const selectRevisionMapping = (state) => state.userFormReducer.revisions;
3556
- const selectRevisions = createSelector([selectRevisionMapping], (revisions) => Object.values(revisions));
3557
- const selectRevisionsForForm = restructureCreateSelectorWithArgs(
3558
- createSelector([selectRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3559
- return revisions.filter((revision) => {
3560
- return revision.form === formId2;
3561
- });
3562
- })
3563
3867
  );
3564
- const selectSubmissionsForForm = restructureCreateSelectorWithArgs(
3868
+ const selectFormSubmission = (submissionId) => (state) => {
3869
+ return state.formSubmissionReducer.formSubmissions[submissionId];
3870
+ };
3871
+ const selectFormSubmissionsOfForm = restructureCreateSelectorWithArgs(
3565
3872
  createSelector(
3566
- [selectSubmissions, selectRevisionMapping, (_state, formId2) => formId2],
3873
+ [selectFormSubmissions, selectFormRevisionMapping, (_state, formId2) => formId2],
3567
3874
  (submissions, revisionMapping, formId2) => {
3568
- return Object.values(submissions).filter((submission) => {
3875
+ return submissions.filter((submission) => {
3569
3876
  const revision = revisionMapping[submission.form_revision];
3570
3877
  return (revision == null ? void 0 : revision.form) === formId2;
3571
3878
  });
3572
3879
  }
3573
3880
  )
3574
3881
  );
3575
- const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3882
+ const selectFormSubmissionsOfIssue = restructureCreateSelectorWithArgs(
3576
3883
  createSelector(
3577
- [(state) => state.userFormReducer.submissions, (_state, issueId) => issueId],
3884
+ [selectFormSubmissions, (_state, issueId) => issueId],
3578
3885
  (submissions, issueId) => {
3579
3886
  return Object.values(submissions).filter((submission) => {
3580
3887
  return submission.issue === issueId;
@@ -3582,9 +3889,9 @@ const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3582
3889
  }
3583
3890
  )
3584
3891
  );
3585
- const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3892
+ const selectFormSubmissionsOfComponent = restructureCreateSelectorWithArgs(
3586
3893
  createSelector(
3587
- [selectSubmissions, (_state, componentId) => componentId],
3894
+ [selectFormSubmissions, (_state, componentId) => componentId],
3588
3895
  (submissions, componentId) => {
3589
3896
  return submissions.filter((submission) => {
3590
3897
  return submission.component === componentId;
@@ -3592,54 +3899,35 @@ const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3592
3899
  }
3593
3900
  )
3594
3901
  );
3595
- const selectUserFormMapping = (state) => {
3596
- return state.userFormReducer.userForms;
3597
- };
3598
- const selectComponentTypeForm = restructureCreateSelectorWithArgs(
3599
- createSelector(
3600
- [selectUserFormMapping, (_state, componentTypeId) => componentTypeId],
3601
- (userForms, componentTypeId) => {
3602
- return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
3902
+ const selectFormSubmissionsByComponents = createSelector(
3903
+ [selectFormSubmissionsMapping, selectComponentsMapping],
3904
+ (submissions, components) => {
3905
+ var _a2;
3906
+ const componentSubmissionMapping = {};
3907
+ for (const componentId in components) {
3908
+ componentSubmissionMapping[componentId] = [];
3603
3909
  }
3604
- )
3910
+ for (const submissionId in submissions) {
3911
+ const submission = submissions[submissionId];
3912
+ if (submission.component) {
3913
+ (_a2 = componentSubmissionMapping[submission.component]) == null ? void 0 : _a2.push(submission);
3914
+ }
3915
+ }
3916
+ return componentSubmissionMapping;
3917
+ }
3605
3918
  );
3606
- const selectLatestRevisionsFromComponentTypeIds = restructureCreateSelectorWithArgs(
3919
+ const selectFormSubmissionAttachmentsMapping = (state) => {
3920
+ return state.formSubmissionReducer.attachments;
3921
+ };
3922
+ const selectAttachmentsOfFormSubmission = restructureCreateSelectorWithArgs(
3607
3923
  createSelector(
3608
- [
3609
- selectUserFormMapping,
3610
- selectRevisionMapping,
3611
- (_state, componentTypeIds) => componentTypeIds
3612
- ],
3613
- (userForms, revisions, componentTypeIds) => {
3614
- const componentTypeIdsSet = new Set(componentTypeIds);
3615
- const ret = {};
3616
- for (const form of Object.values(userForms)) {
3617
- if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
3618
- ret[form.component_type] = _selectLatestFormRevision(revisions, form.offline_id);
3619
- }
3620
- }
3621
- return ret;
3924
+ [selectFormSubmissionAttachmentsMapping, (_state, submissionId) => submissionId],
3925
+ (attachmentsMapping, submissionId) => {
3926
+ return Object.values(attachmentsMapping).filter((attachment) => attachment.submission === submissionId);
3622
3927
  }
3623
3928
  )
3624
3929
  );
3625
- const selectLatestRevisionByFormId = createSelector([selectRevisionMapping], (revisions) => {
3626
- const latestRevisions = {};
3627
- for (const revision of Object.values(revisions)) {
3628
- const formId2 = revision.form;
3629
- const currentLatestRevision = latestRevisions[formId2];
3630
- if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
3631
- latestRevisions[formId2] = revision;
3632
- }
3633
- }
3634
- return latestRevisions;
3635
- });
3636
- const selectNumberOfUserForms = createSelector([selectUserFormMapping], (userForms) => {
3637
- return Object.keys(userForms).length;
3638
- });
3639
- const selectNumberOfGeneralUserForms = createSelector([selectUserFormMapping], (userForms) => {
3640
- return Object.values(userForms).filter((form) => !form.component_type).length;
3641
- });
3642
- const userFormReducer = userFormSlice.reducer;
3930
+ const formSubmissionReducer = formSubmissionSlice.reducer;
3643
3931
  const initialState$2 = {
3644
3932
  emailDomains: {}
3645
3933
  };
@@ -3886,6 +4174,8 @@ const overmapReducers = {
3886
4174
  rehydratedReducer,
3887
4175
  settingReducer,
3888
4176
  userFormReducer,
4177
+ formRevisionReducer,
4178
+ formSubmissionReducer,
3889
4179
  userReducer,
3890
4180
  workspaceReducer,
3891
4181
  emailDomainsReducer,
@@ -3938,7 +4228,7 @@ function handleWorkspaceRemoval(draft, action) {
3938
4228
  throw new Error(`Failed to update index_workspace of issue ${issue.offline_id} to main workspace`);
3939
4229
  }
3940
4230
  }
3941
- const indexedForms = Object.values(draft.userFormReducer.userForms).filter(
4231
+ const indexedForms = Object.values(draft.userFormReducer.forms).filter(
3942
4232
  (form) => form.index_workspace === workspaceId
3943
4233
  );
3944
4234
  for (const form of indexedForms) {
@@ -4254,7 +4544,17 @@ function runMiddleware(action) {
4254
4544
  const discardStatuses = [400, 409, 403, 404, 405, 500];
4255
4545
  const statusMessages = {
4256
4546
  403: { title: "Forbidden", description: "You are not authorized to perform this action.", severity: "danger" },
4257
- 404: { title: "Not found", description: "The requested resource was not found.", severity: "danger" }
4547
+ 404: { title: "Not found", description: "The requested resource was not found.", severity: "danger" },
4548
+ 405: {
4549
+ title: "Not supported",
4550
+ description: "It's not you. It's us. Sorry for the inconvenience.",
4551
+ severity: "danger"
4552
+ },
4553
+ 500: {
4554
+ title: "Server error",
4555
+ description: "Our server seems to be experiencing problems at the moment. We have been alerted and will fix the problem as soon as possible.",
4556
+ severity: "danger"
4557
+ }
4258
4558
  };
4259
4559
  function discard(reason, action, retries = 0) {
4260
4560
  var _a2;
@@ -4427,7 +4727,7 @@ class AttachmentService extends BaseApiService {
4427
4727
  }
4428
4728
  // Attachments aren't models, so we use the OptimisticGenericResult type instead
4429
4729
  async addIssueAttachment(attachmentPayload) {
4430
- const { description: description2, issue, file_sha1, offline_id } = attachmentPayload;
4730
+ const { issue, file_sha1, offline_id } = attachmentPayload;
4431
4731
  if (!attachmentPayload.file.objectURL) {
4432
4732
  throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
4433
4733
  }
@@ -4435,7 +4735,9 @@ class AttachmentService extends BaseApiService {
4435
4735
  ...attachmentPayload,
4436
4736
  file: attachmentPayload.file.objectURL,
4437
4737
  file_name: attachmentPayload.file.name,
4438
- file_type: attachmentPayload.file.type
4738
+ file_type: attachmentPayload.file.type,
4739
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
4740
+ created_by: this.client.store.getState().userReducer.currentUser.id
4439
4741
  };
4440
4742
  await this.client.files.addCache(attachmentPayload.file, file_sha1);
4441
4743
  this.client.store.dispatch(addIssueAttachment(offlineAttachment));
@@ -4447,10 +4749,7 @@ class AttachmentService extends BaseApiService {
4447
4749
  blocks: [offline_id, issue],
4448
4750
  blockers: [file_sha1],
4449
4751
  payload: {
4450
- offline_id,
4451
- issue,
4452
- description: description2 ?? "",
4453
- submitted_at: (/* @__PURE__ */ new Date()).getTime() / 1e3,
4752
+ ...offlineAttachment,
4454
4753
  ...fileProps
4455
4754
  }
4456
4755
  });
@@ -4461,7 +4760,7 @@ class AttachmentService extends BaseApiService {
4461
4760
  return [offlineAttachment, promise];
4462
4761
  }
4463
4762
  async addComponentAttachment(attachmentPayload) {
4464
- const { description: description2, component, file_sha1, offline_id } = attachmentPayload;
4763
+ const { component, file_sha1, offline_id } = attachmentPayload;
4465
4764
  if (!attachmentPayload.file.objectURL) {
4466
4765
  throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
4467
4766
  }
@@ -4469,7 +4768,9 @@ class AttachmentService extends BaseApiService {
4469
4768
  ...attachmentPayload,
4470
4769
  file: attachmentPayload.file.objectURL,
4471
4770
  file_name: attachmentPayload.file.name,
4472
- file_type: attachmentPayload.file.type
4771
+ file_type: attachmentPayload.file.type,
4772
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
4773
+ created_by: this.client.store.getState().userReducer.currentUser.id
4473
4774
  };
4474
4775
  await this.client.files.addCache(attachmentPayload.file, file_sha1);
4475
4776
  this.client.store.dispatch(addComponentAttachment(offlineAttachment));
@@ -4481,10 +4782,7 @@ class AttachmentService extends BaseApiService {
4481
4782
  blocks: [offline_id, component],
4482
4783
  blockers: [file_sha1],
4483
4784
  payload: {
4484
- offline_id,
4485
- component,
4486
- description: description2 ?? "",
4487
- submitted_at: (/* @__PURE__ */ new Date()).getTime() / 1e3,
4785
+ ...offlineAttachment,
4488
4786
  ...fileProps
4489
4787
  }
4490
4788
  });
@@ -4495,7 +4793,7 @@ class AttachmentService extends BaseApiService {
4495
4793
  return [offlineAttachment, promise];
4496
4794
  }
4497
4795
  async addComponentTypeAttachment(attachmentPayload) {
4498
- const { description: description2, component_type, file_sha1, offline_id } = attachmentPayload;
4796
+ const { component_type, file_sha1, offline_id } = attachmentPayload;
4499
4797
  if (!attachmentPayload.file.objectURL) {
4500
4798
  throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
4501
4799
  }
@@ -4503,7 +4801,9 @@ class AttachmentService extends BaseApiService {
4503
4801
  ...attachmentPayload,
4504
4802
  file: attachmentPayload.file.objectURL,
4505
4803
  file_name: attachmentPayload.file.name,
4506
- file_type: attachmentPayload.file.type
4804
+ file_type: attachmentPayload.file.type,
4805
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
4806
+ created_by: this.client.store.getState().userReducer.currentUser.id
4507
4807
  };
4508
4808
  await this.client.files.addCache(attachmentPayload.file, file_sha1);
4509
4809
  this.client.store.dispatch(addComponentTypeAttachment(offlineAttachment));
@@ -4515,10 +4815,7 @@ class AttachmentService extends BaseApiService {
4515
4815
  blocks: [offline_id, component_type],
4516
4816
  blockers: [file_sha1],
4517
4817
  payload: {
4518
- offline_id,
4519
- component_type,
4520
- description: description2 ?? "",
4521
- submitted_at: (/* @__PURE__ */ new Date()).getTime() / 1e3,
4818
+ ...offlineAttachment,
4522
4819
  ...fileProps
4523
4820
  }
4524
4821
  });
@@ -4537,7 +4834,9 @@ class AttachmentService extends BaseApiService {
4537
4834
  ...attachmentPayload,
4538
4835
  file: attachmentPayload.file.objectURL,
4539
4836
  file_name: attachmentPayload.file.name,
4540
- file_type: attachmentPayload.file.type
4837
+ file_type: attachmentPayload.file.type,
4838
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
4839
+ created_by: this.client.store.getState().userReducer.currentUser.id
4541
4840
  };
4542
4841
  await this.client.files.addCache(attachmentPayload.file, file_sha1);
4543
4842
  this.client.store.dispatch(addProjectAttachment(offlineAttachment));
@@ -4577,7 +4876,9 @@ class AttachmentService extends BaseApiService {
4577
4876
  file_name: file2.name,
4578
4877
  file_type: file2.type,
4579
4878
  issue: issueId,
4580
- file_sha1: hash
4879
+ file_sha1: hash,
4880
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
4881
+ created_by: this.client.store.getState().userReducer.currentUser.id
4581
4882
  });
4582
4883
  return this.addIssueAttachment(attachment);
4583
4884
  };
@@ -4596,7 +4897,9 @@ class AttachmentService extends BaseApiService {
4596
4897
  file_name: file2.name,
4597
4898
  file_type: file2.type,
4598
4899
  component: componentId,
4599
- file_sha1: hash
4900
+ file_sha1: hash,
4901
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
4902
+ created_by: this.client.store.getState().userReducer.currentUser.id
4600
4903
  });
4601
4904
  return this.addComponentAttachment(attachment);
4602
4905
  };
@@ -4615,7 +4918,9 @@ class AttachmentService extends BaseApiService {
4615
4918
  file_name: file2.name,
4616
4919
  file_type: file2.type,
4617
4920
  component_type: componentTypeId,
4618
- file_sha1: hash
4921
+ file_sha1: hash,
4922
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
4923
+ created_by: this.client.store.getState().userReducer.currentUser.id
4619
4924
  });
4620
4925
  return this.addComponentTypeAttachment(attachment);
4621
4926
  };
@@ -4634,7 +4939,9 @@ class AttachmentService extends BaseApiService {
4634
4939
  file_name: file2.name,
4635
4940
  file_type: file2.type,
4636
4941
  project: projectId,
4637
- file_sha1: hash
4942
+ file_sha1: hash,
4943
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
4944
+ created_by: this.client.store.getState().userReducer.currentUser.id
4638
4945
  });
4639
4946
  return this.addProjectAttachment(attachment);
4640
4947
  };
@@ -5711,49 +6018,35 @@ class ComponentTypeService extends BaseApiService {
5711
6018
  }
5712
6019
  }
5713
6020
  class IssueCommentService extends BaseApiService {
6021
+ // Omit author and submitted_at since these will always be set internally
5714
6022
  add(comment) {
5715
- const offlinePayload = offline(comment);
5716
- const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
5717
6023
  const { store } = this.client;
5718
- const offlineComment = {
5719
- ...offlinePayload,
6024
+ const offlineComment = offline({
6025
+ ...comment,
5720
6026
  author: store.getState().userReducer.currentUser.id,
5721
- created_at: submittedAt
5722
- };
5723
- store.dispatch(addOrReplaceIssueComment(offlineComment));
6027
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
6028
+ });
6029
+ store.dispatch(addIssueComment(offlineComment));
5724
6030
  const promise = this.enqueueRequest({
5725
6031
  description: `${truncate(comment.content, 80)}`,
5726
6032
  method: HttpMethod.POST,
5727
6033
  url: `/issues/${comment.issue}/comment/`,
5728
- payload: { ...offlinePayload, submitted_at: submittedAt },
6034
+ payload: offlineComment,
5729
6035
  blockers: [comment.issue],
5730
- blocks: [offlinePayload.offline_id]
6036
+ blocks: [offlineComment.offline_id]
6037
+ });
6038
+ promise.catch(() => {
6039
+ store.dispatch(removeIssueComment(offlineComment.offline_id));
5731
6040
  });
5732
6041
  return [offlineComment, promise];
5733
6042
  }
5734
- async refreshStore() {
6043
+ update(comment) {
5735
6044
  const { store } = this.client;
5736
- const result = await this.enqueueRequest({
5737
- description: "Get comments",
5738
- method: HttpMethod.GET,
5739
- // TODO: Choose between /issues/comments/in-project/${projectId}/ and /projects/${projectId}/issue-comments/
5740
- url: `/projects/${store.getState().projectReducer.activeProjectId}/comments/`,
5741
- blockers: [],
5742
- blocks: []
5743
- });
5744
- let filteredResult = result.filter(onlyUniqueOfflineIds);
5745
- filteredResult = filteredResult.map((comment) => {
5746
- return { ...comment };
5747
- });
5748
- if (result.length !== filteredResult.length) {
5749
- console.error(
5750
- `Received duplicate comments from the API (new length ${filteredResult.length}); filtered in browser.`
5751
- );
6045
+ const commentToUpdate = store.getState().issueReducer.comments[comment.offline_id];
6046
+ if (!commentToUpdate) {
6047
+ throw new Error(`Comment with offline_id ${comment.offline_id} not found in store`);
5752
6048
  }
5753
- store.dispatch(setIssueComments(filteredResult));
5754
- }
5755
- update(comment) {
5756
- this.client.store.dispatch(addOrReplaceIssueComment(comment));
6049
+ store.dispatch(setIssueComment(comment));
5757
6050
  const promise = this.enqueueRequest({
5758
6051
  description: `Edit comment: ${truncate(comment.content, 80)}`,
5759
6052
  method: HttpMethod.PATCH,
@@ -5762,17 +6055,62 @@ class IssueCommentService extends BaseApiService {
5762
6055
  blockers: [comment.issue],
5763
6056
  blocks: [comment.offline_id]
5764
6057
  });
6058
+ promise.catch(() => {
6059
+ store.dispatch(setIssueComment(commentToUpdate));
6060
+ });
5765
6061
  return [comment, promise];
5766
6062
  }
5767
6063
  remove(offline_id) {
6064
+ const commentToRemove = this.client.store.getState().issueReducer.comments[offline_id];
6065
+ if (!commentToRemove) {
6066
+ throw new Error(`Comment with offline_id ${offline_id} not found in store`);
6067
+ }
5768
6068
  this.client.store.dispatch(removeIssueComment(offline_id));
5769
- return this.enqueueRequest({
6069
+ const promise = this.enqueueRequest({
5770
6070
  description: "Delete comment",
5771
6071
  method: HttpMethod.DELETE,
5772
6072
  url: `/issues/comments/${offline_id}/`,
5773
6073
  blockers: [offline_id],
5774
6074
  blocks: []
5775
6075
  });
6076
+ promise.catch(() => {
6077
+ this.client.store.dispatch(addIssueComment(commentToRemove));
6078
+ });
6079
+ return promise;
6080
+ }
6081
+ async refreshStore() {
6082
+ const { store } = this.client;
6083
+ const result = await this.enqueueRequest({
6084
+ description: "Get comments",
6085
+ method: HttpMethod.GET,
6086
+ // TODO: Choose between /issues/comments/in-project/${projectId}/ and /projects/${projectId}/issue-comments/
6087
+ url: `/projects/${store.getState().projectReducer.activeProjectId}/comments/`,
6088
+ blockers: [],
6089
+ blocks: []
6090
+ });
6091
+ store.dispatch(setIssueComments(result));
6092
+ }
6093
+ }
6094
+ class IssueUpdateService extends BaseApiService {
6095
+ async refreshStore() {
6096
+ const { store } = this.client;
6097
+ const result = await this.enqueueRequest({
6098
+ description: "Get issue updates",
6099
+ method: HttpMethod.GET,
6100
+ url: `/projects/${store.getState().projectReducer.activeProjectId}/issues/updates/`,
6101
+ blockers: [],
6102
+ blocks: []
6103
+ });
6104
+ let filteredResult = result.filter(onlyUniqueOfflineIds);
6105
+ filteredResult = filteredResult.map((comment) => {
6106
+ return { ...comment };
6107
+ });
6108
+ if (result.length !== filteredResult.length) {
6109
+ console.error(
6110
+ `Received duplicate comments from the API (new length ${filteredResult.length}); filtered in browser.`
6111
+ );
6112
+ }
6113
+ store.dispatch(setIssueUpdates(filteredResult));
5776
6114
  }
5777
6115
  }
5778
6116
  class IssueService extends BaseApiService {
@@ -5853,7 +6191,83 @@ class IssueService extends BaseApiService {
5853
6191
  return [offlineIssues, promise];
5854
6192
  }
5855
6193
  update(issue) {
6194
+ const state = this.client.store.getState();
6195
+ const issueToBeUpdated = state.issueReducer.issues[issue.offline_id];
6196
+ if (!issueToBeUpdated) {
6197
+ throw new Error(
6198
+ `Attempting to update an issue with offline_id ${issue.offline_id} that doesn't exist in the store`
6199
+ );
6200
+ }
5856
6201
  this.client.store.dispatch(updateIssue(issue));
6202
+ const changes = {};
6203
+ for (const issueUpdateChange of [
6204
+ IssueUpdateChange.TITLE,
6205
+ IssueUpdateChange.DESCRIPTION,
6206
+ IssueUpdateChange.STATUS,
6207
+ IssueUpdateChange.CATEGORY,
6208
+ IssueUpdateChange.PRIORITY,
6209
+ IssueUpdateChange.ASSIGNED_TO,
6210
+ IssueUpdateChange.DUE_DATE
6211
+ ]) {
6212
+ if (issueUpdateChange in issue && issue[issueUpdateChange] !== issueToBeUpdated[issueUpdateChange]) {
6213
+ switch (issueUpdateChange) {
6214
+ case "category": {
6215
+ let categoryOrNull = null;
6216
+ const categoryIdOrNull = issue[issueUpdateChange];
6217
+ if (categoryIdOrNull) {
6218
+ categoryOrNull = state.categoryReducer.categories[categoryIdOrNull] ?? null;
6219
+ if (!categoryOrNull)
6220
+ throw new Error(
6221
+ `Trying to update issue category to ${categoryIdOrNull} which does not exist in store`
6222
+ );
6223
+ }
6224
+ changes[issueUpdateChange] = categoryOrNull ? {
6225
+ name: categoryOrNull.name,
6226
+ color: categoryOrNull.color,
6227
+ offline_id: categoryOrNull.offline_id
6228
+ } : null;
6229
+ break;
6230
+ }
6231
+ case "assigned_to": {
6232
+ let userOrNull = null;
6233
+ const userIdOrNull = issue[issueUpdateChange];
6234
+ if (userIdOrNull) {
6235
+ userOrNull = state.userReducer.users[userIdOrNull] ?? null;
6236
+ if (!userOrNull)
6237
+ throw new Error(
6238
+ `Trying to update issue assigned_to to ${userIdOrNull} which does not exist in store`
6239
+ );
6240
+ }
6241
+ changes[issueUpdateChange] = userOrNull ? {
6242
+ full_name: userOrNull.username,
6243
+ id: userOrNull.id
6244
+ } : null;
6245
+ break;
6246
+ }
6247
+ case "description":
6248
+ changes[issueUpdateChange] = issue[issueUpdateChange] ?? null;
6249
+ break;
6250
+ case "title":
6251
+ changes[issueUpdateChange] = issue[issueUpdateChange] ?? null;
6252
+ break;
6253
+ case "priority":
6254
+ changes[issueUpdateChange] = issue[issueUpdateChange];
6255
+ break;
6256
+ case "status":
6257
+ changes[issueUpdateChange] = issue[issueUpdateChange];
6258
+ break;
6259
+ case "due_date":
6260
+ changes[issueUpdateChange] = issue[issueUpdateChange] ? issue[issueUpdateChange] : null;
6261
+ }
6262
+ }
6263
+ }
6264
+ const offlineIssueUpdate = offline({
6265
+ created_by: state.userReducer.currentUser.id,
6266
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
6267
+ issue: issueToBeUpdated.offline_id,
6268
+ changes
6269
+ });
6270
+ this.client.store.dispatch(addIssueUpdate(offlineIssueUpdate));
5857
6271
  const promise = this.enqueueRequest({
5858
6272
  description: "Edit issue",
5859
6273
  method: HttpMethod.PATCH,
@@ -5862,23 +6276,30 @@ class IssueService extends BaseApiService {
5862
6276
  blockers: [issue.offline_id],
5863
6277
  blocks: [issue.offline_id]
5864
6278
  });
6279
+ promise.catch(() => {
6280
+ this.client.store.dispatch(updateIssue(issueToBeUpdated));
6281
+ this.client.store.dispatch(removeIssueUpdate(offlineIssueUpdate.offline_id));
6282
+ });
5865
6283
  const fullIssue = this.client.store.getState().issueReducer.issues[issue.offline_id];
5866
6284
  return [fullIssue, promise];
5867
6285
  }
5868
6286
  async remove(id) {
5869
6287
  const { store } = this.client;
5870
6288
  const state = store.getState();
6289
+ const dispatch = store.dispatch;
5871
6290
  const backup = state.issueReducer.issues[id];
5872
6291
  if (!backup) {
5873
6292
  throw new Error(`No issue with id ${id} found in the store`);
5874
6293
  }
5875
6294
  const attachments = Object.values(state.issueReducer.attachments).filter((a) => a.issue === id);
5876
6295
  const attachmentsOfIssue = selectAttachmentsOfIssue(id)(state);
5877
- this.client.store.dispatch(removeIssue(id));
5878
- store.dispatch(addActiveProjectIssuesCount(-1));
5879
- if (attachmentsOfIssue.length > 0) {
5880
- this.client.store.dispatch(removeAttachmentsOfIssue(id));
5881
- }
6296
+ const updatesOfIssue = selectIssueUpdatesOfIssue(id)(state);
6297
+ dispatch(removeIssue(id));
6298
+ dispatch(addActiveProjectIssuesCount(-1));
6299
+ if (attachmentsOfIssue.length > 0)
6300
+ dispatch(removeAttachmentsOfIssue(id));
6301
+ if (updatesOfIssue.length > 0)
6302
+ dispatch(removeIssueUpdates(updatesOfIssue.map(({ offline_id }) => offline_id)));
5882
6303
  try {
5883
6304
  return await this.enqueueRequest({
5884
6305
  description: "Delete issue",
@@ -5888,9 +6309,10 @@ class IssueService extends BaseApiService {
5888
6309
  blocks: []
5889
6310
  });
5890
6311
  } catch (e) {
5891
- this.client.store.dispatch(addIssue(backup));
5892
- this.client.store.dispatch(addIssueAttachments(attachments));
5893
- store.dispatch(addActiveProjectIssuesCount(1));
6312
+ dispatch(addIssue(backup));
6313
+ dispatch(addIssueAttachments(attachments));
6314
+ dispatch(addIssueUpdates(updatesOfIssue));
6315
+ dispatch(addActiveProjectIssuesCount(1));
5894
6316
  throw e;
5895
6317
  }
5896
6318
  }
@@ -6072,6 +6494,7 @@ class MainService extends BaseApiService {
6072
6494
  store.dispatch(setProjectAttachments(project_attachments));
6073
6495
  });
6074
6496
  void this.client.documents.refreshStore();
6497
+ void this.client.issueUpdates.refreshStore();
6075
6498
  }
6076
6499
  store.dispatch(setIsFetchingInitialData(false));
6077
6500
  if (overwrite) {
@@ -6436,7 +6859,7 @@ class UserFormService extends BaseApiService {
6436
6859
  ...revisionAttachmentPayload,
6437
6860
  file: URL.createObjectURL(image)
6438
6861
  };
6439
- store.dispatch(addUserFormRevisionAttachment(offlinePayload));
6862
+ store.dispatch(addFormRevisionAttachment(offlinePayload));
6440
6863
  return attach;
6441
6864
  });
6442
6865
  });
@@ -6470,8 +6893,8 @@ class UserFormService extends BaseApiService {
6470
6893
  revision: 0
6471
6894
  };
6472
6895
  const { store } = this.client;
6473
- store.dispatch(addUserForm(retForm));
6474
- store.dispatch(addUserFormRevision(retRevision));
6896
+ store.dispatch(addForm(retForm));
6897
+ store.dispatch(addFormRevision(retRevision));
6475
6898
  const formPromise = this.enqueueRequest({
6476
6899
  description: "Create form",
6477
6900
  method: HttpMethod.POST,
@@ -6489,8 +6912,8 @@ class UserFormService extends BaseApiService {
6489
6912
  });
6490
6913
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
6491
6914
  void formPromise.catch((e) => {
6492
- store.dispatch(deleteUserForm(retForm.offline_id));
6493
- store.dispatch(deleteUserFormRevision(retRevision.offline_id));
6915
+ store.dispatch(deleteForm(retForm.offline_id));
6916
+ store.dispatch(deleteFormRevision(retRevision.offline_id));
6494
6917
  throw e;
6495
6918
  });
6496
6919
  const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
@@ -6532,7 +6955,7 @@ class UserFormService extends BaseApiService {
6532
6955
  revision: "Pending",
6533
6956
  form: formId2
6534
6957
  };
6535
- store.dispatch(addUserFormRevision(fullRevision));
6958
+ store.dispatch(addFormRevision(fullRevision));
6536
6959
  const promise = this.enqueueRequest({
6537
6960
  description: "Create form revision",
6538
6961
  method: HttpMethod.PATCH,
@@ -6546,9 +6969,9 @@ class UserFormService extends BaseApiService {
6546
6969
  });
6547
6970
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
6548
6971
  void promise.then((result) => {
6549
- store.dispatch(addUserFormRevision(result));
6972
+ store.dispatch(setFormRevision(result));
6550
6973
  }).catch(() => {
6551
- store.dispatch(deleteUserFormRevision(fullRevision.offline_id));
6974
+ store.dispatch(deleteFormRevision(fullRevision.offline_id));
6552
6975
  });
6553
6976
  const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
6554
6977
  return [fullRevision, settledPromise];
@@ -6594,15 +7017,15 @@ class UserFormService extends BaseApiService {
6594
7017
  if (!userForm) {
6595
7018
  throw new Error("Expected userForm to exist");
6596
7019
  }
6597
- const userFormSubmissions = selectSubmissionsForForm(formId2)(state);
7020
+ const userFormSubmissions = selectFormSubmissionsOfForm(formId2)(state);
6598
7021
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6599
- store.dispatch(deleteUserFormSubmissions(userFormSubmissions));
7022
+ store.dispatch(deleteFormSubmissions(userFormSubmissions.map(({ offline_id }) => offline_id)));
6600
7023
  }
6601
- const userFormRevisions = selectRevisionsForForm(formId2)(state);
7024
+ const userFormRevisions = selectFormRevisionsOfForm(formId2)(state);
6602
7025
  if (userFormRevisions && userFormRevisions.length > 0) {
6603
- store.dispatch(deleteUserFormRevisions(userFormRevisions));
7026
+ store.dispatch(deleteFormRevisions(userFormRevisions.map(({ offline_id }) => offline_id)));
6604
7027
  }
6605
- store.dispatch(deleteUserForm(formId2));
7028
+ store.dispatch(deleteForm(formId2));
6606
7029
  try {
6607
7030
  return await this.enqueueRequest({
6608
7031
  description: "Delete form",
@@ -6612,12 +7035,12 @@ class UserFormService extends BaseApiService {
6612
7035
  blocks: []
6613
7036
  });
6614
7037
  } catch (e) {
6615
- store.dispatch(addUserForm(userForm));
7038
+ store.dispatch(addForm(userForm));
6616
7039
  if (userFormRevisions && userFormRevisions.length > 0) {
6617
- store.dispatch(addUserFormRevisions(userFormRevisions));
7040
+ store.dispatch(addFormRevisions(userFormRevisions));
6618
7041
  }
6619
7042
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6620
- store.dispatch(addUserFormSubmissions(userFormSubmissions));
7043
+ store.dispatch(addFormSubmissions(userFormSubmissions));
6621
7044
  }
6622
7045
  throw e;
6623
7046
  }
@@ -6631,16 +7054,15 @@ class UserFormService extends BaseApiService {
6631
7054
  blockers: [],
6632
7055
  blocks: []
6633
7056
  });
6634
- store.dispatch(addUserForms(Object.values(result.forms)));
6635
- store.dispatch(addUserFormRevisions(Object.values(result.revisions)));
6636
- store.dispatch(setUserFormRevisionAttachments(Object.values(result.attachments)));
7057
+ store.dispatch(setForms(Object.values(result.forms)));
7058
+ store.dispatch(setFormRevisions(Object.values(result.revisions)));
7059
+ store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
6637
7060
  }
6638
7061
  }
6639
7062
  const isArrayOfFiles = (value) => {
6640
7063
  return Array.isArray(value) && value[0] instanceof File;
6641
7064
  };
6642
- const separateFilesFromValues = (payload) => {
6643
- const { values } = payload;
7065
+ const separateFilesFromValues = (values) => {
6644
7066
  const files = {};
6645
7067
  const newValues = {};
6646
7068
  for (const key in values) {
@@ -6655,17 +7077,13 @@ const separateFilesFromValues = (payload) => {
6655
7077
  newValues[key] = value;
6656
7078
  }
6657
7079
  }
6658
- const payloadWithoutFiles = {
6659
- ...payload,
6660
- values: newValues
6661
- };
6662
- return { payloadWithoutFiles, files };
7080
+ return { values: newValues, files };
6663
7081
  };
6664
7082
  class UserFormSubmissionService extends BaseApiService {
6665
7083
  constructor() {
6666
7084
  super(...arguments);
6667
7085
  // Attach files to submission, after uploading them to S3
6668
- __publicField(this, "getAttachFilesPromises", (files, payload) => {
7086
+ __publicField(this, "getAttachFilesPromises", (files, submission) => {
6669
7087
  const { store } = this.client;
6670
7088
  return Object.entries(files).map(async ([key, fileArray]) => {
6671
7089
  const attachResults = [];
@@ -6675,24 +7093,27 @@ class UserFormSubmissionService extends BaseApiService {
6675
7093
  const [fileProps] = await this.client.files.uploadFileToS3(sha1);
6676
7094
  const submissionAttachmentPayload = offline({
6677
7095
  ...fileProps,
6678
- submission: payload.offline_id,
7096
+ submission: submission.offline_id,
6679
7097
  field_identifier: key
6680
7098
  });
6681
7099
  const attach = await this.enqueueRequest({
6682
7100
  description: "Attach file to form submission",
6683
7101
  method: HttpMethod.POST,
6684
- url: `/forms/submission/${payload.offline_id}/attachments/`,
7102
+ url: `/forms/submission/${submission.offline_id}/attachments/`,
6685
7103
  payload: submissionAttachmentPayload,
6686
- blockers: [payload.component, payload.component_stage, payload.issue, payload.form_revision].filter(
6687
- (x) => x !== void 0
6688
- ),
7104
+ blockers: [
7105
+ submission.component,
7106
+ submission.component_stage,
7107
+ submission.issue,
7108
+ submission.form_revision
7109
+ ].filter((x) => x !== void 0),
6689
7110
  blocks: [submissionAttachmentPayload.offline_id]
6690
7111
  });
6691
7112
  const offlinePayload = {
6692
7113
  ...submissionAttachmentPayload,
6693
7114
  file: URL.createObjectURL(file)
6694
7115
  };
6695
- store.dispatch(addUserFormSubmissionAttachment(offlinePayload));
7116
+ store.dispatch(addFormSubmissionAttachment(offlinePayload));
6696
7117
  attachResults.push(attach);
6697
7118
  }
6698
7119
  return attachResults;
@@ -6706,70 +7127,113 @@ class UserFormSubmissionService extends BaseApiService {
6706
7127
  if (!activeProjectId) {
6707
7128
  throw new Error("Expected an active project");
6708
7129
  }
6709
- const { payloadWithoutFiles, files } = separateFilesFromValues(payload);
7130
+ const { values, files } = separateFilesFromValues(payload.values);
7131
+ const offlineSubmission = {
7132
+ ...payload,
7133
+ values,
7134
+ created_by: state.userReducer.currentUser.id,
7135
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
7136
+ };
6710
7137
  const promise = this.enqueueRequest({
6711
7138
  description: "Respond to form",
6712
7139
  method: HttpMethod.POST,
6713
7140
  url: `/forms/revisions/${payload.form_revision}/respond/`,
6714
- payload: { ...payloadWithoutFiles, project: activeProjectId },
7141
+ payload: { ...offlineSubmission, project: activeProjectId },
6715
7142
  blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
6716
7143
  (x) => x !== void 0
6717
7144
  ),
6718
7145
  blocks: [payload.offline_id]
6719
7146
  });
6720
- const attachFilesPromises = this.getAttachFilesPromises(files, payload);
6721
- const now = (/* @__PURE__ */ new Date()).toISOString();
6722
- const fullOfflineResult = {
6723
- ...payload,
6724
- created_by: state.userReducer.currentUser.id,
6725
- created_at: now,
6726
- updated_at: now
6727
- };
6728
- const offlineResultWithoutFiles = {
6729
- ...fullOfflineResult,
6730
- ...payloadWithoutFiles
6731
- };
6732
- store.dispatch(updateOrCreateUserFormSubmission(offlineResultWithoutFiles));
7147
+ const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
7148
+ store.dispatch(addFormSubmission(offlineSubmission));
6733
7149
  void promise.then((result) => {
6734
7150
  store.dispatch(addActiveProjectFormSubmissionsCount(1));
6735
- store.dispatch(updateOrCreateUserFormSubmission(result));
7151
+ store.dispatch(setFormSubmission(result));
6736
7152
  return result;
6737
7153
  }).catch(() => {
6738
- store.dispatch(deleteUserFormSubmission(payload.offline_id));
7154
+ store.dispatch(deleteFormSubmission(payload.offline_id));
6739
7155
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
6740
7156
  });
6741
7157
  const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
6742
- return [fullOfflineResult, settledPromise];
7158
+ return [offlineSubmission, settledPromise];
6743
7159
  }
6744
- update(submission) {
7160
+ // Note currently the bulkAdd method is specific to form submissions for components
7161
+ // TODO: adapt the support bulk adding to any model type
7162
+ bulkAdd(args) {
7163
+ const { form_revision, values: argsValues, component_offline_ids } = args;
6745
7164
  const { store } = this.client;
6746
- const { payloadWithoutFiles, files } = separateFilesFromValues(submission);
6747
- if (!("created_by" in payloadWithoutFiles) || !("created_at" in payloadWithoutFiles)) {
6748
- throw new Error("Expected payloadWithoutFiles to have created_by and created_at fields.");
7165
+ const submissions = [];
7166
+ const submissionOfflineIds = [];
7167
+ const offline_ids_to_component_ids = [];
7168
+ let attachFilesPromises = [];
7169
+ const { values, files } = separateFilesFromValues(argsValues);
7170
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
7171
+ const createdBy = store.getState().userReducer.currentUser.id;
7172
+ for (const component_id of component_offline_ids) {
7173
+ const submission = offline({
7174
+ form_revision,
7175
+ values,
7176
+ created_by: createdBy,
7177
+ submitted_at: submittedAt,
7178
+ component: component_id
7179
+ });
7180
+ attachFilesPromises = attachFilesPromises.concat(this.getAttachFilesPromises(files, submission));
7181
+ submissionOfflineIds.push(submission.offline_id);
7182
+ offline_ids_to_component_ids.push([submission.offline_id, component_id]);
7183
+ submissions.push(submission);
6749
7184
  }
7185
+ store.dispatch(addFormSubmissions(submissions));
7186
+ const promise = this.enqueueRequest({
7187
+ description: "Bulk add form submissions",
7188
+ method: HttpMethod.POST,
7189
+ url: `/forms/revisions/${form_revision}/bulk-respond/`,
7190
+ payload: {
7191
+ form_data: values,
7192
+ submitted_at: submittedAt,
7193
+ offline_ids_to_component_ids
7194
+ },
7195
+ blockers: component_offline_ids,
7196
+ blocks: submissionOfflineIds
7197
+ });
7198
+ promise.then((createdSubmissions) => {
7199
+ store.dispatch(updateFormSubmissions(createdSubmissions));
7200
+ }).catch(() => {
7201
+ store.dispatch(deleteFormSubmissions(submissionOfflineIds));
7202
+ });
7203
+ return [submissions, promise.then(() => Promise.all(attachFilesPromises).then(() => promise))];
7204
+ }
7205
+ update(submission) {
7206
+ const { store } = this.client;
7207
+ const { values, files } = separateFilesFromValues(submission.values);
6750
7208
  const attachFilesPromises = this.getAttachFilesPromises(files, submission);
6751
- const fullResult = {
6752
- ...payloadWithoutFiles,
6753
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
7209
+ const offlineSubmission = {
7210
+ ...submission,
7211
+ values
6754
7212
  };
6755
- store.dispatch(updateOrCreateUserFormSubmission(fullResult));
7213
+ const submissionToBeUpdated = store.getState().formSubmissionReducer.formSubmissions[submission.offline_id];
7214
+ store.dispatch(updateFormSubmission(offlineSubmission));
6756
7215
  const promise = this.enqueueRequest({
6757
7216
  description: "Patch form submission",
6758
7217
  method: HttpMethod.PATCH,
6759
7218
  url: `/forms/submissions/${submission.offline_id}/`,
6760
- payload: fullResult,
6761
- blockers: [fullResult.issue, fullResult.component, fullResult.component_stage].filter(
7219
+ payload: offlineSubmission,
7220
+ blockers: [offlineSubmission.issue, offlineSubmission.component, offlineSubmission.component_stage].filter(
6762
7221
  (x) => x !== void 0
6763
7222
  ),
6764
- blocks: [fullResult.offline_id]
7223
+ blocks: [offlineSubmission.offline_id]
7224
+ });
7225
+ promise.then((createdSubmission) => {
7226
+ store.dispatch(setFormSubmission(createdSubmission));
7227
+ }).catch(() => {
7228
+ store.dispatch(setFormSubmission(submissionToBeUpdated));
6765
7229
  });
6766
- return Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7230
+ return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
6767
7231
  }
6768
7232
  async delete(submissionId) {
6769
7233
  const { store } = this.client;
6770
7234
  const state = store.getState();
6771
- const submission = state.userFormReducer.submissions[submissionId];
6772
- store.dispatch(deleteUserFormSubmission(submissionId));
7235
+ const submission = state.formSubmissionReducer.formSubmissions[submissionId];
7236
+ store.dispatch(deleteFormSubmission(submissionId));
6773
7237
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
6774
7238
  try {
6775
7239
  return await this.enqueueRequest({
@@ -6780,10 +7244,8 @@ class UserFormSubmissionService extends BaseApiService {
6780
7244
  blocks: []
6781
7245
  });
6782
7246
  } catch (e) {
6783
- if (submission) {
6784
- store.dispatch(addActiveProjectFormSubmissionsCount(1));
6785
- store.dispatch(updateOrCreateUserFormSubmission(submission));
6786
- }
7247
+ store.dispatch(addActiveProjectFormSubmissionsCount(1));
7248
+ store.dispatch(addFormSubmission(submission));
6787
7249
  throw e;
6788
7250
  }
6789
7251
  }
@@ -6797,7 +7259,7 @@ class UserFormSubmissionService extends BaseApiService {
6797
7259
  blockers: [],
6798
7260
  blocks: []
6799
7261
  });
6800
- store.dispatch(setUserFormSubmissions(submissions));
7262
+ store.dispatch(setFormSubmissions(submissions));
6801
7263
  const attachments = await this.enqueueRequest({
6802
7264
  description: "Fetch form attachments",
6803
7265
  method: HttpMethod.GET,
@@ -6805,7 +7267,7 @@ class UserFormSubmissionService extends BaseApiService {
6805
7267
  blockers: [],
6806
7268
  blocks: []
6807
7269
  });
6808
- store.dispatch(setUserFormSubmissionAttachments(attachments));
7270
+ store.dispatch(setFormSubmissionAttachments(attachments));
6809
7271
  }
6810
7272
  }
6811
7273
  class WorkspaceService extends BaseApiService {
@@ -7503,7 +7965,7 @@ class AgentService extends BaseApiService {
7503
7965
  const activeProjectId = this.client.store.getState().projectReducer.activeProjectId;
7504
7966
  return this.enqueueRequest({
7505
7967
  description: "Prompt agent",
7506
- method: HttpMethod.PUT,
7968
+ method: HttpMethod.POST,
7507
7969
  url: "/agents/prompt/",
7508
7970
  payload: {
7509
7971
  prompt: request2,
@@ -7517,7 +7979,7 @@ class AgentService extends BaseApiService {
7517
7979
  async rate(responseId, rating) {
7518
7980
  return this.enqueueRequest({
7519
7981
  description: "Rate agent response",
7520
- method: HttpMethod.POST,
7982
+ method: HttpMethod.PUT,
7521
7983
  url: `/agents/responses/${responseId}/rate/`,
7522
7984
  payload: { rating },
7523
7985
  blockers: ["rate"],
@@ -7539,6 +8001,7 @@ class OvermapSDK {
7539
8001
  __publicField(this, "organizationAccess", new OrganizationAccessService(this));
7540
8002
  __publicField(this, "issues", new IssueService(this));
7541
8003
  __publicField(this, "issueComments", new IssueCommentService(this));
8004
+ __publicField(this, "issueUpdates", new IssueUpdateService(this));
7542
8005
  __publicField(this, "workspaces", new WorkspaceService(this));
7543
8006
  __publicField(this, "main", new MainService(this));
7544
8007
  __publicField(this, "components", new ComponentService(this));
@@ -13012,52 +13475,54 @@ const styles$4 = {
13012
13475
  Footer,
13013
13476
  Loading
13014
13477
  };
13015
- const ImageCard = memo((props) => {
13016
- const { file, alt, error: error2, size, rightSlot, className, truncateLength, ...rest } = props;
13017
- const fileCardRef = useRef(null);
13018
- const imageInsetRef = useRef(null);
13019
- const fileCardSize = useSize(fileCardRef);
13020
- useLayoutEffect(() => {
13021
- if (!imageInsetRef.current || !fileCardSize)
13022
- return;
13023
- imageInsetRef.current.style.height = `${fileCardSize.height * 4}px`;
13024
- }, [fileCardSize]);
13025
- const fileName2 = useMemo(() => {
13026
- if (!file)
13027
- return;
13028
- return truncateLength !== void 0 ? truncate(file.name, truncateLength) : file.name;
13029
- }, [file, truncateLength]);
13030
- return /* @__PURE__ */ jsxs(
13031
- Flex,
13032
- {
13033
- className: classNames$1(className, styles$4.ImageCard),
13034
- width: "100%",
13035
- direction: "column",
13036
- position: "relative",
13037
- height: "max-content",
13038
- gap: "0",
13039
- ...rest,
13040
- children: [
13041
- !file && !error2 && /* @__PURE__ */ jsx(Flex, { width: "100%", height: "100%", align: "center", justify: "center", position: "absolute", children: /* @__PURE__ */ jsx(Spinner, {}) }),
13042
- /* @__PURE__ */ jsx(Inset, { className: styles$4.ImageInset, ref: imageInsetRef, clip: "padding-box", side: "y", pb: "0", children: file && !error2 && /* @__PURE__ */ jsx("img", { className: styles$4.Image, src: URL.createObjectURL(file), alt: alt ?? file.name }) }),
13043
- /* @__PURE__ */ jsx(
13044
- OvermapItem,
13045
- {
13046
- className: classNames$1(styles$4.Footer, {
13047
- [styles$4.Loading]: !file
13048
- }),
13049
- size,
13050
- ref: fileCardRef,
13051
- leftSlot: error2 ? /* @__PURE__ */ jsx(RiIcon, { icon: "RiFileWarningLine" }) : file && /* @__PURE__ */ jsx(FileIcon, { fileType: file.type }),
13052
- rightSlot,
13053
- children: error2 ?? fileName2
13054
- }
13055
- )
13056
- ]
13057
- }
13058
- );
13059
- });
13060
- ImageCard.displayName = "ImageCard";
13478
+ const ImageCard = memo(
13479
+ forwardRef((props, forwardedRef) => {
13480
+ const { file, alt, error: error2, size, rightSlot, className, truncateLength, ...rest } = props;
13481
+ const fileCardRef = useRef(null);
13482
+ const imageInsetRef = useRef(null);
13483
+ const fileCardSize = useSize(fileCardRef);
13484
+ useLayoutEffect(() => {
13485
+ if (!imageInsetRef.current || !fileCardSize)
13486
+ return;
13487
+ imageInsetRef.current.style.height = `${fileCardSize.height * 4}px`;
13488
+ }, [fileCardSize]);
13489
+ const fileName2 = useMemo(() => {
13490
+ if (!file)
13491
+ return;
13492
+ return truncateLength !== void 0 ? truncate(file.name, truncateLength) : file.name;
13493
+ }, [file, truncateLength]);
13494
+ return /* @__PURE__ */ jsxs(
13495
+ Flex,
13496
+ {
13497
+ className: classNames$1(className, styles$4.ImageCard),
13498
+ width: "100%",
13499
+ direction: "column",
13500
+ position: "relative",
13501
+ height: "max-content",
13502
+ gap: "0",
13503
+ ref: forwardedRef,
13504
+ ...rest,
13505
+ children: [
13506
+ !file && !error2 && /* @__PURE__ */ jsx(Flex, { width: "100%", height: "100%", align: "center", justify: "center", position: "absolute", children: /* @__PURE__ */ jsx(Spinner, {}) }),
13507
+ /* @__PURE__ */ jsx(Inset, { className: styles$4.ImageInset, ref: imageInsetRef, clip: "padding-box", side: "y", pb: "0", children: file && !error2 && /* @__PURE__ */ jsx("img", { className: styles$4.Image, src: URL.createObjectURL(file), alt: alt ?? file.name }) }),
13508
+ /* @__PURE__ */ jsx(
13509
+ OvermapItem,
13510
+ {
13511
+ className: classNames$1(styles$4.Footer, {
13512
+ [styles$4.Loading]: !file
13513
+ }),
13514
+ size,
13515
+ ref: fileCardRef,
13516
+ leftSlot: error2 ? /* @__PURE__ */ jsx(RiIcon, { icon: "RiFileWarningLine" }) : file && /* @__PURE__ */ jsx(FileIcon, { fileType: file.type }),
13517
+ rightSlot,
13518
+ children: error2 ?? fileName2
13519
+ }
13520
+ )
13521
+ ]
13522
+ }
13523
+ );
13524
+ })
13525
+ );
13061
13526
  const UploadInput = memo((props) => {
13062
13527
  var _a2;
13063
13528
  const [{ inputId, labelId, size, severity, helpText, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
@@ -13656,7 +14121,7 @@ const initialFormValues = (fields, values) => {
13656
14121
  };
13657
14122
  const useAttachImagesToFormRevisionFields = (revision) => {
13658
14123
  const { sdk } = useSDK();
13659
- const attachments = useAppSelector(selectRevisionAttachments((revision == null ? void 0 : revision.offline_id) ?? ""));
14124
+ const attachments = useAppSelector(selectAttachmentsOfFormRevision((revision == null ? void 0 : revision.offline_id) ?? ""));
13660
14125
  return useMemo(() => {
13661
14126
  if (!revision || !attachments)
13662
14127
  return revision;
@@ -13738,7 +14203,7 @@ const FormRenderer = memo(
13738
14203
  const FormSubmissionViewer = memo(
13739
14204
  forwardRef((props, ref) => {
13740
14205
  const { submission, showFormDescription = false, showFormTitle = true } = props;
13741
- const revision = useAppSelector(selectFormRevision(submission.form_revision));
14206
+ const revision = useAppSelector(selectUserFormRevision(submission.form_revision));
13742
14207
  const { sdk } = useSDK();
13743
14208
  if (!revision) {
13744
14209
  throw new Error(
@@ -13753,7 +14218,7 @@ const FormSubmissionViewer = memo(
13753
14218
  return formRevisionToSchema(revisionWithImages, { readonly: true });
13754
14219
  }, [revisionWithImages]);
13755
14220
  const submissionValuesWithAttachments = useMemo(() => {
13756
- const attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? [];
14221
+ const attachments = selectAttachmentsOfFormSubmission(submission.offline_id)(sdk.store.getState()) ?? [];
13757
14222
  const downloadedAttachments = {};
13758
14223
  for (const attachment of attachments) {
13759
14224
  const promise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
@@ -13931,16 +14396,13 @@ const FormSubmissionBrowserEntry = memo((props) => {
13931
14396
  const { submission, onSubmissionClick, compact, labelType, rowDecorator } = props;
13932
14397
  const currentUser = useAppSelector(selectCurrentUser);
13933
14398
  const createdBy = useAppSelector(selectUser("created_by" in submission ? submission.created_by : currentUser.id));
13934
- const dateToUse = getCreatedAtOrSubmittedAtDate(submission);
13935
- const formattedDateTime = isToday(dateToUse) ? dateToUse.toLocaleTimeString([], {
13936
- hour: "2-digit",
13937
- minute: "2-digit"
13938
- }) : getLocalDateString(dateToUse);
13939
- const revision = useAppSelector(selectFormRevision(submission.form_revision));
14399
+ const dateToUse = submission.submitted_at;
14400
+ const formattedDateTime = getLocalDateString(dateToUse);
14401
+ const revision = useAppSelector(selectUserFormRevision(submission.form_revision));
13940
14402
  if (!revision) {
13941
14403
  throw new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`);
13942
14404
  }
13943
- const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevision(revision.form))) == null ? void 0 : _a2.revision;
14405
+ const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevisionOfForm(revision.form))) == null ? void 0 : _a2.revision;
13944
14406
  const creatorProfileSrc = useFileSrc({
13945
14407
  file: (createdBy == null ? void 0 : createdBy.profile.file) ?? null,
13946
14408
  fileSha1: (createdBy == null ? void 0 : createdBy.profile.file_sha1) ?? null
@@ -13971,10 +14433,6 @@ const FormSubmissionBrowserEntry = memo((props) => {
13971
14433
  return row;
13972
14434
  });
13973
14435
  FormSubmissionBrowserEntry.displayName = "FormSubmissionBrowserEntry";
13974
- const getCreatedAtOrSubmittedAtDate = (submission) => {
13975
- const date = "created_at" in submission ? submission.created_at : submission.submitted_at;
13976
- return new Date(date);
13977
- };
13978
14436
  const FormSubmissionBrowser = memo((props) => {
13979
14437
  const {
13980
14438
  formId: formId2,
@@ -13988,10 +14446,10 @@ const FormSubmissionBrowser = memo((props) => {
13988
14446
  if (!!formId2 === !!propSubmissions) {
13989
14447
  throw new Error("Either formId or submissions must be provided, but not both.");
13990
14448
  }
13991
- const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectSubmissionsForForm(formId2));
14449
+ const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectFormSubmissionsOfForm(formId2));
13992
14450
  const sortedSubmissions = useMemo(
13993
14451
  () => submissions == null ? void 0 : submissions.sort((a, b) => {
13994
- return getCreatedAtOrSubmittedAtDate(b).getTime() - getCreatedAtOrSubmittedAtDate(a).getTime();
14452
+ return a.submitted_at.localeCompare(b.submitted_at);
13995
14453
  }),
13996
14454
  [submissions]
13997
14455
  );
@@ -14194,17 +14652,15 @@ const FieldActions = memo((props) => {
14194
14652
  Action.key
14195
14653
  )) }),
14196
14654
  /* @__PURE__ */ jsx(Box, { display: forMobile(true, "block"), children: /* @__PURE__ */ jsx(
14197
- DropdownItemMenu,
14655
+ OvermapDropdownMenu,
14198
14656
  {
14199
14657
  trigger: /* @__PURE__ */ jsx(IconButton, { variant: "ghost", "aria-label": "Actions menu", children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiMore2Line" }) }),
14200
14658
  items: actions.map((Action) => {
14201
14659
  var _a2;
14202
14660
  return {
14203
- content: /* @__PURE__ */ jsxs(Flex$1, { gap: "2", align: "center", children: [
14204
- /* @__PURE__ */ jsx(Action.Icon, {}),
14205
- Action.text
14206
- ] }, Action.key),
14207
- onSelect: (_a2 = Action.buttonProps) == null ? void 0 : _a2.onClick
14661
+ leftSlot: /* @__PURE__ */ jsx(Action.Icon, {}),
14662
+ children: Action.text,
14663
+ onClick: (_a2 = Action.buttonProps) == null ? void 0 : _a2.onClick
14208
14664
  };
14209
14665
  })
14210
14666
  }
@@ -14262,10 +14718,8 @@ const useFieldTypeItems = (onSelect = () => null) => {
14262
14718
  const field = FieldTypeToClsMapping[identifier];
14263
14719
  const Icon = field.Icon;
14264
14720
  return {
14265
- content: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
14266
- /* @__PURE__ */ jsx(Icon, {}),
14267
- /* @__PURE__ */ jsx(Text$1, { children: field.fieldTypeName })
14268
- ] }, identifier),
14721
+ children: field.fieldTypeName,
14722
+ leftSlot: /* @__PURE__ */ jsx(Icon, {}),
14269
14723
  value: identifier,
14270
14724
  onSelect: () => {
14271
14725
  onSelect(identifier);
@@ -14469,7 +14923,7 @@ const FieldBuilder = memo((props) => {
14469
14923
  }
14470
14924
  ),
14471
14925
  /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "3", children: [
14472
- /* @__PURE__ */ jsx(Badge, { className: styles.typeBadge, children: (_f = fieldTypeItems.flat().find((item) => item.value === type)) == null ? void 0 : _f.content }),
14926
+ /* @__PURE__ */ jsx(Badge, { className: styles.typeBadge, children: (_f = fieldTypeItems.flat().find((item) => item.value === type)) == null ? void 0 : _f.children }),
14473
14927
  showPopoverInputs && /* @__PURE__ */ jsx(FieldSettingsPopover, { popoverInputs, hasError: popoverHasErrors })
14474
14928
  ] }),
14475
14929
  resolvedImage && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -14830,7 +15284,7 @@ const FieldSectionWithActions = memo((props) => {
14830
15284
  )),
14831
15285
  droppableProvided.placeholder,
14832
15286
  /* @__PURE__ */ jsx(
14833
- DropdownItemMenu,
15287
+ OvermapDropdownMenu,
14834
15288
  {
14835
15289
  trigger: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "soft", children: [
14836
15290
  /* @__PURE__ */ jsx(RiIcon, { icon: "RiAddLine" }),
@@ -15266,6 +15720,8 @@ export {
15266
15720
  IssuePriority,
15267
15721
  IssueService,
15268
15722
  IssueStatus,
15723
+ IssueUpdateChange,
15724
+ IssueUpdateService,
15269
15725
  LicenseLevel,
15270
15726
  LicenseService,
15271
15727
  LicenseStatus,
@@ -15311,6 +15767,7 @@ export {
15311
15767
  VerificationCodeType,
15312
15768
  WorkspaceService,
15313
15769
  YELLOW,
15770
+ _selectLatestFormRevision,
15314
15771
  _setLatestRetryTime,
15315
15772
  acceptProjectInvite,
15316
15773
  addActiveProjectFormSubmissionsCount,
@@ -15326,9 +15783,23 @@ export {
15326
15783
  addDocuments,
15327
15784
  addEmailDomain,
15328
15785
  addFavouriteProjectId,
15786
+ addForm,
15787
+ addFormRevision,
15788
+ addFormRevisionAttachment,
15789
+ addFormRevisionAttachments,
15790
+ addFormRevisions,
15791
+ addFormSubmission,
15792
+ addFormSubmissionAttachment,
15793
+ addFormSubmissionAttachments,
15794
+ addFormSubmissions,
15795
+ addForms,
15329
15796
  addIssue,
15330
15797
  addIssueAttachment,
15331
15798
  addIssueAttachments,
15799
+ addIssueComment,
15800
+ addIssueComments,
15801
+ addIssueUpdate,
15802
+ addIssueUpdates,
15332
15803
  addLicenses,
15333
15804
  addOrReplaceCategories,
15334
15805
  addOrReplaceIssueComment,
@@ -15342,13 +15813,6 @@ export {
15342
15813
  addStageCompletions,
15343
15814
  addStages,
15344
15815
  addToRecentIssues,
15345
- addUserForm,
15346
- addUserFormRevision,
15347
- addUserFormRevisionAttachment,
15348
- addUserFormRevisions,
15349
- addUserFormSubmissionAttachment,
15350
- addUserFormSubmissions,
15351
- addUserForms,
15352
15816
  addUsers,
15353
15817
  addWorkspace,
15354
15818
  areArraysEqual,
@@ -15379,12 +15843,16 @@ export {
15379
15843
  defaultBadgeColor,
15380
15844
  defaultStore,
15381
15845
  deleteComponentType,
15846
+ deleteForm,
15847
+ deleteFormRevision,
15848
+ deleteFormRevisionAttachment,
15849
+ deleteFormRevisionAttachments,
15850
+ deleteFormRevisions,
15851
+ deleteFormSubmission,
15852
+ deleteFormSubmissionAttachment,
15853
+ deleteFormSubmissionAttachments,
15854
+ deleteFormSubmissions,
15382
15855
  deleteProject,
15383
- deleteUserForm,
15384
- deleteUserFormRevision,
15385
- deleteUserFormRevisions,
15386
- deleteUserFormSubmission,
15387
- deleteUserFormSubmissions,
15388
15856
  dequeue,
15389
15857
  deserialize,
15390
15858
  deserializeField,
@@ -15413,7 +15881,11 @@ export {
15413
15881
  fileSlice,
15414
15882
  fileToBlob,
15415
15883
  flipCoordinates,
15884
+ formRevisionReducer,
15416
15885
  formRevisionToSchema,
15886
+ formRevisionsSlice,
15887
+ formSubmissionReducer,
15888
+ formSubmissionSlice,
15417
15889
  index as forms,
15418
15890
  fullComponentMarkerSize,
15419
15891
  generateBadgeColors,
@@ -15488,6 +15960,9 @@ export {
15488
15960
  removeIssue,
15489
15961
  removeIssueAttachment,
15490
15962
  removeIssueComment,
15963
+ removeIssueComments,
15964
+ removeIssueUpdate,
15965
+ removeIssueUpdates,
15491
15966
  removeOrganizationAccess,
15492
15967
  removeProjectAccess,
15493
15968
  removeProjectAccessesOfProject,
@@ -15533,6 +16008,8 @@ export {
15533
16008
  selectAttachmentsOfComponentByType,
15534
16009
  selectAttachmentsOfComponentType,
15535
16010
  selectAttachmentsOfComponentTypeByType,
16011
+ selectAttachmentsOfFormRevision,
16012
+ selectAttachmentsOfFormSubmission,
15536
16013
  selectAttachmentsOfIssue,
15537
16014
  selectAttachmentsOfIssueByType,
15538
16015
  selectAttachmentsOfProject,
@@ -15554,6 +16031,7 @@ export {
15554
16031
  selectComponentTypeForm,
15555
16032
  selectComponentTypeFromComponent,
15556
16033
  selectComponentTypeFromComponents,
16034
+ selectComponentTypeStagesMapping,
15557
16035
  selectComponentTypes,
15558
16036
  selectComponentTypesByName,
15559
16037
  selectComponentTypesFromIds,
@@ -15561,6 +16039,7 @@ export {
15561
16039
  selectComponents,
15562
16040
  selectComponentsByType,
15563
16041
  selectComponentsFromComponentType,
16042
+ selectComponentsMapping,
15564
16043
  selectCreateProjectType,
15565
16044
  selectCurrentUser,
15566
16045
  selectDeletedRequests,
@@ -15578,7 +16057,17 @@ export {
15578
16057
  selectFavouriteProjects,
15579
16058
  selectFileAttachmentsOfIssue,
15580
16059
  selectFilteredUserForms,
15581
- selectFormRevision,
16060
+ selectFormRevisionMapping,
16061
+ selectFormRevisions,
16062
+ selectFormRevisionsOfForm,
16063
+ selectFormSubmission,
16064
+ selectFormSubmissionAttachmentsMapping,
16065
+ selectFormSubmissions,
16066
+ selectFormSubmissionsByComponents,
16067
+ selectFormSubmissionsMapping,
16068
+ selectFormSubmissionsOfComponent,
16069
+ selectFormSubmissionsOfForm,
16070
+ selectFormSubmissionsOfIssue,
15582
16071
  selectHiddenCategoryCount,
15583
16072
  selectHiddenComponentTypeIds,
15584
16073
  selectIsFetchingInitialData,
@@ -15589,11 +16078,13 @@ export {
15589
16078
  selectIssueAttachmentMapping,
15590
16079
  selectIssueAttachments,
15591
16080
  selectIssueMapping,
16081
+ selectIssueUpdateMapping,
16082
+ selectIssueUpdatesOfIssue,
15592
16083
  selectIssues,
15593
- selectLatestFormRevision,
16084
+ selectLatestFormRevisionByForm,
16085
+ selectLatestFormRevisionOfForm,
16086
+ selectLatestFormRevisionsOfComponentTypes,
15594
16087
  selectLatestRetryTime,
15595
- selectLatestRevisionByFormId,
15596
- selectLatestRevisionsFromComponentTypeIds,
15597
16088
  selectLicense,
15598
16089
  selectLicenseForProject,
15599
16090
  selectLicenses,
@@ -15631,8 +16122,6 @@ export {
15631
16122
  selectRecentIssuesAsSearchResults,
15632
16123
  selectRecentProjects,
15633
16124
  selectRehydrated,
15634
- selectRevisionAttachments,
15635
- selectRevisionsForForm,
15636
16125
  selectRootDocuments,
15637
16126
  selectShowTooltips,
15638
16127
  selectSortedEmailDomains,
@@ -15640,21 +16129,20 @@ export {
15640
16129
  selectSortedOrganizationUsers,
15641
16130
  selectSortedProjectUsers,
15642
16131
  selectSortedProjects,
16132
+ selectStage,
15643
16133
  selectStageFormIdsFromStageIds,
15644
16134
  selectStageMapping,
15645
16135
  selectStages,
15646
16136
  selectStagesFromComponentType,
15647
16137
  selectStagesFromComponentTypeIds,
15648
16138
  selectStagesFromStageIds,
15649
- selectSubmissionAttachments,
15650
- selectSubmissionsForComponent,
15651
- selectSubmissionsForForm,
15652
- selectSubmissionsForIssue,
15653
16139
  selectUploadUrl,
15654
16140
  selectUsedColors,
15655
16141
  selectUser,
15656
16142
  selectUserForm,
15657
16143
  selectUserFormMapping,
16144
+ selectUserFormRevision,
16145
+ selectUserFormRevisionAttachmentsMapping,
15658
16146
  selectUsersAsMapping,
15659
16147
  selectVisibleStatuses,
15660
16148
  selectVisibleUserIds,
@@ -15680,11 +16168,20 @@ export {
15680
16168
  setEnableClustering,
15681
16169
  setEnableDuplicateIssues,
15682
16170
  setEnablePlacementMode,
16171
+ setFormRevision,
16172
+ setFormRevisionAttachments,
16173
+ setFormRevisions,
16174
+ setFormSubmission,
16175
+ setFormSubmissionAttachments,
16176
+ setFormSubmissions,
16177
+ setForms,
15683
16178
  setIsFetchingInitialData,
15684
16179
  setIsImportingProjectFile,
15685
16180
  setIsLoading,
15686
16181
  setIssueAttachments,
16182
+ setIssueComment,
15687
16183
  setIssueComments,
16184
+ setIssueUpdates,
15688
16185
  setIssues,
15689
16186
  setLicenses,
15690
16187
  setLoggedIn,
@@ -15702,9 +16199,6 @@ export {
15702
16199
  setTokens,
15703
16200
  setTourStep,
15704
16201
  setUploadUrl,
15705
- setUserFormRevisionAttachments,
15706
- setUserFormSubmissionAttachments,
15707
- setUserFormSubmissions,
15708
16202
  setUsers,
15709
16203
  setVisibleStatuses,
15710
16204
  setVisibleUserIds,
@@ -15728,11 +16222,12 @@ export {
15728
16222
  updateComponentAttachment,
15729
16223
  updateComponentTypeAttachment,
15730
16224
  updateDocuments,
16225
+ updateFormSubmission,
16226
+ updateFormSubmissions,
15731
16227
  updateIssue,
15732
16228
  updateIssueAttachment,
15733
16229
  updateLicense,
15734
16230
  updateOrCreateProject,
15735
- updateOrCreateUserFormSubmission,
15736
16231
  updateOrganizationAccess,
15737
16232
  updateProjectAccess,
15738
16233
  updateProjectAttachment,