@overmap-ai/core 1.0.51 → 1.0.53-add-agent-slice.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 (53) hide show
  1. package/README.md +4 -4
  2. package/dist/forms/builder/constants.d.ts +1 -0
  3. package/dist/forms/builder/utils.d.ts +1 -1
  4. package/dist/forms/fields/QrField/QrField.d.ts +21 -0
  5. package/dist/forms/fields/QrField/QrInput.d.ts +10 -0
  6. package/dist/forms/fields/QrField/index.d.ts +2 -0
  7. package/dist/forms/fields/constants.d.ts +8 -0
  8. package/dist/forms/fields/index.d.ts +1 -0
  9. package/dist/forms/renderer/FormSubmissionBrowser/FormSubmissionBrowser.d.ts +5 -5
  10. package/dist/forms/renderer/FormSubmissionViewer/FormSubmissionViewer.d.ts +3 -3
  11. package/dist/forms/typings.d.ts +5 -2
  12. package/dist/overmap-core.js +1472 -485
  13. package/dist/overmap-core.js.map +1 -1
  14. package/dist/overmap-core.umd.cjs +1472 -486
  15. package/dist/overmap-core.umd.cjs.map +1 -1
  16. package/dist/sdk/sdk.d.ts +3 -1
  17. package/dist/sdk/services/AttachmentService.d.ts +2 -2
  18. package/dist/sdk/services/DocumentService.d.ts +5 -5
  19. package/dist/sdk/services/IssueService.d.ts +2 -2
  20. package/dist/sdk/services/IssueTypeService.d.ts +9 -0
  21. package/dist/sdk/services/TeamService.d.ts +12 -0
  22. package/dist/sdk/services/UserFormService.d.ts +10 -2
  23. package/dist/sdk/services/UserFormSubmissionService.d.ts +9 -2
  24. package/dist/sdk/services/index.d.ts +2 -0
  25. package/dist/store/slices/agentSlice.d.ts +14 -0
  26. package/dist/store/slices/categorySlice.d.ts +7 -1
  27. package/dist/store/slices/documentSlice.d.ts +326 -13
  28. package/dist/store/slices/formRevisionSlice.d.ts +68 -0
  29. package/dist/store/slices/formSlice.d.ts +117 -0
  30. package/dist/store/slices/formSubmissionSlice.d.ts +49 -0
  31. package/dist/store/slices/index.d.ts +6 -1
  32. package/dist/store/slices/issueSlice.d.ts +11 -2
  33. package/dist/store/slices/issueTypeSlice.d.ts +20 -0
  34. package/dist/store/slices/projectFileSlice.d.ts +6 -1
  35. package/dist/store/slices/teamSlice.d.ts +19 -0
  36. package/dist/store/slices/utils.d.ts +1 -0
  37. package/dist/store/slices/workspaceSlice.d.ts +6 -1
  38. package/dist/store/store.d.ts +20 -4
  39. package/dist/style.css +5 -0
  40. package/dist/typings/files.d.ts +11 -1
  41. package/dist/typings/models/attachments.d.ts +11 -15
  42. package/dist/typings/models/base.d.ts +14 -0
  43. package/dist/typings/models/documents.d.ts +18 -7
  44. package/dist/typings/models/forms.d.ts +9 -13
  45. package/dist/typings/models/index.d.ts +2 -0
  46. package/dist/typings/models/issueTypes.d.ts +8 -0
  47. package/dist/typings/models/issues.d.ts +7 -7
  48. package/dist/typings/models/organizations.d.ts +2 -3
  49. package/dist/typings/models/teams.d.ts +10 -0
  50. package/dist/utils/file.d.ts +2 -0
  51. package/dist/utils/forms.d.ts +2 -0
  52. package/package.json +153 -152
  53. package/dist/store/slices/userFormSlice.d.ts +0 -145
@@ -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, OvermapDropdownMenu, 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, Overlay, Button, Spinner, useViewportSize, ButtonGroup, IconColorUtility, Tooltip, Popover, useSize, ToggleButton, Separator, OvermapItem, 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";
@@ -27,6 +27,7 @@ import { useField, useFormikContext, useFormik, FormikProvider } from "formik";
27
27
  import get from "lodash.get";
28
28
  import Linkify from "linkify-react";
29
29
  import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
30
+ import QrScannerAPI from "qr-scanner";
30
31
  import { read, utils } from "xlsx";
31
32
  import { pdfjs, Document, Page } from "react-pdf";
32
33
  import "react-pdf/dist/Page/AnnotationLayer.css";
@@ -677,15 +678,15 @@ const wrapMigration = (migrator) => (state) => {
677
678
  };
678
679
  const migrations = [initialVersioning, signOut, signOut, createOutboxState];
679
680
  const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
680
- const initialState$n = {
681
+ const initialState$s = {
681
682
  accessToken: "",
682
683
  refreshToken: "",
683
684
  isLoggedIn: false
684
685
  };
685
686
  const authSlice = createSlice({
686
687
  name: "auth",
687
- initialState: initialState$n,
688
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
688
+ initialState: initialState$s,
689
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$s)),
689
690
  reducers: {
690
691
  setTokens: (state, action) => {
691
692
  state.accessToken = action.payload.accessToken;
@@ -850,6 +851,19 @@ function downloadInMemoryFile(filename, text) {
850
851
  element.click();
851
852
  document.body.removeChild(element);
852
853
  }
854
+ const constructUploadedFilePayloads = async (files) => {
855
+ const filePayloads = {};
856
+ for (const file of files) {
857
+ const sha1 = await hashFile(file);
858
+ filePayloads[sha1] = {
859
+ sha1,
860
+ extension: file.name.split(".").pop() || "",
861
+ file_type: file.type,
862
+ size: file.size
863
+ };
864
+ }
865
+ return Object.values(filePayloads);
866
+ };
853
867
  const fileToBlob = async (dataUrl) => {
854
868
  return (await fetch(dataUrl)).blob();
855
869
  };
@@ -1416,7 +1430,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
1416
1430
  return getLocalDateString(date);
1417
1431
  return relative.format(days, "days");
1418
1432
  });
1419
- const initialState$m = {
1433
+ const initialState$r = {
1420
1434
  categories: {},
1421
1435
  usedCategoryColors: [],
1422
1436
  categoryVisibility: {
@@ -1426,8 +1440,8 @@ const initialState$m = {
1426
1440
  };
1427
1441
  const categorySlice = createSlice({
1428
1442
  name: "categories",
1429
- initialState: initialState$m,
1430
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
1443
+ initialState: initialState$r,
1444
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$r)),
1431
1445
  reducers: {
1432
1446
  setCategories: (state, action) => {
1433
1447
  if (!Array.isArray(action.payload))
@@ -1559,6 +1573,9 @@ const selectHiddenCategoryCount = (state) => {
1559
1573
  hiddenCategoryCount++;
1560
1574
  return hiddenCategoryCount;
1561
1575
  };
1576
+ const selectIssueCountOfCategory = (categoryId) => (state) => {
1577
+ return Object.values(state.issueReducer.issues).filter((issue) => issue.category === categoryId).length;
1578
+ };
1562
1579
  const categoryReducer = categorySlice.reducer;
1563
1580
  function setAttachments(state, action) {
1564
1581
  state.attachments = {};
@@ -1596,14 +1613,14 @@ function removeAttachments(state, action) {
1596
1613
  delete state.attachments[attachmentId];
1597
1614
  }
1598
1615
  }
1599
- const initialState$l = {
1616
+ const initialState$q = {
1600
1617
  components: {},
1601
1618
  attachments: {}
1602
1619
  };
1603
1620
  const componentSlice = createSlice({
1604
1621
  name: "components",
1605
- initialState: initialState$l,
1606
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1622
+ initialState: initialState$q,
1623
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$q)),
1607
1624
  reducers: {
1608
1625
  addComponent: (state, action) => {
1609
1626
  state.components[action.payload.offline_id] = action.payload;
@@ -1759,13 +1776,13 @@ const {
1759
1776
  removeAllComponentsOfType
1760
1777
  } = componentSlice.actions;
1761
1778
  const componentReducer = componentSlice.reducer;
1762
- const initialState$k = {
1779
+ const initialState$p = {
1763
1780
  completionsByComponentId: {}
1764
1781
  };
1765
1782
  const componentStageCompletionSlice = createSlice({
1766
1783
  name: "componentStageCompletions",
1767
- initialState: initialState$k,
1768
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1784
+ initialState: initialState$p,
1785
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$p)),
1769
1786
  reducers: {
1770
1787
  addStageCompletion: (state, action) => {
1771
1788
  let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
@@ -1816,13 +1833,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
1816
1833
  return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
1817
1834
  };
1818
1835
  const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
1819
- const initialState$j = {
1836
+ const initialState$o = {
1820
1837
  stages: {}
1821
1838
  };
1822
1839
  const componentStageSlice = createSlice({
1823
1840
  name: "componentStages",
1824
- initialState: initialState$j,
1825
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1841
+ initialState: initialState$o,
1842
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$o)),
1826
1843
  reducers: {
1827
1844
  addStages: (state, action) => {
1828
1845
  Object.assign(state.stages, toOfflineIdRecord(action.payload));
@@ -1932,15 +1949,15 @@ const selectStageFormIdsFromStageIds = restructureCreateSelectorWithArgs(
1932
1949
  );
1933
1950
  const { addStages, updateStages, removeStages, linkStageToForm, unlinkStageToForm } = componentStageSlice.actions;
1934
1951
  const componentStageReducer = componentStageSlice.reducer;
1935
- const initialState$i = {
1952
+ const initialState$n = {
1936
1953
  componentTypes: {},
1937
1954
  hiddenComponentTypeIds: {},
1938
1955
  attachments: {}
1939
1956
  };
1940
1957
  const componentTypeSlice = createSlice({
1941
1958
  name: "componentTypes",
1942
- initialState: initialState$i,
1943
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1959
+ initialState: initialState$n,
1960
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
1944
1961
  reducers: {
1945
1962
  addComponentType: (state, action) => {
1946
1963
  state.componentTypes[action.payload.offline_id] = action.payload;
@@ -2051,13 +2068,13 @@ const {
2051
2068
  deleteComponentType
2052
2069
  } = componentTypeSlice.actions;
2053
2070
  const componentTypeReducer = componentTypeSlice.reducer;
2054
- const initialState$h = {
2071
+ const initialState$m = {
2055
2072
  workspaces: {},
2056
2073
  activeWorkspaceId: null
2057
2074
  };
2058
2075
  const workspaceSlice = createSlice({
2059
2076
  name: "workspace",
2060
- initialState: initialState$h,
2077
+ initialState: initialState$m,
2061
2078
  // The `reducers` field lets us define reducers and generate associated actions
2062
2079
  reducers: {
2063
2080
  setWorkspaces: (state, action) => {
@@ -2114,7 +2131,7 @@ const selectPermittedWorkspaceIds = createSelector(
2114
2131
  );
2115
2132
  const workspaceReducer = workspaceSlice.reducer;
2116
2133
  const maxRecentIssues = 10;
2117
- const initialState$g = {
2134
+ const initialState$l = {
2118
2135
  issues: {},
2119
2136
  attachments: {},
2120
2137
  comments: {},
@@ -2126,9 +2143,9 @@ const initialState$g = {
2126
2143
  };
2127
2144
  const issueSlice = createSlice({
2128
2145
  name: "issues",
2129
- initialState: initialState$g,
2146
+ initialState: initialState$l,
2130
2147
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
2131
- Object.assign(state, initialState$g);
2148
+ Object.assign(state, initialState$l);
2132
2149
  }),
2133
2150
  reducers: {
2134
2151
  setIssues: (state, action) => {
@@ -2159,6 +2176,16 @@ const issueSlice = createSlice({
2159
2176
  }
2160
2177
  state.issues[action.payload.offline_id] = action.payload;
2161
2178
  },
2179
+ addIssues: (state, action) => {
2180
+ for (const issue of action.payload) {
2181
+ if (issue.offline_id in state.issues) {
2182
+ throw new Error(`Tried to add duplicate issue with ID: ${issue.offline_id}`);
2183
+ }
2184
+ }
2185
+ for (const issue of action.payload) {
2186
+ state.issues[issue.offline_id] = issue;
2187
+ }
2188
+ },
2162
2189
  addIssueAttachment: addAttachment,
2163
2190
  addIssueAttachments: addAttachments,
2164
2191
  addIssueUpdate: (state, action) => {
@@ -2190,6 +2217,11 @@ const issueSlice = createSlice({
2190
2217
  throw new Error(`Failed to remove issue because ID doesn't exist: ${action.payload}`);
2191
2218
  }
2192
2219
  },
2220
+ removeIssues: (state, action) => {
2221
+ for (const issueId of action.payload) {
2222
+ delete state.issues[issueId];
2223
+ }
2224
+ },
2193
2225
  removeIssueAttachment: removeAttachment,
2194
2226
  removeIssueUpdate: (state, action) => {
2195
2227
  if (action.payload in state.updates) {
@@ -2294,6 +2326,7 @@ const {
2294
2326
  addIssueAttachment,
2295
2327
  addIssueAttachments,
2296
2328
  addIssue,
2329
+ addIssues,
2297
2330
  addIssueUpdate,
2298
2331
  addIssueUpdates,
2299
2332
  addOrReplaceIssueComment,
@@ -2302,6 +2335,7 @@ const {
2302
2335
  removeIssueAttachment,
2303
2336
  removeAttachmentsOfIssue,
2304
2337
  removeIssue,
2338
+ removeIssues,
2305
2339
  removeIssueUpdate,
2306
2340
  removeIssueUpdates,
2307
2341
  removeRecentIssue,
@@ -2536,15 +2570,89 @@ const selectRecentIssuesAsSearchResults = createSelector(
2536
2570
  }
2537
2571
  );
2538
2572
  const issueReducer = issueSlice.reducer;
2539
- const initialState$f = {
2573
+ const initialState$k = {
2574
+ issueTypes: {}
2575
+ };
2576
+ const issueTypeSlice = createSlice({
2577
+ name: "issueTypes",
2578
+ initialState: initialState$k,
2579
+ extraReducers: (builder) => builder.addCase("RESET", (state) => {
2580
+ Object.assign(state, initialState$k);
2581
+ }),
2582
+ reducers: {
2583
+ setIssueTypes: (state, action) => {
2584
+ for (const issueType of action.payload) {
2585
+ state.issueTypes[issueType.offline_id] = issueType;
2586
+ }
2587
+ },
2588
+ setIssueType: (state, action) => {
2589
+ state.issueTypes[action.payload.offline_id] = action.payload;
2590
+ },
2591
+ addIssueType: (state, action) => {
2592
+ if (action.payload.offline_id in state.issueTypes) {
2593
+ throw new Error(`IssueType with offline_id ${action.payload.offline_id} already exists in the store.`);
2594
+ }
2595
+ state.issueTypes[action.payload.offline_id] = action.payload;
2596
+ },
2597
+ updateIssueType: (state, action) => {
2598
+ if (!(action.payload.offline_id in state.issueTypes)) {
2599
+ throw new Error(`IssueType with offline_id ${action.payload.offline_id} does not exist in the store.`);
2600
+ }
2601
+ state.issueTypes[action.payload.offline_id] = action.payload;
2602
+ },
2603
+ removeIssueType: (state, action) => {
2604
+ if (!(action.payload in state.issueTypes)) {
2605
+ throw new Error(`IssueType with offline_id ${action.payload} does not exist in the store.`);
2606
+ }
2607
+ delete state.issueTypes[action.payload];
2608
+ }
2609
+ }
2610
+ });
2611
+ const { setIssueTypes, setIssueType, addIssueType, updateIssueType, removeIssueType } = issueTypeSlice.actions;
2612
+ const selectIssueTypeMapping = (state) => {
2613
+ return state.issueTypeReducer.issueTypes;
2614
+ };
2615
+ const selectIssueTypes = createSelector(selectIssueTypeMapping, (issueTypes) => {
2616
+ return Object.values(issueTypes);
2617
+ });
2618
+ const selectIssueType = restructureCreateSelectorWithArgs(
2619
+ createSelector(
2620
+ [selectIssueTypeMapping, (_, issueTypeId) => issueTypeId],
2621
+ (issueTypesMapping, issueTypeId) => {
2622
+ return issueTypesMapping[issueTypeId];
2623
+ }
2624
+ )
2625
+ );
2626
+ const selectIssueTypesOfOrganization = restructureCreateSelectorWithArgs(
2627
+ createSelector(
2628
+ [selectIssueTypes, (_, organizationId) => organizationId],
2629
+ (issueTypes, organizationId) => {
2630
+ return issueTypes.filter((issueType) => issueType.organization === organizationId);
2631
+ }
2632
+ )
2633
+ );
2634
+ const selectIssuesOfIssueType = restructureCreateSelectorWithArgs(
2635
+ createSelector(
2636
+ [(state) => state.issueReducer.issues, (_, issueTypeId) => issueTypeId],
2637
+ (issuesMapping, issueTypeId) => {
2638
+ return Object.values(issuesMapping).filter((issue) => issue.issue_type === issueTypeId);
2639
+ }
2640
+ )
2641
+ );
2642
+ const selectIssuesOfIssueTypeCount = (issueTypeId) => (state) => {
2643
+ var _a2;
2644
+ return ((_a2 = selectIssuesOfIssueType(issueTypeId)(state)) == null ? void 0 : _a2.length) ?? 0;
2645
+ };
2646
+ const issueTypeReducer = issueTypeSlice.reducer;
2647
+ const initialState$j = {
2540
2648
  s3Urls: {}
2541
2649
  };
2542
2650
  const msPerHour = 1e3 * 60 * 60;
2543
2651
  const msPerWeek = msPerHour * 24 * 7;
2544
2652
  const fileSlice = createSlice({
2545
2653
  name: "file",
2546
- initialState: initialState$f,
2547
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
2654
+ initialState: initialState$j,
2655
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
2548
2656
  reducers: {
2549
2657
  setUploadUrl: (state, action) => {
2550
2658
  const { url, fields, sha1 } = action.payload;
@@ -2571,7 +2679,7 @@ const selectUploadUrl = (sha1) => (state) => {
2571
2679
  return url;
2572
2680
  };
2573
2681
  const fileReducer = fileSlice.reducer;
2574
- const initialState$e = {
2682
+ const initialState$i = {
2575
2683
  // TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
2576
2684
  mapStyle: MapStyle.SATELLITE,
2577
2685
  showTooltips: false,
@@ -2579,8 +2687,8 @@ const initialState$e = {
2579
2687
  };
2580
2688
  const mapSlice = createSlice({
2581
2689
  name: "map",
2582
- initialState: initialState$e,
2583
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2690
+ initialState: initialState$i,
2691
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
2584
2692
  reducers: {
2585
2693
  setMapStyle: (state, action) => {
2586
2694
  state.mapStyle = action.payload;
@@ -2649,7 +2757,7 @@ var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
2649
2757
  LicenseStatus2[LicenseStatus2["PAST_DUE"] = 8] = "PAST_DUE";
2650
2758
  return LicenseStatus2;
2651
2759
  })(LicenseStatus || {});
2652
- const initialState$d = {
2760
+ const initialState$h = {
2653
2761
  users: {},
2654
2762
  currentUser: {
2655
2763
  id: 0,
@@ -2660,8 +2768,8 @@ const initialState$d = {
2660
2768
  };
2661
2769
  const userSlice = createSlice({
2662
2770
  name: "users",
2663
- initialState: initialState$d,
2664
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2771
+ initialState: initialState$h,
2772
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
2665
2773
  reducers: {
2666
2774
  setUsers: (state, action) => {
2667
2775
  const usersMapping = {};
@@ -2723,13 +2831,13 @@ const selectUser = (userId) => (state) => {
2723
2831
  const selectUsersAsMapping = (state) => state.userReducer.users;
2724
2832
  const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
2725
2833
  const userReducer = userSlice.reducer;
2726
- const initialState$c = {
2834
+ const initialState$g = {
2727
2835
  organizationAccesses: {}
2728
2836
  };
2729
2837
  const organizationAccessSlice = createSlice({
2730
2838
  name: "organizationAccess",
2731
- initialState: initialState$c,
2732
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2839
+ initialState: initialState$g,
2840
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
2733
2841
  reducers: {
2734
2842
  setOrganizationAccesses: (state, action) => {
2735
2843
  if (!Array.isArray(action.payload))
@@ -2792,13 +2900,13 @@ const selectOrganizationAccessUserMapping = (state) => {
2792
2900
  return organizationAccesses;
2793
2901
  };
2794
2902
  const organizationAccessReducer = organizationAccessSlice.reducer;
2795
- const initialState$b = {
2903
+ const initialState$f = {
2796
2904
  licenses: {}
2797
2905
  };
2798
2906
  const licenseSlice = createSlice({
2799
2907
  name: "license",
2800
- initialState: initialState$b,
2801
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2908
+ initialState: initialState$f,
2909
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
2802
2910
  reducers: {
2803
2911
  setLicenses: (state, action) => {
2804
2912
  if (!Array.isArray(action.payload))
@@ -2843,13 +2951,13 @@ const selectLicensesForProjectsMapping = createSelector(
2843
2951
  (licenses) => Object.values(licenses).filter((license) => license.project).reduce((accum, license) => ({ ...accum, [license.project]: license }), {})
2844
2952
  );
2845
2953
  const licenseReducer = licenseSlice.reducer;
2846
- const initialState$a = {
2954
+ const initialState$e = {
2847
2955
  projectAccesses: {}
2848
2956
  };
2849
2957
  const projectAccessSlice = createSlice({
2850
2958
  name: "projectAccess",
2851
- initialState: initialState$a,
2852
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2959
+ initialState: initialState$e,
2960
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2853
2961
  reducers: {
2854
2962
  setProjectAccesses: (state, action) => {
2855
2963
  if (!Array.isArray(action.payload))
@@ -2917,7 +3025,7 @@ const selectProjectAccessUserMapping = (state) => {
2917
3025
  return projectAccesses;
2918
3026
  };
2919
3027
  const projectAccessReducer = projectAccessSlice.reducer;
2920
- const initialState$9 = {
3028
+ const initialState$d = {
2921
3029
  projects: {},
2922
3030
  activeProjectId: null,
2923
3031
  recentProjectIds: [],
@@ -2927,7 +3035,7 @@ const initialState$9 = {
2927
3035
  };
2928
3036
  const projectSlice = createSlice({
2929
3037
  name: "projects",
2930
- initialState: initialState$9,
3038
+ initialState: initialState$d,
2931
3039
  reducers: {
2932
3040
  setProjects: (state, action) => {
2933
3041
  const projectsMap = {};
@@ -3114,14 +3222,14 @@ const selectAttachmentsOfProjectByType = restructureCreateSelectorWithArgs(
3114
3222
  }
3115
3223
  )
3116
3224
  );
3117
- const initialState$8 = {
3225
+ const initialState$c = {
3118
3226
  organizations: {},
3119
3227
  activeOrganizationId: null
3120
3228
  };
3121
3229
  const organizationSlice = createSlice({
3122
3230
  name: "organizations",
3123
- initialState: initialState$8,
3124
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
3231
+ initialState: initialState$c,
3232
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
3125
3233
  reducers: {
3126
3234
  setOrganizations: (state, action) => {
3127
3235
  for (const org of action.payload) {
@@ -3240,14 +3348,14 @@ const createOfflineAction = (request2, baseUrl) => {
3240
3348
  }
3241
3349
  };
3242
3350
  };
3243
- const initialState$7 = {
3351
+ const initialState$b = {
3244
3352
  deletedRequests: [],
3245
3353
  latestRetryTime: 0
3246
3354
  };
3247
3355
  const outboxSlice = createSlice({
3248
3356
  name: "outbox",
3249
- initialState: initialState$7,
3250
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
3357
+ initialState: initialState$b,
3358
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
3251
3359
  reducers: {
3252
3360
  // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
3253
3361
  // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
@@ -3279,7 +3387,7 @@ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
3279
3387
  const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
3280
3388
  const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
3281
3389
  const outboxReducer = outboxSlice.reducer;
3282
- const initialState$6 = {
3390
+ const initialState$a = {
3283
3391
  projectFiles: {},
3284
3392
  activeProjectFileId: null,
3285
3393
  isImportingProjectFile: false,
@@ -3287,8 +3395,8 @@ const initialState$6 = {
3287
3395
  };
3288
3396
  const projectFileSlice = createSlice({
3289
3397
  name: "projectFiles",
3290
- initialState: initialState$6,
3291
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
3398
+ initialState: initialState$a,
3399
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
3292
3400
  reducers: {
3293
3401
  addOrReplaceProjectFiles: (state, action) => {
3294
3402
  for (let fileObj of action.payload) {
@@ -3389,12 +3497,12 @@ const selectProjectFiles = createSelector(
3389
3497
  const selectActiveProjectFileId = (state) => state.projectFileReducer.activeProjectFileId;
3390
3498
  const selectIsImportingProjectFile = (state) => state.projectFileReducer.isImportingProjectFile;
3391
3499
  const projectFileReducer = projectFileSlice.reducer;
3392
- const initialState$5 = {
3500
+ const initialState$9 = {
3393
3501
  isRehydrated: false
3394
3502
  };
3395
3503
  const rehydratedSlice = createSlice({
3396
3504
  name: "rehydrated",
3397
- initialState: initialState$5,
3505
+ initialState: initialState$9,
3398
3506
  // The `reducers` field lets us define reducers and generate associated actions
3399
3507
  reducers: {
3400
3508
  setRehydrated: (state, action) => {
@@ -3404,7 +3512,7 @@ const rehydratedSlice = createSlice({
3404
3512
  });
3405
3513
  const selectRehydrated = (state) => state.rehydratedReducer.isRehydrated;
3406
3514
  const rehydratedReducer = rehydratedSlice.reducer;
3407
- const initialState$4 = {
3515
+ const initialState$8 = {
3408
3516
  useIssueTemplate: false,
3409
3517
  placementMode: false,
3410
3518
  enableClustering: false,
@@ -3421,8 +3529,8 @@ const initialState$4 = {
3421
3529
  };
3422
3530
  const settingSlice = createSlice({
3423
3531
  name: "settings",
3424
- initialState: initialState$4,
3425
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
3532
+ initialState: initialState$8,
3533
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
3426
3534
  reducers: {
3427
3535
  setEnableDuplicateIssues: (state, action) => {
3428
3536
  state.useIssueTemplate = action.payload;
@@ -3468,146 +3576,231 @@ const selectAppearance = (state) => state.settingReducer.appearance;
3468
3576
  const settingReducer = settingSlice.reducer;
3469
3577
  const selectIsFetchingInitialData = (state) => state.settingReducer.isFetchingInitialData;
3470
3578
  const selectIsLoading = (state) => state.settingReducer.isLoading;
3471
- const LATEST_REVISION_CACHE = {};
3472
- function considerCachingRevision(revision, formId2, preferPending = false) {
3473
- var _a2;
3474
- if (!revision) {
3475
- if (!formId2) {
3476
- throw new Error("If revision is null, formId is required.");
3477
- }
3478
- const currentLatestRevision = getLatestRevisionFromCache(formId2);
3479
- if (currentLatestRevision)
3480
- return;
3481
- LATEST_REVISION_CACHE[formId2] = null;
3482
- return;
3483
- }
3484
- if (revision.revision === "Pending") {
3485
- if (preferPending) {
3486
- LATEST_REVISION_CACHE[revision.form] = revision;
3487
- }
3488
- return;
3489
- }
3490
- const cachedRevision = (_a2 = LATEST_REVISION_CACHE[revision.form]) == null ? void 0 : _a2.revision;
3491
- if (revision.revision > (typeof cachedRevision === "number" ? cachedRevision : -1)) {
3492
- LATEST_REVISION_CACHE[revision.form] = revision;
3579
+ const formRevisionSortFn = (formRevisionA, formRevisionB) => {
3580
+ const revisionA = formRevisionA.revision;
3581
+ const revisionB = formRevisionB.revision;
3582
+ if (revisionA === "Pending" && revisionB === "Pending") {
3583
+ return formRevisionA.submitted_at < formRevisionB.submitted_at ? -1 : 1;
3584
+ } else if (revisionA === "Pending") {
3585
+ return 1;
3586
+ } else if (revisionB === "Pending") {
3587
+ return -1;
3588
+ } else {
3589
+ return revisionA < revisionB ? -1 : 1;
3493
3590
  }
3494
- }
3495
- function getLatestRevisionFromCache(formId2) {
3496
- return LATEST_REVISION_CACHE[formId2];
3497
- }
3498
- const initialState$3 = {
3499
- userForms: {},
3500
- revisions: {},
3501
- submissions: {},
3502
- submissionAttachments: {},
3503
- revisionAttachments: {}
3504
- };
3505
- const userFormSlice = createSlice({
3506
- name: "userForms",
3507
- initialState: initialState$3,
3508
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
3591
+ };
3592
+ const initialState$7 = {
3593
+ formRevisions: {},
3594
+ attachments: {}
3595
+ };
3596
+ const formRevisionsSlice = createSlice({
3597
+ name: "formRevisions",
3598
+ initialState: initialState$7,
3599
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
3509
3600
  reducers: {
3510
- setUserForms: (state, action) => {
3511
- state.userForms = {};
3512
- action.payload.forEach((userForm) => {
3513
- state.userForms[userForm.offline_id] = userForm;
3514
- });
3515
- },
3516
- addUserForm: (state, action) => {
3517
- state.userForms[action.payload.offline_id] = action.payload;
3518
- },
3519
- addUserForms: (state, action) => {
3520
- action.payload.forEach((userForm) => {
3521
- state.userForms[userForm.offline_id] = userForm;
3522
- });
3601
+ // revision related actions
3602
+ setFormRevision: (state, action) => {
3603
+ state.formRevisions[action.payload.offline_id] = action.payload;
3523
3604
  },
3524
- addUserFormRevisions: (state, action) => {
3525
- action.payload.forEach((userFormRevision) => {
3526
- state.revisions[userFormRevision.offline_id] = userFormRevision;
3527
- considerCachingRevision(userFormRevision);
3528
- });
3529
- },
3530
- addUserFormRevision: (state, action) => {
3531
- state.revisions[action.payload.offline_id] = action.payload;
3532
- considerCachingRevision(action.payload);
3605
+ setFormRevisions: (state, action) => {
3606
+ state.formRevisions = {};
3607
+ for (const revision of action.payload) {
3608
+ state.formRevisions[revision.offline_id] = revision;
3609
+ }
3533
3610
  },
3534
- deleteUserFormRevision: (state, action) => {
3535
- delete state.revisions[action.payload];
3536
- delete LATEST_REVISION_CACHE[action.payload];
3611
+ addFormRevision: (state, action) => {
3612
+ if (state.formRevisions[action.payload.offline_id] !== void 0) {
3613
+ throw new Error(`Revision with offline_id ${action.payload.offline_id} already exists`);
3614
+ }
3615
+ state.formRevisions[action.payload.offline_id] = action.payload;
3537
3616
  },
3538
- deleteUserFormRevisions: (state, action) => {
3617
+ addFormRevisions: (state, action) => {
3539
3618
  for (const userFormRevision of action.payload) {
3540
- delete state.revisions[userFormRevision.offline_id];
3541
- delete LATEST_REVISION_CACHE[userFormRevision.offline_id];
3619
+ if (state.formRevisions[userFormRevision.offline_id] !== void 0) {
3620
+ throw new Error(`Revision with offline_id ${userFormRevision.offline_id} already exists`);
3621
+ }
3542
3622
  }
3543
- },
3544
- updateOrCreateUserFormSubmission: (state, action) => {
3545
- state.submissions[action.payload.offline_id] = action.payload;
3546
- },
3547
- addUserFormSubmissionAttachment: (state, action) => {
3548
- const submissionId = action.payload.submission;
3549
- const submissionAttachments = state.submissionAttachments[submissionId];
3550
- if (submissionAttachments) {
3551
- submissionAttachments.push(action.payload);
3552
- } else {
3553
- state.submissionAttachments[submissionId] = [action.payload];
3623
+ for (const userFormRevision of action.payload) {
3624
+ state.formRevisions[userFormRevision.offline_id] = userFormRevision;
3554
3625
  }
3555
3626
  },
3556
- addUserFormRevisionAttachment: (state, action) => {
3557
- const revisionId = action.payload.revision;
3558
- const revisionAttachments = state.revisionAttachments[revisionId];
3559
- if (revisionAttachments) {
3560
- revisionAttachments.push(action.payload);
3561
- } else {
3562
- state.revisionAttachments[revisionId] = [action.payload];
3627
+ // UserFormRevisions do not get updated
3628
+ deleteFormRevision: (state, action) => {
3629
+ if (state.formRevisions[action.payload] === void 0) {
3630
+ throw new Error(`Revision with offline_id ${action.payload} does not exist`);
3563
3631
  }
3632
+ delete state.formRevisions[action.payload];
3564
3633
  },
3565
- setUserFormSubmissionAttachments: (state, action) => {
3566
- state.submissionAttachments = {};
3567
- for (const attachment of action.payload) {
3568
- const submissionId = attachment.submission;
3569
- const submissionAttachments = state.submissionAttachments[submissionId];
3570
- if (submissionAttachments) {
3571
- submissionAttachments.push(attachment);
3572
- } else {
3573
- state.submissionAttachments[submissionId] = [attachment];
3634
+ deleteFormRevisions: (state, action) => {
3635
+ for (const offlineId of action.payload) {
3636
+ if (state.formRevisions[offlineId] === void 0) {
3637
+ throw new Error(`Revision with offline_id ${offlineId} does not exist`);
3574
3638
  }
3575
3639
  }
3640
+ for (const offlineId of action.payload) {
3641
+ delete state.formRevisions[offlineId];
3642
+ }
3576
3643
  },
3577
- setUserFormRevisionAttachments: (state, action) => {
3578
- state.revisionAttachments = {};
3644
+ // attachment related actions
3645
+ setFormRevisionAttachments: (state, action) => {
3646
+ state.attachments = {};
3579
3647
  for (const attachment of action.payload) {
3580
- const revisionId = attachment.revision;
3581
- const revisionAttachments = state.revisionAttachments[revisionId];
3582
- if (revisionAttachments) {
3583
- revisionAttachments.push(attachment);
3584
- } else {
3585
- state.revisionAttachments[revisionId] = [attachment];
3586
- }
3648
+ state.attachments[attachment.offline_id] = attachment;
3587
3649
  }
3588
3650
  },
3589
- deleteUserFormSubmission: (state, action) => {
3590
- delete state.submissions[action.payload];
3651
+ addFormRevisionAttachment: (state, action) => {
3652
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3653
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3654
+ }
3655
+ state.attachments[action.payload.offline_id] = action.payload;
3591
3656
  },
3592
- deleteUserFormSubmissions: (state, action) => {
3593
- for (const userFormSubmission of action.payload) {
3594
- delete state.submissions[userFormSubmission.offline_id];
3657
+ addFormRevisionAttachments: (state, action) => {
3658
+ for (const attachment of action.payload) {
3659
+ if (state.attachments[attachment.offline_id] !== void 0) {
3660
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3661
+ }
3662
+ }
3663
+ for (const attachment of action.payload) {
3664
+ state.attachments[attachment.offline_id] = attachment;
3595
3665
  }
3596
3666
  },
3597
- addUserFormSubmissions: (state, action) => {
3598
- for (const submission of action.payload) {
3599
- state.submissions[submission.offline_id] = submission;
3667
+ deleteFormRevisionAttachment: (state, action) => {
3668
+ if (state.attachments[action.payload] === void 0) {
3669
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3600
3670
  }
3671
+ delete state.attachments[action.payload];
3601
3672
  },
3602
- setUserFormSubmissions: (state, action) => {
3603
- state.submissions = {};
3604
- action.payload.forEach((submission) => {
3605
- state.submissions[submission.offline_id] = submission;
3673
+ deleteFormRevisionAttachments: (state, action) => {
3674
+ for (const offlineId of action.payload) {
3675
+ if (state.attachments[offlineId] === void 0) {
3676
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3677
+ }
3678
+ }
3679
+ for (const offlineId of action.payload) {
3680
+ delete state.attachments[offlineId];
3681
+ }
3682
+ }
3683
+ }
3684
+ });
3685
+ const {
3686
+ setFormRevision,
3687
+ setFormRevisions,
3688
+ addFormRevision,
3689
+ addFormRevisions,
3690
+ deleteFormRevision,
3691
+ deleteFormRevisions,
3692
+ setFormRevisionAttachments,
3693
+ addFormRevisionAttachment,
3694
+ addFormRevisionAttachments,
3695
+ deleteFormRevisionAttachment,
3696
+ deleteFormRevisionAttachments
3697
+ } = formRevisionsSlice.actions;
3698
+ const selectFormRevisionMapping = (state) => state.formRevisionReducer.formRevisions;
3699
+ const selectFormRevisions = createSelector(
3700
+ [selectFormRevisionMapping],
3701
+ (formRevisions) => Object.values(formRevisions)
3702
+ );
3703
+ const selectFormRevision = (formRevisionId) => (state) => {
3704
+ return state.formRevisionReducer.formRevisions[formRevisionId];
3705
+ };
3706
+ const _selectLatestFormRevision = (formRevisions, formId2) => {
3707
+ let ret = null;
3708
+ for (const candidate of Object.values(formRevisions)) {
3709
+ if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
3710
+ ret = candidate;
3711
+ }
3712
+ }
3713
+ if (!ret) {
3714
+ throw new Error("No form revision found for form " + formId2);
3715
+ }
3716
+ return ret;
3717
+ };
3718
+ const selectLatestFormRevisionOfForm = restructureCreateSelectorWithArgs(
3719
+ createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3720
+ return revisions.filter((revision) => revision.form === formId2).sort(formRevisionSortFn).pop();
3721
+ })
3722
+ );
3723
+ const selectFormRevisionsOfForm = restructureCreateSelectorWithArgs(
3724
+ createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3725
+ return revisions.filter((revision) => {
3726
+ return revision.form === formId2;
3727
+ });
3728
+ })
3729
+ );
3730
+ const selectLatestFormRevisionsOfComponentTypes = restructureCreateSelectorWithArgs(
3731
+ createSelector(
3732
+ [
3733
+ (state) => state.formReducer.forms,
3734
+ selectFormRevisionMapping,
3735
+ (_state, componentTypeIds) => componentTypeIds
3736
+ ],
3737
+ (userForms, revisions, componentTypeIds) => {
3738
+ const componentTypeIdsSet = new Set(componentTypeIds);
3739
+ const formsOfComponentTypes = {};
3740
+ const ret = {};
3741
+ for (const form of Object.values(userForms)) {
3742
+ if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
3743
+ formsOfComponentTypes[form.offline_id] = form;
3744
+ }
3745
+ }
3746
+ for (const revision of Object.values(revisions)) {
3747
+ const form = formsOfComponentTypes[revision.form];
3748
+ if (!form || !form.component_type || ret[form.component_type] && formRevisionSortFn(ret[form.component_type], revision) > 0)
3749
+ continue;
3750
+ ret[form.component_type] = revision;
3751
+ }
3752
+ return ret;
3753
+ }
3754
+ )
3755
+ );
3756
+ const selectLatestFormRevisionByForm = createSelector([selectFormRevisionMapping], (revisions) => {
3757
+ const latestRevisions = {};
3758
+ for (const revision of Object.values(revisions)) {
3759
+ const formId2 = revision.form;
3760
+ const currentLatestRevision = latestRevisions[formId2];
3761
+ if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
3762
+ latestRevisions[formId2] = revision;
3763
+ }
3764
+ }
3765
+ return latestRevisions;
3766
+ });
3767
+ const selectUserFormRevisionAttachmentsMapping = (state) => {
3768
+ return state.formRevisionReducer.attachments;
3769
+ };
3770
+ const selectAttachmentsOfFormRevision = restructureCreateSelectorWithArgs(
3771
+ createSelector(
3772
+ [selectUserFormRevisionAttachmentsMapping, (_state, revisionId) => revisionId],
3773
+ (attachments, revisionId) => {
3774
+ return Object.values(attachments).filter((attachment) => attachment.revision === revisionId);
3775
+ }
3776
+ )
3777
+ );
3778
+ const formRevisionReducer = formRevisionsSlice.reducer;
3779
+ const initialState$6 = {
3780
+ forms: {}
3781
+ };
3782
+ const formSlice = createSlice({
3783
+ name: "forms",
3784
+ initialState: initialState$6,
3785
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
3786
+ reducers: {
3787
+ setForms: (state, action) => {
3788
+ state.forms = {};
3789
+ action.payload.forEach((userForm) => {
3790
+ state.forms[userForm.offline_id] = userForm;
3606
3791
  });
3607
3792
  },
3793
+ addForm: (state, action) => {
3794
+ state.forms[action.payload.offline_id] = action.payload;
3795
+ },
3796
+ addForms: (state, action) => {
3797
+ for (const userForm of action.payload) {
3798
+ state.forms[userForm.offline_id] = userForm;
3799
+ }
3800
+ },
3608
3801
  favoriteForm: (state, action) => {
3609
3802
  const { formId: formId2 } = action.payload;
3610
- const form = state.userForms[formId2];
3803
+ const form = state.forms[formId2];
3611
3804
  if (!form) {
3612
3805
  throw new Error("No form exists with the id " + formId2);
3613
3806
  }
@@ -3615,48 +3808,23 @@ const userFormSlice = createSlice({
3615
3808
  },
3616
3809
  unfavoriteForm: (state, action) => {
3617
3810
  const { formId: formId2 } = action.payload;
3618
- const form = state.userForms[formId2];
3811
+ const form = state.forms[formId2];
3619
3812
  if (!form) {
3620
3813
  throw new Error("No form exists with the id " + formId2);
3621
3814
  }
3622
3815
  form.favorite = false;
3623
3816
  },
3624
- deleteUserForm: (state, action) => {
3625
- delete state.userForms[action.payload];
3817
+ deleteForm: (state, action) => {
3818
+ delete state.forms[action.payload];
3626
3819
  }
3627
3820
  }
3628
3821
  });
3629
- const {
3630
- addUserForm,
3631
- addUserForms,
3632
- addUserFormRevisions,
3633
- updateOrCreateUserFormSubmission,
3634
- addUserFormSubmissions,
3635
- deleteUserFormSubmission,
3636
- deleteUserFormSubmissions,
3637
- favoriteForm,
3638
- unfavoriteForm,
3639
- deleteUserForm,
3640
- deleteUserFormRevision,
3641
- deleteUserFormRevisions,
3642
- setUserFormSubmissions,
3643
- addUserFormRevision,
3644
- addUserFormSubmissionAttachment,
3645
- addUserFormRevisionAttachment,
3646
- setUserFormSubmissionAttachments,
3647
- setUserFormRevisionAttachments
3648
- } = userFormSlice.actions;
3649
- const selectSubmissionAttachments = (submissionId) => (state) => {
3650
- return state.userFormReducer.submissionAttachments[submissionId] || [];
3651
- };
3652
- const selectRevisionAttachments = (revisionId) => (state) => {
3653
- return state.userFormReducer.revisionAttachments[revisionId] || [];
3654
- };
3655
- const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3822
+ const { setForms, addForm, addForms, favoriteForm, unfavoriteForm, deleteForm } = formSlice.actions;
3823
+ const selectFilteredForms = restructureCreateSelectorWithArgs(
3656
3824
  createSelector(
3657
3825
  [
3658
- (state) => state.userFormReducer.userForms,
3659
- (state) => state.userFormReducer.revisions,
3826
+ (state) => state.formReducer.forms,
3827
+ (state) => state.formRevisionReducer.formRevisions,
3660
3828
  (_state, search) => search
3661
3829
  ],
3662
3830
  (userForms, revisions, search) => {
@@ -3690,63 +3858,233 @@ const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3690
3858
  { memoizeOptions: { equalityCheck: shallowEqual$1 } }
3691
3859
  )
3692
3860
  );
3693
- const selectFormRevision = (revisionId) => (state) => {
3694
- return state.userFormReducer.revisions[revisionId];
3861
+ const selectForm = (formId2) => (state) => {
3862
+ return state.formReducer.forms[formId2];
3695
3863
  };
3696
- const _selectLatestFormRevision = (revisions, formId2) => {
3697
- let ret = null;
3698
- for (const candidate of Object.values(revisions)) {
3699
- if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
3700
- ret = candidate;
3701
- }
3702
- }
3703
- if (!ret) {
3704
- throw new Error("No revision found for form " + formId2);
3705
- }
3706
- return ret;
3864
+ const selectFormMapping = (state) => {
3865
+ return state.formReducer.forms;
3707
3866
  };
3708
- const selectLatestFormRevision = restructureCreateSelectorWithArgs(
3867
+ const selectFormOfComponentType = restructureCreateSelectorWithArgs(
3709
3868
  createSelector(
3710
- [(state) => state.userFormReducer.revisions, (_state, formId2) => formId2],
3711
- (revisions, formId2) => {
3712
- if (!formId2) {
3713
- throw new Error("formId is required");
3714
- }
3715
- return _selectLatestFormRevision(revisions, formId2);
3869
+ [selectFormMapping, (_state, componentTypeId) => componentTypeId],
3870
+ (userForms, componentTypeId) => {
3871
+ return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
3716
3872
  }
3717
3873
  )
3718
3874
  );
3719
- const selectUserForm = (formId2) => (state) => {
3720
- return state.userFormReducer.userForms[formId2];
3721
- };
3722
- const selectSubmissionMapping = (state) => state.userFormReducer.submissions;
3723
- const selectUserFormSubmission = (submissionId) => (state) => {
3724
- return state.userFormReducer.submissions[submissionId];
3725
- };
3726
- const selectSubmissions = createSelector([selectSubmissionMapping], (submissions) => Object.values(submissions));
3727
- const selectRevisionMapping = (state) => state.userFormReducer.revisions;
3728
- const selectRevisions = createSelector([selectRevisionMapping], (revisions) => Object.values(revisions));
3729
- const selectRevisionsForForm = restructureCreateSelectorWithArgs(
3730
- createSelector([selectRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3731
- return revisions.filter((revision) => {
3732
- return revision.form === formId2;
3733
- });
3734
- })
3875
+ const selectFormOfIssueType = restructureCreateSelectorWithArgs(
3876
+ createSelector(
3877
+ [selectFormMapping, (_state, issueTypeId) => issueTypeId],
3878
+ (userForms, issueTypeId) => {
3879
+ return Object.values(userForms).find((userForm) => userForm.issue_type === issueTypeId);
3880
+ }
3881
+ )
3882
+ );
3883
+ const selectFormsCount = createSelector([selectFormMapping], (userForms) => {
3884
+ return Object.keys(userForms).length;
3885
+ });
3886
+ const selectGeneralFormCount = createSelector([selectFormMapping], (userForms) => {
3887
+ return Object.values(userForms).filter((form) => !form.component_type).length;
3888
+ });
3889
+ const formReducer = formSlice.reducer;
3890
+ const initialState$5 = {
3891
+ formSubmissions: {},
3892
+ attachments: {}
3893
+ };
3894
+ const formSubmissionSlice = createSlice({
3895
+ name: "formSubmissions",
3896
+ initialState: initialState$5,
3897
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
3898
+ reducers: {
3899
+ setFormSubmission: (state, action) => {
3900
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3901
+ },
3902
+ setFormSubmissions: (state, action) => {
3903
+ state.formSubmissions = {};
3904
+ for (const submission of action.payload) {
3905
+ state.formSubmissions[submission.offline_id] = submission;
3906
+ }
3907
+ },
3908
+ addFormSubmission: (state, action) => {
3909
+ if (action.payload.offline_id in state.formSubmissions) {
3910
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} already exists`);
3911
+ }
3912
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3913
+ },
3914
+ addFormSubmissions: (state, action) => {
3915
+ for (const submission of action.payload) {
3916
+ if (state.formSubmissions[submission.offline_id] !== void 0) {
3917
+ throw new Error(`Submission with offline_id ${submission.offline_id} already exists`);
3918
+ }
3919
+ }
3920
+ for (const submission of action.payload) {
3921
+ state.formSubmissions[submission.offline_id] = submission;
3922
+ }
3923
+ },
3924
+ updateFormSubmission: (state, action) => {
3925
+ if (state.formSubmissions[action.payload.offline_id] === void 0) {
3926
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} does not exist`);
3927
+ }
3928
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3929
+ },
3930
+ updateFormSubmissions: (state, action) => {
3931
+ for (const submission of action.payload) {
3932
+ if (state.formSubmissions[submission.offline_id] === void 0) {
3933
+ throw new Error(`Submission with offline_id ${submission.offline_id} does not exist`);
3934
+ }
3935
+ }
3936
+ for (const submission of action.payload) {
3937
+ state.formSubmissions[submission.offline_id] = submission;
3938
+ }
3939
+ },
3940
+ deleteFormSubmission: (state, action) => {
3941
+ if (state.formSubmissions[action.payload] === void 0) {
3942
+ throw new Error(`Submission with offline_id ${action.payload} does not exist`);
3943
+ }
3944
+ delete state.formSubmissions[action.payload];
3945
+ },
3946
+ deleteFormSubmissions: (state, action) => {
3947
+ for (const offlineId of action.payload) {
3948
+ if (state.formSubmissions[offlineId] === void 0) {
3949
+ throw new Error(`Submission with offline_id ${offlineId} does not exist`);
3950
+ }
3951
+ delete state.formSubmissions[offlineId];
3952
+ }
3953
+ for (const offlineId of action.payload) {
3954
+ delete state.formSubmissions[offlineId];
3955
+ }
3956
+ },
3957
+ // Attachments
3958
+ addFormSubmissionAttachment: (state, action) => {
3959
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3960
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3961
+ }
3962
+ state.attachments[action.payload.offline_id] = action.payload;
3963
+ },
3964
+ addFormSubmissionAttachments: (state, action) => {
3965
+ for (const attachment of action.payload) {
3966
+ if (state.attachments[attachment.offline_id] !== void 0) {
3967
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3968
+ }
3969
+ }
3970
+ for (const attachment of action.payload) {
3971
+ state.attachments[attachment.offline_id] = attachment;
3972
+ }
3973
+ },
3974
+ // We only need a multi set for attachments because they are not updated, only added and deleted
3975
+ setFormSubmissionAttachments: (state, action) => {
3976
+ state.attachments = {};
3977
+ for (const attachment of action.payload) {
3978
+ state.attachments[attachment.offline_id] = attachment;
3979
+ }
3980
+ },
3981
+ updateFormSubmissionAttachments: (state, action) => {
3982
+ for (const attachment of action.payload) {
3983
+ if (state.attachments[attachment.offline_id] === void 0) {
3984
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} does not exist`);
3985
+ }
3986
+ }
3987
+ for (const attachment of action.payload) {
3988
+ state.attachments[attachment.offline_id] = attachment;
3989
+ }
3990
+ },
3991
+ // The delete actions for UserFormSubmissionAttachments are not used in the app, but are included for completeness
3992
+ // Could be used if editing a submission is ever supported, will be applicable for supporting tip tap content in submissions
3993
+ deleteFormSubmissionAttachment: (state, action) => {
3994
+ if (state.attachments[action.payload] === void 0) {
3995
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3996
+ }
3997
+ delete state.attachments[action.payload];
3998
+ },
3999
+ deleteFormSubmissionAttachments: (state, action) => {
4000
+ for (const offlineId of action.payload) {
4001
+ if (state.attachments[offlineId] === void 0) {
4002
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
4003
+ }
4004
+ delete state.attachments[offlineId];
4005
+ }
4006
+ }
4007
+ }
4008
+ });
4009
+ const {
4010
+ setFormSubmission,
4011
+ setFormSubmissions,
4012
+ addFormSubmission,
4013
+ addFormSubmissions,
4014
+ updateFormSubmission,
4015
+ updateFormSubmissions,
4016
+ deleteFormSubmission,
4017
+ deleteFormSubmissions,
4018
+ addFormSubmissionAttachment,
4019
+ addFormSubmissionAttachments,
4020
+ setFormSubmissionAttachments,
4021
+ updateFormSubmissionAttachments,
4022
+ deleteFormSubmissionAttachment,
4023
+ deleteFormSubmissionAttachments
4024
+ } = formSubmissionSlice.actions;
4025
+ const selectFormSubmissionsMapping = (state) => {
4026
+ return state.formSubmissionReducer.formSubmissions;
4027
+ };
4028
+ const selectFormSubmissions = createSelector(
4029
+ [selectFormSubmissionsMapping],
4030
+ (submissions) => {
4031
+ return Object.values(submissions);
4032
+ }
3735
4033
  );
3736
- const selectSubmissionsForForm = restructureCreateSelectorWithArgs(
4034
+ const selectFormSubmission = (submissionId) => (state) => {
4035
+ return state.formSubmissionReducer.formSubmissions[submissionId];
4036
+ };
4037
+ const selectFormSubmissionsOfForm = restructureCreateSelectorWithArgs(
3737
4038
  createSelector(
3738
- [selectSubmissions, selectRevisionMapping, (_state, formId2) => formId2],
4039
+ [selectFormSubmissions, selectFormRevisionMapping, (_state, formId2) => formId2],
3739
4040
  (submissions, revisionMapping, formId2) => {
3740
- return Object.values(submissions).filter((submission) => {
4041
+ return submissions.filter((submission) => {
3741
4042
  const revision = revisionMapping[submission.form_revision];
3742
4043
  return (revision == null ? void 0 : revision.form) === formId2;
3743
4044
  });
3744
4045
  }
3745
4046
  )
3746
4047
  );
3747
- const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
4048
+ const selectFormSubmissionsByFormRevisions = createSelector([selectFormRevisionMapping, selectFormSubmissions], (revisions, submissions) => {
4049
+ var _a2;
4050
+ const submissionMapping = {};
4051
+ for (const revisionId in revisions) {
4052
+ submissionMapping[revisionId] = [];
4053
+ }
4054
+ for (const submission of submissions) {
4055
+ (_a2 = submissionMapping[submission.form_revision]) == null ? void 0 : _a2.push(submission);
4056
+ }
4057
+ return submissionMapping;
4058
+ });
4059
+ const selectSortedFormSubmissionsOfForm = restructureCreateSelectorWithArgs(
4060
+ createSelector(
4061
+ [
4062
+ selectFormRevisionMapping,
4063
+ selectFormSubmissionsByFormRevisions,
4064
+ (_state, formId2) => formId2
4065
+ ],
4066
+ (revisionsMapping, submissionsByRevision, formId2) => {
4067
+ const submissionsByFormRevisions = {};
4068
+ for (const revisionId in revisionsMapping) {
4069
+ const revision = revisionsMapping[revisionId];
4070
+ const submissionsOfRevision = submissionsByRevision[revisionId];
4071
+ if (revision && submissionsOfRevision && revision.form === formId2) {
4072
+ submissionsByFormRevisions[revisionId] = submissionsOfRevision.sort(
4073
+ (a, b) => a.submitted_at < b.submitted_at ? -1 : 1
4074
+ );
4075
+ }
4076
+ }
4077
+ return Object.entries(submissionsByFormRevisions).sort((a, b) => {
4078
+ const aRevision = revisionsMapping[a[0]];
4079
+ const bRevision = revisionsMapping[b[0]];
4080
+ return formRevisionSortFn(aRevision, bRevision);
4081
+ }).map(([_revisionId, submissions]) => submissions).flat();
4082
+ }
4083
+ )
4084
+ );
4085
+ const selectFormSubmissionsOfIssue = restructureCreateSelectorWithArgs(
3748
4086
  createSelector(
3749
- [(state) => state.userFormReducer.submissions, (_state, issueId) => issueId],
4087
+ [selectFormSubmissions, (_state, issueId) => issueId],
3750
4088
  (submissions, issueId) => {
3751
4089
  return Object.values(submissions).filter((submission) => {
3752
4090
  return submission.issue === issueId;
@@ -3754,9 +4092,9 @@ const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3754
4092
  }
3755
4093
  )
3756
4094
  );
3757
- const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
4095
+ const selectFormSubmissionsOfComponent = restructureCreateSelectorWithArgs(
3758
4096
  createSelector(
3759
- [selectSubmissions, (_state, componentId) => componentId],
4097
+ [selectFormSubmissions, (_state, componentId) => componentId],
3760
4098
  (submissions, componentId) => {
3761
4099
  return submissions.filter((submission) => {
3762
4100
  return submission.component === componentId;
@@ -3764,8 +4102,8 @@ const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3764
4102
  }
3765
4103
  )
3766
4104
  );
3767
- const selectComponentSubmissionMapping = createSelector(
3768
- [selectSubmissionMapping, selectComponentsMapping],
4105
+ const selectFormSubmissionsByComponents = createSelector(
4106
+ [selectFormSubmissionsMapping, selectComponentsMapping],
3769
4107
  (submissions, components) => {
3770
4108
  var _a2;
3771
4109
  const componentSubmissionMapping = {};
@@ -3781,60 +4119,24 @@ const selectComponentSubmissionMapping = createSelector(
3781
4119
  return componentSubmissionMapping;
3782
4120
  }
3783
4121
  );
3784
- const selectUserFormMapping = (state) => {
3785
- return state.userFormReducer.userForms;
4122
+ const selectFormSubmissionAttachmentsMapping = (state) => {
4123
+ return state.formSubmissionReducer.attachments;
3786
4124
  };
3787
- const selectComponentTypeForm = restructureCreateSelectorWithArgs(
4125
+ const selectAttachmentsOfFormSubmission = restructureCreateSelectorWithArgs(
3788
4126
  createSelector(
3789
- [selectUserFormMapping, (_state, componentTypeId) => componentTypeId],
3790
- (userForms, componentTypeId) => {
3791
- return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
4127
+ [selectFormSubmissionAttachmentsMapping, (_state, submissionId) => submissionId],
4128
+ (attachmentsMapping, submissionId) => {
4129
+ return Object.values(attachmentsMapping).filter((attachment) => attachment.submission === submissionId);
3792
4130
  }
3793
4131
  )
3794
4132
  );
3795
- const selectLatestRevisionsFromComponentTypeIds = restructureCreateSelectorWithArgs(
3796
- createSelector(
3797
- [
3798
- selectUserFormMapping,
3799
- selectRevisionMapping,
3800
- (_state, componentTypeIds) => componentTypeIds
3801
- ],
3802
- (userForms, revisions, componentTypeIds) => {
3803
- const componentTypeIdsSet = new Set(componentTypeIds);
3804
- const ret = {};
3805
- for (const form of Object.values(userForms)) {
3806
- if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
3807
- ret[form.component_type] = _selectLatestFormRevision(revisions, form.offline_id);
3808
- }
3809
- }
3810
- return ret;
3811
- }
3812
- )
3813
- );
3814
- const selectLatestRevisionByFormId = createSelector([selectRevisionMapping], (revisions) => {
3815
- const latestRevisions = {};
3816
- for (const revision of Object.values(revisions)) {
3817
- const formId2 = revision.form;
3818
- const currentLatestRevision = latestRevisions[formId2];
3819
- if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
3820
- latestRevisions[formId2] = revision;
3821
- }
3822
- }
3823
- return latestRevisions;
3824
- });
3825
- const selectNumberOfUserForms = createSelector([selectUserFormMapping], (userForms) => {
3826
- return Object.keys(userForms).length;
3827
- });
3828
- const selectNumberOfGeneralUserForms = createSelector([selectUserFormMapping], (userForms) => {
3829
- return Object.values(userForms).filter((form) => !form.component_type).length;
3830
- });
3831
- const userFormReducer = userFormSlice.reducer;
3832
- const initialState$2 = {
4133
+ const formSubmissionReducer = formSubmissionSlice.reducer;
4134
+ const initialState$4 = {
3833
4135
  emailDomains: {}
3834
4136
  };
3835
4137
  const emailDomainsSlice = createSlice({
3836
4138
  name: "emailDomains",
3837
- initialState: initialState$2,
4139
+ initialState: initialState$4,
3838
4140
  reducers: {
3839
4141
  setEmailDomains: (state, action) => {
3840
4142
  const emailDomains = {};
@@ -3861,15 +4163,15 @@ const selectSortedEmailDomains = (state) => Object.values(state.emailDomainsRedu
3861
4163
  (ed1, ed2) => ed1.domain.localeCompare(ed2.domain)
3862
4164
  );
3863
4165
  const emailDomainsReducer = emailDomainsSlice.reducer;
3864
- const initialState$1 = {
4166
+ const initialState$3 = {
3865
4167
  documents: {},
3866
4168
  attachments: {}
3867
4169
  };
3868
4170
  const documentSlice = createSlice({
3869
4171
  name: "documents",
3870
- initialState: initialState$1,
4172
+ initialState: initialState$3,
3871
4173
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
3872
- Object.assign(state, initialState$1);
4174
+ Object.assign(state, initialState$3);
3873
4175
  }),
3874
4176
  reducers: {
3875
4177
  setDocuments: (state, action) => {
@@ -3906,9 +4208,18 @@ const documentSlice = createSlice({
3906
4208
  }
3907
4209
  }
3908
4210
  for (const document2 of action.payload) {
4211
+ const existingDocument = state.documents[document2.offline_id];
4212
+ if (document2.organization !== void 0 && document2.organization !== existingDocument.organization) {
4213
+ throw new Error("organization cannot be updated");
4214
+ }
4215
+ if (document2.project !== void 0 && document2.project !== existingDocument.project) {
4216
+ throw new Error("project cannot be updated");
4217
+ }
3909
4218
  state.documents[document2.offline_id] = {
3910
- ...state.documents[document2.offline_id],
4219
+ ...existingDocument,
3911
4220
  ...document2
4221
+ // Without the cast, TypeScript doesn't realize that we have guaranteed that the document doesn't
4222
+ // have both a project and an organization.
3912
4223
  };
3913
4224
  }
3914
4225
  },
@@ -4085,6 +4396,78 @@ const selectAttachmentsOfDocumentByType = restructureCreateSelectorWithArgs(
4085
4396
  )
4086
4397
  );
4087
4398
  const documentsReducer = documentSlice.reducer;
4399
+ const initialState$2 = {
4400
+ teams: {}
4401
+ };
4402
+ const teamSlice = createSlice({
4403
+ name: "teams",
4404
+ initialState: initialState$2,
4405
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$2)),
4406
+ reducers: {
4407
+ setTeam: (state, action) => {
4408
+ state.teams[action.payload.offline_id] = action.payload;
4409
+ },
4410
+ setTeams: (state, action) => {
4411
+ state.teams = {};
4412
+ for (const team of action.payload) {
4413
+ state.teams[team.offline_id] = team;
4414
+ }
4415
+ },
4416
+ addTeam: (state, action) => {
4417
+ if (state.teams[action.payload.offline_id]) {
4418
+ throw new Error(`Team with offline_id ${action.payload.offline_id} already exists`);
4419
+ }
4420
+ state.teams[action.payload.offline_id] = action.payload;
4421
+ },
4422
+ updateTeam: (state, action) => {
4423
+ if (!state.teams[action.payload.offline_id]) {
4424
+ throw new Error(`Team with offline_id ${action.payload.offline_id} does not exist`);
4425
+ }
4426
+ state.teams[action.payload.offline_id] = action.payload;
4427
+ },
4428
+ deleteTeam: (state, action) => {
4429
+ delete state.teams[action.payload];
4430
+ }
4431
+ }
4432
+ });
4433
+ const { setTeam, setTeams, addTeam, updateTeam, deleteTeam } = teamSlice.actions;
4434
+ const selectTeamsMapping = (state) => state.teamReducer.teams;
4435
+ const selectTeams = createSelector([selectTeamsMapping], (teams) => {
4436
+ return Object.values(teams);
4437
+ });
4438
+ const selectTeam = (teamId) => (state) => {
4439
+ return state.teamReducer.teams[teamId];
4440
+ };
4441
+ const selectTeamsOfOrganization = restructureCreateSelectorWithArgs(
4442
+ createSelector(
4443
+ [selectTeams, (_state, organizationId) => organizationId],
4444
+ (teams, organizationId) => {
4445
+ return teams.filter((team) => team.organization === organizationId);
4446
+ }
4447
+ )
4448
+ );
4449
+ const selectTeamsOfUser = restructureCreateSelectorWithArgs(
4450
+ createSelector([selectTeams, (_state, userId) => userId], (teams, userId) => {
4451
+ return teams.filter((team) => team.members.includes(userId));
4452
+ })
4453
+ );
4454
+ const teamReducer = teamSlice.reducer;
4455
+ const initialState$1 = {
4456
+ conversationId: void 0
4457
+ };
4458
+ const agentSlice = createSlice({
4459
+ name: "agents",
4460
+ initialState: initialState$1,
4461
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$1)),
4462
+ reducers: {
4463
+ setConversationId: (state, action) => {
4464
+ state.conversationId = action.payload;
4465
+ }
4466
+ }
4467
+ });
4468
+ const { setConversationId } = agentSlice.actions;
4469
+ const selectConversationId = (state) => state.agentReducer.conversationId;
4470
+ const agentReducer = agentSlice.reducer;
4088
4471
  const initialState = {
4089
4472
  version: 0
4090
4473
  };
@@ -4117,6 +4500,7 @@ const overmapReducers = {
4117
4500
  componentStageReducer,
4118
4501
  componentTypeReducer,
4119
4502
  issueReducer,
4503
+ issueTypeReducer,
4120
4504
  mapReducer,
4121
4505
  organizationReducer,
4122
4506
  outboxReducer,
@@ -4126,12 +4510,16 @@ const overmapReducers = {
4126
4510
  projectFileReducer,
4127
4511
  rehydratedReducer,
4128
4512
  settingReducer,
4129
- userFormReducer,
4513
+ formReducer,
4514
+ formRevisionReducer,
4515
+ formSubmissionReducer,
4130
4516
  userReducer,
4131
4517
  workspaceReducer,
4132
4518
  emailDomainsReducer,
4133
4519
  licenseReducer,
4134
- documentsReducer
4520
+ documentsReducer,
4521
+ teamReducer,
4522
+ agentReducer
4135
4523
  };
4136
4524
  const overmapReducer = combineReducers(overmapReducers);
4137
4525
  const resetStore = "RESET";
@@ -4179,9 +4567,7 @@ function handleWorkspaceRemoval(draft, action) {
4179
4567
  throw new Error(`Failed to update index_workspace of issue ${issue.offline_id} to main workspace`);
4180
4568
  }
4181
4569
  }
4182
- const indexedForms = Object.values(draft.userFormReducer.userForms).filter(
4183
- (form) => form.index_workspace === workspaceId
4184
- );
4570
+ const indexedForms = Object.values(draft.formReducer.forms).filter((form) => form.index_workspace === workspaceId);
4185
4571
  for (const form of indexedForms) {
4186
4572
  form.index_workspace = mainWorkspace.offline_id;
4187
4573
  }
@@ -6060,7 +6446,7 @@ class IssueService extends BaseApiService {
6060
6446
  // Basic CRUD functions
6061
6447
  // TODO: Once all models are represented in `Created<TModel>`, use `Created` in `OptimisticModelResult`, so we don't
6062
6448
  // have to repeat it for all optimistic model results (all optimistic results are created).
6063
- add(issue) {
6449
+ add(issue, issue_type = null) {
6064
6450
  const { store } = this.client;
6065
6451
  const dateWithoutMilliseconds = /* @__PURE__ */ new Date();
6066
6452
  const state = store.getState();
@@ -6086,7 +6472,8 @@ class IssueService extends BaseApiService {
6086
6472
  method: HttpMethod.POST,
6087
6473
  url: "/issues/",
6088
6474
  queryParams: {
6089
- workspace_id: workspaceId
6475
+ workspace_id: workspaceId,
6476
+ ...issue_type ? { issue_type } : {}
6090
6477
  },
6091
6478
  payload: issuePayload,
6092
6479
  blockers: [
@@ -6259,16 +6646,113 @@ class IssueService extends BaseApiService {
6259
6646
  throw e;
6260
6647
  }
6261
6648
  }
6262
- // Special functions
6649
+ // Special functions
6650
+ async refreshStore() {
6651
+ const { store } = this.client;
6652
+ const projectId = store.getState().projectReducer.activeProjectId;
6653
+ if (!projectId) {
6654
+ throw new Error("No active project");
6655
+ }
6656
+ const [_offlineIssues, promise] = this.fetchAll(projectId);
6657
+ const result = await promise;
6658
+ store.dispatch(setIssues(result));
6659
+ }
6660
+ }
6661
+ class IssueTypeService extends BaseApiService {
6662
+ add(payload) {
6663
+ const { store } = this.client;
6664
+ const activeOrganizationId = store.getState().organizationReducer.activeOrganizationId;
6665
+ if (!activeOrganizationId) {
6666
+ throw new Error(`No active organization, got ${activeOrganizationId} for activeOrganizationId.`);
6667
+ }
6668
+ const offlineIssueType = offline({
6669
+ ...payload,
6670
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
6671
+ created_by: store.getState().userReducer.currentUser.id,
6672
+ organization: activeOrganizationId
6673
+ });
6674
+ store.dispatch(addIssueType(offlineIssueType));
6675
+ const promise = this.enqueueRequest({
6676
+ method: HttpMethod.POST,
6677
+ url: `/organizations/${activeOrganizationId}/issue-types/`,
6678
+ // Sending only whats needed here
6679
+ payload: {
6680
+ offline_id: offlineIssueType.offline_id,
6681
+ submitted_at: offlineIssueType.submitted_at,
6682
+ icon: offlineIssueType.icon,
6683
+ icon_color: offlineIssueType.icon_color,
6684
+ name: offlineIssueType.name,
6685
+ description: offlineIssueType.description
6686
+ },
6687
+ blockers: [],
6688
+ blocks: [offlineIssueType.offline_id]
6689
+ });
6690
+ promise.then((createdIssueType) => {
6691
+ store.dispatch(setIssueType(createdIssueType));
6692
+ }).catch(() => {
6693
+ store.dispatch(removeIssueType(offlineIssueType.offline_id));
6694
+ });
6695
+ return [offlineIssueType, promise];
6696
+ }
6697
+ update(issueTypeFields) {
6698
+ const { store } = this.client;
6699
+ const issueTypeToBeUpdated = store.getState().issueTypeReducer.issueTypes[issueTypeFields.offline_id];
6700
+ if (!issueTypeToBeUpdated) {
6701
+ throw new Error(`IssueType with offline_id ${issueTypeFields.offline_id} does not exist in the store.`);
6702
+ }
6703
+ const offlineUpdatedIssueType = {
6704
+ ...issueTypeToBeUpdated,
6705
+ ...issueTypeFields
6706
+ };
6707
+ store.dispatch(updateIssueType(offlineUpdatedIssueType));
6708
+ const promise = this.enqueueRequest({
6709
+ method: HttpMethod.PATCH,
6710
+ url: `/issues/types/${issueTypeFields.offline_id}/`,
6711
+ payload: issueTypeFields,
6712
+ blockers: [issueTypeFields.offline_id],
6713
+ blocks: [issueTypeFields.offline_id]
6714
+ });
6715
+ promise.then((updatedIssueType) => {
6716
+ store.dispatch(setIssueType(updatedIssueType));
6717
+ }).catch(() => {
6718
+ store.dispatch(setIssueType(issueTypeToBeUpdated));
6719
+ });
6720
+ return [offlineUpdatedIssueType, promise];
6721
+ }
6722
+ delete(issueTypeId) {
6723
+ const { store } = this.client;
6724
+ const issueTypeToDelete = store.getState().issueTypeReducer.issueTypes[issueTypeId];
6725
+ if (!issueTypeToDelete) {
6726
+ throw new Error(`IssueType with offline_id ${issueTypeId} does not exist in the store.`);
6727
+ }
6728
+ const issuesOfIssueType = selectIssuesOfIssueType(issueTypeId)(store.getState()) ?? [];
6729
+ store.dispatch(removeIssueType(issueTypeId));
6730
+ store.dispatch(removeIssues(issuesOfIssueType.map((issue) => issue.offline_id)));
6731
+ const promise = this.enqueueRequest({
6732
+ method: HttpMethod.DELETE,
6733
+ url: `/issues/types/${issueTypeId}/`,
6734
+ blockers: [issueTypeId],
6735
+ blocks: []
6736
+ });
6737
+ promise.catch(() => {
6738
+ store.dispatch(setIssueType(issueTypeToDelete));
6739
+ store.dispatch(addIssues(issuesOfIssueType));
6740
+ });
6741
+ return promise;
6742
+ }
6263
6743
  async refreshStore() {
6264
6744
  const { store } = this.client;
6265
- const projectId = store.getState().projectReducer.activeProjectId;
6266
- if (!projectId) {
6267
- throw new Error("No active project");
6745
+ const activeOrganizationId = store.getState().organizationReducer.activeOrganizationId;
6746
+ if (!activeOrganizationId) {
6747
+ throw new Error(`No active organization, got ${activeOrganizationId} for activeOrganizationId.`);
6268
6748
  }
6269
- const [_offlineIssues, promise] = this.fetchAll(projectId);
6270
- const result = await promise;
6271
- store.dispatch(setIssues(result));
6749
+ const result = await this.enqueueRequest({
6750
+ method: HttpMethod.GET,
6751
+ url: `/organizations/${activeOrganizationId}/issue-types/`,
6752
+ blockers: [],
6753
+ blocks: []
6754
+ });
6755
+ store.dispatch(setIssueTypes(result));
6272
6756
  }
6273
6757
  }
6274
6758
  class MainService extends BaseApiService {
@@ -6372,6 +6856,7 @@ class MainService extends BaseApiService {
6372
6856
  }
6373
6857
  if (currentOrgId) {
6374
6858
  await this.client.organizations.fetchInitialOrganizationData(currentOrgId, false);
6859
+ void this.client.teams.refreshStore();
6375
6860
  }
6376
6861
  if (!isProjectIdValid) {
6377
6862
  if (validProjects.length !== 0) {
@@ -6445,6 +6930,7 @@ class MainService extends BaseApiService {
6445
6930
  });
6446
6931
  void this.client.documents.refreshStore();
6447
6932
  void this.client.issueUpdates.refreshStore();
6933
+ void this.client.issueTypes.refreshStore();
6448
6934
  }
6449
6935
  store.dispatch(setIsFetchingInitialData(false));
6450
6936
  if (overwrite) {
@@ -6809,12 +7295,12 @@ class UserFormService extends BaseApiService {
6809
7295
  ...revisionAttachmentPayload,
6810
7296
  file: URL.createObjectURL(image)
6811
7297
  };
6812
- store.dispatch(addUserFormRevisionAttachment(offlinePayload));
7298
+ store.dispatch(addFormRevisionAttachment(offlinePayload));
6813
7299
  return attach;
6814
7300
  });
6815
7301
  });
6816
7302
  }
6817
- async add(state, initialRevision, url, ownerUser, ownerOrganization, componentTypeId) {
7303
+ async add(state, initialRevision, url, ownerUser, ownerOrganization, componentTypeId, issueTypeId) {
6818
7304
  if (!!ownerUser === !!ownerOrganization) {
6819
7305
  throw new Error("Exactly one of ownerUser and ownerOrganization must be defined.");
6820
7306
  }
@@ -6824,15 +7310,17 @@ class UserFormService extends BaseApiService {
6824
7310
  };
6825
7311
  const currentUser = state.userReducer.currentUser;
6826
7312
  const activeWorkspaceId = state.workspaceReducer.activeWorkspaceId;
7313
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
6827
7314
  const offlineFormPayload = offline({});
6828
- const offlineRevisionPayload = offline(initialRevision);
7315
+ const offlineRevisionPayload = offline({ ...initialRevision, submitted_at: submittedAt });
6829
7316
  const retForm = {
6830
7317
  ...offlineFormPayload,
6831
7318
  index_workspace: activeWorkspaceId,
6832
7319
  favorite: true,
6833
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
7320
+ submitted_at: submittedAt,
6834
7321
  created_by: currentUser.id,
6835
7322
  ...componentTypeId && { component_type: componentTypeId },
7323
+ ...issueTypeId && { issue_type: issueTypeId },
6836
7324
  ...ownerAttrs
6837
7325
  };
6838
7326
  const { payloadWithoutImage, images } = await separateImageFromFields(offlineRevisionPayload);
@@ -6840,11 +7328,12 @@ class UserFormService extends BaseApiService {
6840
7328
  ...payloadWithoutImage,
6841
7329
  created_by: currentUser.id,
6842
7330
  form: retForm.offline_id,
6843
- revision: 0
7331
+ revision: 0,
7332
+ submitted_at: submittedAt
6844
7333
  };
6845
7334
  const { store } = this.client;
6846
- store.dispatch(addUserForm(retForm));
6847
- store.dispatch(addUserFormRevision(retRevision));
7335
+ store.dispatch(addForm(retForm));
7336
+ store.dispatch(addFormRevision(retRevision));
6848
7337
  const formPromise = this.enqueueRequest({
6849
7338
  description: "Create form",
6850
7339
  method: HttpMethod.POST,
@@ -6855,21 +7344,22 @@ class UserFormService extends BaseApiService {
6855
7344
  payload: {
6856
7345
  ...offlineFormPayload,
6857
7346
  ...componentTypeId && { component_type: componentTypeId },
7347
+ ...issueTypeId && { issue_type: issueTypeId },
6858
7348
  initial_revision: payloadWithoutImage
6859
7349
  },
6860
- blockers: componentTypeId ? [componentTypeId] : [],
7350
+ blockers: componentTypeId ? [componentTypeId] : issueTypeId ? [issueTypeId] : [],
6861
7351
  blocks: [offlineFormPayload.offline_id, payloadWithoutImage.offline_id]
6862
7352
  });
6863
7353
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
6864
7354
  void formPromise.catch((e) => {
6865
- store.dispatch(deleteUserForm(retForm.offline_id));
6866
- store.dispatch(deleteUserFormRevision(retRevision.offline_id));
7355
+ store.dispatch(deleteForm(retForm.offline_id));
7356
+ store.dispatch(deleteFormRevision(retRevision.offline_id));
6867
7357
  throw e;
6868
7358
  });
6869
7359
  const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
6870
7360
  return [retForm, retRevision, formPromise, settledPromise];
6871
7361
  }
6872
- async addForOrganization(initialRevision, componentTypeId) {
7362
+ async addForOrganization(initialRevision, attachedTo) {
6873
7363
  const state = this.client.store.getState();
6874
7364
  const activeOrganizationId = state.organizationReducer.activeOrganizationId;
6875
7365
  if (!activeOrganizationId) {
@@ -6881,13 +7371,22 @@ class UserFormService extends BaseApiService {
6881
7371
  `/forms/in-organization/${activeOrganizationId}/`,
6882
7372
  void 0,
6883
7373
  activeOrganizationId,
6884
- componentTypeId
7374
+ attachedTo && "componentTypeId" in attachedTo ? attachedTo.componentTypeId : void 0,
7375
+ attachedTo && "issueTypeId" in attachedTo ? attachedTo.issueTypeId : void 0
6885
7376
  );
6886
7377
  }
6887
- async addForCurrentUser(initialRevision, componentTypeId) {
7378
+ async addForCurrentUser(initialRevision, attachedTo) {
6888
7379
  const state = this.client.store.getState();
6889
7380
  const currentUser = state.userReducer.currentUser;
6890
- return await this.add(state, initialRevision, "/forms/my-forms/", currentUser.id, void 0, componentTypeId);
7381
+ return await this.add(
7382
+ state,
7383
+ initialRevision,
7384
+ "/forms/my-forms/",
7385
+ currentUser.id,
7386
+ void 0,
7387
+ attachedTo && "componentTypeId" in attachedTo ? attachedTo.componentTypeId : void 0,
7388
+ attachedTo && "issueTypeId" in attachedTo ? attachedTo.issueTypeId : void 0
7389
+ );
6891
7390
  }
6892
7391
  async createRevision(formId2, revision) {
6893
7392
  const offlineRevision = offline(revision);
@@ -6903,9 +7402,10 @@ class UserFormService extends BaseApiService {
6903
7402
  ...payloadWithoutImage,
6904
7403
  created_by: currentUserId,
6905
7404
  revision: "Pending",
6906
- form: formId2
7405
+ form: formId2,
7406
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
6907
7407
  };
6908
- store.dispatch(addUserFormRevision(fullRevision));
7408
+ store.dispatch(addFormRevision(fullRevision));
6909
7409
  const promise = this.enqueueRequest({
6910
7410
  description: "Create form revision",
6911
7411
  method: HttpMethod.PATCH,
@@ -6919,9 +7419,9 @@ class UserFormService extends BaseApiService {
6919
7419
  });
6920
7420
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
6921
7421
  void promise.then((result) => {
6922
- store.dispatch(addUserFormRevision(result));
7422
+ store.dispatch(setFormRevision(result));
6923
7423
  }).catch(() => {
6924
- store.dispatch(deleteUserFormRevision(fullRevision.offline_id));
7424
+ store.dispatch(deleteFormRevision(fullRevision.offline_id));
6925
7425
  });
6926
7426
  const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
6927
7427
  return [fullRevision, settledPromise];
@@ -6963,19 +7463,19 @@ class UserFormService extends BaseApiService {
6963
7463
  async delete(formId2) {
6964
7464
  const { store } = this.client;
6965
7465
  const state = store.getState();
6966
- const userForm = selectUserForm(formId2)(state);
7466
+ const userForm = selectForm(formId2)(state);
6967
7467
  if (!userForm) {
6968
7468
  throw new Error("Expected userForm to exist");
6969
7469
  }
6970
- const userFormSubmissions = selectSubmissionsForForm(formId2)(state);
7470
+ const userFormSubmissions = selectFormSubmissionsOfForm(formId2)(state);
6971
7471
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6972
- store.dispatch(deleteUserFormSubmissions(userFormSubmissions));
7472
+ store.dispatch(deleteFormSubmissions(userFormSubmissions.map(({ offline_id }) => offline_id)));
6973
7473
  }
6974
- const userFormRevisions = selectRevisionsForForm(formId2)(state);
7474
+ const userFormRevisions = selectFormRevisionsOfForm(formId2)(state);
6975
7475
  if (userFormRevisions && userFormRevisions.length > 0) {
6976
- store.dispatch(deleteUserFormRevisions(userFormRevisions));
7476
+ store.dispatch(deleteFormRevisions(userFormRevisions.map(({ offline_id }) => offline_id)));
6977
7477
  }
6978
- store.dispatch(deleteUserForm(formId2));
7478
+ store.dispatch(deleteForm(formId2));
6979
7479
  try {
6980
7480
  return await this.enqueueRequest({
6981
7481
  description: "Delete form",
@@ -6985,12 +7485,12 @@ class UserFormService extends BaseApiService {
6985
7485
  blocks: []
6986
7486
  });
6987
7487
  } catch (e) {
6988
- store.dispatch(addUserForm(userForm));
7488
+ store.dispatch(addForm(userForm));
6989
7489
  if (userFormRevisions && userFormRevisions.length > 0) {
6990
- store.dispatch(addUserFormRevisions(userFormRevisions));
7490
+ store.dispatch(addFormRevisions(userFormRevisions));
6991
7491
  }
6992
7492
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6993
- store.dispatch(addUserFormSubmissions(userFormSubmissions));
7493
+ store.dispatch(addFormSubmissions(userFormSubmissions));
6994
7494
  }
6995
7495
  throw e;
6996
7496
  }
@@ -7004,16 +7504,15 @@ class UserFormService extends BaseApiService {
7004
7504
  blockers: [],
7005
7505
  blocks: []
7006
7506
  });
7007
- store.dispatch(addUserForms(Object.values(result.forms)));
7008
- store.dispatch(addUserFormRevisions(Object.values(result.revisions)));
7009
- store.dispatch(setUserFormRevisionAttachments(Object.values(result.attachments)));
7507
+ store.dispatch(setForms(Object.values(result.forms)));
7508
+ store.dispatch(setFormRevisions(Object.values(result.revisions)));
7509
+ store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
7010
7510
  }
7011
7511
  }
7012
7512
  const isArrayOfFiles = (value) => {
7013
7513
  return Array.isArray(value) && value[0] instanceof File;
7014
7514
  };
7015
- const separateFilesFromValues = (payload) => {
7016
- const { values } = payload;
7515
+ const separateFilesFromValues = (values) => {
7017
7516
  const files = {};
7018
7517
  const newValues = {};
7019
7518
  for (const key in values) {
@@ -7028,17 +7527,13 @@ const separateFilesFromValues = (payload) => {
7028
7527
  newValues[key] = value;
7029
7528
  }
7030
7529
  }
7031
- const payloadWithoutFiles = {
7032
- ...payload,
7033
- values: newValues
7034
- };
7035
- return { payloadWithoutFiles, files };
7530
+ return { values: newValues, files };
7036
7531
  };
7037
7532
  class UserFormSubmissionService extends BaseApiService {
7038
7533
  constructor() {
7039
7534
  super(...arguments);
7040
7535
  // Attach files to submission, after uploading them to S3
7041
- __publicField(this, "getAttachFilesPromises", (files, payload) => {
7536
+ __publicField(this, "getAttachFilesPromises", (files, submission) => {
7042
7537
  const { store } = this.client;
7043
7538
  return Object.entries(files).map(async ([key, fileArray]) => {
7044
7539
  const attachResults = [];
@@ -7048,24 +7543,27 @@ class UserFormSubmissionService extends BaseApiService {
7048
7543
  const [fileProps] = await this.client.files.uploadFileToS3(sha1);
7049
7544
  const submissionAttachmentPayload = offline({
7050
7545
  ...fileProps,
7051
- submission: payload.offline_id,
7546
+ submission: submission.offline_id,
7052
7547
  field_identifier: key
7053
7548
  });
7054
7549
  const attach = await this.enqueueRequest({
7055
7550
  description: "Attach file to form submission",
7056
7551
  method: HttpMethod.POST,
7057
- url: `/forms/submission/${payload.offline_id}/attachments/`,
7552
+ url: `/forms/submission/${submission.offline_id}/attachments/`,
7058
7553
  payload: submissionAttachmentPayload,
7059
- blockers: [payload.component, payload.component_stage, payload.issue, payload.form_revision].filter(
7060
- (x) => x !== void 0
7061
- ),
7554
+ blockers: [
7555
+ submission.component,
7556
+ submission.component_stage,
7557
+ submission.issue,
7558
+ submission.form_revision
7559
+ ].filter((x) => x !== void 0),
7062
7560
  blocks: [submissionAttachmentPayload.offline_id]
7063
7561
  });
7064
7562
  const offlinePayload = {
7065
7563
  ...submissionAttachmentPayload,
7066
7564
  file: URL.createObjectURL(file)
7067
7565
  };
7068
- store.dispatch(addUserFormSubmissionAttachment(offlinePayload));
7566
+ store.dispatch(addFormSubmissionAttachment(offlinePayload));
7069
7567
  attachResults.push(attach);
7070
7568
  }
7071
7569
  return attachResults;
@@ -7079,71 +7577,168 @@ class UserFormSubmissionService extends BaseApiService {
7079
7577
  if (!activeProjectId) {
7080
7578
  throw new Error("Expected an active project");
7081
7579
  }
7082
- const { payloadWithoutFiles, files } = separateFilesFromValues(payload);
7580
+ const { values, files } = separateFilesFromValues(payload.values);
7581
+ const offlineSubmission = {
7582
+ ...payload,
7583
+ values,
7584
+ created_by: state.userReducer.currentUser.id,
7585
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
7586
+ };
7083
7587
  const promise = this.enqueueRequest({
7084
7588
  description: "Respond to form",
7085
7589
  method: HttpMethod.POST,
7086
7590
  url: `/forms/revisions/${payload.form_revision}/respond/`,
7087
- payload: { ...payloadWithoutFiles, project: activeProjectId },
7591
+ payload: { ...offlineSubmission, project: activeProjectId },
7088
7592
  blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
7089
7593
  (x) => x !== void 0
7090
7594
  ),
7091
7595
  blocks: [payload.offline_id]
7092
7596
  });
7093
- const attachFilesPromises = this.getAttachFilesPromises(files, payload);
7094
- const now = (/* @__PURE__ */ new Date()).toISOString();
7095
- const fullOfflineResult = {
7096
- ...payload,
7097
- created_by: state.userReducer.currentUser.id,
7098
- created_at: now,
7099
- updated_at: now
7100
- };
7101
- const offlineResultWithoutFiles = {
7102
- ...fullOfflineResult,
7103
- ...payloadWithoutFiles
7104
- };
7105
- store.dispatch(updateOrCreateUserFormSubmission(offlineResultWithoutFiles));
7597
+ const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
7598
+ store.dispatch(addFormSubmission(offlineSubmission));
7106
7599
  void promise.then((result) => {
7107
7600
  store.dispatch(addActiveProjectFormSubmissionsCount(1));
7108
- store.dispatch(updateOrCreateUserFormSubmission(result));
7601
+ store.dispatch(setFormSubmission(result));
7109
7602
  return result;
7110
7603
  }).catch(() => {
7111
- store.dispatch(deleteUserFormSubmission(payload.offline_id));
7604
+ store.dispatch(deleteFormSubmission(payload.offline_id));
7112
7605
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
7113
7606
  });
7114
7607
  const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7115
- return [fullOfflineResult, settledPromise];
7608
+ return [offlineSubmission, settledPromise];
7116
7609
  }
7117
- update(submission) {
7610
+ // Note currently the bulkAdd method is specific to form submissions for components
7611
+ // TODO: adapt the support bulk adding to any model type
7612
+ async bulkAdd(args) {
7613
+ const { formRevision, values: argsValues, componentOfflineIds } = args;
7118
7614
  const { store } = this.client;
7119
- const { payloadWithoutFiles, files } = separateFilesFromValues(submission);
7120
- if (!("created_by" in payloadWithoutFiles) || !("created_at" in payloadWithoutFiles)) {
7121
- throw new Error("Expected payloadWithoutFiles to have created_by and created_at fields.");
7615
+ const offlineSubmissions = [];
7616
+ const offlineAttachments = [];
7617
+ const submissionOfflineIds = [];
7618
+ const submissionsPayload = [];
7619
+ const attachmentsPayload = [];
7620
+ const { values, files } = separateFilesFromValues(argsValues);
7621
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
7622
+ const createdBy = store.getState().userReducer.currentUser.id;
7623
+ for (const component_id of componentOfflineIds) {
7624
+ const submission = offline({
7625
+ form_revision: formRevision,
7626
+ values,
7627
+ created_by: createdBy,
7628
+ submitted_at: submittedAt,
7629
+ component: component_id
7630
+ });
7631
+ submissionOfflineIds.push(submission.offline_id);
7632
+ submissionsPayload.push({ offline_id: submission.offline_id, component_id });
7633
+ offlineSubmissions.push(submission);
7634
+ for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
7635
+ for (const file of fileArray) {
7636
+ const sha1 = await hashFile(file);
7637
+ await this.client.files.addCache(file, sha1);
7638
+ const offlineAttachment = offline({
7639
+ file_name: file.name,
7640
+ file_sha1: sha1,
7641
+ file: URL.createObjectURL(file),
7642
+ submission: submission.offline_id,
7643
+ field_identifier: fieldIdentifier
7644
+ });
7645
+ offlineAttachments.push(offlineAttachment);
7646
+ attachmentsPayload.push({
7647
+ offline_id: offlineAttachment.offline_id,
7648
+ submission_id: submission.offline_id,
7649
+ sha1,
7650
+ name: file.name,
7651
+ field_identifier: fieldIdentifier
7652
+ });
7653
+ }
7654
+ }
7122
7655
  }
7656
+ const filesRecord = {};
7657
+ for (const file of Object.values(files).flat()) {
7658
+ const sha1 = await hashFile(file);
7659
+ filesRecord[sha1] = {
7660
+ sha1,
7661
+ extension: file.name.split(".").pop() || "",
7662
+ file_type: file.type,
7663
+ size: file.size
7664
+ };
7665
+ }
7666
+ store.dispatch(addFormSubmissions(offlineSubmissions));
7667
+ store.dispatch(addFormSubmissionAttachments(offlineAttachments));
7668
+ const promise = this.enqueueRequest({
7669
+ description: "Bulk add form submissions",
7670
+ method: HttpMethod.POST,
7671
+ url: `/forms/revisions/${formRevision}/bulk-respond/`,
7672
+ payload: {
7673
+ form_data: values,
7674
+ submitted_at: submittedAt,
7675
+ submissions: submissionsPayload,
7676
+ attachments: attachmentsPayload,
7677
+ files: Object.values(filesRecord)
7678
+ },
7679
+ blockers: componentOfflineIds,
7680
+ blocks: submissionOfflineIds
7681
+ });
7682
+ promise.then(({ submissions, attachments, presigned_urls }) => {
7683
+ store.dispatch(updateFormSubmissions(submissions));
7684
+ store.dispatch(updateFormSubmissionAttachments(attachments));
7685
+ for (const [sha1, presigned_url] of Object.entries(presigned_urls)) {
7686
+ const file = filesRecord[sha1];
7687
+ if (!file)
7688
+ continue;
7689
+ void this.enqueueRequest({
7690
+ url: presigned_url.url,
7691
+ description: "Upload file",
7692
+ method: HttpMethod.POST,
7693
+ isExternalUrl: true,
7694
+ isAuthNeeded: false,
7695
+ attachmentHash: sha1,
7696
+ blockers: [`s3-${file.sha1}.${file.extension}`],
7697
+ blocks: [sha1],
7698
+ s3url: presigned_url
7699
+ });
7700
+ }
7701
+ }).catch(() => {
7702
+ store.dispatch(deleteFormSubmissions(submissionOfflineIds));
7703
+ store.dispatch(deleteFormSubmissionAttachments(offlineAttachments.map((x) => x.offline_id)));
7704
+ });
7705
+ return [offlineSubmissions, promise.then(({ submissions }) => submissions)];
7706
+ }
7707
+ update(submission) {
7708
+ const { store } = this.client;
7709
+ const { values, files } = separateFilesFromValues(submission.values);
7123
7710
  const attachFilesPromises = this.getAttachFilesPromises(files, submission);
7124
- const fullResult = {
7125
- ...payloadWithoutFiles,
7126
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
7711
+ const offlineSubmission = {
7712
+ ...submission,
7713
+ values
7127
7714
  };
7128
- store.dispatch(updateOrCreateUserFormSubmission(fullResult));
7715
+ const submissionToBeUpdated = store.getState().formSubmissionReducer.formSubmissions[submission.offline_id];
7716
+ store.dispatch(updateFormSubmission(offlineSubmission));
7129
7717
  const promise = this.enqueueRequest({
7130
7718
  description: "Patch form submission",
7131
7719
  method: HttpMethod.PATCH,
7132
7720
  url: `/forms/submissions/${submission.offline_id}/`,
7133
- payload: fullResult,
7134
- blockers: [fullResult.issue, fullResult.component, fullResult.component_stage].filter(
7721
+ payload: offlineSubmission,
7722
+ blockers: [offlineSubmission.issue, offlineSubmission.component, offlineSubmission.component_stage].filter(
7135
7723
  (x) => x !== void 0
7136
7724
  ),
7137
- blocks: [fullResult.offline_id]
7725
+ blocks: [offlineSubmission.offline_id]
7138
7726
  });
7139
- return Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7727
+ promise.then((createdSubmission) => {
7728
+ store.dispatch(setFormSubmission(createdSubmission));
7729
+ }).catch(() => {
7730
+ store.dispatch(setFormSubmission(submissionToBeUpdated));
7731
+ });
7732
+ return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
7140
7733
  }
7141
7734
  async delete(submissionId) {
7142
7735
  const { store } = this.client;
7143
7736
  const state = store.getState();
7144
- const submission = state.userFormReducer.submissions[submissionId];
7145
- store.dispatch(deleteUserFormSubmission(submissionId));
7737
+ const submission = state.formSubmissionReducer.formSubmissions[submissionId];
7738
+ const submissionAttachments = selectAttachmentsOfFormSubmission(submissionId)(state);
7739
+ store.dispatch(deleteFormSubmission(submissionId));
7146
7740
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
7741
+ store.dispatch(deleteFormSubmissionAttachments(submissionAttachments.map((x) => x.offline_id)));
7147
7742
  try {
7148
7743
  return await this.enqueueRequest({
7149
7744
  description: "Delete user form submissions",
@@ -7153,10 +7748,9 @@ class UserFormSubmissionService extends BaseApiService {
7153
7748
  blocks: []
7154
7749
  });
7155
7750
  } catch (e) {
7156
- if (submission) {
7157
- store.dispatch(addActiveProjectFormSubmissionsCount(1));
7158
- store.dispatch(updateOrCreateUserFormSubmission(submission));
7159
- }
7751
+ store.dispatch(addActiveProjectFormSubmissionsCount(1));
7752
+ store.dispatch(addFormSubmission(submission));
7753
+ store.dispatch(addFormSubmissionAttachments(submissionAttachments));
7160
7754
  throw e;
7161
7755
  }
7162
7756
  }
@@ -7170,7 +7764,7 @@ class UserFormSubmissionService extends BaseApiService {
7170
7764
  blockers: [],
7171
7765
  blocks: []
7172
7766
  });
7173
- store.dispatch(setUserFormSubmissions(submissions));
7767
+ store.dispatch(setFormSubmissions(submissions));
7174
7768
  const attachments = await this.enqueueRequest({
7175
7769
  description: "Fetch form attachments",
7176
7770
  method: HttpMethod.GET,
@@ -7178,7 +7772,7 @@ class UserFormSubmissionService extends BaseApiService {
7178
7772
  blockers: [],
7179
7773
  blocks: []
7180
7774
  });
7181
- store.dispatch(setUserFormSubmissionAttachments(attachments));
7775
+ store.dispatch(setFormSubmissionAttachments(attachments));
7182
7776
  }
7183
7777
  }
7184
7778
  class WorkspaceService extends BaseApiService {
@@ -7738,17 +8332,28 @@ class LicenseService extends BaseApiService {
7738
8332
  }
7739
8333
  }
7740
8334
  class DocumentService extends BaseApiService {
8335
+ // TODO: Support adding for project or organization
7741
8336
  add(document2) {
7742
8337
  const { store } = this.client;
7743
8338
  const currentUserId = store.getState().userReducer.currentUser.id;
7744
8339
  const activeProjectId = store.getState().projectReducer.activeProjectId;
7745
- const offlineDocument = offline({ ...document2, created_by: currentUserId });
7746
- store.dispatch(addDocuments([offlineDocument]));
8340
+ if (!activeProjectId) {
8341
+ throw new Error("No active project ID while creating document.");
8342
+ }
8343
+ const offlineDocument = offline(document2);
8344
+ const submittedDocument = {
8345
+ ...offlineDocument,
8346
+ created_by: currentUserId,
8347
+ project: activeProjectId,
8348
+ organization: null,
8349
+ children_documents: []
8350
+ };
8351
+ store.dispatch(addDocuments([submittedDocument]));
7747
8352
  const promise = this.enqueueRequest({
7748
8353
  description: "Create Document",
7749
8354
  method: HttpMethod.POST,
7750
- url: `/projects/${activeProjectId}/create-document/`,
7751
- payload: { ...offlineDocument },
8355
+ url: `/projects/${activeProjectId}/documents/`,
8356
+ payload: offlineDocument,
7752
8357
  queryParams: {
7753
8358
  parent_document: offlineDocument.parent_document ?? void 0
7754
8359
  },
@@ -7759,7 +8364,7 @@ class DocumentService extends BaseApiService {
7759
8364
  promise.catch(() => {
7760
8365
  store.dispatch(removeDocuments([offlineDocument.offline_id]));
7761
8366
  });
7762
- return [offlineDocument, promise];
8367
+ return [submittedDocument, promise];
7763
8368
  }
7764
8369
  update(document2) {
7765
8370
  const { store } = this.client;
@@ -7859,15 +8464,25 @@ class DocumentService extends BaseApiService {
7859
8464
  }
7860
8465
  async refreshStore() {
7861
8466
  const { store } = this.client;
7862
- const activeProjectId = store.getState().projectReducer.activeProjectId;
7863
- const result = await this.enqueueRequest({
8467
+ const state = store.getState();
8468
+ const activeProjectId = state.projectReducer.activeProjectId;
8469
+ const projectDocumentsPromise = this.enqueueRequest({
7864
8470
  description: "Get project documents",
7865
8471
  method: HttpMethod.GET,
7866
- url: `/documents/projects/${activeProjectId}/`,
8472
+ url: `/projects/${activeProjectId}/documents/`,
8473
+ blockers: [],
8474
+ blocks: []
8475
+ });
8476
+ const activeOrganizationId = state.organizationReducer.activeOrganizationId;
8477
+ const organizationDocumentsPromise = this.enqueueRequest({
8478
+ description: "Get organization documents",
8479
+ method: HttpMethod.GET,
8480
+ url: `/organizations/${activeOrganizationId}/documents/`,
7867
8481
  blockers: [],
7868
8482
  blocks: []
7869
8483
  });
7870
- store.dispatch(setDocuments(result));
8484
+ store.dispatch(setDocuments(await projectDocumentsPromise));
8485
+ store.dispatch(addDocuments(await organizationDocumentsPromise));
7871
8486
  }
7872
8487
  }
7873
8488
  class AgentService extends BaseApiService {
@@ -7902,6 +8517,142 @@ class AgentService extends BaseApiService {
7902
8517
  });
7903
8518
  }
7904
8519
  }
8520
+ class TeamService extends BaseApiService {
8521
+ add(teamPayload) {
8522
+ const { store } = this.client;
8523
+ const state = store.getState();
8524
+ const activeOrganizationId = state.organizationReducer.activeOrganizationId;
8525
+ if (!activeOrganizationId) {
8526
+ throw new Error(`Expected active organization to be set, got ${activeOrganizationId}`);
8527
+ }
8528
+ const offlineTeam = offline({
8529
+ ...teamPayload,
8530
+ organization: activeOrganizationId,
8531
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
8532
+ // TODO: uncomment once supported
8533
+ // created_by: state.userReducer.currentUser.id,
8534
+ });
8535
+ store.dispatch(addTeam(offlineTeam));
8536
+ const promise = this.enqueueRequest({
8537
+ description: "Create team",
8538
+ method: HttpMethod.POST,
8539
+ url: `/organizations/${activeOrganizationId}/teams/`,
8540
+ payload: offlineTeam,
8541
+ // No blocks since users and organizations are not offline
8542
+ blockers: [],
8543
+ blocks: [offlineTeam.offline_id]
8544
+ });
8545
+ promise.then((createdTeam) => {
8546
+ store.dispatch(setTeam(createdTeam));
8547
+ }).catch(() => {
8548
+ store.dispatch(deleteTeam(offlineTeam.offline_id));
8549
+ });
8550
+ return [offlineTeam, promise];
8551
+ }
8552
+ // TODO: @Audiopolis / Magnus - should we pass a offline_id as one arg and a UpdatedTeamProps as a second arg instead of this set up?
8553
+ update(team) {
8554
+ const { store } = this.client;
8555
+ const teamToBeUpdated = store.getState().teamReducer.teams[team.offline_id];
8556
+ const offlineUpdatedTeam = {
8557
+ ...teamToBeUpdated,
8558
+ ...team
8559
+ };
8560
+ store.dispatch(updateTeam(offlineUpdatedTeam));
8561
+ const promise = this.enqueueRequest({
8562
+ description: "Update team",
8563
+ method: HttpMethod.PATCH,
8564
+ url: `/organizations/teams/${team.offline_id}/`,
8565
+ payload: offlineUpdatedTeam,
8566
+ blockers: [team.offline_id],
8567
+ blocks: [team.offline_id]
8568
+ });
8569
+ promise.then((updatedTeam) => {
8570
+ store.dispatch(setTeam(updatedTeam));
8571
+ }).catch(() => {
8572
+ store.dispatch(setTeam(teamToBeUpdated));
8573
+ });
8574
+ return [offlineUpdatedTeam, promise];
8575
+ }
8576
+ async delete(teamId) {
8577
+ const { store } = this.client;
8578
+ const state = store.getState();
8579
+ const team = state.teamReducer.teams[teamId];
8580
+ if (!team) {
8581
+ throw new Error(`Expected team with id ${teamId} to exist`);
8582
+ }
8583
+ store.dispatch(deleteTeam(teamId));
8584
+ try {
8585
+ return await this.enqueueRequest({
8586
+ description: "Delete team",
8587
+ method: HttpMethod.DELETE,
8588
+ url: `/organizations/teams/${teamId}/`,
8589
+ blockers: [teamId],
8590
+ blocks: [teamId]
8591
+ });
8592
+ } catch (e) {
8593
+ store.dispatch(setTeam(team));
8594
+ throw e;
8595
+ }
8596
+ }
8597
+ async setMembers(teamId, members) {
8598
+ const { store } = this.client;
8599
+ const team = store.getState().teamReducer.teams[teamId];
8600
+ if (!team) {
8601
+ throw new Error(`Expected team with id ${teamId} to exist`);
8602
+ }
8603
+ if (members.length !== new Set(members).size) {
8604
+ throw new Error("Duplicate members found in the list");
8605
+ }
8606
+ store.dispatch(updateTeam({ ...team, members }));
8607
+ const promise = this.enqueueRequest({
8608
+ description: "Set team members",
8609
+ method: HttpMethod.PUT,
8610
+ url: `/organizations/teams/${teamId}/set-members/`,
8611
+ payload: {
8612
+ users: members
8613
+ },
8614
+ blockers: [teamId],
8615
+ blocks: [teamId]
8616
+ });
8617
+ promise.catch(() => {
8618
+ store.dispatch(setTeam(team));
8619
+ });
8620
+ return promise;
8621
+ }
8622
+ async addMembers(teamId, members) {
8623
+ const { store } = this.client;
8624
+ const team = store.getState().teamReducer.teams[teamId];
8625
+ if (!team) {
8626
+ throw new Error(`Expected team with id ${teamId} to exist`);
8627
+ }
8628
+ const newMembers = [...team.members, ...members];
8629
+ return this.setMembers(teamId, newMembers);
8630
+ }
8631
+ async removeMembers(teamId, members) {
8632
+ const { store } = this.client;
8633
+ const team = store.getState().teamReducer.teams[teamId];
8634
+ if (!team) {
8635
+ throw new Error(`Expected team with id ${teamId} to exist`);
8636
+ }
8637
+ const newMembers = team.members.filter((member) => !members.includes(member));
8638
+ return this.setMembers(teamId, newMembers);
8639
+ }
8640
+ async refreshStore() {
8641
+ const { store } = this.client;
8642
+ const activeOrganizationId = store.getState().organizationReducer.activeOrganizationId;
8643
+ if (!activeOrganizationId) {
8644
+ throw new Error(`Expected active organization to be set, got ${activeOrganizationId}`);
8645
+ }
8646
+ const result = await this.enqueueRequest({
8647
+ description: "Fetch teams",
8648
+ method: HttpMethod.GET,
8649
+ url: `/organizations/${activeOrganizationId}/teams/`,
8650
+ blockers: [],
8651
+ blocks: []
8652
+ });
8653
+ store.dispatch(setTeams(result));
8654
+ }
8655
+ }
7905
8656
  class OvermapSDK {
7906
8657
  constructor(apiUrl, store) {
7907
8658
  __publicField(this, "API_URL");
@@ -7915,6 +8666,7 @@ class OvermapSDK {
7915
8666
  __publicField(this, "organizations", new OrganizationService(this));
7916
8667
  __publicField(this, "organizationAccess", new OrganizationAccessService(this));
7917
8668
  __publicField(this, "issues", new IssueService(this));
8669
+ __publicField(this, "issueTypes", new IssueTypeService(this));
7918
8670
  __publicField(this, "issueComments", new IssueCommentService(this));
7919
8671
  __publicField(this, "issueUpdates", new IssueUpdateService(this));
7920
8672
  __publicField(this, "workspaces", new WorkspaceService(this));
@@ -7931,6 +8683,7 @@ class OvermapSDK {
7931
8683
  __publicField(this, "emailDomains", new EmailDomainsService(this));
7932
8684
  __publicField(this, "licenses", new LicenseService(this));
7933
8685
  __publicField(this, "documents", new DocumentService(this));
8686
+ __publicField(this, "teams", new TeamService(this));
7934
8687
  this.API_URL = apiUrl;
7935
8688
  this.store = store;
7936
8689
  }
@@ -7972,7 +8725,7 @@ const tabTrigger = "_tabTrigger_1w0fq_69";
7972
8725
  const patchfieldBorder = "_patchfieldBorder_1w0fq_73";
7973
8726
  const title = "_title_1w0fq_73";
7974
8727
  const error = "_error_1w0fq_89";
7975
- const styles$c = {
8728
+ const styles$d = {
7976
8729
  description: description$2,
7977
8730
  floatingButtonContainer: floatingButtonContainer$2,
7978
8731
  FullScreenImageContainer: FullScreenImageContainer$2,
@@ -8093,7 +8846,7 @@ const fileName$1 = "_fileName_10o76_31";
8093
8846
  const longIconButton$1 = "_longIconButton_10o76_36";
8094
8847
  const previewImage$1 = "_previewImage_10o76_42";
8095
8848
  const FullScreenImage$1 = "_FullScreenImage_10o76_12";
8096
- const styles$b = {
8849
+ const styles$c = {
8097
8850
  description: description$1,
8098
8851
  floatingButtonContainer: floatingButtonContainer$1,
8099
8852
  FullScreenImageContainer: FullScreenImageContainer$1,
@@ -8117,7 +8870,7 @@ const FullScreenImagePreview = memo((props) => {
8117
8870
  /* @__PURE__ */ jsx(
8118
8871
  "button",
8119
8872
  {
8120
- className: styles$b.FullScreenImageContainer,
8873
+ className: styles$c.FullScreenImageContainer,
8121
8874
  type: "button",
8122
8875
  onClick: () => {
8123
8876
  setShowPreview(false);
@@ -8125,7 +8878,7 @@ const FullScreenImagePreview = memo((props) => {
8125
8878
  children: /* @__PURE__ */ jsx(
8126
8879
  "img",
8127
8880
  {
8128
- className: styles$b.FullScreenImage,
8881
+ className: styles$c.FullScreenImage,
8129
8882
  src: url,
8130
8883
  alt: name,
8131
8884
  onClick: (e) => {
@@ -8135,11 +8888,11 @@ const FullScreenImagePreview = memo((props) => {
8135
8888
  )
8136
8889
  }
8137
8890
  ),
8138
- /* @__PURE__ */ jsxs(Flex$1, { className: styles$b.TopBarContainer, align: "center", children: [
8891
+ /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.TopBarContainer, align: "center", children: [
8139
8892
  /* @__PURE__ */ jsx(
8140
8893
  IconButton,
8141
8894
  {
8142
- className: styles$b.longIconButton,
8895
+ className: styles$c.longIconButton,
8143
8896
  variant: "soft",
8144
8897
  "aria-label": "Exit preview",
8145
8898
  onClick: () => {
@@ -8148,11 +8901,11 @@ const FullScreenImagePreview = memo((props) => {
8148
8901
  children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiArrowLeftLine" })
8149
8902
  }
8150
8903
  ),
8151
- /* @__PURE__ */ jsx(Text$1, { className: styles$b.fileName, children: name }),
8904
+ /* @__PURE__ */ jsx(Text$1, { className: styles$c.fileName, children: name }),
8152
8905
  /* @__PURE__ */ jsx(
8153
8906
  IconButton,
8154
8907
  {
8155
- className: styles$b.longIconButton,
8908
+ className: styles$c.longIconButton,
8156
8909
  variant: "soft",
8157
8910
  "aria-label": `Download ${name}`,
8158
8911
  onClick: handleDownload,
@@ -8180,7 +8933,7 @@ const InputWithLabel = (props) => {
8180
8933
  /* @__PURE__ */ jsx(
8181
8934
  "img",
8182
8935
  {
8183
- className: styles$b.previewImage,
8936
+ className: styles$c.previewImage,
8184
8937
  src: resolvedImageURL,
8185
8938
  alt: resolvedImage.name,
8186
8939
  onClick: () => {
@@ -8208,7 +8961,7 @@ const InputWithHelpText = (props) => {
8208
8961
  const { helpText, children, severity } = props;
8209
8962
  return /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "1", children: [
8210
8963
  children,
8211
- /* @__PURE__ */ jsx(Flex$1, { direction: "column", children: /* @__PURE__ */ jsx(Text$1, { size: "1", severity, className: styles$b.description, children: helpText }) })
8964
+ /* @__PURE__ */ jsx(Flex$1, { direction: "column", children: /* @__PURE__ */ jsx(Text$1, { size: "1", severity, className: styles$c.description, children: helpText }) })
8212
8965
  ] });
8213
8966
  };
8214
8967
  const InputWithLabelAndHelpText = (props) => {
@@ -8442,6 +9195,9 @@ function RiArrowUpLine(props) {
8442
9195
  function RiCalendarLine(props) {
8443
9196
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M9 1V3H15V1H17V3H21C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H7V1H9ZM20 11H4V19H20V11ZM7 5H4V9H20V5H17V7H15V5H9V7H7V5Z" }, "child": [] }] })(props);
8444
9197
  }
9198
+ function RiQrCodeLine(props) {
9199
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M16 17V16H13V13H16V15H18V17H17V19H15V21H13V18H15V17H16ZM21 21H17V19H19V17H21V21ZM3 3H11V11H3V3ZM5 5V9H9V5H5ZM13 3H21V11H13V3ZM15 5V9H19V5H15ZM3 13H11V21H3V13ZM5 15V19H9V15H5ZM18 13H21V15H18V13ZM6 6H8V8H6V6ZM6 16H8V18H6V16ZM16 6H18V8H16V6Z" }, "child": [] }] })(props);
9200
+ }
8445
9201
  function RiFileCopyLine(props) {
8446
9202
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M6.9998 6V3C6.9998 2.44772 7.44752 2 7.9998 2H19.9998C20.5521 2 20.9998 2.44772 20.9998 3V17C20.9998 17.5523 20.5521 18 19.9998 18H16.9998V20.9991C16.9998 21.5519 16.5499 22 15.993 22H4.00666C3.45059 22 3 21.5554 3 20.9991L3.0026 7.00087C3.0027 6.44811 3.45264 6 4.00942 6H6.9998ZM5.00242 8L5.00019 20H14.9998V8H5.00242ZM8.9998 6H16.9998V16H18.9998V4H8.9998V6Z" }, "child": [] }] })(props);
8447
9203
  }
@@ -9345,9 +10101,9 @@ const Inset = React.forwardRef((props, forwardedRef) => {
9345
10101
  return React.createElement("div", { ...insetProps, ref: forwardedRef, className: classNames("rt-Inset", className, withBreakpoints(side, "rt-r-side"), withBreakpoints(clip, "rt-r-clip"), withBreakpoints(p, "rt-r-p"), withBreakpoints(px, "rt-r-px"), withBreakpoints(py, "rt-r-py"), withBreakpoints(pt, "rt-r-pt"), withBreakpoints(pr, "rt-r-pr"), withBreakpoints(pb, "rt-r-pb"), withBreakpoints(pl, "rt-r-pl"), withMarginProps(marginProps)) });
9346
10102
  });
9347
10103
  Inset.displayName = "Inset";
9348
- const sizes$7 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
10104
+ const sizes$8 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9349
10105
  const headingPropDefs = {
9350
- size: { type: "enum", values: sizes$7, default: "6", responsive: true },
10106
+ size: { type: "enum", values: sizes$8, default: "6", responsive: true },
9351
10107
  weight: { ...weightProp, default: "bold" },
9352
10108
  align: alignProp,
9353
10109
  trim: trimProp,
@@ -9360,9 +10116,9 @@ const Heading = React.forwardRef((props, forwardedRef) => {
9360
10116
  return React.createElement($5e63c961fc1ce211$export$8c6ed5c666ac1360, { "data-accent-color": color, ...headingProps, ref: forwardedRef, className: classNames("rt-Heading", className, withBreakpoints(size, "rt-r-size"), withBreakpoints(weight, "rt-r-weight"), withBreakpoints(align, "rt-r-ta"), withBreakpoints(trim, "rt-r-lt"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) }, asChild ? children : React.createElement(Tag, null, children));
9361
10117
  });
9362
10118
  Heading.displayName = "Heading";
9363
- const sizes$6 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
10119
+ const sizes$7 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9364
10120
  const textPropDefs = {
9365
- size: { type: "enum", values: sizes$6, default: void 0, responsive: true },
10121
+ size: { type: "enum", values: sizes$7, default: void 0, responsive: true },
9366
10122
  weight: weightProp,
9367
10123
  align: alignProp,
9368
10124
  trim: trimProp,
@@ -9375,6 +10131,21 @@ const Text = React.forwardRef((props, forwardedRef) => {
9375
10131
  return React.createElement($5e63c961fc1ce211$export$8c6ed5c666ac1360, { "data-accent-color": color, ...textProps, ref: forwardedRef, className: classNames("rt-Text", className, withBreakpoints(size, "rt-r-size"), withBreakpoints(weight, "rt-r-weight"), withBreakpoints(align, "rt-r-ta"), withBreakpoints(trim, "rt-r-lt"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) }, asChild ? children : React.createElement(Tag, null, children));
9376
10132
  });
9377
10133
  Text.displayName = "Text";
10134
+ const sizes$6 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
10135
+ const variants$4 = ["solid", "soft", "outline", "ghost"];
10136
+ const codePropDefs = {
10137
+ size: { type: "enum", values: sizes$6, default: void 0, responsive: true },
10138
+ variant: { type: "enum", values: variants$4, default: "soft" },
10139
+ weight: weightProp,
10140
+ color: colorProp,
10141
+ highContrast: highContrastProp
10142
+ };
10143
+ const Code = React.forwardRef((props, forwardedRef) => {
10144
+ const { rest: marginRest, ...marginProps } = extractMarginProps(props);
10145
+ const { className, size = codePropDefs.size.default, variant = codePropDefs.variant.default, weight = codePropDefs.weight.default, color = codePropDefs.color.default, highContrast = codePropDefs.highContrast.default, ...codeProps } = marginRest;
10146
+ return React.createElement("code", { "data-accent-color": color, ...codeProps, ref: forwardedRef, className: classNames("rt-Code", className, withBreakpoints(size, "rt-r-size"), `rt-variant-${variant}`, withBreakpoints(weight, "rt-r-weight"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) });
10147
+ });
10148
+ Code.displayName = "Code";
9378
10149
  const Em = React.forwardRef((props, forwardedRef) => React.createElement("em", { ...props, ref: forwardedRef, className: classNames("rt-Em", props.className) }));
9379
10150
  Em.displayName = "Em";
9380
10151
  const Strong = React.forwardRef((props, forwardedRef) => React.createElement("strong", { ...props, ref: forwardedRef, className: classNames("rt-Strong", props.className) }));
@@ -11765,7 +12536,7 @@ __publicField(StringOrTextField, "_validateMax", (path) => (value, allValues) =>
11765
12536
  });
11766
12537
  const clickableLinkContainer = "_clickableLinkContainer_1ace7_1";
11767
12538
  const TextFieldInputCopy = "_TextFieldInputCopy_1ace7_5";
11768
- const styles$a = {
12539
+ const styles$b = {
11769
12540
  clickableLinkContainer,
11770
12541
  TextFieldInputCopy
11771
12542
  };
@@ -11794,13 +12565,13 @@ const StringInput = memo((props) => {
11794
12565
  placeholder: field.placeholder,
11795
12566
  color
11796
12567
  }
11797
- ) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$a.clickableLinkContainer, children: [
12568
+ ) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$b.clickableLinkContainer, children: [
11798
12569
  /* @__PURE__ */ jsx(
11799
12570
  "div",
11800
12571
  {
11801
12572
  className: classNames$1(
11802
12573
  "rt-TextFieldInput rt-r-size-2 rt-variant-surface",
11803
- styles$a.TextFieldInputCopy
12574
+ styles$b.TextFieldInputCopy
11804
12575
  ),
11805
12576
  children: /* @__PURE__ */ jsx(
11806
12577
  Linkify,
@@ -12372,8 +13143,7 @@ class BaseSelectField extends BaseField {
12372
13143
  description: "List possible options for the user to select from.",
12373
13144
  required: true,
12374
13145
  identifier: `${path}options`,
12375
- minimum_length: 2,
12376
- maximum_length: 20
13146
+ minimum_length: 2
12377
13147
  }),
12378
13148
  showDirectly: true
12379
13149
  }
@@ -12492,6 +13262,158 @@ __publicField(_MultiSelectField, "fieldTypeName", "Multi-select");
12492
13262
  __publicField(_MultiSelectField, "fieldTypeDescription", "Allows the user to select a multiple options from a list of options.");
12493
13263
  __publicField(_MultiSelectField, "Icon", RiCheckboxLine);
12494
13264
  let MultiSelectField = _MultiSelectField;
13265
+ const QrScannerWrapper = "_QrScannerWrapper_1puz3_1";
13266
+ const styles$a = {
13267
+ QrScannerWrapper
13268
+ };
13269
+ const QrInput = memo((props) => {
13270
+ const [{ inputId, labelId, label, helpText, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
13271
+ const [showQrScanner, setShowQrScanner] = useState(false);
13272
+ const value = fieldProps.value;
13273
+ const handleQrScan = useCallback(
13274
+ (data) => {
13275
+ fieldProps.onChange({ target: { value: data } });
13276
+ setShowQrScanner(false);
13277
+ },
13278
+ [fieldProps]
13279
+ );
13280
+ const handleClearScanResult = useCallback(() => {
13281
+ fieldProps.onChange({ target: { value: "" } });
13282
+ }, [fieldProps]);
13283
+ const handleScanButtonClicked = useCallback(() => {
13284
+ setShowQrScanner(true);
13285
+ }, []);
13286
+ const handleQrScannerClose = useCallback(() => {
13287
+ setShowQrScanner(false);
13288
+ }, []);
13289
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsxs(
13290
+ InputWithLabel,
13291
+ {
13292
+ size,
13293
+ severity,
13294
+ inputId,
13295
+ labelId,
13296
+ label: showInputOnly ? label : "",
13297
+ image: showInputOnly ? void 0 : field.image,
13298
+ flexProps: { direction: "column", justify: "start", align: "start", gap: "1" },
13299
+ children: [
13300
+ /* @__PURE__ */ jsx(
13301
+ Overlay,
13302
+ {
13303
+ open: showQrScanner,
13304
+ content: () => /* @__PURE__ */ jsx(QrScanner, { onQrScan: handleQrScan, onClose: handleQrScannerClose }),
13305
+ onOpenChange: setShowQrScanner
13306
+ }
13307
+ ),
13308
+ /* @__PURE__ */ jsxs(Flex, { width: "max-content", gap: "1", align: "center", children: [
13309
+ /* @__PURE__ */ jsxs(Button, { ...rest, variant: "soft", onClick: handleScanButtonClicked, children: [
13310
+ /* @__PURE__ */ jsx(RiIcon, { icon: "RiQrCodeLine" }),
13311
+ "Scan"
13312
+ ] }),
13313
+ value && /* @__PURE__ */ jsx(Text, { color: "jade", size: "1", children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCheckLine", style: { verticalAlign: "bottom" } }) })
13314
+ ] }),
13315
+ value && /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex, { width: "max-content", gap: "2", align: "center", children: [
13316
+ /* @__PURE__ */ jsx(Code, { color: "gray", highContrast: true, children: value }),
13317
+ /* @__PURE__ */ jsx(
13318
+ IconButton,
13319
+ {
13320
+ severity: "info",
13321
+ variant: "ghost",
13322
+ "aria-label": "delete",
13323
+ size: "small",
13324
+ onClick: handleClearScanResult,
13325
+ children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCloseLine" })
13326
+ }
13327
+ )
13328
+ ] }) })
13329
+ ]
13330
+ }
13331
+ ) });
13332
+ });
13333
+ QrInput.displayName = "QrInput";
13334
+ const QrScanner = memo((props) => {
13335
+ const { onQrScan, onClose } = props;
13336
+ const videoRef = useRef(null);
13337
+ const [isScannerLoading, setIsScannerLoading] = useState(false);
13338
+ useEffect(() => {
13339
+ if (!videoRef.current)
13340
+ return;
13341
+ const qrScanner = new QrScannerAPI(
13342
+ videoRef.current,
13343
+ (result) => {
13344
+ const data = result.data;
13345
+ onQrScan(data);
13346
+ qrScanner.destroy();
13347
+ },
13348
+ {
13349
+ highlightCodeOutline: true,
13350
+ highlightScanRegion: true,
13351
+ maxScansPerSecond: 1
13352
+ }
13353
+ );
13354
+ setIsScannerLoading(true);
13355
+ qrScanner.start().then(() => {
13356
+ setIsScannerLoading(false);
13357
+ }).catch(() => {
13358
+ setIsScannerLoading(false);
13359
+ });
13360
+ }, [onQrScan]);
13361
+ return /* @__PURE__ */ jsxs(
13362
+ Flex,
13363
+ {
13364
+ className: styles$a.QrScannerWrapper,
13365
+ width: "100%",
13366
+ height: "100%",
13367
+ direction: "column",
13368
+ gap: "2",
13369
+ justify: "center",
13370
+ position: "relative",
13371
+ children: [
13372
+ /* @__PURE__ */ jsx(Flex, { width: "100%", position: "absolute", top: "0", p: "2", children: /* @__PURE__ */ jsx(IconButton, { "aria-label": "close", variant: "soft", severity: "info", highContrast: true, onClick: onClose, children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCloseLine" }) }) }),
13373
+ /* @__PURE__ */ jsxs(Box, { style: { maxWidth: "100%", maxHeight: "100%" }, position: "relative", children: [
13374
+ /* @__PURE__ */ jsx("video", { ref: videoRef, style: { width: "100%", height: "100%" } }),
13375
+ isScannerLoading && /* @__PURE__ */ jsx(
13376
+ Flex,
13377
+ {
13378
+ position: "absolute",
13379
+ inset: "0",
13380
+ style: { background: "var(--color-background)" },
13381
+ justify: "center",
13382
+ align: "center",
13383
+ children: /* @__PURE__ */ jsx(Spinner, {})
13384
+ }
13385
+ )
13386
+ ] })
13387
+ ]
13388
+ }
13389
+ );
13390
+ });
13391
+ QrScanner.displayName = "QrScanner";
13392
+ const emptyQrField = {
13393
+ ...emptyBaseField,
13394
+ type: "qr"
13395
+ };
13396
+ const _QrField = class _QrField extends BaseField {
13397
+ constructor(options) {
13398
+ super({ ...options, type: "qr" });
13399
+ __publicField(this, "onlyValidateAfterTouched", false);
13400
+ }
13401
+ serialize() {
13402
+ return super._serialize();
13403
+ }
13404
+ static deserialize(data) {
13405
+ if (data.type !== "qr")
13406
+ throw new Error("Type mismatch.");
13407
+ return new _QrField(data);
13408
+ }
13409
+ getInput(props) {
13410
+ return /* @__PURE__ */ jsx(QrInput, { ...props, field: this });
13411
+ }
13412
+ };
13413
+ __publicField(_QrField, "fieldTypeName", "QR");
13414
+ __publicField(_QrField, "fieldTypeDescription", "Used for scanning/reading QR codes.");
13415
+ __publicField(_QrField, "Icon", RiQrCodeLine);
13416
+ let QrField = _QrField;
12495
13417
  const FieldInputCloner = memo((props) => {
12496
13418
  const { field, ...rest } = props;
12497
13419
  const [{ value: identifier }] = useField(field.options.clonedFieldIdentifier);
@@ -13749,6 +14671,7 @@ const FieldTypeToClsMapping = {
13749
14671
  text: TextField,
13750
14672
  custom: CustomField,
13751
14673
  upload: UploadField,
14674
+ qr: QrField,
13752
14675
  // TODO: Underscore
13753
14676
  "multi-string": MultiStringField,
13754
14677
  "multi-select": MultiSelectField
@@ -13762,6 +14685,7 @@ const FieldTypeToEmptyFieldMapping = {
13762
14685
  text: emptyTextField,
13763
14686
  custom: emptyCustomField,
13764
14687
  upload: emptyUploadField,
14688
+ qr: emptyQrField,
13765
14689
  // TODO: Underscore
13766
14690
  "multi-string": emptyMultiStringField,
13767
14691
  "multi-select": emptyMultiSelectField
@@ -13849,7 +14773,7 @@ const FieldSectionLayout = memo((props) => {
13849
14773
  return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "3", children: [
13850
14774
  /* @__PURE__ */ jsxs(Flex$1, { direction: "column", children: [
13851
14775
  /* @__PURE__ */ jsx(Heading, { as: "h3", size: "3", children: label }),
13852
- /* @__PURE__ */ jsx(Text$1, { className: styles$b.description, children: description2 })
14776
+ /* @__PURE__ */ jsx(Text$1, { className: styles$c.description, children: description2 })
13853
14777
  ] }),
13854
14778
  inputs
13855
14779
  ] }) });
@@ -14036,7 +14960,7 @@ const initialFormValues = (fields, values) => {
14036
14960
  };
14037
14961
  const useAttachImagesToFormRevisionFields = (revision) => {
14038
14962
  const { sdk } = useSDK();
14039
- const attachments = useAppSelector(selectRevisionAttachments((revision == null ? void 0 : revision.offline_id) ?? ""));
14963
+ const attachments = useAppSelector(selectAttachmentsOfFormRevision((revision == null ? void 0 : revision.offline_id) ?? ""));
14040
14964
  return useMemo(() => {
14041
14965
  if (!revision || !attachments)
14042
14966
  return revision;
@@ -14092,7 +15016,7 @@ const FormRenderer = memo(
14092
15016
  [schema.title]
14093
15017
  );
14094
15018
  const Description = useMemo(
14095
- () => typeof schema.description === "string" ? /* @__PURE__ */ jsx(Text$1, { className: styles$b.description, children: schema.description }) : schema.description,
15019
+ () => typeof schema.description === "string" ? /* @__PURE__ */ jsx(Text$1, { className: styles$c.description, children: schema.description }) : schema.description,
14096
15020
  [schema.description]
14097
15021
  );
14098
15022
  const inputs = useFieldInputs(schema.fields, { formId: formId2, disabled: readonly });
@@ -14108,7 +15032,7 @@ const FormRenderer = memo(
14108
15032
  !hideDescription && Description
14109
15033
  ] }) }),
14110
15034
  inputs,
14111
- !readonly && /* @__PURE__ */ jsxs(Flex$1, { className: styles$b.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
15035
+ !readonly && /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
14112
15036
  cancelText && /* @__PURE__ */ jsx(Button, { severity: "info", ...buttonProps, type: "button", onClick: onCancel, children: cancelText }),
14113
15037
  /* @__PURE__ */ jsx(Button, { ...buttonProps, type: "submit", disabled: !formik.isValid, children: submitText })
14114
15038
  ] })
@@ -14133,7 +15057,7 @@ const FormSubmissionViewer = memo(
14133
15057
  return formRevisionToSchema(revisionWithImages, { readonly: true });
14134
15058
  }, [revisionWithImages]);
14135
15059
  const submissionValuesWithAttachments = useMemo(() => {
14136
- const attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? [];
15060
+ const attachments = selectAttachmentsOfFormSubmission(submission.offline_id)(sdk.store.getState()) ?? [];
14137
15061
  const downloadedAttachments = {};
14138
15062
  for (const attachment of attachments) {
14139
15063
  const promise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
@@ -14183,9 +15107,9 @@ const FormBrowser = memo(
14183
15107
  }
14184
15108
  return ret;
14185
15109
  }, [filter, maxResults, ownerFilter]);
14186
- const userForms = useAppSelector(selectFilteredUserForms(ownerFilterOptions)) ?? [];
14187
- const userFormMapping = useAppSelector(selectUserFormMapping);
14188
- const attachableUserForms = userForms.filter((form) => !form.component_type);
15110
+ const userForms = useAppSelector(selectFilteredForms(ownerFilterOptions)) ?? [];
15111
+ const userFormMapping = useAppSelector(selectFormMapping);
15112
+ const attachableUserForms = userForms.filter((form) => !form.component_type && !form.issue_type);
14189
15113
  const attachableUserFormMapping = Object.values(userFormMapping).filter(
14190
15114
  (form) => !form.component_type
14191
15115
  );
@@ -14217,7 +15141,7 @@ const FormBrowser = memo(
14217
15141
  const handleChange = useCallback((e) => {
14218
15142
  setFilter(e.currentTarget.value);
14219
15143
  }, []);
14220
- const numberOfForms = useAppSelector(selectNumberOfGeneralUserForms) || 0;
15144
+ const numberOfForms = useAppSelector(selectGeneralFormCount) || 0;
14221
15145
  const numberOfHiddenForms = numberOfForms - attachableUserForms.length;
14222
15146
  const overflowMessage = attachableUserForms.length == maxResults && numberOfHiddenForms > 0 ? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)` : numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`;
14223
15147
  return /* @__PURE__ */ jsxs(Flex$1, { ref, direction: "column", gap: "2", children: [
@@ -14311,16 +15235,13 @@ const FormSubmissionBrowserEntry = memo((props) => {
14311
15235
  const { submission, onSubmissionClick, compact, labelType, rowDecorator } = props;
14312
15236
  const currentUser = useAppSelector(selectCurrentUser);
14313
15237
  const createdBy = useAppSelector(selectUser("created_by" in submission ? submission.created_by : currentUser.id));
14314
- const dateToUse = getCreatedAtOrSubmittedAtDate(submission);
14315
- const formattedDateTime = isToday(dateToUse) ? dateToUse.toLocaleTimeString([], {
14316
- hour: "2-digit",
14317
- minute: "2-digit"
14318
- }) : getLocalDateString(dateToUse);
15238
+ const dateToUse = submission.submitted_at;
15239
+ const formattedDateTime = getLocalDateString(dateToUse);
14319
15240
  const revision = useAppSelector(selectFormRevision(submission.form_revision));
14320
15241
  if (!revision) {
14321
15242
  throw new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`);
14322
15243
  }
14323
- const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevision(revision.form))) == null ? void 0 : _a2.revision;
15244
+ const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevisionOfForm(revision.form))) == null ? void 0 : _a2.revision;
14324
15245
  const creatorProfileSrc = useFileSrc({
14325
15246
  file: (createdBy == null ? void 0 : createdBy.profile.file) ?? null,
14326
15247
  fileSha1: (createdBy == null ? void 0 : createdBy.profile.file_sha1) ?? null
@@ -14351,10 +15272,6 @@ const FormSubmissionBrowserEntry = memo((props) => {
14351
15272
  return row;
14352
15273
  });
14353
15274
  FormSubmissionBrowserEntry.displayName = "FormSubmissionBrowserEntry";
14354
- const getCreatedAtOrSubmittedAtDate = (submission) => {
14355
- const date = "created_at" in submission ? submission.created_at : submission.submitted_at;
14356
- return new Date(date);
14357
- };
14358
15275
  const FormSubmissionBrowser = memo((props) => {
14359
15276
  const {
14360
15277
  formId: formId2,
@@ -14368,10 +15285,10 @@ const FormSubmissionBrowser = memo((props) => {
14368
15285
  if (!!formId2 === !!propSubmissions) {
14369
15286
  throw new Error("Either formId or submissions must be provided, but not both.");
14370
15287
  }
14371
- const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectSubmissionsForForm(formId2));
15288
+ const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectFormSubmissionsOfForm(formId2));
14372
15289
  const sortedSubmissions = useMemo(
14373
15290
  () => submissions == null ? void 0 : submissions.sort((a, b) => {
14374
- return getCreatedAtOrSubmittedAtDate(b).getTime() - getCreatedAtOrSubmittedAtDate(a).getTime();
15291
+ return a.submitted_at.localeCompare(b.submitted_at);
14375
15292
  }),
14376
15293
  [submissions]
14377
15294
  );
@@ -15463,12 +16380,12 @@ const FormBuilder = memo(
15463
16380
  });
15464
16381
  const previewSchema = useMemo(() => formRevisionToSchema(formik.values), [formik.values]);
15465
16382
  return /* @__PURE__ */ jsx(Tabs.Root, { ref, defaultValue: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "2", children: [
15466
- showTabs && /* @__PURE__ */ jsxs(Tabs.List, { className: classNames$1(styles$c.tabsList, tabsListClassName), children: [
15467
- /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$c.tabTrigger, value: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
16383
+ showTabs && /* @__PURE__ */ jsxs(Tabs.List, { className: classNames$1(styles$d.tabsList, tabsListClassName), children: [
16384
+ /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$d.tabTrigger, value: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15468
16385
  /* @__PURE__ */ jsx(RiIcon, { icon: "RiPencilLine" }),
15469
16386
  "Edit"
15470
16387
  ] }) }),
15471
- /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$c.tabTrigger, value: "preview", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
16388
+ /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$d.tabTrigger, value: "preview", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15472
16389
  /* @__PURE__ */ jsx(RiIcon, { icon: "RiEyeLine" }),
15473
16390
  "Preview"
15474
16391
  ] }) })
@@ -15492,8 +16409,8 @@ const FormBuilder = memo(
15492
16409
  render: ({ setValue, value, meta }) => /* @__PURE__ */ jsx(InputWithHelpText, { severity: "danger", helpText: meta.error ?? null, children: /* @__PURE__ */ jsx(
15493
16410
  Input,
15494
16411
  {
15495
- className: classNames$1(styles$c.title, {
15496
- [styles$c.error]: meta.error
16412
+ className: classNames$1(styles$d.title, {
16413
+ [styles$d.error]: meta.error
15497
16414
  }),
15498
16415
  placeholder: "Form title",
15499
16416
  value,
@@ -15515,7 +16432,7 @@ const FormBuilder = memo(
15515
16432
  render: ({ setValue, value }) => /* @__PURE__ */ jsx(
15516
16433
  TextArea,
15517
16434
  {
15518
- className: styles$c.description,
16435
+ className: styles$d.description,
15519
16436
  placeholder: "Explain the purpose of this form",
15520
16437
  value,
15521
16438
  onChange: (event) => {
@@ -15533,7 +16450,7 @@ const FormBuilder = memo(
15533
16450
  /* @__PURE__ */ jsx(FieldsEditor, { fieldsOnly }),
15534
16451
  /* @__PURE__ */ jsx(Text$1, { severity: "danger", size: "1", children: typeof formik.errors.fields === "string" && formik.errors.fields })
15535
16452
  ] }),
15536
- /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
16453
+ /* @__PURE__ */ jsxs(Flex$1, { className: styles$d.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
15537
16454
  onCancel && /* @__PURE__ */ jsx(Button, { type: "button", variant: "solid", severity: "info", onClick: onCancel, children: "Cancel" }),
15538
16455
  /* @__PURE__ */ jsx(Button, { type: "submit", children: "Save form" })
15539
16456
  ] })
@@ -15568,6 +16485,9 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
15568
16485
  NumberInput,
15569
16486
  PatchField,
15570
16487
  PatchFormProvider,
16488
+ QrField,
16489
+ QrInput,
16490
+ QrScanner,
15571
16491
  SelectField,
15572
16492
  SelectInput,
15573
16493
  StringField,
@@ -15582,6 +16502,7 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
15582
16502
  emptyMultiSelectField,
15583
16503
  emptyMultiStringField,
15584
16504
  emptyNumberField,
16505
+ emptyQrField,
15585
16506
  emptySelectField,
15586
16507
  emptyStringField,
15587
16508
  emptyTextField,
@@ -15642,6 +16563,7 @@ export {
15642
16563
  IssuePriority,
15643
16564
  IssueService,
15644
16565
  IssueStatus,
16566
+ IssueTypeService,
15645
16567
  IssueUpdateChange,
15646
16568
  IssueUpdateService,
15647
16569
  LicenseLevel,
@@ -15672,6 +16594,9 @@ export {
15672
16594
  ProjectFileService,
15673
16595
  ProjectService,
15674
16596
  ProjectType,
16597
+ QrField,
16598
+ QrInput,
16599
+ QrScanner,
15675
16600
  SDKContext,
15676
16601
  SDKProvider,
15677
16602
  SUPPORTED_IMAGE_FILE_TYPES,
@@ -15682,6 +16607,7 @@ export {
15682
16607
  SpreadsheetViewer,
15683
16608
  StringField,
15684
16609
  StringInput,
16610
+ TeamService,
15685
16611
  TextField,
15686
16612
  TextInput,
15687
16613
  UserFormService,
@@ -15689,6 +16615,7 @@ export {
15689
16615
  VerificationCodeType,
15690
16616
  WorkspaceService,
15691
16617
  YELLOW,
16618
+ _selectLatestFormRevision,
15692
16619
  _setLatestRetryTime,
15693
16620
  acceptProjectInvite,
15694
16621
  addActiveProjectFormSubmissionsCount,
@@ -15706,13 +16633,25 @@ export {
15706
16633
  addDocuments,
15707
16634
  addEmailDomain,
15708
16635
  addFavouriteProjectId,
16636
+ addForm,
16637
+ addFormRevision,
16638
+ addFormRevisionAttachment,
16639
+ addFormRevisionAttachments,
16640
+ addFormRevisions,
16641
+ addFormSubmission,
16642
+ addFormSubmissionAttachment,
16643
+ addFormSubmissionAttachments,
16644
+ addFormSubmissions,
16645
+ addForms,
15709
16646
  addIssue,
15710
16647
  addIssueAttachment,
15711
16648
  addIssueAttachments,
15712
16649
  addIssueComment,
15713
16650
  addIssueComments,
16651
+ addIssueType,
15714
16652
  addIssueUpdate,
15715
16653
  addIssueUpdates,
16654
+ addIssues,
15716
16655
  addLicenses,
15717
16656
  addOrReplaceCategories,
15718
16657
  addOrReplaceIssueComment,
@@ -15725,16 +16664,12 @@ export {
15725
16664
  addStageCompletion,
15726
16665
  addStageCompletions,
15727
16666
  addStages,
16667
+ addTeam,
15728
16668
  addToRecentIssues,
15729
- addUserForm,
15730
- addUserFormRevision,
15731
- addUserFormRevisionAttachment,
15732
- addUserFormRevisions,
15733
- addUserFormSubmissionAttachment,
15734
- addUserFormSubmissions,
15735
- addUserForms,
15736
16669
  addUsers,
15737
16670
  addWorkspace,
16671
+ agentReducer,
16672
+ agentSlice,
15738
16673
  areArraysEqual,
15739
16674
  authReducer,
15740
16675
  authSlice,
@@ -15753,6 +16688,7 @@ export {
15753
16688
  componentStageSlice,
15754
16689
  componentTypeReducer,
15755
16690
  componentTypeSlice,
16691
+ constructUploadedFilePayloads,
15756
16692
  coordinatesAreEqual,
15757
16693
  coordinatesToLiteral,
15758
16694
  coordinatesToPointGeometry,
@@ -15763,12 +16699,17 @@ export {
15763
16699
  defaultBadgeColor,
15764
16700
  defaultStore,
15765
16701
  deleteComponentType,
16702
+ deleteForm,
16703
+ deleteFormRevision,
16704
+ deleteFormRevisionAttachment,
16705
+ deleteFormRevisionAttachments,
16706
+ deleteFormRevisions,
16707
+ deleteFormSubmission,
16708
+ deleteFormSubmissionAttachment,
16709
+ deleteFormSubmissionAttachments,
16710
+ deleteFormSubmissions,
15766
16711
  deleteProject,
15767
- deleteUserForm,
15768
- deleteUserFormRevision,
15769
- deleteUserFormRevisions,
15770
- deleteUserFormSubmission,
15771
- deleteUserFormSubmissions,
16712
+ deleteTeam,
15772
16713
  dequeue,
15773
16714
  deserialize,
15774
16715
  deserializeField,
@@ -15786,6 +16727,7 @@ export {
15786
16727
  emptyMultiSelectField,
15787
16728
  emptyMultiStringField,
15788
16729
  emptyNumberField,
16730
+ emptyQrField,
15789
16731
  emptySelectField,
15790
16732
  emptyStringField,
15791
16733
  emptyTextField,
@@ -15797,7 +16739,13 @@ export {
15797
16739
  fileSlice,
15798
16740
  fileToBlob,
15799
16741
  flipCoordinates,
16742
+ formReducer,
16743
+ formRevisionReducer,
15800
16744
  formRevisionToSchema,
16745
+ formRevisionsSlice,
16746
+ formSlice,
16747
+ formSubmissionReducer,
16748
+ formSubmissionSlice,
15801
16749
  index as forms,
15802
16750
  fullComponentMarkerSize,
15803
16751
  generateBadgeColors,
@@ -15817,6 +16765,8 @@ export {
15817
16765
  issueReducer,
15818
16766
  issueSlice,
15819
16767
  issueToSearchResult,
16768
+ issueTypeReducer,
16769
+ issueTypeSlice,
15820
16770
  licenseReducer,
15821
16771
  licenseSlice,
15822
16772
  linkStageToForm,
@@ -15875,8 +16825,10 @@ export {
15875
16825
  removeIssueAttachment,
15876
16826
  removeIssueComment,
15877
16827
  removeIssueComments,
16828
+ removeIssueType,
15878
16829
  removeIssueUpdate,
15879
16830
  removeIssueUpdates,
16831
+ removeIssues,
15880
16832
  removeOrganizationAccess,
15881
16833
  removeProjectAccess,
15882
16834
  removeProjectAccessesOfProject,
@@ -15925,6 +16877,8 @@ export {
15925
16877
  selectAttachmentsOfComponentTypeByType,
15926
16878
  selectAttachmentsOfDocument,
15927
16879
  selectAttachmentsOfDocumentByType,
16880
+ selectAttachmentsOfFormRevision,
16881
+ selectAttachmentsOfFormSubmission,
15928
16882
  selectAttachmentsOfIssue,
15929
16883
  selectAttachmentsOfIssueByType,
15930
16884
  selectAttachmentsOfProject,
@@ -15942,11 +16896,9 @@ export {
15942
16896
  selectComponent,
15943
16897
  selectComponentAttachment,
15944
16898
  selectComponentAttachmentMapping,
15945
- selectComponentSubmissionMapping,
15946
16899
  selectComponentType,
15947
16900
  selectComponentTypeAttachment,
15948
16901
  selectComponentTypeAttachmentMapping,
15949
- selectComponentTypeForm,
15950
16902
  selectComponentTypeFromComponent,
15951
16903
  selectComponentTypeFromComponents,
15952
16904
  selectComponentTypeStagesMapping,
@@ -15958,6 +16910,7 @@ export {
15958
16910
  selectComponentsByType,
15959
16911
  selectComponentsFromComponentType,
15960
16912
  selectComponentsMapping,
16913
+ selectConversationId,
15961
16914
  selectCreateProjectType,
15962
16915
  selectCurrentUser,
15963
16916
  selectDeletedRequests,
@@ -15976,8 +16929,26 @@ export {
15976
16929
  selectExpandedSections,
15977
16930
  selectFavouriteProjects,
15978
16931
  selectFileAttachmentsOfIssue,
15979
- selectFilteredUserForms,
16932
+ selectFilteredForms,
16933
+ selectForm,
16934
+ selectFormMapping,
16935
+ selectFormOfComponentType,
16936
+ selectFormOfIssueType,
15980
16937
  selectFormRevision,
16938
+ selectFormRevisionMapping,
16939
+ selectFormRevisions,
16940
+ selectFormRevisionsOfForm,
16941
+ selectFormSubmission,
16942
+ selectFormSubmissionAttachmentsMapping,
16943
+ selectFormSubmissions,
16944
+ selectFormSubmissionsByComponents,
16945
+ selectFormSubmissionsByFormRevisions,
16946
+ selectFormSubmissionsMapping,
16947
+ selectFormSubmissionsOfComponent,
16948
+ selectFormSubmissionsOfForm,
16949
+ selectFormSubmissionsOfIssue,
16950
+ selectFormsCount,
16951
+ selectGeneralFormCount,
15981
16952
  selectHiddenCategoryCount,
15982
16953
  selectHiddenComponentTypeIds,
15983
16954
  selectIsFetchingInitialData,
@@ -15988,14 +16959,21 @@ export {
15988
16959
  selectIssueAttachment,
15989
16960
  selectIssueAttachmentMapping,
15990
16961
  selectIssueAttachments,
16962
+ selectIssueCountOfCategory,
15991
16963
  selectIssueMapping,
16964
+ selectIssueType,
16965
+ selectIssueTypeMapping,
16966
+ selectIssueTypes,
16967
+ selectIssueTypesOfOrganization,
15992
16968
  selectIssueUpdateMapping,
15993
16969
  selectIssueUpdatesOfIssue,
15994
16970
  selectIssues,
15995
- selectLatestFormRevision,
16971
+ selectIssuesOfIssueType,
16972
+ selectIssuesOfIssueTypeCount,
16973
+ selectLatestFormRevisionByForm,
16974
+ selectLatestFormRevisionOfForm,
16975
+ selectLatestFormRevisionsOfComponentTypes,
15996
16976
  selectLatestRetryTime,
15997
- selectLatestRevisionByFormId,
15998
- selectLatestRevisionsFromComponentTypeIds,
15999
16977
  selectLicense,
16000
16978
  selectLicenseForProject,
16001
16979
  selectLicenses,
@@ -16004,8 +16982,6 @@ export {
16004
16982
  selectMapStyle,
16005
16983
  selectNumberOfComponentTypesMatchingCaseInsensitiveName,
16006
16984
  selectNumberOfComponentsOfComponentType,
16007
- selectNumberOfGeneralUserForms,
16008
- selectNumberOfUserForms,
16009
16985
  selectOrganization,
16010
16986
  selectOrganizationAccess,
16011
16987
  selectOrganizationAccessForUser,
@@ -16033,11 +17009,10 @@ export {
16033
17009
  selectRecentIssuesAsSearchResults,
16034
17010
  selectRecentProjects,
16035
17011
  selectRehydrated,
16036
- selectRevisionAttachments,
16037
- selectRevisionsForForm,
16038
17012
  selectRootDocuments,
16039
17013
  selectShowTooltips,
16040
17014
  selectSortedEmailDomains,
17015
+ selectSortedFormSubmissionsOfForm,
16041
17016
  selectSortedOrganizationLicenses,
16042
17017
  selectSortedOrganizationUsers,
16043
17018
  selectSortedProjectUsers,
@@ -16049,16 +17024,15 @@ export {
16049
17024
  selectStagesFromComponentType,
16050
17025
  selectStagesFromComponentTypeIds,
16051
17026
  selectStagesFromStageIds,
16052
- selectSubmissionAttachments,
16053
- selectSubmissionsForComponent,
16054
- selectSubmissionsForForm,
16055
- selectSubmissionsForIssue,
17027
+ selectTeam,
17028
+ selectTeams,
17029
+ selectTeamsMapping,
17030
+ selectTeamsOfOrganization,
17031
+ selectTeamsOfUser,
16056
17032
  selectUploadUrl,
16057
17033
  selectUsedColors,
16058
17034
  selectUser,
16059
- selectUserForm,
16060
- selectUserFormMapping,
16061
- selectUserFormSubmission,
17035
+ selectUserFormRevisionAttachmentsMapping,
16062
17036
  selectUsersAsMapping,
16063
17037
  selectVisibleStatuses,
16064
17038
  selectVisibleUserIds,
@@ -16077,6 +17051,7 @@ export {
16077
17051
  setComponentTypeAttachments,
16078
17052
  setComponentTypes,
16079
17053
  setComponents,
17054
+ setConversationId,
16080
17055
  setCreateProjectType,
16081
17056
  setCurrentUser,
16082
17057
  setDocumentAttachments,
@@ -16085,12 +17060,21 @@ export {
16085
17060
  setEnableClustering,
16086
17061
  setEnableDuplicateIssues,
16087
17062
  setEnablePlacementMode,
17063
+ setFormRevision,
17064
+ setFormRevisionAttachments,
17065
+ setFormRevisions,
17066
+ setFormSubmission,
17067
+ setFormSubmissionAttachments,
17068
+ setFormSubmissions,
17069
+ setForms,
16088
17070
  setIsFetchingInitialData,
16089
17071
  setIsImportingProjectFile,
16090
17072
  setIsLoading,
16091
17073
  setIssueAttachments,
16092
17074
  setIssueComment,
16093
17075
  setIssueComments,
17076
+ setIssueType,
17077
+ setIssueTypes,
16094
17078
  setIssueUpdates,
16095
17079
  setIssues,
16096
17080
  setLicenses,
@@ -16106,12 +17090,11 @@ export {
16106
17090
  setSectionExpanded,
16107
17091
  setShowTooltips,
16108
17092
  setStageCompletions,
17093
+ setTeam,
17094
+ setTeams,
16109
17095
  setTokens,
16110
17096
  setTourStep,
16111
17097
  setUploadUrl,
16112
- setUserFormRevisionAttachments,
16113
- setUserFormSubmissionAttachments,
16114
- setUserFormSubmissions,
16115
17098
  setUsers,
16116
17099
  setVisibleStatuses,
16117
17100
  setVisibleUserIds,
@@ -16122,6 +17105,8 @@ export {
16122
17105
  slugify,
16123
17106
  spacesToDashesLower,
16124
17107
  successColor,
17108
+ teamReducer,
17109
+ teamSlice,
16125
17110
  toFileNameSafeString,
16126
17111
  toOfflineIdRecord,
16127
17112
  toggleComponentTypeVisibility,
@@ -16136,15 +17121,19 @@ export {
16136
17121
  updateComponentTypeAttachment,
16137
17122
  updateDocumentAttachment,
16138
17123
  updateDocuments,
17124
+ updateFormSubmission,
17125
+ updateFormSubmissionAttachments,
17126
+ updateFormSubmissions,
16139
17127
  updateIssue,
16140
17128
  updateIssueAttachment,
17129
+ updateIssueType,
16141
17130
  updateLicense,
16142
17131
  updateOrCreateProject,
16143
- updateOrCreateUserFormSubmission,
16144
17132
  updateOrganizationAccess,
16145
17133
  updateProjectAccess,
16146
17134
  updateProjectAttachment,
16147
17135
  updateStages,
17136
+ updateTeam,
16148
17137
  useAppDispatch,
16149
17138
  useAppSelector,
16150
17139
  useFieldInput,
@@ -16154,8 +17143,6 @@ export {
16154
17143
  useFormikInput,
16155
17144
  useMemoCompare,
16156
17145
  useSDK,
16157
- userFormReducer,
16158
- userFormSlice,
16159
17146
  userReducer,
16160
17147
  userSlice,
16161
17148
  valueIsFile,