@overmap-ai/core 1.0.35-projects-licensing.20 → 1.0.36-add-image-to-forms.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 (39) hide show
  1. package/dist/forms/builder/FieldActions.d.ts +4 -1
  2. package/dist/forms/constants.d.ts +9 -0
  3. package/dist/forms/fields/BaseField/BaseField.d.ts +1 -0
  4. package/dist/forms/fields/BaseField/layouts.d.ts +1 -0
  5. package/dist/forms/fields/SelectField/BaseSelectField.d.ts +1 -0
  6. package/dist/forms/fields/constants.d.ts +3 -0
  7. package/dist/forms/renderer/PatchForm/Provider.d.ts +4 -0
  8. package/dist/forms/typings.d.ts +1 -0
  9. package/dist/forms/utils.d.ts +2 -0
  10. package/dist/overmap-core.js +1058 -847
  11. package/dist/overmap-core.js.map +1 -1
  12. package/dist/overmap-core.umd.cjs +1051 -840
  13. package/dist/overmap-core.umd.cjs.map +1 -1
  14. package/dist/sdk/sdk.d.ts +1 -2
  15. package/dist/sdk/services/MainService.d.ts +1 -2
  16. package/dist/sdk/services/ProjectService.d.ts +3 -2
  17. package/dist/sdk/services/UserFormService.d.ts +4 -3
  18. package/dist/sdk/services/index.d.ts +0 -1
  19. package/dist/store/slices/categorySlice.d.ts +0 -1
  20. package/dist/store/slices/index.d.ts +0 -1
  21. package/dist/store/slices/issueSlice.d.ts +4 -2
  22. package/dist/store/slices/organizationSlice.d.ts +1 -5
  23. package/dist/store/slices/projectFileSlice.d.ts +0 -1
  24. package/dist/store/slices/projectSlice.d.ts +1 -7
  25. package/dist/store/slices/settingsSlice.d.ts +1 -7
  26. package/dist/store/slices/userFormSlice.d.ts +11 -2
  27. package/dist/store/slices/workspaceSlice.d.ts +0 -1
  28. package/dist/store/store.d.ts +1 -4
  29. package/dist/style.css +161 -48
  30. package/dist/typings/models/base.d.ts +0 -4
  31. package/dist/typings/models/forms.d.ts +5 -0
  32. package/dist/typings/models/index.d.ts +0 -1
  33. package/dist/typings/models/organizations.d.ts +0 -2
  34. package/dist/typings/models/projects.d.ts +0 -2
  35. package/package.json +1 -1
  36. package/dist/forms/builder/componentConstants.d.ts +0 -8
  37. package/dist/sdk/services/LicenseService.d.ts +0 -10
  38. package/dist/store/slices/licenseSlice.d.ts +0 -25
  39. package/dist/typings/models/license.d.ts +0 -19
@@ -6,9 +6,9 @@ var __publicField = (obj, key, value) => {
6
6
  };
7
7
  var _a;
8
8
  import * as React from "react";
9
- import React__default, { useState, useEffect, useRef, memo, useMemo, forwardRef, createElement, useCallback, createContext, useContext, Children, isValidElement, cloneElement, Fragment, useLayoutEffect, useReducer } from "react";
10
- import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
11
- import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex, Text, useSeverityColor, Checkbox, TextArea, Select, useToast, IconButton, Badge, MultiSelect, Button, ButtonList, divButtonProps, Tooltip, DropdownItemMenu, Popover, Input, useAlertDialog } from "@overmap-ai/blocks";
9
+ import React__default, { useState, useEffect, useRef, memo, useMemo, forwardRef, createElement, useCallback, createContext, useContext, Children, isValidElement, cloneElement, Fragment as Fragment$1, useLayoutEffect, useReducer } from "react";
10
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
11
+ import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex, IconButton, Text, useSeverityColor, Checkbox, TextArea, Select, useToast, Badge, MultiSelect, Button, ButtonList, divButtonProps, Tooltip, DropdownItemMenu, Popover, 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";
@@ -22,11 +22,11 @@ import ColorCls from "color";
22
22
  import jwtDecode from "jwt-decode";
23
23
  import { RESET_STATE } from "@redux-offline/redux-offline/lib/constants";
24
24
  import { openDB } from "idb";
25
+ import saveAs, { saveAs as saveAs$1 } from "file-saver";
25
26
  import { useField, useFormikContext, useFormik, FormikProvider } from "formik";
26
27
  import get from "lodash.get";
27
28
  import Linkify from "linkify-react";
28
29
  import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
29
- import { saveAs } from "file-saver";
30
30
  import set from "lodash.set";
31
31
  import cloneDeep from "lodash.clonedeep";
32
32
  import { flushSync } from "react-dom";
@@ -626,15 +626,15 @@ const wrapMigration = (migrator) => (state) => {
626
626
  };
627
627
  const migrations = [initialVersioning, signOut, signOut, createOutboxState];
628
628
  const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
629
- const initialState$m = {
629
+ const initialState$l = {
630
630
  accessToken: "",
631
631
  refreshToken: "",
632
632
  isLoggedIn: false
633
633
  };
634
634
  const authSlice = createSlice({
635
635
  name: "auth",
636
- initialState: initialState$m,
637
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
636
+ initialState: initialState$l,
637
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
638
638
  reducers: {
639
639
  setTokens: (state, action) => {
640
640
  state.accessToken = action.payload.accessToken;
@@ -1338,7 +1338,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
1338
1338
  return getLocalDateString(date);
1339
1339
  return relative.format(days, "days");
1340
1340
  });
1341
- const initialState$l = {
1341
+ const initialState$k = {
1342
1342
  categories: {},
1343
1343
  usedCategoryColors: [],
1344
1344
  categoryVisibility: {
@@ -1348,8 +1348,8 @@ const initialState$l = {
1348
1348
  };
1349
1349
  const categorySlice = createSlice({
1350
1350
  name: "categories",
1351
- initialState: initialState$l,
1352
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1351
+ initialState: initialState$k,
1352
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1353
1353
  reducers: {
1354
1354
  setCategories: (state, action) => {
1355
1355
  if (!Array.isArray(action.payload))
@@ -1482,13 +1482,13 @@ const selectHiddenCategoryCount = (state) => {
1482
1482
  return hiddenCategoryCount;
1483
1483
  };
1484
1484
  const categoryReducer = categorySlice.reducer;
1485
- const initialState$k = {
1485
+ const initialState$j = {
1486
1486
  components: {}
1487
1487
  };
1488
1488
  const componentSlice = createSlice({
1489
1489
  name: "components",
1490
- initialState: initialState$k,
1491
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1490
+ initialState: initialState$j,
1491
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1492
1492
  reducers: {
1493
1493
  addComponent: (state, action) => {
1494
1494
  state.components[action.payload.offline_id] = action.payload;
@@ -1600,13 +1600,13 @@ const {
1600
1600
  removeAllComponentsOfType
1601
1601
  } = componentSlice.actions;
1602
1602
  const componentReducer = componentSlice.reducer;
1603
- const initialState$j = {
1603
+ const initialState$i = {
1604
1604
  completionsByComponentId: {}
1605
1605
  };
1606
1606
  const componentStageCompletionSlice = createSlice({
1607
1607
  name: "componentStageCompletions",
1608
- initialState: initialState$j,
1609
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1608
+ initialState: initialState$i,
1609
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1610
1610
  reducers: {
1611
1611
  addStageCompletion: (state, action) => {
1612
1612
  let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
@@ -1657,13 +1657,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
1657
1657
  return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
1658
1658
  };
1659
1659
  const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
1660
- const initialState$i = {
1660
+ const initialState$h = {
1661
1661
  stages: {}
1662
1662
  };
1663
1663
  const componentStageSlice = createSlice({
1664
1664
  name: "componentStages",
1665
- initialState: initialState$i,
1666
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1665
+ initialState: initialState$h,
1666
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
1667
1667
  reducers: {
1668
1668
  addStages: (state, action) => {
1669
1669
  Object.assign(state.stages, toOfflineIdRecord(action.payload));
@@ -1723,14 +1723,14 @@ const selectStagesFromStageIds = restructureCreateSelectorWithArgs(
1723
1723
  );
1724
1724
  const { addStages, updateStages, removeStages } = componentStageSlice.actions;
1725
1725
  const componentStageReducer = componentStageSlice.reducer;
1726
- const initialState$h = {
1726
+ const initialState$g = {
1727
1727
  componentTypes: {},
1728
1728
  hiddenComponentTypeIds: {}
1729
1729
  };
1730
1730
  const componentTypeSlice = createSlice({
1731
1731
  name: "componentTypes",
1732
- initialState: initialState$h,
1733
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
1732
+ initialState: initialState$g,
1733
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
1734
1734
  reducers: {
1735
1735
  addComponentType: (state, action) => {
1736
1736
  state.componentTypes[action.payload.offline_id] = action.payload;
@@ -1789,13 +1789,13 @@ const selectComponentTypesByName = restructureCreateSelectorWithArgs(
1789
1789
  const selectHiddenComponentTypeIds = (state) => state.componentTypeReducer.hiddenComponentTypeIds;
1790
1790
  const { addComponentType, setComponentTypes, toggleComponentTypeVisibility, deleteComponentType } = componentTypeSlice.actions;
1791
1791
  const componentTypeReducer = componentTypeSlice.reducer;
1792
- const initialState$g = {
1792
+ const initialState$f = {
1793
1793
  workspaces: {},
1794
1794
  activeWorkspaceId: null
1795
1795
  };
1796
1796
  const workspaceSlice = createSlice({
1797
1797
  name: "workspace",
1798
- initialState: initialState$g,
1798
+ initialState: initialState$f,
1799
1799
  // The `reducers` field lets us define reducers and generate associated actions
1800
1800
  reducers: {
1801
1801
  setWorkspaces: (state, action) => {
@@ -1852,20 +1852,21 @@ const selectPermittedWorkspaceIds = createSelector(
1852
1852
  );
1853
1853
  const workspaceReducer = workspaceSlice.reducer;
1854
1854
  const maxRecentIssues = 10;
1855
- const initialState$f = {
1855
+ const initialState$e = {
1856
1856
  issues: {},
1857
1857
  attachments: {},
1858
1858
  comments: {},
1859
1859
  visibleStatuses: [IssueStatus.BACKLOG, IssueStatus.SELECTED],
1860
+ isFetchingInitialData: false,
1860
1861
  visibleUserIds: null,
1861
1862
  recentIssueIds: [],
1862
1863
  activeIssueId: null
1863
1864
  };
1864
1865
  const issueSlice = createSlice({
1865
1866
  name: "issues",
1866
- initialState: initialState$f,
1867
+ initialState: initialState$e,
1867
1868
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
1868
- Object.assign(state, initialState$f);
1869
+ Object.assign(state, initialState$e);
1869
1870
  }),
1870
1871
  reducers: {
1871
1872
  setIssues: (state, action) => {
@@ -1944,6 +1945,9 @@ const issueSlice = createSlice({
1944
1945
  setVisibleStatuses: (state, action) => {
1945
1946
  state.visibleStatuses = action.payload;
1946
1947
  },
1948
+ setIsFetchingInitialData: (state, action) => {
1949
+ state.isFetchingInitialData = action.payload;
1950
+ },
1947
1951
  setVisibleUserIds: (state, action) => {
1948
1952
  state.visibleUserIds = [...new Set(action.payload)];
1949
1953
  },
@@ -2002,6 +2006,7 @@ const {
2002
2006
  resetRecentIssues,
2003
2007
  setActiveIssueId,
2004
2008
  setAttachments,
2009
+ setIsFetchingInitialData,
2005
2010
  setIssueComments,
2006
2011
  setIssues,
2007
2012
  setVisibleStatuses,
@@ -2100,6 +2105,7 @@ const selectIssue = restructureCreateSelectorWithArgs(
2100
2105
  return mapping[id];
2101
2106
  })
2102
2107
  );
2108
+ const selectIsFetchingInitialData = (state) => state.issueReducer.isFetchingInitialData;
2103
2109
  const selectAllAttachments = createSelector([selectIssueAttachmentMapping], (mapping) => Object.values(mapping));
2104
2110
  const searchIssues = restructureCreateSelectorWithArgs(
2105
2111
  createSelector(
@@ -2191,15 +2197,15 @@ const selectRecentIssuesAsSearchResults = createSelector(
2191
2197
  }
2192
2198
  );
2193
2199
  const issueReducer = issueSlice.reducer;
2194
- const initialState$e = {
2200
+ const initialState$d = {
2195
2201
  s3Urls: {}
2196
2202
  };
2197
2203
  const msPerHour = 1e3 * 60 * 60;
2198
2204
  const msPerWeek = msPerHour * 24 * 7;
2199
2205
  const fileSlice = createSlice({
2200
2206
  name: "file",
2201
- initialState: initialState$e,
2202
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2207
+ initialState: initialState$d,
2208
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2203
2209
  reducers: {
2204
2210
  setUploadUrl: (state, action) => {
2205
2211
  const { url, fields, sha1 } = action.payload;
@@ -2226,7 +2232,7 @@ const selectUploadUrl = (sha1) => (state) => {
2226
2232
  return url;
2227
2233
  };
2228
2234
  const fileReducer = fileSlice.reducer;
2229
- const initialState$d = {
2235
+ const initialState$c = {
2230
2236
  // TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
2231
2237
  mapStyle: MapStyle.SATELLITE,
2232
2238
  showTooltips: false,
@@ -2234,8 +2240,8 @@ const initialState$d = {
2234
2240
  };
2235
2241
  const mapSlice = createSlice({
2236
2242
  name: "map",
2237
- initialState: initialState$d,
2238
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2243
+ initialState: initialState$c,
2244
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2239
2245
  reducers: {
2240
2246
  setMapStyle: (state, action) => {
2241
2247
  state.mapStyle = action.payload;
@@ -2277,18 +2283,7 @@ var VerificationCodeType = /* @__PURE__ */ ((VerificationCodeType2) => {
2277
2283
  VerificationCodeType2[VerificationCodeType2["RESET_PASSWORD"] = 10] = "RESET_PASSWORD";
2278
2284
  return VerificationCodeType2;
2279
2285
  })(VerificationCodeType || {});
2280
- var LicenseLevel = /* @__PURE__ */ ((LicenseLevel2) => {
2281
- LicenseLevel2[LicenseLevel2["PRO"] = 0] = "PRO";
2282
- return LicenseLevel2;
2283
- })(LicenseLevel || {});
2284
- var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
2285
- LicenseStatus2[LicenseStatus2["ACTIVE"] = 0] = "ACTIVE";
2286
- LicenseStatus2[LicenseStatus2["PAUSED"] = 2] = "PAUSED";
2287
- LicenseStatus2[LicenseStatus2["CANCELED"] = 4] = "CANCELED";
2288
- LicenseStatus2[LicenseStatus2["INACTIVE"] = 6] = "INACTIVE";
2289
- return LicenseStatus2;
2290
- })(LicenseStatus || {});
2291
- const initialState$c = {
2286
+ const initialState$b = {
2292
2287
  users: {},
2293
2288
  currentUser: {
2294
2289
  id: 0,
@@ -2299,8 +2294,8 @@ const initialState$c = {
2299
2294
  };
2300
2295
  const userSlice = createSlice({
2301
2296
  name: "users",
2302
- initialState: initialState$c,
2303
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2297
+ initialState: initialState$b,
2298
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2304
2299
  reducers: {
2305
2300
  setUsers: (state, action) => {
2306
2301
  const usersMapping = {};
@@ -2362,13 +2357,13 @@ const selectUser = (userId) => (state) => {
2362
2357
  const selectUsersAsMapping = (state) => state.userReducer.users;
2363
2358
  const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
2364
2359
  const userReducer = userSlice.reducer;
2365
- const initialState$b = {
2360
+ const initialState$a = {
2366
2361
  organizationAccesses: {}
2367
2362
  };
2368
2363
  const organizationAccessSlice = createSlice({
2369
2364
  name: "organizationAccess",
2370
- initialState: initialState$b,
2371
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2365
+ initialState: initialState$a,
2366
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2372
2367
  reducers: {
2373
2368
  setOrganizationAccesses: (state, action) => {
2374
2369
  if (!Array.isArray(action.payload))
@@ -2431,13 +2426,151 @@ const selectOrganizationAccessUserMapping = (state) => {
2431
2426
  return organizationAccesses;
2432
2427
  };
2433
2428
  const organizationAccessReducer = organizationAccessSlice.reducer;
2434
- const initialState$a = {
2429
+ const initialState$9 = {
2430
+ organizations: {},
2431
+ activeOrganizationId: null
2432
+ };
2433
+ const organizationSlice = createSlice({
2434
+ name: "organizations",
2435
+ initialState: initialState$9,
2436
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
2437
+ reducers: {
2438
+ setOrganizations: (state, action) => {
2439
+ for (const org of action.payload) {
2440
+ state.organizations[org.id] = org;
2441
+ }
2442
+ },
2443
+ updateActiveOrganization: (state, action) => {
2444
+ if (!state.activeOrganizationId) {
2445
+ throw new Error("Cannot update name of active organization. Active organization ID does not exist");
2446
+ }
2447
+ if (state.activeOrganizationId !== action.payload.id) {
2448
+ throw new Error("Tried updating active organization with different organization");
2449
+ }
2450
+ state.organizations[state.activeOrganizationId] = action.payload;
2451
+ },
2452
+ setActiveOrganizationId: (state, action) => {
2453
+ state.activeOrganizationId = action.payload;
2454
+ }
2455
+ }
2456
+ });
2457
+ const { setOrganizations, setActiveOrganizationId, updateActiveOrganization } = organizationSlice.actions;
2458
+ const selectActiveOrganizationId = (state) => {
2459
+ return state.organizationReducer.activeOrganizationId;
2460
+ };
2461
+ const selectOrganizations = (state) => {
2462
+ return Object.values(state.organizationReducer.organizations);
2463
+ };
2464
+ const selectOrganizationsWithAccess = createSelector(
2465
+ [selectOrganizations],
2466
+ (organizations) => Object.values(organizations).filter((organization) => organization.has_access)
2467
+ );
2468
+ const selectActiveOrganization = (state) => {
2469
+ const id = selectActiveOrganizationId(state);
2470
+ if (!id) {
2471
+ return null;
2472
+ }
2473
+ const organization = state.organizationReducer.organizations[id];
2474
+ if (!organization) {
2475
+ return null;
2476
+ }
2477
+ return organization;
2478
+ };
2479
+ const selectOrganizationUsersIds = createSelector(
2480
+ [selectOrganizationAccesses],
2481
+ (organizationAccesses) => Object.values(organizationAccesses).map((organizationAccess) => organizationAccess.user)
2482
+ );
2483
+ const selectOrganizationUsersAsMapping = createSelector(
2484
+ [selectOrganizationUsersIds, selectUsersAsMapping],
2485
+ (organizationUserIds, users) => organizationUserIds.reduce((accum, userId) => ({ ...accum, [userId]: users[userId] }), {})
2486
+ );
2487
+ const selectSortedOrganizationUsers = createSelector(
2488
+ [selectCurrentUser, selectOrganizationUsersAsMapping, selectOrganizationAccessUserMapping],
2489
+ (currentUser, userMapping, organizationAccessMapping) => {
2490
+ return Object.values(userMapping).sort((userA, userB) => {
2491
+ if (userA.id === currentUser.id) {
2492
+ return -1;
2493
+ } else if (userB.id === currentUser.id) {
2494
+ return 1;
2495
+ }
2496
+ const organizationAccessesA = organizationAccessMapping[userA.id];
2497
+ const organizationAccessesB = organizationAccessMapping[userB.id];
2498
+ if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === (organizationAccessesB == null ? void 0 : organizationAccessesB.access_level)) {
2499
+ return userA.username.localeCompare(userB.username);
2500
+ }
2501
+ if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === OrganizationAccessLevel.ADMIN) {
2502
+ return -1;
2503
+ }
2504
+ return 1;
2505
+ });
2506
+ }
2507
+ );
2508
+ const selectOrganization = (id) => (state) => {
2509
+ return state.organizationReducer.organizations[id];
2510
+ };
2511
+ const organizationReducer = organizationSlice.reducer;
2512
+ const createOfflineAction = (request2, baseUrl) => {
2513
+ const requestWithUuid = request2.uuid ? request2 : { ...request2, uuid: v4() };
2514
+ return {
2515
+ payload: requestWithUuid,
2516
+ type: "",
2517
+ meta: {
2518
+ offline: {
2519
+ effect: {
2520
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2521
+ request: requestWithUuid,
2522
+ BASE_URL: baseUrl
2523
+ }
2524
+ }
2525
+ }
2526
+ };
2527
+ };
2528
+ const initialState$8 = {
2529
+ deletedRequests: [],
2530
+ latestRetryTime: 0
2531
+ };
2532
+ const outboxSlice = createSlice({
2533
+ name: "outbox",
2534
+ initialState: initialState$8,
2535
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
2536
+ reducers: {
2537
+ // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
2538
+ // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
2539
+ // Then this reducer enqueueRequest() is responsible for adding the actual request data to the outbox
2540
+ enqueueRequest: {
2541
+ reducer: (state, _action) => {
2542
+ return state;
2543
+ },
2544
+ prepare: (payload) => {
2545
+ console.debug("Preparing to enqueue request", payload);
2546
+ const { BASE_URL, ...rest } = payload;
2547
+ return createOfflineAction(rest, BASE_URL);
2548
+ }
2549
+ },
2550
+ markForDeletion(state, action) {
2551
+ state.deletedRequests.push(action.payload);
2552
+ },
2553
+ markAsDeleted(state, action) {
2554
+ const index2 = state.deletedRequests.indexOf(action.payload);
2555
+ if (index2 !== -1)
2556
+ state.deletedRequests.splice(index2, 1);
2557
+ },
2558
+ _setLatestRetryTime: (state, action) => {
2559
+ state.latestRetryTime = action.payload;
2560
+ }
2561
+ }
2562
+ });
2563
+ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
2564
+ const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
2565
+ const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
2566
+ const outboxReducer = outboxSlice.reducer;
2567
+ const initialState$7 = {
2435
2568
  projectAccesses: {}
2436
2569
  };
2437
2570
  const projectAccessSlice = createSlice({
2438
2571
  name: "projectAccess",
2439
- initialState: initialState$a,
2440
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2572
+ initialState: initialState$7,
2573
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
2441
2574
  reducers: {
2442
2575
  setProjectAccesses: (state, action) => {
2443
2576
  if (!Array.isArray(action.payload))
@@ -2505,7 +2638,7 @@ const selectProjectAccessUserMapping = (state) => {
2505
2638
  return projectAccesses;
2506
2639
  };
2507
2640
  const projectAccessReducer = projectAccessSlice.reducer;
2508
- const initialState$9 = {
2641
+ const initialState$6 = {
2509
2642
  projects: {},
2510
2643
  activeProjectId: null,
2511
2644
  recentProjectIds: [],
@@ -2514,7 +2647,7 @@ const initialState$9 = {
2514
2647
  };
2515
2648
  const projectSlice = createSlice({
2516
2649
  name: "projects",
2517
- initialState: initialState$9,
2650
+ initialState: initialState$6,
2518
2651
  reducers: {
2519
2652
  setProjects: (state, action) => {
2520
2653
  const projectsMap = {};
@@ -2560,20 +2693,6 @@ const projectSlice = createSlice({
2560
2693
  } else {
2561
2694
  throw new Error("Accept project invite: user is not in this project");
2562
2695
  }
2563
- },
2564
- updateActiveProjectIssuesCount: (state, action) => {
2565
- if (state.activeProjectId) {
2566
- state.projects[state.activeProjectId].issues_count += action.payload;
2567
- } else {
2568
- throw new Error("Update issues count: no active project");
2569
- }
2570
- },
2571
- updateActiveProjectFormSubmissionsCount: (state, action) => {
2572
- if (state.activeProjectId) {
2573
- state.projects[state.activeProjectId].form_submissions_count += action.payload;
2574
- } else {
2575
- throw new Error("Update form submissions count: no active project");
2576
- }
2577
2696
  }
2578
2697
  }
2579
2698
  });
@@ -2584,9 +2703,7 @@ const {
2584
2703
  setActiveProjectId,
2585
2704
  setCreateProjectType,
2586
2705
  deleteProject,
2587
- acceptProjectInvite,
2588
- updateActiveProjectIssuesCount,
2589
- updateActiveProjectFormSubmissionsCount
2706
+ acceptProjectInvite
2590
2707
  } = projectSlice.actions;
2591
2708
  const selectProjects = (state) => state.projectReducer.projects;
2592
2709
  const selectActiveProjectId = (state) => state.projectReducer.activeProjectId;
@@ -2650,264 +2767,39 @@ const selectSortedProjectUsers = createSelector(
2650
2767
  });
2651
2768
  }
2652
2769
  );
2653
- const initialState$8 = {
2654
- licenses: {}
2770
+ const initialState$5 = {
2771
+ projectFiles: {},
2772
+ activeProjectFileId: null,
2773
+ isImportingProjectFile: false,
2774
+ enabledProjectFiles: {}
2655
2775
  };
2656
- const licenseSlice = createSlice({
2657
- name: "license",
2658
- initialState: initialState$8,
2659
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
2776
+ const projectFileSlice = createSlice({
2777
+ name: "projectFiles",
2778
+ initialState: initialState$5,
2779
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
2660
2780
  reducers: {
2661
- setLicenses: (state, action) => {
2662
- if (!Array.isArray(action.payload))
2663
- throw new Error("Expected an array of Licenses");
2664
- if (action.payload.filter(onlyUniqueOfflineIds).length !== action.payload.length) {
2665
- throw new Error("Tried to use setLicenses reducer with duplicate ID's");
2666
- }
2667
- const licenses = {};
2668
- for (const license of action.payload) {
2669
- licenses[license.offline_id] = license;
2781
+ addOrReplaceProjectFiles: (state, action) => {
2782
+ for (let fileObj of action.payload) {
2783
+ let file = fileObj.file;
2784
+ if (file.includes("+")) {
2785
+ console.warn("Attempting to apply fix for image URL with '+' character:", file);
2786
+ const parts = file.split("/");
2787
+ if (parts.length < 2) {
2788
+ throw new Error("Invalid URL: " + file);
2789
+ }
2790
+ const lastPart = encodeURIComponent(parts[parts.length - 1]);
2791
+ file = parts.slice(0, -1).join("/") + "/" + lastPart;
2792
+ console.warn("Fixed URL:", file);
2793
+ fileObj = { ...fileObj, file };
2794
+ }
2795
+ state.projectFiles[fileObj.offline_id] = fileObj;
2670
2796
  }
2671
- state.licenses = licenses;
2672
2797
  },
2673
- addLicenses: (state, action) => {
2674
- for (const license of action.payload) {
2675
- state.licenses[license.offline_id] = license;
2798
+ addOrReplaceProjectFile: (state, action) => {
2799
+ if (!action.payload.project) {
2800
+ throw new Error("ProjectFile has no project. A project must be set before storing.");
2676
2801
  }
2677
- },
2678
- updateLicense: (state, action) => {
2679
- if (!(action.payload.offline_id in state.licenses)) {
2680
- throw new Error("Tried to update license that does not exist.");
2681
- }
2682
- state.licenses[action.payload.offline_id] = action.payload;
2683
- }
2684
- }
2685
- });
2686
- const { setLicenses, addLicenses, updateLicense } = licenseSlice.actions;
2687
- const selectLicenses = (state) => {
2688
- return state.licenseReducer.licenses;
2689
- };
2690
- const selectLicense = (licenseId) => (state) => state.licenseReducer.licenses[licenseId];
2691
- const selectActiveLicense = createSelector(
2692
- [selectLicenses, selectActiveProjectId],
2693
- (licenses, activeProjectId) => {
2694
- const activeLicense = Object.values(licenses).find((license) => license.project === activeProjectId);
2695
- return activeLicense ?? null;
2696
- }
2697
- );
2698
- const selectLicenseForProject = restructureCreateSelectorWithArgs(
2699
- createSelector(
2700
- [selectLicenses, (_state, projectId) => projectId],
2701
- (licenses, projectId) => Object.values(licenses).find((license) => license.project === projectId) ?? null
2702
- )
2703
- );
2704
- const selectActiveStatusLicenses = createSelector(
2705
- [selectLicenses],
2706
- (licenses) => Object.values(licenses).filter((license) => license.is_active)
2707
- );
2708
- const selectLicencesMapping = createSelector(
2709
- [selectLicenses],
2710
- (licenses) => Object.values(licenses).filter((license) => license.project).reduce((accum, license) => ({ ...accum, [license.project]: license }), {})
2711
- );
2712
- const licenseReducer = licenseSlice.reducer;
2713
- const initialState$7 = {
2714
- organizations: {},
2715
- activeOrganizationId: null
2716
- };
2717
- const organizationSlice = createSlice({
2718
- name: "organizations",
2719
- initialState: initialState$7,
2720
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
2721
- reducers: {
2722
- setOrganizations: (state, action) => {
2723
- for (const org of action.payload) {
2724
- state.organizations[org.id] = org;
2725
- }
2726
- },
2727
- updateActiveOrganization: (state, action) => {
2728
- if (!state.activeOrganizationId) {
2729
- throw new Error("Cannot update name of active organization. Active organization ID does not exist");
2730
- }
2731
- if (state.activeOrganizationId !== action.payload.id) {
2732
- throw new Error("Tried updating active organization with different organization");
2733
- }
2734
- state.organizations[state.activeOrganizationId] = action.payload;
2735
- },
2736
- setActiveOrganizationId: (state, action) => {
2737
- state.activeOrganizationId = action.payload;
2738
- }
2739
- }
2740
- });
2741
- const { setOrganizations, setActiveOrganizationId, updateActiveOrganization } = organizationSlice.actions;
2742
- const selectActiveOrganizationId = (state) => {
2743
- return state.organizationReducer.activeOrganizationId;
2744
- };
2745
- const selectOrganizations = (state) => {
2746
- return Object.values(state.organizationReducer.organizations);
2747
- };
2748
- const selectOrganizationsMapping = (state) => {
2749
- return state.organizationReducer.organizations;
2750
- };
2751
- const selectOrganizationsWithAccess = createSelector(
2752
- [selectOrganizations],
2753
- (organizations) => Object.values(organizations).filter((organization) => organization.has_access)
2754
- );
2755
- const selectActiveOrganization = (state) => {
2756
- const id = selectActiveOrganizationId(state);
2757
- if (!id) {
2758
- return null;
2759
- }
2760
- const organization = state.organizationReducer.organizations[id];
2761
- if (!organization) {
2762
- return null;
2763
- }
2764
- return organization;
2765
- };
2766
- const selectOrganizationUsersIds = createSelector(
2767
- [selectOrganizationAccesses],
2768
- (organizationAccesses) => Object.values(organizationAccesses).map((organizationAccess) => organizationAccess.user)
2769
- );
2770
- const selectActiveOrganizationProjects = createSelector(
2771
- [selectProjects, selectActiveOrganizationId],
2772
- (projects, activeOrganizationId) => activeOrganizationId ? Object.values(projects).filter((project) => project.owner_organization === activeOrganizationId) : []
2773
- );
2774
- const selectActiveOrganizationLicenses = createSelector(
2775
- [selectActiveOrganizationId, selectLicenses],
2776
- (activeOrganizationId, licenses) => !activeOrganizationId ? [] : Object.values(licenses).filter((license) => license.organization_owner === activeOrganizationId)
2777
- );
2778
- const selectSortedOrganizationLicenses = createSelector(
2779
- [selectActiveOrganizationLicenses, selectProjects],
2780
- (licences, projects) => licences.sort((licenseA, licenseB) => {
2781
- if (!licenseA.project) {
2782
- return 1;
2783
- }
2784
- if (!licenseB.project) {
2785
- return -1;
2786
- }
2787
- return projects[licenseA.project].name.toLowerCase().localeCompare(
2788
- projects[licenseB.project].name.toLowerCase(),
2789
- void 0,
2790
- { numeric: true }
2791
- );
2792
- })
2793
- );
2794
- const selectOrganizationUsersAsMapping = createSelector(
2795
- [selectOrganizationUsersIds, selectUsersAsMapping],
2796
- (organizationUserIds, users) => organizationUserIds.reduce((accum, userId) => ({ ...accum, [userId]: users[userId] }), {})
2797
- );
2798
- const selectSortedOrganizationUsers = createSelector(
2799
- [selectCurrentUser, selectOrganizationUsersAsMapping, selectOrganizationAccessUserMapping],
2800
- (currentUser, userMapping, organizationAccessMapping) => {
2801
- return Object.values(userMapping).sort((userA, userB) => {
2802
- if (userA.id === currentUser.id) {
2803
- return -1;
2804
- } else if (userB.id === currentUser.id) {
2805
- return 1;
2806
- }
2807
- const organizationAccessesA = organizationAccessMapping[userA.id];
2808
- const organizationAccessesB = organizationAccessMapping[userB.id];
2809
- if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === (organizationAccessesB == null ? void 0 : organizationAccessesB.access_level)) {
2810
- return userA.username.localeCompare(userB.username);
2811
- }
2812
- if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === OrganizationAccessLevel.ADMIN) {
2813
- return -1;
2814
- }
2815
- return 1;
2816
- });
2817
- }
2818
- );
2819
- const selectOrganization = (id) => (state) => {
2820
- return state.organizationReducer.organizations[id];
2821
- };
2822
- const organizationReducer = organizationSlice.reducer;
2823
- const createOfflineAction = (request2, baseUrl) => {
2824
- const requestWithUuid = request2.uuid ? request2 : { ...request2, uuid: v4() };
2825
- return {
2826
- payload: requestWithUuid,
2827
- type: "",
2828
- meta: {
2829
- offline: {
2830
- effect: {
2831
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2832
- request: requestWithUuid,
2833
- BASE_URL: baseUrl
2834
- }
2835
- }
2836
- }
2837
- };
2838
- };
2839
- const initialState$6 = {
2840
- deletedRequests: [],
2841
- latestRetryTime: 0
2842
- };
2843
- const outboxSlice = createSlice({
2844
- name: "outbox",
2845
- initialState: initialState$6,
2846
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
2847
- reducers: {
2848
- // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
2849
- // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
2850
- // Then this reducer enqueueRequest() is responsible for adding the actual request data to the outbox
2851
- enqueueRequest: {
2852
- reducer: (state, _action) => {
2853
- return state;
2854
- },
2855
- prepare: (payload) => {
2856
- console.debug("Preparing to enqueue request", payload);
2857
- const { BASE_URL, ...rest } = payload;
2858
- return createOfflineAction(rest, BASE_URL);
2859
- }
2860
- },
2861
- markForDeletion(state, action) {
2862
- state.deletedRequests.push(action.payload);
2863
- },
2864
- markAsDeleted(state, action) {
2865
- const index2 = state.deletedRequests.indexOf(action.payload);
2866
- if (index2 !== -1)
2867
- state.deletedRequests.splice(index2, 1);
2868
- },
2869
- _setLatestRetryTime: (state, action) => {
2870
- state.latestRetryTime = action.payload;
2871
- }
2872
- }
2873
- });
2874
- const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
2875
- const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
2876
- const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
2877
- const outboxReducer = outboxSlice.reducer;
2878
- const initialState$5 = {
2879
- projectFiles: {},
2880
- activeProjectFileId: null,
2881
- isImportingProjectFile: false,
2882
- enabledProjectFiles: {}
2883
- };
2884
- const projectFileSlice = createSlice({
2885
- name: "projectFiles",
2886
- initialState: initialState$5,
2887
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
2888
- reducers: {
2889
- addOrReplaceProjectFiles: (state, action) => {
2890
- for (let fileObj of action.payload) {
2891
- let file = fileObj.file;
2892
- if (file.includes("+")) {
2893
- console.warn("Attempting to apply fix for image URL with '+' character:", file);
2894
- const parts = file.split("/");
2895
- if (parts.length < 2) {
2896
- throw new Error("Invalid URL: " + file);
2897
- }
2898
- const lastPart = encodeURIComponent(parts[parts.length - 1]);
2899
- file = parts.slice(0, -1).join("/") + "/" + lastPart;
2900
- console.warn("Fixed URL:", file);
2901
- fileObj = { ...fileObj, file };
2902
- }
2903
- state.projectFiles[fileObj.offline_id] = fileObj;
2904
- }
2905
- },
2906
- addOrReplaceProjectFile: (state, action) => {
2907
- if (!action.payload.project) {
2908
- throw new Error("ProjectFile has no project. A project must be set before storing.");
2909
- }
2910
- state.projectFiles[action.payload.offline_id] = action.payload;
2802
+ state.projectFiles[action.payload.offline_id] = action.payload;
2911
2803
  },
2912
2804
  setProjectFileVisible: (state, action) => {
2913
2805
  state.enabledProjectFiles[action.payload.fileId] = action.payload.visible;
@@ -3011,9 +2903,7 @@ const initialState$3 = {
3011
2903
  Components: false,
3012
2904
  Experimental: false
3013
2905
  },
3014
- appearance: "dark",
3015
- isFetchingInitialData: false,
3016
- isLoading: false
2906
+ appearance: "dark"
3017
2907
  };
3018
2908
  const settingSlice = createSlice({
3019
2909
  name: "settings",
@@ -3037,12 +2927,6 @@ const settingSlice = createSlice({
3037
2927
  },
3038
2928
  setAppearance: (state, action) => {
3039
2929
  state.appearance = action.payload;
3040
- },
3041
- setIsFetchingInitialData: (state, action) => {
3042
- state.isFetchingInitialData = action.payload;
3043
- },
3044
- setIsLoading: (state, action) => {
3045
- state.isLoading = action.payload;
3046
2930
  }
3047
2931
  }
3048
2932
  });
@@ -3051,9 +2935,7 @@ const {
3051
2935
  setEnablePlacementMode,
3052
2936
  setSectionExpanded,
3053
2937
  setEnableClustering,
3054
- setAppearance,
3055
- setIsFetchingInitialData,
3056
- setIsLoading
2938
+ setAppearance
3057
2939
  } = settingSlice.actions;
3058
2940
  const selectEnablePlacementMode = (state) => state.settingReducer.placementMode;
3059
2941
  const selectEnableDuplicateIssues = (state) => state.settingReducer.useIssueTemplate;
@@ -3062,8 +2944,6 @@ const selectExpandedSections = (state) => state.settingReducer.expandedSections;
3062
2944
  const selectEnableClustering = (state) => state.settingReducer.enableClustering;
3063
2945
  const selectAppearance = (state) => state.settingReducer.appearance;
3064
2946
  const settingReducer = settingSlice.reducer;
3065
- const selectIsFetchingInitialData = (state) => state.settingReducer.isFetchingInitialData;
3066
- const selectIsLoading = (state) => state.settingReducer.isLoading;
3067
2947
  const LATEST_REVISION_CACHE = {};
3068
2948
  function considerCachingRevision(revision, formId2, preferPending = false) {
3069
2949
  var _a2;
@@ -3095,7 +2975,8 @@ const initialState$2 = {
3095
2975
  userForms: {},
3096
2976
  revisions: {},
3097
2977
  submissions: {},
3098
- submissionAttachments: {}
2978
+ submissionAttachments: {},
2979
+ revisionAttachments: {}
3099
2980
  };
3100
2981
  const userFormSlice = createSlice({
3101
2982
  name: "userForms",
@@ -3148,6 +3029,15 @@ const userFormSlice = createSlice({
3148
3029
  state.submissionAttachments[submissionId] = [action.payload];
3149
3030
  }
3150
3031
  },
3032
+ addUserFormRevisionAttachment: (state, action) => {
3033
+ const revisionId = action.payload.revision;
3034
+ const revisionAttachments = state.revisionAttachments[revisionId];
3035
+ if (revisionAttachments) {
3036
+ revisionAttachments.push(action.payload);
3037
+ } else {
3038
+ state.revisionAttachments[revisionId] = [action.payload];
3039
+ }
3040
+ },
3151
3041
  setUserFormSubmissionAttachments: (state, action) => {
3152
3042
  state.submissionAttachments = {};
3153
3043
  for (const attachment of action.payload) {
@@ -3160,6 +3050,18 @@ const userFormSlice = createSlice({
3160
3050
  }
3161
3051
  }
3162
3052
  },
3053
+ setUserFormRevisionAttachments: (state, action) => {
3054
+ state.revisionAttachments = {};
3055
+ for (const attachment of action.payload) {
3056
+ const revisionId = attachment.revision;
3057
+ const revisionAttachments = state.revisionAttachments[revisionId];
3058
+ if (revisionAttachments) {
3059
+ revisionAttachments.push(attachment);
3060
+ } else {
3061
+ state.revisionAttachments[revisionId] = [attachment];
3062
+ }
3063
+ }
3064
+ },
3163
3065
  deleteUserFormSubmission: (state, action) => {
3164
3066
  delete state.submissions[action.payload];
3165
3067
  },
@@ -3216,11 +3118,16 @@ const {
3216
3118
  setUserFormSubmissions,
3217
3119
  addUserFormRevision,
3218
3120
  addUserFormSubmissionAttachment,
3219
- setUserFormSubmissionAttachments
3121
+ addUserFormRevisionAttachment,
3122
+ setUserFormSubmissionAttachments,
3123
+ setUserFormRevisionAttachments
3220
3124
  } = userFormSlice.actions;
3221
3125
  const selectSubmissionAttachments = (submissionId) => (state) => {
3222
3126
  return state.userFormReducer.submissionAttachments[submissionId] || [];
3223
3127
  };
3128
+ const selectRevisionAttachments = (revisionId) => (state) => {
3129
+ return state.userFormReducer.revisionAttachments[revisionId] || [];
3130
+ };
3224
3131
  const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3225
3132
  createSelector(
3226
3133
  [
@@ -3291,6 +3198,7 @@ const selectUserForm = (formId2) => (state) => {
3291
3198
  const selectSubmissionMapping = (state) => state.userFormReducer.submissions;
3292
3199
  const selectSubmissions = createSelector([selectSubmissionMapping], (submissions) => Object.values(submissions));
3293
3200
  const selectRevisionMapping = (state) => state.userFormReducer.revisions;
3201
+ const selectRevisionAttachmentsMapping = (state) => state.userFormReducer.revisionAttachments;
3294
3202
  const selectRevisions = createSelector([selectRevisionMapping], (revisions) => Object.values(revisions));
3295
3203
  const selectRevisionsForForm = restructureCreateSelectorWithArgs(
3296
3204
  createSelector([selectRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
@@ -3344,6 +3252,19 @@ const selectLatestRevisionByFormId = createSelector([selectRevisionMapping], (re
3344
3252
  }
3345
3253
  return latestRevisions;
3346
3254
  });
3255
+ const selectAllRevisionAttachmentsByLatestRevisionId = createSelector(
3256
+ [selectUserFormMapping, selectRevisionMapping, selectRevisionAttachmentsMapping],
3257
+ (forms, revisions, attachments) => {
3258
+ const mappedAttachments = {};
3259
+ for (const form of Object.values(forms)) {
3260
+ const latestRevision = _selectLatestFormRevision(revisions, form.offline_id);
3261
+ if (attachments[latestRevision.offline_id] !== void 0) {
3262
+ mappedAttachments[latestRevision.offline_id] = attachments[latestRevision.offline_id];
3263
+ }
3264
+ }
3265
+ return mappedAttachments;
3266
+ }
3267
+ );
3347
3268
  const selectNumberOfUserForms = createSelector([selectUserFormMapping], (userForms) => {
3348
3269
  return Object.keys(userForms).length;
3349
3270
  });
@@ -3424,8 +3345,7 @@ const overmapReducers = {
3424
3345
  userFormReducer,
3425
3346
  userReducer,
3426
3347
  workspaceReducer,
3427
- emailDomainsReducer,
3428
- licenseReducer
3348
+ emailDomainsReducer
3429
3349
  };
3430
3350
  const overmapReducer = combineReducers(overmapReducers);
3431
3351
  const resetStore = "RESET";
@@ -3586,6 +3506,19 @@ function extractErrorMessage(errorRes, err) {
3586
3506
  return errorRes.body.error;
3587
3507
  if (typeof errorRes.body.message === "string")
3588
3508
  return errorRes.body.message;
3509
+ try {
3510
+ return Object.entries(errorRes.body).map(([key, value]) => {
3511
+ if (typeof value === "string") {
3512
+ return `${key}: ${value}`;
3513
+ }
3514
+ if (Array.isArray(value)) {
3515
+ return value.map((v) => `${key}: ${v}`).join("\n");
3516
+ }
3517
+ return `${key}: ${JSON.stringify(value)}`;
3518
+ }).join("\n");
3519
+ } catch (e) {
3520
+ console.error("Failed to extract error message from response body", e);
3521
+ }
3589
3522
  } else if (typeof errorRes.body === "string")
3590
3523
  return errorRes.body;
3591
3524
  } else if (errorRes == null ? void 0 : errorRes.text) {
@@ -4126,7 +4059,7 @@ class AuthService extends BaseApiService {
4126
4059
  * @returns {Promise<TokenPair>} The new access and refresh tokens
4127
4060
  */
4128
4061
  __publicField(this, "_getRenewedTokens", async (refreshToken) => {
4129
- const response = await this.enqueueRequest({
4062
+ const promise = this.enqueueRequest({
4130
4063
  description: "Get renewed tokens",
4131
4064
  method: HttpMethod.POST,
4132
4065
  url: "/api/token/refresh/",
@@ -4139,6 +4072,14 @@ class AuthService extends BaseApiService {
4139
4072
  // Don't wait for other requests to finish, or we might end up in a deadlock.
4140
4073
  immediate: true
4141
4074
  });
4075
+ let response = void 0;
4076
+ try {
4077
+ response = await promise;
4078
+ } catch (e) {
4079
+ await this.logout();
4080
+ }
4081
+ if (!response)
4082
+ throw new Error("No response");
4142
4083
  if (!response.access)
4143
4084
  throw new Error("Missing access token");
4144
4085
  if (!response.refresh)
@@ -4858,7 +4799,6 @@ class IssueService extends BaseApiService {
4858
4799
  });
4859
4800
  store.dispatch(addIssue(issuePayload));
4860
4801
  store.dispatch(addToRecentIssues(issuePayload.offline_id));
4861
- store.dispatch(updateActiveProjectIssuesCount(1));
4862
4802
  const promise = this.enqueueRequest({
4863
4803
  description: "Create issue",
4864
4804
  method: HttpMethod.POST,
@@ -4885,7 +4825,6 @@ class IssueService extends BaseApiService {
4885
4825
  });
4886
4826
  }
4887
4827
  store.dispatch(removeIssue(issuePayload.offline_id));
4888
- store.dispatch(updateActiveProjectIssuesCount(-1));
4889
4828
  throw error2;
4890
4829
  });
4891
4830
  return [issuePayload, promise];
@@ -4924,8 +4863,7 @@ class IssueService extends BaseApiService {
4924
4863
  return [fullIssue, promise];
4925
4864
  }
4926
4865
  async remove(id) {
4927
- const { store } = this.client;
4928
- const state = store.getState();
4866
+ const state = this.client.store.getState();
4929
4867
  const backup = state.issueReducer.issues[id];
4930
4868
  if (!backup) {
4931
4869
  throw new Error(`No issue with id ${id} found in the store`);
@@ -4933,7 +4871,6 @@ class IssueService extends BaseApiService {
4933
4871
  const attachments = Object.values(state.issueReducer.attachments).filter((a) => a.issue_id === id);
4934
4872
  const attachmentsOfIssue = selectPhotoAttachmentsOfIssue(id)(state);
4935
4873
  this.client.store.dispatch(removeIssue(id));
4936
- store.dispatch(updateActiveProjectIssuesCount(-1));
4937
4874
  if (attachmentsOfIssue) {
4938
4875
  this.client.store.dispatch(removeAttachmentsOfIssue(id));
4939
4876
  }
@@ -4948,7 +4885,6 @@ class IssueService extends BaseApiService {
4948
4885
  } catch (e) {
4949
4886
  this.client.store.dispatch(addIssue(backup));
4950
4887
  this.client.store.dispatch(addAttachments(attachments));
4951
- store.dispatch(updateActiveProjectIssuesCount(1));
4952
4888
  throw e;
4953
4889
  }
4954
4890
  }
@@ -5024,9 +4960,7 @@ class MainService extends BaseApiService {
5024
4960
  owner_organization: projectData.organization_owner,
5025
4961
  owner_user: projectData.user_owner,
5026
4962
  bounds: projectData.bounds,
5027
- invited: projectData.invited || false,
5028
- issues_count: projectData.issues_count,
5029
- form_submissions_count: projectData.form_submissions_count
4963
+ invited: projectData.invited || false
5030
4964
  });
5031
4965
  if (currentProjectId === projectData.id && !projectData.invited) {
5032
4966
  isProjectIdValid = true;
@@ -5044,7 +4978,6 @@ class MainService extends BaseApiService {
5044
4978
  }
5045
4979
  store.dispatch(setCurrentUser(data.user));
5046
4980
  store.dispatch(addUsers(data.project_owners));
5047
- store.dispatch(setLicenses(data.licenses));
5048
4981
  const organizationsData = data.organizations;
5049
4982
  store.dispatch(setOrganizations(organizationsData));
5050
4983
  const validProjects = projects.filter((project) => !project.invited);
@@ -5357,7 +5290,6 @@ class ProjectService extends BaseApiService {
5357
5290
  if (!project) {
5358
5291
  throw new Error("Expected project to exist");
5359
5292
  }
5360
- const license = selectLicenseForProject(project.id);
5361
5293
  const activeProjectId = state.projectReducer.activeProjectId;
5362
5294
  if (activeProjectId === projectId) {
5363
5295
  store.dispatch({ type: "project/setActiveProjectId", payload: null });
@@ -5368,9 +5300,6 @@ class ProjectService extends BaseApiService {
5368
5300
  store.dispatch(removeProjectAccessesOfProject(project.id));
5369
5301
  store.dispatch({ type: "rehydrated/setRehydrated", payload: false });
5370
5302
  store.dispatch(deleteProject(project));
5371
- if (license) {
5372
- store.dispatch(updateLicense({ ...license, project: null }));
5373
- }
5374
5303
  try {
5375
5304
  await this.enqueueRequest({
5376
5305
  description: "Delete project",
@@ -5386,9 +5315,6 @@ class ProjectService extends BaseApiService {
5386
5315
  store.dispatch(addOrReplaceProjectFiles(filesToDelete));
5387
5316
  store.dispatch(setActiveProjectId(activeProjectId));
5388
5317
  store.dispatch({ type: "rehydrated/setRehydrated", payload: true });
5389
- if (license) {
5390
- store.dispatch(updateLicense({ ...license, project: project.id }));
5391
- }
5392
5318
  throw e;
5393
5319
  }
5394
5320
  }
@@ -5427,8 +5353,72 @@ class ProjectService extends BaseApiService {
5427
5353
  });
5428
5354
  }
5429
5355
  }
5356
+ const separateImageFromFields = async (payload) => {
5357
+ const { fields } = payload;
5358
+ const images = {};
5359
+ const newFields = [];
5360
+ for (const section of fields) {
5361
+ if (section.type !== "section") {
5362
+ throw new Error(`Expected ISerializedField type to be a section. Got ${section.type} instead.`);
5363
+ }
5364
+ const { fields: sectionFields } = section;
5365
+ const newSectionFields = [];
5366
+ for (const field of sectionFields) {
5367
+ if (field.image) {
5368
+ if (field.image instanceof Promise) {
5369
+ try {
5370
+ images[field.identifier] = await field.image;
5371
+ } catch (e) {
5372
+ console.error("Failed to get image from promise", e);
5373
+ }
5374
+ } else {
5375
+ images[field.identifier] = field.image;
5376
+ }
5377
+ delete field.image;
5378
+ }
5379
+ newSectionFields.push(field);
5380
+ }
5381
+ newFields.push({ ...section, fields: newSectionFields });
5382
+ }
5383
+ const payloadWithoutImage = {
5384
+ ...payload,
5385
+ fields: newFields
5386
+ };
5387
+ return { payloadWithoutImage, images };
5388
+ };
5430
5389
  class UserFormService extends BaseApiService {
5431
- add(state, initialRevision, url, ownerUser, ownerOrganization) {
5390
+ constructor() {
5391
+ super(...arguments);
5392
+ // Attach images to revision, after uploading them to S3
5393
+ __publicField(this, "getAttachImagePromises", (images, offlineRevisionId) => {
5394
+ const { store } = this.client;
5395
+ return Object.entries(images).map(async ([key, image]) => {
5396
+ const sha1 = await hashFile(image);
5397
+ await this.client.files.addCache(image, sha1);
5398
+ const [fileProps] = await this.client.files.uploadFileToS3(sha1);
5399
+ const revisionAttachmentPayload = offline({
5400
+ ...fileProps,
5401
+ revision: offlineRevisionId,
5402
+ field_identifier: key
5403
+ });
5404
+ const attach = await this.enqueueRequest({
5405
+ description: "Attach image to form revision field",
5406
+ method: HttpMethod.POST,
5407
+ url: `/forms/revisions/${offlineRevisionId}/attachments/`,
5408
+ payload: revisionAttachmentPayload,
5409
+ blockers: [revisionAttachmentPayload.revision],
5410
+ blocks: [revisionAttachmentPayload.offline_id]
5411
+ });
5412
+ const offlinePayload = {
5413
+ ...revisionAttachmentPayload,
5414
+ file: URL.createObjectURL(image)
5415
+ };
5416
+ store.dispatch(addUserFormRevisionAttachment(offlinePayload));
5417
+ return attach;
5418
+ });
5419
+ });
5420
+ }
5421
+ async add(state, initialRevision, url, ownerUser, ownerOrganization) {
5432
5422
  if (!!ownerUser === !!ownerOrganization) {
5433
5423
  throw new Error("Exactly one of ownerUser and ownerOrganization must be defined.");
5434
5424
  }
@@ -5448,8 +5438,9 @@ class UserFormService extends BaseApiService {
5448
5438
  created_by: currentUser.id,
5449
5439
  ...ownerAttrs
5450
5440
  };
5441
+ const { payloadWithoutImage, images } = await separateImageFromFields(offlineRevisionPayload);
5451
5442
  const retRevision = {
5452
- ...offlineRevisionPayload,
5443
+ ...payloadWithoutImage,
5453
5444
  created_by: currentUser.id,
5454
5445
  form: retForm.offline_id,
5455
5446
  revision: 0
@@ -5464,24 +5455,26 @@ class UserFormService extends BaseApiService {
5464
5455
  queryParams: activeWorkspaceId ? {
5465
5456
  workspace_id: activeWorkspaceId
5466
5457
  } : void 0,
5467
- payload: { ...offlineFormPayload, initial_revision: offlineRevisionPayload },
5458
+ payload: { ...offlineFormPayload, initial_revision: payloadWithoutImage },
5468
5459
  blockers: [],
5469
- blocks: [offlineFormPayload.offline_id, offlineRevisionPayload.offline_id]
5460
+ blocks: [offlineFormPayload.offline_id, payloadWithoutImage.offline_id]
5470
5461
  });
5462
+ const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
5471
5463
  void formPromise.catch((e) => {
5472
5464
  store.dispatch(deleteUserForm(retForm.offline_id));
5473
5465
  store.dispatch(deleteUserFormRevision(retRevision.offline_id));
5474
5466
  throw e;
5475
5467
  });
5476
- return [retForm, retRevision, formPromise];
5468
+ const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
5469
+ return [retForm, retRevision, formPromise, settledPromise];
5477
5470
  }
5478
- addForOrganization(initialRevision) {
5471
+ async addForOrganization(initialRevision) {
5479
5472
  const state = this.client.store.getState();
5480
5473
  const activeOrganizationId = state.organizationReducer.activeOrganizationId;
5481
5474
  if (!activeOrganizationId) {
5482
5475
  throw new Error("Cannot add forms for organization when there is no active organization.");
5483
5476
  }
5484
- return this.add(
5477
+ return await this.add(
5485
5478
  state,
5486
5479
  initialRevision,
5487
5480
  `/forms/in-organization/${activeOrganizationId}/`,
@@ -5489,12 +5482,12 @@ class UserFormService extends BaseApiService {
5489
5482
  activeOrganizationId
5490
5483
  );
5491
5484
  }
5492
- addForCurrentUser(initialRevision) {
5485
+ async addForCurrentUser(initialRevision) {
5493
5486
  const state = this.client.store.getState();
5494
5487
  const currentUser = state.userReducer.currentUser;
5495
- return this.add(state, initialRevision, "/forms/my-forms/", currentUser.id);
5488
+ return await this.add(state, initialRevision, "/forms/my-forms/", currentUser.id);
5496
5489
  }
5497
- createRevision(formId2, revision) {
5490
+ async createRevision(formId2, revision) {
5498
5491
  const offlineRevision = offline(revision);
5499
5492
  const { store } = this.client;
5500
5493
  const state = store.getState();
@@ -5503,8 +5496,9 @@ class UserFormService extends BaseApiService {
5503
5496
  throw new Error("Cannot create form revision when there is no active project.");
5504
5497
  }
5505
5498
  const currentUserId = state.userReducer.currentUser.id;
5499
+ const { payloadWithoutImage, images } = await separateImageFromFields(offlineRevision);
5506
5500
  const fullRevision = {
5507
- ...offlineRevision,
5501
+ ...payloadWithoutImage,
5508
5502
  created_by: currentUserId,
5509
5503
  revision: "Pending",
5510
5504
  form: formId2
@@ -5514,19 +5508,21 @@ class UserFormService extends BaseApiService {
5514
5508
  description: "Create form revision",
5515
5509
  method: HttpMethod.PATCH,
5516
5510
  url: `/forms/${formId2}/`,
5517
- payload: { initial_revision: offlineRevision },
5511
+ payload: { initial_revision: payloadWithoutImage },
5518
5512
  queryParams: {
5519
5513
  project_id: activeProjectId.toString()
5520
5514
  },
5521
5515
  blockers: [formId2],
5522
5516
  blocks: [offlineRevision.offline_id]
5523
5517
  });
5518
+ const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
5524
5519
  void promise.then((result) => {
5525
5520
  store.dispatch(addUserFormRevision(result));
5526
5521
  }).catch(() => {
5527
5522
  store.dispatch(deleteUserFormRevision(fullRevision.offline_id));
5528
5523
  });
5529
- return [fullRevision, promise];
5524
+ const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
5525
+ return [fullRevision, settledPromise];
5530
5526
  }
5531
5527
  async favorite(formId2) {
5532
5528
  const { store } = this.client;
@@ -5608,6 +5604,7 @@ class UserFormService extends BaseApiService {
5608
5604
  });
5609
5605
  store.dispatch(addUserForms(Object.values(result.forms)));
5610
5606
  store.dispatch(addUserFormRevisions(Object.values(result.revisions)));
5607
+ store.dispatch(setUserFormRevisionAttachments(Object.values(result.attachments)));
5611
5608
  }
5612
5609
  }
5613
5610
  const isArrayOfFiles = (value) => {
@@ -5694,11 +5691,9 @@ class UserFormSubmissionService extends BaseApiService {
5694
5691
  store.dispatch(addUserFormSubmission(offlineResultWithoutFiles));
5695
5692
  void promise.then((result) => {
5696
5693
  store.dispatch(addUserFormSubmission(result));
5697
- store.dispatch(updateActiveProjectFormSubmissionsCount(1));
5698
5694
  return result;
5699
5695
  }).catch(() => {
5700
5696
  store.dispatch(deleteUserFormSubmission(payload.offline_id));
5701
- store.dispatch(updateActiveProjectFormSubmissionsCount(-1));
5702
5697
  });
5703
5698
  const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
5704
5699
  return [fullOfflineResult, settledPromise];
@@ -5708,7 +5703,6 @@ class UserFormSubmissionService extends BaseApiService {
5708
5703
  const state = store.getState();
5709
5704
  const submission = state.userFormReducer.submissions[submissionId];
5710
5705
  store.dispatch(deleteUserFormSubmission(submissionId));
5711
- store.dispatch(updateActiveProjectFormSubmissionsCount(-1));
5712
5706
  try {
5713
5707
  return await this.enqueueRequest({
5714
5708
  description: "Delete user form submissions",
@@ -5720,7 +5714,6 @@ class UserFormSubmissionService extends BaseApiService {
5720
5714
  } catch (e) {
5721
5715
  if (submission) {
5722
5716
  store.dispatch(addUserFormSubmission(submission));
5723
- store.dispatch(updateActiveProjectFormSubmissionsCount(1));
5724
5717
  }
5725
5718
  throw e;
5726
5719
  }
@@ -6133,12 +6126,10 @@ class OrganizationService extends BaseApiService {
6133
6126
  const organizationAccesses = data.organization_accesses;
6134
6127
  const emailDomains = data.email_domains;
6135
6128
  const users = data.users;
6136
- const licenses = data.licenses;
6137
6129
  store.dispatch(addUsers(users));
6138
6130
  store.dispatch(setActiveOrganizationId(activeOrganization.id));
6139
6131
  store.dispatch(setOrganizationAccesses(organizationAccesses));
6140
6132
  store.dispatch(setEmailDomains(emailDomains));
6141
- store.dispatch(addLicenses(licenses));
6142
6133
  if (showLoading) {
6143
6134
  store.dispatch(setIsFetchingInitialData(false));
6144
6135
  }
@@ -6179,109 +6170,6 @@ class OrganizationService extends BaseApiService {
6179
6170
  });
6180
6171
  }
6181
6172
  }
6182
- class LicenseService extends BaseApiService {
6183
- async getLicensesForOrganization(organizationId, showLoading = false) {
6184
- if (showLoading) {
6185
- this.client.store.dispatch(setIsFetchingInitialData(true));
6186
- }
6187
- return this.enqueueRequest({
6188
- description: "Get licenses",
6189
- method: HttpMethod.GET,
6190
- url: `/organizations/${organizationId}/licenses/`,
6191
- isAuthNeeded: true,
6192
- blockers: [organizationId.toString()],
6193
- blocks: []
6194
- }).then((result) => {
6195
- if (showLoading) {
6196
- this.client.store.dispatch(setIsFetchingInitialData(false));
6197
- }
6198
- return result;
6199
- });
6200
- }
6201
- async pauseLicense(license) {
6202
- this.client.store.dispatch(setIsFetchingInitialData(true));
6203
- return this.enqueueRequest({
6204
- description: "Pause license",
6205
- method: HttpMethod.DELETE,
6206
- url: `/billing/${license.offline_id}/suspend/`,
6207
- isAuthNeeded: true,
6208
- blockers: [
6209
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6210
- ],
6211
- blocks: []
6212
- }).then((result) => {
6213
- this.client.store.dispatch(updateLicense(result));
6214
- this.client.store.dispatch(setIsFetchingInitialData(false));
6215
- return result;
6216
- });
6217
- }
6218
- async resumeLicense(license) {
6219
- this.client.store.dispatch(setIsFetchingInitialData(true));
6220
- return this.enqueueRequest({
6221
- description: "Resume license",
6222
- method: HttpMethod.PATCH,
6223
- url: `/billing/${license.offline_id}/suspend/`,
6224
- isAuthNeeded: true,
6225
- blockers: [
6226
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6227
- ],
6228
- blocks: []
6229
- }).then((result) => {
6230
- this.client.store.dispatch(updateLicense(result));
6231
- this.client.store.dispatch(setIsFetchingInitialData(false));
6232
- return result;
6233
- });
6234
- }
6235
- async cancelLicense(license) {
6236
- this.client.store.dispatch(setIsFetchingInitialData(true));
6237
- return this.enqueueRequest({
6238
- description: "Cancel license",
6239
- method: HttpMethod.DELETE,
6240
- url: `/billing/${license.offline_id}/`,
6241
- isAuthNeeded: true,
6242
- blockers: [
6243
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6244
- ],
6245
- blocks: []
6246
- }).then((result) => {
6247
- this.client.store.dispatch(updateLicense(result));
6248
- this.client.store.dispatch(setIsFetchingInitialData(false));
6249
- return result;
6250
- });
6251
- }
6252
- async attachLicenseToProject(license, project) {
6253
- return this.enqueueRequest({
6254
- description: "Attach license",
6255
- method: HttpMethod.PATCH,
6256
- url: `/billing/${license.offline_id}/project/`,
6257
- isAuthNeeded: true,
6258
- payload: { project: project.id },
6259
- blockers: [
6260
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : "",
6261
- project.id ? project.id.toString() : ""
6262
- ],
6263
- blocks: []
6264
- }).then((result) => {
6265
- this.client.store.dispatch(updateLicense(result));
6266
- return result;
6267
- });
6268
- }
6269
- async detachLicenseFromProject(license) {
6270
- return this.enqueueRequest({
6271
- description: "Detach license",
6272
- method: HttpMethod.DELETE,
6273
- url: `/billing/${license.offline_id}/project/`,
6274
- isAuthNeeded: true,
6275
- blockers: [
6276
- license.organization_owner ? license.organization_owner.toString() : license.user_owner ? license.user_owner.toString() : ""
6277
- ],
6278
- blocks: []
6279
- }).then((result) => {
6280
- this.client.store.dispatch(updateLicense(result));
6281
- return result;
6282
- });
6283
- }
6284
- }
6285
6173
  class OvermapSDK {
6286
6174
  constructor(apiUrl, store) {
6287
6175
  __publicField(this, "API_URL");
@@ -6307,7 +6195,6 @@ class OvermapSDK {
6307
6195
  __publicField(this, "projectFiles", new ProjectFileService(this));
6308
6196
  __publicField(this, "emailVerification", new EmailVerificationService(this));
6309
6197
  __publicField(this, "emailDomains", new EmailDomainsService(this));
6310
- __publicField(this, "licenses", new LicenseService(this));
6311
6198
  this.API_URL = apiUrl;
6312
6199
  this.store = store;
6313
6200
  }
@@ -6336,16 +6223,26 @@ const OvermapProvider = (props) => {
6336
6223
  }
6337
6224
  return /* @__PURE__ */ jsx(OvermapContext.Provider, { value: null, children: ret });
6338
6225
  };
6339
- const description$1 = "_description_o5vqt_1";
6340
- const floatingButtonContainer$1 = "_floatingButtonContainer_o5vqt_5";
6341
- const tabsList = "_tabsList_o5vqt_12";
6342
- const tabTrigger = "_tabTrigger_o5vqt_20";
6343
- const patchfieldBorder = "_patchfieldBorder_o5vqt_24";
6344
- const title = "_title_o5vqt_24";
6345
- const error = "_error_o5vqt_40";
6226
+ const description$2 = "_description_1rtl0_1";
6227
+ const floatingButtonContainer$2 = "_floatingButtonContainer_1rtl0_5";
6228
+ const FullScreenImageContainer$2 = "_FullScreenImageContainer_1rtl0_12";
6229
+ const fileName$2 = "_fileName_1rtl0_22";
6230
+ const longIconButton$2 = "_longIconButton_1rtl0_27";
6231
+ const previewImage$3 = "_previewImage_1rtl0_33";
6232
+ const FullScreenImage$2 = "_FullScreenImage_1rtl0_12";
6233
+ const tabsList = "_tabsList_1rtl0_51";
6234
+ const tabTrigger = "_tabTrigger_1rtl0_59";
6235
+ const patchfieldBorder = "_patchfieldBorder_1rtl0_63";
6236
+ const title = "_title_1rtl0_63";
6237
+ const error = "_error_1rtl0_79";
6346
6238
  const styles$7 = {
6347
- description: description$1,
6348
- floatingButtonContainer: floatingButtonContainer$1,
6239
+ description: description$2,
6240
+ floatingButtonContainer: floatingButtonContainer$2,
6241
+ FullScreenImageContainer: FullScreenImageContainer$2,
6242
+ fileName: fileName$2,
6243
+ longIconButton: longIconButton$2,
6244
+ previewImage: previewImage$3,
6245
+ FullScreenImage: FullScreenImage$2,
6349
6246
  tabsList,
6350
6247
  tabTrigger,
6351
6248
  patchfieldBorder,
@@ -6386,12 +6283,13 @@ const emptyBaseField = {
6386
6283
  };
6387
6284
  class BaseField extends BaseFormElement {
6388
6285
  constructor(options) {
6389
- const { label, required, fieldValidators = [], formValidators = [], ...base } = options;
6286
+ const { label, required, image, fieldValidators = [], formValidators = [], ...base } = options;
6390
6287
  super(base);
6391
6288
  __publicField(this, "required");
6392
6289
  __publicField(this, "formValidators");
6393
6290
  __publicField(this, "fieldValidators");
6394
6291
  __publicField(this, "label");
6292
+ __publicField(this, "image");
6395
6293
  /**
6396
6294
  * By default, validation doesn't execute on `onChange` events when editing fields
6397
6295
  * until the field has been `touched`. This can be overridden by setting this to `false`
@@ -6401,6 +6299,7 @@ class BaseField extends BaseFormElement {
6401
6299
  __publicField(this, "onlyValidateAfterTouched", true);
6402
6300
  this.label = label;
6403
6301
  this.required = required;
6302
+ this.image = image;
6404
6303
  this.fieldValidators = fieldValidators;
6405
6304
  this.formValidators = formValidators;
6406
6305
  }
@@ -6435,7 +6334,8 @@ class BaseField extends BaseFormElement {
6435
6334
  return {
6436
6335
  ...super._serialize(),
6437
6336
  label: this.label,
6438
- required: this.required
6337
+ required: this.required,
6338
+ image: this.image
6439
6339
  };
6440
6340
  }
6441
6341
  getFieldValidators() {
@@ -6447,108 +6347,22 @@ class BaseField extends BaseFormElement {
6447
6347
  }
6448
6348
  __publicField(BaseField, "fieldTypeName");
6449
6349
  __publicField(BaseField, "fieldTypeDescription");
6450
- const description = "_description_1p32e_1";
6451
- const floatingButtonContainer = "_floatingButtonContainer_1p32e_5";
6350
+ const description$1 = "_description_1nfty_1";
6351
+ const floatingButtonContainer$1 = "_floatingButtonContainer_1nfty_5";
6352
+ const FullScreenImageContainer$1 = "_FullScreenImageContainer_1nfty_12";
6353
+ const fileName$1 = "_fileName_1nfty_22";
6354
+ const longIconButton$1 = "_longIconButton_1nfty_27";
6355
+ const previewImage$2 = "_previewImage_1nfty_33";
6356
+ const FullScreenImage$1 = "_FullScreenImage_1nfty_12";
6452
6357
  const styles$6 = {
6453
- description,
6454
- floatingButtonContainer
6455
- };
6456
- const InputWithLabel = (props) => {
6457
- const { label, children, size, severity, inputId, labelId, flexProps } = props;
6458
- return /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "1", asChild: true, ...flexProps, children: /* @__PURE__ */ jsxs("label", { htmlFor: inputId, children: [
6459
- /* @__PURE__ */ jsx(Text, { size, severity, id: labelId, children: label }),
6460
- children
6461
- ] }) });
6462
- };
6463
- const InputWithHelpText = (props) => {
6464
- const { helpText, children, severity } = props;
6465
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "1", children: [
6466
- children,
6467
- /* @__PURE__ */ jsx(Flex, { direction: "column", children: /* @__PURE__ */ jsx(Text, { size: "1", severity, className: styles$6.description, children: helpText }) })
6468
- ] });
6469
- };
6470
- const InputWithLabelAndHelpText = (props) => {
6471
- const { children, ...restProps } = props;
6472
- return /* @__PURE__ */ jsx(InputWithHelpText, { ...restProps, children });
6473
- };
6474
- const useFormikInput = (props) => {
6475
- const { id, field, formId: formId2, size, showInputOnly, ...rest } = props;
6476
- const [fieldProps, meta, helpers] = useField(field.getId());
6477
- const { touched } = meta;
6478
- const helpText = meta.error ?? field.description;
6479
- const severity = meta.error ? "danger" : void 0;
6480
- const inputId = id ?? `${formId2}-${field.getId()}-input`;
6481
- const labelId = `${inputId}-label`;
6482
- const label = field.required ? `${field.label} *` : field.label;
6483
- const fieldPropsWithValidation = useMemo(() => {
6484
- const handleChange = (e) => {
6485
- const value = field.getValueFromChangeEvent(e);
6486
- void helpers.setValue(value, false).then();
6487
- if (touched || !field.onlyValidateAfterTouched) {
6488
- helpers.setError(field.getError(value));
6489
- }
6490
- };
6491
- const handleBlur = (e) => {
6492
- void helpers.setTouched(true, false).then();
6493
- helpers.setError(field.getError(field.getValueFromChangeEvent(e)));
6494
- };
6495
- return {
6496
- ...fieldProps,
6497
- onChange: handleChange,
6498
- onBlur: handleBlur
6499
- };
6500
- }, [field, fieldProps, helpers, touched]);
6501
- return [
6502
- {
6503
- helpText,
6504
- size,
6505
- severity,
6506
- inputId,
6507
- labelId,
6508
- label,
6509
- showInputOnly,
6510
- fieldProps: fieldPropsWithValidation,
6511
- helpers,
6512
- field
6513
- },
6514
- { ...rest, "aria-labelledby": labelId }
6515
- ];
6358
+ description: description$1,
6359
+ floatingButtonContainer: floatingButtonContainer$1,
6360
+ FullScreenImageContainer: FullScreenImageContainer$1,
6361
+ fileName: fileName$1,
6362
+ longIconButton: longIconButton$1,
6363
+ previewImage: previewImage$2,
6364
+ FullScreenImage: FullScreenImage$1
6516
6365
  };
6517
- const truthyValues = [true, "true"];
6518
- const BooleanInput = memo((props) => {
6519
- const [{ inputId, labelId, size, severity, showInputOnly, fieldProps }, rest] = useFormikInput(props);
6520
- let [{ helpText, label }] = useFormikInput(props);
6521
- helpText = showInputOnly ? null : helpText;
6522
- label = showInputOnly ? "" : label;
6523
- const color = useSeverityColor(severity);
6524
- const value = truthyValues.includes(fieldProps.value);
6525
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
6526
- InputWithLabel,
6527
- {
6528
- size,
6529
- severity,
6530
- inputId,
6531
- labelId,
6532
- label,
6533
- flexProps: { direction: "row-reverse", justify: "end", align: "center", gap: "2" },
6534
- children: /* @__PURE__ */ jsx(
6535
- Checkbox,
6536
- {
6537
- ...rest,
6538
- ...fieldProps,
6539
- id: inputId,
6540
- color,
6541
- value: value.toString(),
6542
- checked: value,
6543
- onCheckedChange: fieldProps.onChange,
6544
- onChange: void 0,
6545
- onBlur: void 0
6546
- }
6547
- )
6548
- }
6549
- ) });
6550
- });
6551
- BooleanInput.displayName = "BooleanInput";
6552
6366
  function _objectWithoutPropertiesLoose(source, excluded) {
6553
6367
  if (source == null)
6554
6368
  return {};
@@ -6813,6 +6627,24 @@ var GearIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6813
6627
  clipRule: "evenodd"
6814
6628
  }));
6815
6629
  });
6630
+ var _excluded$2C = ["color"];
6631
+ var ImageIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6632
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$2C);
6633
+ return createElement("svg", Object.assign({
6634
+ width: "15",
6635
+ height: "15",
6636
+ viewBox: "0 0 15 15",
6637
+ fill: "none",
6638
+ xmlns: "http://www.w3.org/2000/svg"
6639
+ }, props, {
6640
+ ref: forwardedRef
6641
+ }), createElement("path", {
6642
+ d: "M2.5 1H12.5C13.3284 1 14 1.67157 14 2.5V12.5C14 13.3284 13.3284 14 12.5 14H2.5C1.67157 14 1 13.3284 1 12.5V2.5C1 1.67157 1.67157 1 2.5 1ZM2.5 2C2.22386 2 2 2.22386 2 2.5V8.3636L3.6818 6.6818C3.76809 6.59551 3.88572 6.54797 4.00774 6.55007C4.12975 6.55216 4.24568 6.60372 4.32895 6.69293L7.87355 10.4901L10.6818 7.6818C10.8575 7.50607 11.1425 7.50607 11.3182 7.6818L13 9.3636V2.5C13 2.22386 12.7761 2 12.5 2H2.5ZM2 12.5V9.6364L3.98887 7.64753L7.5311 11.4421L8.94113 13H2.5C2.22386 13 2 12.7761 2 12.5ZM12.5 13H10.155L8.48336 11.153L11 8.6364L13 10.6364V12.5C13 12.7761 12.7761 13 12.5 13ZM6.64922 5.5C6.64922 5.03013 7.03013 4.64922 7.5 4.64922C7.96987 4.64922 8.35078 5.03013 8.35078 5.5C8.35078 5.96987 7.96987 6.35078 7.5 6.35078C7.03013 6.35078 6.64922 5.96987 6.64922 5.5ZM7.5 3.74922C6.53307 3.74922 5.74922 4.53307 5.74922 5.5C5.74922 6.46693 6.53307 7.25078 7.5 7.25078C8.46693 7.25078 9.25078 6.46693 9.25078 5.5C9.25078 4.53307 8.46693 3.74922 7.5 3.74922Z",
6643
+ fill: color,
6644
+ fillRule: "evenodd",
6645
+ clipRule: "evenodd"
6646
+ }));
6647
+ });
6816
6648
  var _excluded$2E = ["color"];
6817
6649
  var InputIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6818
6650
  var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$2E);
@@ -7009,6 +6841,196 @@ var UploadIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
7009
6841
  clipRule: "evenodd"
7010
6842
  }));
7011
6843
  });
6844
+ const FullScreenImagePreview = memo((props) => {
6845
+ const { file, url, name, setShowPreview } = props;
6846
+ const handleDownload = useCallback(
6847
+ (event) => {
6848
+ event.stopPropagation();
6849
+ const blob = new Blob([file]);
6850
+ saveAs(blob, name);
6851
+ },
6852
+ [name, file]
6853
+ );
6854
+ return /* @__PURE__ */ jsxs(
6855
+ "button",
6856
+ {
6857
+ className: styles$6.FullScreenImageContainer,
6858
+ onClick: () => {
6859
+ setShowPreview(false);
6860
+ },
6861
+ children: [
6862
+ /* @__PURE__ */ jsxs(Flex, { align: "center", children: [
6863
+ /* @__PURE__ */ jsx(
6864
+ IconButton,
6865
+ {
6866
+ className: styles$6.longIconButton,
6867
+ variant: "soft",
6868
+ "aria-label": "Exit preview",
6869
+ onClick: () => {
6870
+ setShowPreview(false);
6871
+ },
6872
+ children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
6873
+ }
6874
+ ),
6875
+ /* @__PURE__ */ jsx(Text, { className: styles$6.fileName, children: name }),
6876
+ /* @__PURE__ */ jsx(
6877
+ IconButton,
6878
+ {
6879
+ className: styles$6.longIconButton,
6880
+ variant: "soft",
6881
+ "aria-label": `Download ${name}`,
6882
+ onClick: handleDownload,
6883
+ children: /* @__PURE__ */ jsx(DownloadIcon, {})
6884
+ }
6885
+ )
6886
+ ] }),
6887
+ /* @__PURE__ */ jsx(
6888
+ "img",
6889
+ {
6890
+ className: styles$6.FullScreenImage,
6891
+ src: url,
6892
+ alt: name,
6893
+ onClick: (e) => {
6894
+ e.stopPropagation();
6895
+ }
6896
+ }
6897
+ )
6898
+ ]
6899
+ }
6900
+ );
6901
+ });
6902
+ FullScreenImagePreview.displayName = "FullScreenImagePreview";
6903
+ const InputWithLabel = (props) => {
6904
+ const { label, children, size, severity, inputId, labelId, image, flexProps } = props;
6905
+ const [resolvedImage, setResolvedImage] = useState(void 0);
6906
+ const [showImagePreview, setShowImagePreview] = useState(false);
6907
+ useEffect(() => {
6908
+ if (image instanceof Promise) {
6909
+ image.then(setResolvedImage).catch(console.error);
6910
+ } else {
6911
+ setResolvedImage(image);
6912
+ }
6913
+ }, [image]);
6914
+ const resolvedImageURL = resolvedImage ? URL.createObjectURL(resolvedImage) : void 0;
6915
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
6916
+ resolvedImage && /* @__PURE__ */ jsxs(Fragment, { children: [
6917
+ /* @__PURE__ */ jsx(
6918
+ "img",
6919
+ {
6920
+ className: styles$6.previewImage,
6921
+ src: resolvedImageURL,
6922
+ alt: resolvedImage.name,
6923
+ onClick: () => {
6924
+ setShowImagePreview(true);
6925
+ }
6926
+ }
6927
+ ),
6928
+ showImagePreview && /* @__PURE__ */ jsx(
6929
+ FullScreenImagePreview,
6930
+ {
6931
+ file: resolvedImage,
6932
+ url: resolvedImageURL,
6933
+ name: resolvedImage.name,
6934
+ setShowPreview: setShowImagePreview
6935
+ }
6936
+ )
6937
+ ] }),
6938
+ /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "1", asChild: true, ...flexProps, children: /* @__PURE__ */ jsxs("label", { htmlFor: inputId, children: [
6939
+ /* @__PURE__ */ jsx(Text, { size, severity, id: labelId, children: label }),
6940
+ children
6941
+ ] }) })
6942
+ ] });
6943
+ };
6944
+ const InputWithHelpText = (props) => {
6945
+ const { helpText, children, severity } = props;
6946
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "1", children: [
6947
+ children,
6948
+ /* @__PURE__ */ jsx(Flex, { direction: "column", children: /* @__PURE__ */ jsx(Text, { size: "1", severity, className: styles$6.description, children: helpText }) })
6949
+ ] });
6950
+ };
6951
+ const InputWithLabelAndHelpText = (props) => {
6952
+ const { children, ...restProps } = props;
6953
+ return /* @__PURE__ */ jsx(InputWithHelpText, { ...restProps, children });
6954
+ };
6955
+ const useFormikInput = (props) => {
6956
+ const { id, field, formId: formId2, size, showInputOnly, ...rest } = props;
6957
+ const [fieldProps, meta, helpers] = useField(field.getId());
6958
+ const { touched } = meta;
6959
+ const helpText = meta.error ?? field.description;
6960
+ const severity = meta.error ? "danger" : void 0;
6961
+ const inputId = id ?? `${formId2}-${field.getId()}-input`;
6962
+ const labelId = `${inputId}-label`;
6963
+ const label = field.required ? `${field.label} *` : field.label;
6964
+ const fieldPropsWithValidation = useMemo(() => {
6965
+ const handleChange = (e) => {
6966
+ const value = field.getValueFromChangeEvent(e);
6967
+ void helpers.setValue(value, false).then();
6968
+ if (touched || !field.onlyValidateAfterTouched) {
6969
+ helpers.setError(field.getError(value));
6970
+ }
6971
+ };
6972
+ const handleBlur = (e) => {
6973
+ void helpers.setTouched(true, false).then();
6974
+ helpers.setError(field.getError(field.getValueFromChangeEvent(e)));
6975
+ };
6976
+ return {
6977
+ ...fieldProps,
6978
+ onChange: handleChange,
6979
+ onBlur: handleBlur
6980
+ };
6981
+ }, [field, fieldProps, helpers, touched]);
6982
+ return [
6983
+ {
6984
+ helpText,
6985
+ size,
6986
+ severity,
6987
+ inputId,
6988
+ labelId,
6989
+ label,
6990
+ showInputOnly,
6991
+ fieldProps: fieldPropsWithValidation,
6992
+ helpers,
6993
+ field
6994
+ },
6995
+ { ...rest, "aria-labelledby": labelId }
6996
+ ];
6997
+ };
6998
+ const truthyValues = [true, "true"];
6999
+ const BooleanInput = memo((props) => {
7000
+ const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
7001
+ let [{ helpText, label }] = useFormikInput(props);
7002
+ helpText = showInputOnly ? null : helpText;
7003
+ label = showInputOnly ? "" : label;
7004
+ const color = useSeverityColor(severity);
7005
+ const value = truthyValues.includes(fieldProps.value);
7006
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
7007
+ InputWithLabel,
7008
+ {
7009
+ size,
7010
+ severity,
7011
+ inputId,
7012
+ labelId,
7013
+ label,
7014
+ image: showInputOnly ? void 0 : field.image,
7015
+ flexProps: { direction: "row-reverse", justify: "end", align: "center", gap: "2" },
7016
+ children: /* @__PURE__ */ jsx(
7017
+ Checkbox,
7018
+ {
7019
+ ...rest,
7020
+ ...fieldProps,
7021
+ id: inputId,
7022
+ color,
7023
+ value: value.toString(),
7024
+ checked: value,
7025
+ onCheckedChange: fieldProps.onChange,
7026
+ onChange: void 0,
7027
+ onBlur: void 0
7028
+ }
7029
+ )
7030
+ }
7031
+ ) });
7032
+ });
7033
+ BooleanInput.displayName = "BooleanInput";
7012
7034
  const emptyBooleanField = {
7013
7035
  ...emptyBaseField,
7014
7036
  type: "boolean"
@@ -7258,7 +7280,7 @@ const $5e63c961fc1ce211$var$SlotClone = /* @__PURE__ */ forwardRef((props, forwa
7258
7280
  });
7259
7281
  $5e63c961fc1ce211$var$SlotClone.displayName = "SlotClone";
7260
7282
  const $5e63c961fc1ce211$export$d9f1ccf0bdb05d45 = ({ children }) => {
7261
- return /* @__PURE__ */ createElement(Fragment, null, children);
7283
+ return /* @__PURE__ */ createElement(Fragment$1, null, children);
7262
7284
  };
7263
7285
  function $5e63c961fc1ce211$var$isSlottable(child) {
7264
7286
  return /* @__PURE__ */ isValidElement(child) && child.type === $5e63c961fc1ce211$export$d9f1ccf0bdb05d45;
@@ -8437,25 +8459,36 @@ const Tabs = Object.assign({}, {
8437
8459
  Content: TabsContent
8438
8460
  });
8439
8461
  const NumberInput = memo((props) => {
8440
- const [{ inputId, labelId, size, severity, showInputOnly, fieldProps, field }, rest] = useFormikInput(props);
8462
+ const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
8441
8463
  let [{ helpText, label }] = useFormikInput(props);
8442
8464
  helpText = showInputOnly ? null : helpText;
8443
8465
  label = showInputOnly ? "" : label;
8444
8466
  const color = useSeverityColor(severity);
8445
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8446
- TextField$1.Input,
8467
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
8468
+ InputWithLabel,
8447
8469
  {
8448
- ...rest,
8449
- ...fieldProps,
8450
- type: "number",
8451
- id: inputId,
8452
- placeholder: "Enter a number",
8453
- min: field.minimum,
8454
- max: field.maximum,
8455
- step: field.integers ? 1 : 0.1,
8456
- color
8470
+ size,
8471
+ severity,
8472
+ inputId,
8473
+ labelId,
8474
+ label,
8475
+ image: showInputOnly ? void 0 : field.image,
8476
+ children: /* @__PURE__ */ jsx(
8477
+ TextField$1.Input,
8478
+ {
8479
+ ...rest,
8480
+ ...fieldProps,
8481
+ type: "number",
8482
+ id: inputId,
8483
+ placeholder: "Enter a number",
8484
+ min: field.minimum,
8485
+ max: field.maximum,
8486
+ step: field.integers ? 1 : 0.1,
8487
+ color
8488
+ }
8489
+ )
8457
8490
  }
8458
- ) }) });
8491
+ ) });
8459
8492
  });
8460
8493
  NumberInput.displayName = "NumberInput";
8461
8494
  const emptyNumberField = {
@@ -8589,13 +8622,24 @@ __publicField(_NumberField, "_validateMax", (path) => (value, allValues) => {
8589
8622
  });
8590
8623
  let NumberField = _NumberField;
8591
8624
  const DateInput = memo((props) => {
8592
- const [{ inputId, labelId, size, severity, showInputOnly, fieldProps }, rest] = useFormikInput(props);
8625
+ const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
8593
8626
  let [{ helpText, label }] = useFormikInput(props);
8594
8627
  helpText = showInputOnly ? null : helpText;
8595
8628
  label = showInputOnly ? "" : label;
8596
8629
  const color = useSeverityColor(severity);
8597
8630
  const value = fieldProps.value ? fieldProps.value.split("T")[0] : "";
8598
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(TextField$1.Input, { ...rest, ...fieldProps, type: "date", id: inputId, color, value }) }) });
8631
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
8632
+ InputWithLabel,
8633
+ {
8634
+ size,
8635
+ severity,
8636
+ inputId,
8637
+ labelId,
8638
+ label,
8639
+ image: showInputOnly ? void 0 : field.image,
8640
+ children: /* @__PURE__ */ jsx(TextField$1.Input, { ...rest, ...fieldProps, type: "date", id: inputId, color, value })
8641
+ }
8642
+ ) });
8599
8643
  });
8600
8644
  DateInput.displayName = "DateInput";
8601
8645
  const emptyDateField = {
@@ -8739,43 +8783,54 @@ const styles$5 = {
8739
8783
  TextFieldInputCopy
8740
8784
  };
8741
8785
  const StringInput = memo((props) => {
8742
- const [{ inputId, labelId, size, severity, showInputOnly, fieldProps, field }, rest] = useFormikInput(props);
8786
+ const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
8743
8787
  let [{ helpText, label }] = useFormikInput(props);
8744
8788
  helpText = showInputOnly ? null : helpText;
8745
8789
  label = showInputOnly ? "" : label;
8746
8790
  const color = useSeverityColor(severity);
8747
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: !rest.disabled || !fieldProps.value ? /* @__PURE__ */ jsx(
8748
- TextField$1.Input,
8791
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
8792
+ InputWithLabel,
8749
8793
  {
8750
- ...rest,
8751
- ...fieldProps,
8752
- type: field.inputType,
8753
- id: inputId,
8754
- placeholder: "Enter a short description",
8755
- color
8756
- }
8757
- ) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$5.clickableLinkContainer, children: [
8758
- /* @__PURE__ */ jsx(
8759
- "div",
8760
- {
8761
- className: classNames$1(
8762
- "rt-TextFieldInput rt-r-size-2 rt-variant-surface",
8763
- styles$5.TextFieldInputCopy
8764
- ),
8765
- children: /* @__PURE__ */ jsx(
8766
- Linkify,
8794
+ size,
8795
+ severity,
8796
+ inputId,
8797
+ labelId,
8798
+ label,
8799
+ image: showInputOnly ? void 0 : field.image,
8800
+ children: !rest.disabled || !fieldProps.value ? /* @__PURE__ */ jsx(
8801
+ TextField$1.Input,
8802
+ {
8803
+ ...rest,
8804
+ ...fieldProps,
8805
+ type: field.inputType,
8806
+ id: inputId,
8807
+ placeholder: "Enter a short description",
8808
+ color
8809
+ }
8810
+ ) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$5.clickableLinkContainer, children: [
8811
+ /* @__PURE__ */ jsx(
8812
+ "div",
8767
8813
  {
8768
- options: {
8769
- target: "_blank",
8770
- rel: "noopener"
8771
- },
8772
- children: fieldProps.value
8814
+ className: classNames$1(
8815
+ "rt-TextFieldInput rt-r-size-2 rt-variant-surface",
8816
+ styles$5.TextFieldInputCopy
8817
+ ),
8818
+ children: /* @__PURE__ */ jsx(
8819
+ Linkify,
8820
+ {
8821
+ options: {
8822
+ target: "_blank",
8823
+ rel: "noopener"
8824
+ },
8825
+ children: fieldProps.value
8826
+ }
8827
+ )
8773
8828
  }
8774
- )
8775
- }
8776
- ),
8777
- /* @__PURE__ */ jsx("div", { className: "rt-TextFieldChrome" })
8778
- ] }) }) });
8829
+ ),
8830
+ /* @__PURE__ */ jsx("div", { className: "rt-TextFieldChrome" })
8831
+ ] })
8832
+ }
8833
+ ) });
8779
8834
  });
8780
8835
  StringInput.displayName = "StringInput";
8781
8836
  const emptyStringField = {
@@ -8811,21 +8866,32 @@ __publicField(_StringField, "fieldTypeDescription", "Short text fields can hold
8811
8866
  __publicField(_StringField, "Icon", InputIcon);
8812
8867
  let StringField = _StringField;
8813
8868
  const TextInput = memo((props) => {
8814
- const [{ inputId, labelId, size, severity, showInputOnly, fieldProps }, rest] = useFormikInput(props);
8869
+ const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
8815
8870
  let [{ helpText, label }] = useFormikInput(props);
8816
8871
  helpText = showInputOnly ? null : helpText;
8817
8872
  label = showInputOnly ? "" : label;
8818
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8819
- TextArea,
8873
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
8874
+ InputWithLabel,
8820
8875
  {
8821
- ...rest,
8822
- ...fieldProps,
8823
- resize: "vertical",
8824
- id: inputId,
8825
- placeholder: "Enter a description",
8826
- severity
8876
+ size,
8877
+ severity,
8878
+ inputId,
8879
+ labelId,
8880
+ label,
8881
+ image: showInputOnly ? void 0 : field.image,
8882
+ children: /* @__PURE__ */ jsx(
8883
+ TextArea,
8884
+ {
8885
+ ...rest,
8886
+ ...fieldProps,
8887
+ resize: "vertical",
8888
+ id: inputId,
8889
+ placeholder: "Enter a description",
8890
+ severity
8891
+ }
8892
+ )
8827
8893
  }
8828
- ) }) });
8894
+ ) });
8829
8895
  });
8830
8896
  TextInput.displayName = "TextInput";
8831
8897
  const emptyTextField = {
@@ -8857,7 +8923,7 @@ __publicField(_TextField, "fieldTypeDescription", "Paragraph fields can hold up
8857
8923
  __publicField(_TextField, "Icon", RowsIcon);
8858
8924
  let TextField = _TextField;
8859
8925
  const SelectInput = memo((props) => {
8860
- const [{ inputId, labelId, size, severity, showInputOnly, fieldProps, field }, rest] = useFormikInput(props);
8926
+ const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
8861
8927
  const { onChange, onBlur } = fieldProps;
8862
8928
  let [{ helpText, label }] = useFormikInput(props);
8863
8929
  helpText = showInputOnly ? null : helpText;
@@ -8873,18 +8939,29 @@ const SelectInput = memo((props) => {
8873
8939
  },
8874
8940
  [onChange, onBlur]
8875
8941
  );
8876
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8877
- Select,
8942
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
8943
+ InputWithLabel,
8878
8944
  {
8879
- items: options,
8880
- ...fieldProps,
8881
- onValueChange: handleChange,
8882
- placeholder: "Select one...",
8883
- id: inputId,
8945
+ size,
8884
8946
  severity,
8885
- ...rest
8947
+ inputId,
8948
+ labelId,
8949
+ label,
8950
+ image: showInputOnly ? void 0 : field.image,
8951
+ children: /* @__PURE__ */ jsx(
8952
+ Select,
8953
+ {
8954
+ items: options,
8955
+ ...fieldProps,
8956
+ onValueChange: handleChange,
8957
+ placeholder: "Select one...",
8958
+ id: inputId,
8959
+ severity,
8960
+ ...rest
8961
+ }
8962
+ )
8886
8963
  }
8887
- ) }) });
8964
+ ) });
8888
8965
  });
8889
8966
  SelectInput.displayName = "SelectInput";
8890
8967
  const emptySection = (id = "", fields = []) => ({
@@ -9052,7 +9129,7 @@ const useFieldReordering = () => {
9052
9129
  return { reorderSection, reorderField };
9053
9130
  };
9054
9131
  const MultiStringInput = memo((props) => {
9055
- const [{ inputId, labelId, size, severity, showInputOnly, fieldProps }, rest] = useFormikInput(props);
9132
+ const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
9056
9133
  let [{ helpText, label }] = useFormikInput(props);
9057
9134
  helpText = showInputOnly ? null : helpText;
9058
9135
  label = showInputOnly ? "" : label;
@@ -9125,32 +9202,43 @@ const MultiStringInput = memo((props) => {
9125
9202
  [setValueAndTouched, value]
9126
9203
  );
9127
9204
  return /* @__PURE__ */ jsx(DragDropContext, { onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
9128
- /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText: updatedHelpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: (!disabled || value.length === 0) && /* @__PURE__ */ jsxs(Flex, { gap: "2", children: [
9129
- /* @__PURE__ */ jsx(Box, { grow: "1", children: /* @__PURE__ */ jsx(
9130
- TextField$1.Input,
9131
- {
9132
- placeholder: "Press enter to add a new option",
9133
- ...rest,
9134
- ...fieldProps,
9135
- value: intermediateValue,
9136
- onChange: handleChange,
9137
- onKeyDown: handleKeyDown,
9138
- id: inputId,
9139
- color: updatedColor,
9140
- onBlur: void 0
9141
- }
9142
- ) }),
9143
- /* @__PURE__ */ jsx(
9144
- IconButton,
9145
- {
9146
- type: "button",
9147
- "aria-label": "Add option",
9148
- disabled: !!internalError || disabled,
9149
- onClick: addOption,
9150
- children: /* @__PURE__ */ jsx(PlusIcon, {})
9151
- }
9152
- )
9153
- ] }) }) }),
9205
+ /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText: updatedHelpText, severity, children: /* @__PURE__ */ jsx(
9206
+ InputWithLabel,
9207
+ {
9208
+ size,
9209
+ severity,
9210
+ inputId,
9211
+ labelId,
9212
+ label,
9213
+ image: showInputOnly ? void 0 : field.image,
9214
+ children: (!disabled || value.length === 0) && /* @__PURE__ */ jsxs(Flex, { gap: "2", children: [
9215
+ /* @__PURE__ */ jsx(Box, { grow: "1", children: /* @__PURE__ */ jsx(
9216
+ TextField$1.Input,
9217
+ {
9218
+ placeholder: "Press enter to add a new option",
9219
+ ...rest,
9220
+ ...fieldProps,
9221
+ value: intermediateValue,
9222
+ onChange: handleChange,
9223
+ onKeyDown: handleKeyDown,
9224
+ id: inputId,
9225
+ color: updatedColor,
9226
+ onBlur: void 0
9227
+ }
9228
+ ) }),
9229
+ /* @__PURE__ */ jsx(
9230
+ IconButton,
9231
+ {
9232
+ type: "button",
9233
+ "aria-label": "Add option",
9234
+ disabled: !!internalError || disabled,
9235
+ onClick: addOption,
9236
+ children: /* @__PURE__ */ jsx(PlusIcon, {})
9237
+ }
9238
+ )
9239
+ ] })
9240
+ }
9241
+ ) }),
9154
9242
  /* @__PURE__ */ jsx(Droppable, { droppableId, children: (droppableProvided) => /* @__PURE__ */ jsxs(Flex, { ...droppableProvided.droppableProps, ref: droppableProvided.innerRef, direction: "column", children: [
9155
9243
  value.map((option, index2) => /* @__PURE__ */ jsx(
9156
9244
  Draggable,
@@ -9332,7 +9420,7 @@ const parseValueToArray = (value) => {
9332
9420
  return [value];
9333
9421
  };
9334
9422
  const MultiSelectInput = memo((props) => {
9335
- const [{ inputId, labelId, size, severity, showInputOnly, fieldProps, field }, rest] = useFormikInput(props);
9423
+ const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
9336
9424
  const { onChange, onBlur } = fieldProps;
9337
9425
  let [{ helpText, label }] = useFormikInput(props);
9338
9426
  helpText = showInputOnly ? null : helpText;
@@ -9345,19 +9433,30 @@ const MultiSelectInput = memo((props) => {
9345
9433
  },
9346
9434
  [onChange, onBlur]
9347
9435
  );
9348
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
9349
- MultiSelect,
9436
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
9437
+ InputWithLabel,
9350
9438
  {
9351
- value,
9352
- onValueChange: handleChange,
9353
- options: field.options,
9354
- name: fieldProps.name,
9355
- placeholder: "Select one or more...",
9356
- id: inputId,
9439
+ size,
9357
9440
  severity,
9358
- ...rest
9441
+ inputId,
9442
+ labelId,
9443
+ label,
9444
+ image: showInputOnly ? void 0 : field.image,
9445
+ children: /* @__PURE__ */ jsx(
9446
+ MultiSelect,
9447
+ {
9448
+ value,
9449
+ onValueChange: handleChange,
9450
+ options: field.options,
9451
+ name: fieldProps.name,
9452
+ placeholder: "Select one or more...",
9453
+ id: inputId,
9454
+ severity,
9455
+ ...rest
9456
+ }
9457
+ )
9359
9458
  }
9360
- ) }) });
9459
+ ) });
9361
9460
  });
9362
9461
  MultiSelectInput.displayName = "MultiSelectInput";
9363
9462
  const emptyMultiSelectField = {
@@ -9433,23 +9532,15 @@ class FieldInputClonerField extends CustomField {
9433
9532
  super(options, FieldInputCloner);
9434
9533
  }
9435
9534
  }
9436
- const previewImage = "_previewImage_y4yd1_1";
9437
- const nameContainer = "_nameContainer_y4yd1_9";
9438
- const hasPreview = "_hasPreview_y4yd1_14";
9439
- const useEllipsis = "_useEllipsis_y4yd1_19";
9440
- const FullScreenImageContainer = "_FullScreenImageContainer_y4yd1_25";
9441
- const fileName = "_fileName_y4yd1_35";
9442
- const longIconButton = "_longIconButton_y4yd1_40";
9443
- const FullScreenImage = "_FullScreenImage_y4yd1_25";
9535
+ const previewImage$1 = "_previewImage_ebhyt_1";
9536
+ const nameContainer = "_nameContainer_ebhyt_9";
9537
+ const hasPreview = "_hasPreview_ebhyt_14";
9538
+ const useEllipsis = "_useEllipsis_ebhyt_19";
9444
9539
  const styles$4 = {
9445
- previewImage,
9540
+ previewImage: previewImage$1,
9446
9541
  nameContainer,
9447
9542
  hasPreview,
9448
- useEllipsis,
9449
- FullScreenImageContainer,
9450
- fileName,
9451
- longIconButton,
9452
- FullScreenImage
9543
+ useEllipsis
9453
9544
  };
9454
9545
  const convertBytesToLargestUnit = (bytes) => {
9455
9546
  const units = ["byte", "kilobyte", "megabyte"];
@@ -9469,7 +9560,7 @@ const convertBytesToLargestUnit = (bytes) => {
9469
9560
  };
9470
9561
  const UploadInput = memo((props) => {
9471
9562
  var _a2;
9472
- const [{ inputId, labelId, size, severity, helpText, showInputOnly, fieldProps, field }, rest] = useFormikInput(props);
9563
+ const [{ inputId, labelId, size, severity, helpText, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
9473
9564
  const { onChange } = fieldProps;
9474
9565
  let [{ label }] = useFormikInput(props);
9475
9566
  label = showInputOnly ? "" : label;
@@ -9503,28 +9594,39 @@ const UploadInput = memo((props) => {
9503
9594
  const singleButtonText = value ? "Select new file" : "Select a file";
9504
9595
  const buttonText = field.maxFiles > 1 ? multipleButtonText : singleButtonText;
9505
9596
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
9506
- /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText: updatedHelpText, severity, children: /* @__PURE__ */ jsxs(InputWithLabel, { size, severity, inputId, labelId, label, children: [
9507
- /* @__PURE__ */ jsx(Flex, { direction: "row", gap: "2", children: /* @__PURE__ */ jsx(Box, { width: "max-content", asChild: true, children: /* @__PURE__ */ jsxs(Button, { ...rest, variant: "soft", onClick: handleClick, id: "upload-input-upload-button", children: [
9508
- /* @__PURE__ */ jsx(UploadIcon, {}),
9509
- " ",
9510
- buttonText
9511
- ] }) }) }),
9512
- /* @__PURE__ */ jsx(
9513
- "input",
9514
- {
9515
- ...rest,
9516
- type: "file",
9517
- ref: input,
9518
- id: inputId,
9519
- accept: (_a2 = field.extensions) == null ? void 0 : _a2.join(","),
9520
- multiple: field.maxFiles > 1,
9521
- color,
9522
- style: { display: "none" },
9523
- ...fieldProps,
9524
- value: ""
9525
- }
9526
- )
9527
- ] }) }),
9597
+ /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText: updatedHelpText, severity, children: /* @__PURE__ */ jsxs(
9598
+ InputWithLabel,
9599
+ {
9600
+ size,
9601
+ severity,
9602
+ inputId,
9603
+ labelId,
9604
+ label,
9605
+ image: showInputOnly ? void 0 : field.image,
9606
+ children: [
9607
+ /* @__PURE__ */ jsx(Flex, { direction: "row", gap: "2", children: /* @__PURE__ */ jsx(Box, { width: "max-content", asChild: true, children: /* @__PURE__ */ jsxs(Button, { ...rest, variant: "soft", onClick: handleClick, id: "upload-input-upload-button", children: [
9608
+ /* @__PURE__ */ jsx(UploadIcon, {}),
9609
+ " ",
9610
+ buttonText
9611
+ ] }) }) }),
9612
+ /* @__PURE__ */ jsx(
9613
+ "input",
9614
+ {
9615
+ ...rest,
9616
+ type: "file",
9617
+ ref: input,
9618
+ id: inputId,
9619
+ accept: (_a2 = field.extensions) == null ? void 0 : _a2.join(","),
9620
+ multiple: field.maxFiles > 1,
9621
+ color,
9622
+ style: { display: "none" },
9623
+ ...fieldProps,
9624
+ value: ""
9625
+ }
9626
+ )
9627
+ ]
9628
+ }
9629
+ ) }),
9528
9630
  Array.isArray(value) && value.length > 0 && /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "2", children: value.map((file, index2) => /* @__PURE__ */ jsx(
9529
9631
  DisplayFile,
9530
9632
  {
@@ -9575,7 +9677,7 @@ const DisplayFile = memo((props) => {
9575
9677
  throw new Error("Cannot download a file that is not resolved.");
9576
9678
  }
9577
9679
  const blob = new Blob([resolvedFile]);
9578
- saveAs(blob, name);
9680
+ saveAs$1(blob, name);
9579
9681
  },
9580
9682
  [name, resolvedFile]
9581
9683
  );
@@ -9618,7 +9720,7 @@ const DisplayFile = memo((props) => {
9618
9720
  }
9619
9721
  )
9620
9722
  ] }),
9621
- url && /* @__PURE__ */ jsxs(Fragment$1, { children: [
9723
+ url && /* @__PURE__ */ jsxs(Fragment, { children: [
9622
9724
  /* @__PURE__ */ jsx(
9623
9725
  "img",
9624
9726
  {
@@ -9630,51 +9732,13 @@ const DisplayFile = memo((props) => {
9630
9732
  }
9631
9733
  }
9632
9734
  ),
9633
- showPreview && /* @__PURE__ */ jsxs(
9634
- "div",
9735
+ showPreview && /* @__PURE__ */ jsx(
9736
+ FullScreenImagePreview,
9635
9737
  {
9636
- className: styles$4.FullScreenImageContainer,
9637
- onClick: () => {
9638
- setShowPreview(false);
9639
- },
9640
- children: [
9641
- /* @__PURE__ */ jsxs(Flex, { align: "center", children: [
9642
- /* @__PURE__ */ jsx(
9643
- IconButton,
9644
- {
9645
- className: styles$4.longIconButton,
9646
- variant: "soft",
9647
- "aria-label": "Exit preview",
9648
- onClick: () => {
9649
- setShowPreview(false);
9650
- },
9651
- children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
9652
- }
9653
- ),
9654
- /* @__PURE__ */ jsx(Text, { className: styles$4.fileName, children: name }),
9655
- /* @__PURE__ */ jsx(
9656
- IconButton,
9657
- {
9658
- className: styles$4.longIconButton,
9659
- variant: "soft",
9660
- "aria-label": `Download ${name}`,
9661
- onClick: handleDownload,
9662
- children: /* @__PURE__ */ jsx(DownloadIcon, {})
9663
- }
9664
- )
9665
- ] }),
9666
- /* @__PURE__ */ jsx(
9667
- "img",
9668
- {
9669
- className: styles$4.FullScreenImage,
9670
- src: url,
9671
- alt: name,
9672
- onClick: (e) => {
9673
- e.stopPropagation();
9674
- }
9675
- }
9676
- )
9677
- ]
9738
+ file: resolvedFile,
9739
+ url,
9740
+ name,
9741
+ setShowPreview
9678
9742
  }
9679
9743
  )
9680
9744
  ] })
@@ -9688,7 +9752,6 @@ const emptyUploadField = {
9688
9752
  maximum_size: void 0,
9689
9753
  maximum_files: 1
9690
9754
  };
9691
- const largestSupportedSize = 50;
9692
9755
  const _UploadField = class _UploadField extends BaseField {
9693
9756
  constructor(options) {
9694
9757
  const { extensions, maximum_files, maximum_size, ...base } = options;
@@ -9726,11 +9789,11 @@ const _UploadField = class _UploadField extends BaseField {
9726
9789
  field: new NumberField({
9727
9790
  // TODO: Default value
9728
9791
  label: "What is the maximum size of each file?",
9729
- description: `Maximum file size in megabytes (between 1MB–${largestSupportedSize}MB).`,
9792
+ description: `Maximum file size in megabytes (between 1MB–${maxFileSizeMB}MB).`,
9730
9793
  required: false,
9731
9794
  identifier: `${path}maximum_size`,
9732
9795
  minimum: 1,
9733
- maximum: largestSupportedSize,
9796
+ maximum: maxFileSizeMB,
9734
9797
  integers: true
9735
9798
  }),
9736
9799
  showDirectly: false
@@ -9770,7 +9833,7 @@ const _UploadField = class _UploadField extends BaseField {
9770
9833
  }
9771
9834
  getFieldValidators() {
9772
9835
  const validators = super.getFieldValidators();
9773
- const maxFileSizeInMB = this.maxFileSize ?? largestSupportedSize;
9836
+ const maxFileSizeInMB = this.maxFileSize ?? maxFileSizeMB;
9774
9837
  const maxFileSizeInB = maxFileSizeInMB * 1e3 * 1e3;
9775
9838
  const maxFiles = this.maxFiles || 1;
9776
9839
  validators.push((value) => {
@@ -9832,6 +9895,9 @@ const FieldTypeToEmptyFieldMapping = {
9832
9895
  "multi-string": emptyMultiStringField,
9833
9896
  "multi-select": emptyMultiSelectField
9834
9897
  };
9898
+ const maxFileSizeMB = 50;
9899
+ const maxFileSizeKB = maxFileSizeMB * 1e3;
9900
+ const maxFileSizeB = maxFileSizeKB * 1e3;
9835
9901
  const deserializeField = (serializedField) => {
9836
9902
  const fieldType = serializedField.type;
9837
9903
  const fieldCls = FieldTypeToClsMapping[fieldType];
@@ -10097,6 +10163,29 @@ const initialFormValues = (fields, values) => {
10097
10163
  cloneDeep(values)
10098
10164
  );
10099
10165
  };
10166
+ const useAttachImagesToFormRevisionFields = (revision) => {
10167
+ const { sdk } = useSDK();
10168
+ const revisionCopy = useMemo(
10169
+ () => JSON.parse(JSON.stringify(revision)),
10170
+ [revision]
10171
+ );
10172
+ useEffect(() => {
10173
+ const attachments = selectRevisionAttachments(revisionCopy.offline_id)(sdk.store.getState()) ?? [];
10174
+ for (const attachment of attachments) {
10175
+ const filePromise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
10176
+ let sectionIndex = -1;
10177
+ let fieldIndex = -1;
10178
+ sectionIndex = revisionCopy.fields.findIndex((section) => {
10179
+ fieldIndex = section.fields.findIndex((field) => field.identifier === attachment.field_identifier);
10180
+ return fieldIndex !== -1;
10181
+ });
10182
+ if (sectionIndex !== -1 && fieldIndex !== -1) {
10183
+ set(revisionCopy, `fields[${sectionIndex}].fields[${fieldIndex}].image`, filePromise);
10184
+ }
10185
+ }
10186
+ }, [revisionCopy, sdk]);
10187
+ return revisionCopy;
10188
+ };
10100
10189
  const defaultHandleSubmit = () => {
10101
10190
  throw new Error("onSubmit must be provided if form is not readonly.");
10102
10191
  };
@@ -10165,9 +10254,10 @@ const FormSubmissionViewer = memo(
10165
10254
  `Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`
10166
10255
  );
10167
10256
  }
10257
+ const revisionWithImages = useAttachImagesToFormRevisionFields(revision);
10168
10258
  const schema = useMemo(() => {
10169
- return formRevisionToSchema(revision, { readonly: true });
10170
- }, [revision]);
10259
+ return formRevisionToSchema(revisionWithImages, { readonly: true });
10260
+ }, [revisionWithImages]);
10171
10261
  const submissionValuesWithAttachments = useMemo(() => {
10172
10262
  const attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? [];
10173
10263
  const downloadedAttachments = {};
@@ -10449,14 +10539,14 @@ const PatchField = memo((props) => {
10449
10539
  }
10450
10540
  });
10451
10541
  }, [render, fieldProps.value, _meta, submitForm, helpers]);
10452
- return /* @__PURE__ */ jsx(Fragment$1, { children: ret });
10542
+ return /* @__PURE__ */ jsx(Fragment, { children: ret });
10453
10543
  });
10454
10544
  PatchField.displayName = "PatchField";
10455
10545
  const PatchFormProvider = memo(
10456
10546
  forwardRef((props, ref) => {
10457
- const { children, schema, values, onPatch, onError, ...rest } = props;
10547
+ const { children, schema, values, onPatch, onError, requiresDiff = true, onDirtyChange, ...rest } = props;
10458
10548
  const initialValues2 = useMemo(() => initialFormValues(schema.fields, values), [schema.fields, values]);
10459
- const handlePatch = useCallback(
10549
+ const getDiff = useCallback(
10460
10550
  (values2) => {
10461
10551
  const diff = {};
10462
10552
  for (const key in values2) {
@@ -10465,11 +10555,18 @@ const PatchFormProvider = memo(
10465
10555
  diff[key] = value;
10466
10556
  }
10467
10557
  }
10468
- if (!hasKeys(diff))
10558
+ return diff;
10559
+ },
10560
+ [initialValues2]
10561
+ );
10562
+ const handlePatch = useCallback(
10563
+ (values2) => {
10564
+ const diff = getDiff(values2);
10565
+ if (requiresDiff && !hasKeys(diff))
10469
10566
  return;
10470
10567
  onPatch(diff);
10471
10568
  },
10472
- [initialValues2, onPatch]
10569
+ [getDiff, onPatch, requiresDiff]
10473
10570
  );
10474
10571
  const validate = useCallback(
10475
10572
  (form) => {
@@ -10477,9 +10574,13 @@ const PatchFormProvider = memo(
10477
10574
  if (error2) {
10478
10575
  onError(error2);
10479
10576
  }
10577
+ if (onDirtyChange) {
10578
+ const diff = getDiff(form);
10579
+ onDirtyChange(hasKeys(diff));
10580
+ }
10480
10581
  return error2;
10481
10582
  },
10482
- [schema, onError]
10583
+ [schema, onDirtyChange, onError, getDiff]
10483
10584
  );
10484
10585
  const formik = useFormik({
10485
10586
  initialValues: initialValues2,
@@ -10489,13 +10590,21 @@ const PatchFormProvider = memo(
10489
10590
  validateOnBlur: false,
10490
10591
  validateOnChange: false
10491
10592
  });
10593
+ const handleChange = useCallback(() => {
10594
+ if (onDirtyChange) {
10595
+ const diff = getDiff(formik.values);
10596
+ if (hasKeys(diff)) {
10597
+ onDirtyChange(true);
10598
+ }
10599
+ }
10600
+ }, [formik.values, getDiff, onDirtyChange]);
10492
10601
  const { errors, resetForm } = formik;
10493
10602
  useEffect(() => {
10494
10603
  if (hasKeys(errors)) {
10495
10604
  resetForm({ values: initialValues2, errors: {} });
10496
10605
  }
10497
10606
  }, [errors, initialValues2, resetForm]);
10498
- return /* @__PURE__ */ jsx(FormikProvider, { value: formik, children: /* @__PURE__ */ jsx("form", { ...rest, ref, onSubmit: formik.handleSubmit, children }) });
10607
+ return /* @__PURE__ */ jsx(FormikProvider, { value: formik, children: /* @__PURE__ */ jsx("form", { ...rest, ref, onSubmit: formik.handleSubmit, onChange: handleChange, children }) });
10499
10608
  })
10500
10609
  );
10501
10610
  const typeBadge$1 = "_typeBadge_an5ff_1";
@@ -10509,8 +10618,12 @@ const forMobile = (mobile, display) => ({
10509
10618
  sm: mobile ? "none" : display
10510
10619
  });
10511
10620
  const FieldActions = memo((props) => {
10512
- const { index: index2, sectionIndex, remove: remove2, duplicate, move } = props;
10621
+ const { index: index2, type, sectionIndex, remove: remove2, duplicate, move, upload } = props;
10622
+ if (type !== "section" && !upload) {
10623
+ throw new Error("Upload function prop must be defined for non-section fields.");
10624
+ }
10513
10625
  const { values } = useFormikContext();
10626
+ const fileInputRef = useRef(null);
10514
10627
  const actions = useMemo(() => {
10515
10628
  const actions2 = [
10516
10629
  {
@@ -10521,11 +10634,24 @@ const FieldActions = memo((props) => {
10521
10634
  },
10522
10635
  {
10523
10636
  Icon: TrashIcon,
10524
- buttonProps: { onClick: remove2 },
10525
10637
  key: "delete",
10526
- text: "Delete"
10638
+ text: "Delete",
10639
+ buttonProps: { onClick: remove2 }
10527
10640
  }
10528
10641
  ];
10642
+ if (type !== "section") {
10643
+ actions2.unshift({
10644
+ Icon: ImageIcon,
10645
+ key: "upload",
10646
+ text: "Upload image",
10647
+ buttonProps: {
10648
+ onClick: () => {
10649
+ var _a2;
10650
+ (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
10651
+ }
10652
+ }
10653
+ });
10654
+ }
10529
10655
  if (sectionIndex === void 0 && index2 !== values.fields.length - 1 || sectionIndex !== void 0 && (sectionIndex < values.fields.length - 1 || index2 !== values.fields[sectionIndex].fields.length - 1)) {
10530
10656
  actions2.unshift({
10531
10657
  Icon: ArrowDownIcon,
@@ -10551,8 +10677,8 @@ const FieldActions = memo((props) => {
10551
10677
  });
10552
10678
  }
10553
10679
  return actions2;
10554
- }, [duplicate, index2, move, remove2, sectionIndex, values.fields]);
10555
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
10680
+ }, [duplicate, index2, move, remove2, sectionIndex, type, values.fields]);
10681
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
10556
10682
  /* @__PURE__ */ jsx(Flex, { display: forMobile(false, "flex"), direction: "column", gap: "5", mx: "2", children: actions.map((Action) => /* @__PURE__ */ jsx(
10557
10683
  IconButton,
10558
10684
  {
@@ -10580,17 +10706,36 @@ const FieldActions = memo((props) => {
10580
10706
  };
10581
10707
  })
10582
10708
  }
10583
- ) })
10709
+ ) }),
10710
+ type !== "section" && /* @__PURE__ */ jsx("input", { style: { display: "none" }, ref: fileInputRef, type: "file", accept: "image/*", onChange: upload })
10584
10711
  ] });
10585
10712
  });
10586
10713
  FieldActions.displayName = "FieldActions";
10587
- const popoverInputsContainer = "_popoverInputsContainer_wqdmr_1";
10588
- const typeBadge = "_typeBadge_wqdmr_5";
10589
- const previewInput = "_previewInput_wqdmr_10";
10590
- const directInput = "_directInput_wqdmr_14";
10591
- const grow = "_grow_wqdmr_19";
10714
+ const description = "_description_13g4a_1";
10715
+ const floatingButtonContainer = "_floatingButtonContainer_13g4a_5";
10716
+ const FullScreenImageContainer = "_FullScreenImageContainer_13g4a_12";
10717
+ const fileName = "_fileName_13g4a_22";
10718
+ const longIconButton = "_longIconButton_13g4a_27";
10719
+ const previewImage = "_previewImage_13g4a_33";
10720
+ const FullScreenImage = "_FullScreenImage_13g4a_12";
10721
+ const popoverInputsContainer = "_popoverInputsContainer_13g4a_51";
10722
+ const imageContainer = "_imageContainer_13g4a_55";
10723
+ const deleteImageButton = "_deleteImageButton_13g4a_60";
10724
+ const typeBadge = "_typeBadge_13g4a_71";
10725
+ const previewInput = "_previewInput_13g4a_76";
10726
+ const directInput = "_directInput_13g4a_80";
10727
+ const grow = "_grow_13g4a_85";
10592
10728
  const styles = {
10729
+ description,
10730
+ floatingButtonContainer,
10731
+ FullScreenImageContainer,
10732
+ fileName,
10733
+ longIconButton,
10734
+ previewImage,
10735
+ FullScreenImage,
10593
10736
  popoverInputsContainer,
10737
+ imageContainer,
10738
+ deleteImageButton,
10594
10739
  typeBadge,
10595
10740
  previewInput,
10596
10741
  directInput,
@@ -10626,6 +10771,9 @@ const useFieldTypeItems = (onSelect = () => null) => {
10626
10771
  });
10627
10772
  }, [onSelect]);
10628
10773
  };
10774
+ const isSection = (field) => {
10775
+ return field.type === "section";
10776
+ };
10629
10777
  const FieldSettingsPopover = memo((props) => {
10630
10778
  const { popoverInputs, hasError } = props;
10631
10779
  return /* @__PURE__ */ jsx(
@@ -10655,6 +10803,8 @@ FieldSettingsPopover.displayName = "FieldSettingsPopover";
10655
10803
  const FieldBuilder = memo((props) => {
10656
10804
  var _a2, _b, _c, _d, _e, _f;
10657
10805
  const { parentPath, index: index2, initial, conditionalSourceFields } = props;
10806
+ const { values, setFieldValue, errors } = useFormikContext();
10807
+ const fieldTypeItems = useFieldTypeItems();
10658
10808
  const RADIX_SM_MIN_WIDTH = 576;
10659
10809
  const [isLargeScreen, setIsLargeScreen] = useState(
10660
10810
  window.matchMedia(`(min-width: ${RADIX_SM_MIN_WIDTH}px)`).matches
@@ -10669,22 +10819,39 @@ const FieldBuilder = memo((props) => {
10669
10819
  mediaQuery.removeEventListener("change", handleMediaQueryChange);
10670
10820
  };
10671
10821
  }, []);
10672
- const { values, setFieldValue, errors } = useFormikContext();
10673
- const fieldTypeItems = useFieldTypeItems();
10674
- const isSection = useCallback((field) => {
10675
- return field.type === "section";
10676
- }, []);
10822
+ const [resolvedImage, setResolvedImage] = useState(void 0);
10823
+ const [showImagePreview, setShowImagePreview] = useState(false);
10824
+ useEffect(() => {
10825
+ if (!isSection(initial)) {
10826
+ if (initial.image instanceof Promise) {
10827
+ initial.image.then(setResolvedImage).catch(console.error);
10828
+ } else {
10829
+ setResolvedImage(initial.image);
10830
+ }
10831
+ } else {
10832
+ setResolvedImage(void 0);
10833
+ }
10834
+ }, [initial]);
10835
+ const resolvedImageURL = resolvedImage ? URL.createObjectURL(resolvedImage) : void 0;
10836
+ const handleImageDelete = useCallback(
10837
+ (event) => {
10838
+ event.stopPropagation();
10839
+ const { image: _, ...fieldWithoutImage } = initial;
10840
+ void setFieldValue(`${parentPath}.${index2}`, fieldWithoutImage).then();
10841
+ },
10842
+ [index2, initial, parentPath, setFieldValue]
10843
+ );
10677
10844
  useEffect(() => {
10678
10845
  if (isSection(initial) && !initial.conditional) {
10679
10846
  void setFieldValue(`${parentPath}.${index2}.condition`, null).then();
10680
10847
  }
10681
- }, [index2, initial, isSection, parentPath, setFieldValue]);
10848
+ }, [index2, initial, parentPath, setFieldValue]);
10682
10849
  const conditionLabel = useMemo(
10683
10850
  () => {
10684
10851
  var _a3, _b2;
10685
10852
  return isSection(initial) ? (_b2 = findFieldByIdentifier(values.fields, (_a3 = initial.condition) == null ? void 0 : _a3.identifier)) == null ? void 0 : _b2.label : void 0;
10686
10853
  },
10687
- [initial, isSection, values.fields]
10854
+ [initial, values.fields]
10688
10855
  );
10689
10856
  const conditionComparison = isSection(initial) ? Array.isArray((_a2 = initial.condition) == null ? void 0 : _a2.value) ? "contains all of" : "equals" : void 0;
10690
10857
  let conditionValue = void 0;
@@ -10795,6 +10962,41 @@ const FieldBuilder = memo((props) => {
10795
10962
  /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "3", children: [
10796
10963
  /* @__PURE__ */ jsx(Badge, { className: styles.typeBadge, children: (_f = fieldTypeItems.flat().find((item) => item.value === type)) == null ? void 0 : _f.content }),
10797
10964
  showPopoverInputs && /* @__PURE__ */ jsx(FieldSettingsPopover, { popoverInputs, hasError: popoverHasErrors })
10965
+ ] }),
10966
+ resolvedImage && /* @__PURE__ */ jsxs(Fragment, { children: [
10967
+ /* @__PURE__ */ jsxs("div", { className: styles.imageContainer, children: [
10968
+ /* @__PURE__ */ jsx(
10969
+ "img",
10970
+ {
10971
+ className: styles.previewImage,
10972
+ src: resolvedImageURL,
10973
+ alt: resolvedImage.name,
10974
+ onClick: () => {
10975
+ setShowImagePreview(true);
10976
+ }
10977
+ }
10978
+ ),
10979
+ /* @__PURE__ */ jsx(
10980
+ IconButton,
10981
+ {
10982
+ className: styles.deleteImageButton,
10983
+ variant: "solid",
10984
+ severity: "danger",
10985
+ "aria-label": "delete",
10986
+ onClick: handleImageDelete,
10987
+ children: /* @__PURE__ */ jsx(TrashIcon, {})
10988
+ }
10989
+ )
10990
+ ] }),
10991
+ showImagePreview && /* @__PURE__ */ jsx(
10992
+ FullScreenImagePreview,
10993
+ {
10994
+ file: resolvedImage,
10995
+ url: resolvedImageURL,
10996
+ name: resolvedImage.name,
10997
+ setShowPreview: setShowImagePreview
10998
+ }
10999
+ )
10798
11000
  ] })
10799
11001
  ] }),
10800
11002
  /* @__PURE__ */ jsx(
@@ -10851,6 +11053,7 @@ const FieldWithActions = memo((props) => {
10851
11053
  const { field, index: index2, sectionIndex, takenLabels, remove: remove2 } = props;
10852
11054
  const { setFieldValue, values } = useFormikContext();
10853
11055
  const { reorderField } = useFieldReordering();
11056
+ const { showError } = useToast();
10854
11057
  const parentPath = `fields.${sectionIndex}.fields`;
10855
11058
  const editFieldProps = useMemo(
10856
11059
  () => ({
@@ -10894,6 +11097,28 @@ const FieldWithActions = memo((props) => {
10894
11097
  },
10895
11098
  [sectionIndex, values.fields, index2, reorderField, setFieldValue]
10896
11099
  );
11100
+ const uploadImage = useCallback(
11101
+ (event) => {
11102
+ const { files } = event.target;
11103
+ if (!files || files.length !== 1)
11104
+ return;
11105
+ const file = files.item(0);
11106
+ if (!file)
11107
+ return;
11108
+ if (file.size > maxFileSizeB) {
11109
+ showError({
11110
+ title: "File upload error",
11111
+ description: `The file ${file.name} exceeded the maximum file size`
11112
+ });
11113
+ return;
11114
+ }
11115
+ void setFieldValue(`${parentPath}.${index2}`, {
11116
+ ...field,
11117
+ image: file
11118
+ }).then();
11119
+ },
11120
+ [field, index2, parentPath, setFieldValue, showError]
11121
+ );
10897
11122
  return /* @__PURE__ */ jsx(Draggable, { draggableId: field.identifier, index: index2, children: (draggableProvided) => /* @__PURE__ */ jsx(
10898
11123
  Card,
10899
11124
  {
@@ -10912,10 +11137,12 @@ const FieldWithActions = memo((props) => {
10912
11137
  FieldActions,
10913
11138
  {
10914
11139
  index: index2,
11140
+ type: field.type,
10915
11141
  sectionIndex,
10916
11142
  remove: remove2,
10917
11143
  duplicate: duplicateField,
10918
- move: moveField
11144
+ move: moveField,
11145
+ upload: uploadImage
10919
11146
  }
10920
11147
  )
10921
11148
  ] })
@@ -10923,12 +11150,6 @@ const FieldWithActions = memo((props) => {
10923
11150
  ) });
10924
11151
  });
10925
11152
  FieldWithActions.displayName = "FieldWithActions";
10926
- const FieldTypeDropdown = memo((props) => {
10927
- const { setFieldType, children } = props;
10928
- const fieldTypeItems = useFieldTypeItems(setFieldType);
10929
- return /* @__PURE__ */ jsx(DropdownItemMenu, { trigger: children, items: fieldTypeItems.flat() });
10930
- });
10931
- FieldTypeDropdown.displayName = "FieldTypeDropdown";
10932
11153
  const FieldSectionWithActions = memo((props) => {
10933
11154
  var _a2;
10934
11155
  const { field, index: sectionIndex, dropState } = props;
@@ -11064,6 +11285,7 @@ const FieldSectionWithActions = memo((props) => {
11064
11285
  },
11065
11286
  [sectionIndex, field.fields.length, values, setFieldValue]
11066
11287
  );
11288
+ const fieldTypeItems = useFieldTypeItems(handleCreateField);
11067
11289
  return /* @__PURE__ */ jsx(Draggable, { draggableId: field.identifier, index: sectionIndex, children: (draggableProvided) => {
11068
11290
  return /* @__PURE__ */ jsx(
11069
11291
  Card,
@@ -11103,10 +11325,16 @@ const FieldSectionWithActions = memo((props) => {
11103
11325
  child.identifier
11104
11326
  )),
11105
11327
  droppableProvided.placeholder,
11106
- /* @__PURE__ */ jsx(FieldTypeDropdown, { setFieldType: handleCreateField, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "soft", children: [
11107
- /* @__PURE__ */ jsx(PlusIcon, {}),
11108
- " Add field"
11109
- ] }) })
11328
+ /* @__PURE__ */ jsx(
11329
+ DropdownItemMenu,
11330
+ {
11331
+ trigger: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "soft", children: [
11332
+ /* @__PURE__ */ jsx(PlusIcon, {}),
11333
+ " Add field"
11334
+ ] }),
11335
+ items: fieldTypeItems.flat()
11336
+ }
11337
+ )
11110
11338
  ]
11111
11339
  }
11112
11340
  )
@@ -11117,6 +11345,7 @@ const FieldSectionWithActions = memo((props) => {
11117
11345
  FieldActions,
11118
11346
  {
11119
11347
  index: sectionIndex,
11348
+ type: field.type,
11120
11349
  remove: removeSection,
11121
11350
  duplicate: duplicateSection,
11122
11351
  move: moveSection
@@ -11241,7 +11470,7 @@ const FieldsEditor = memo(() => {
11241
11470
  direction: "column",
11242
11471
  gap: "0",
11243
11472
  children: [
11244
- values.fields.map((field, index2) => /* @__PURE__ */ jsxs(Fragment, { children: [
11473
+ values.fields.map((field, index2) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
11245
11474
  /* @__PURE__ */ jsx(FieldSectionWithActions, { field, index: index2, dropState }),
11246
11475
  /* @__PURE__ */ jsxs(
11247
11476
  Button,
@@ -11496,9 +11725,6 @@ export {
11496
11725
  IssuePriority,
11497
11726
  IssueService,
11498
11727
  IssueStatus,
11499
- LicenseLevel,
11500
- LicenseService,
11501
- LicenseStatus,
11502
11728
  MainService,
11503
11729
  MapStyle,
11504
11730
  MultiSelectField,
@@ -11546,7 +11772,6 @@ export {
11546
11772
  addEmailDomain,
11547
11773
  addFavouriteProjectId,
11548
11774
  addIssue,
11549
- addLicenses,
11550
11775
  addOrReplaceCategories,
11551
11776
  addOrReplaceIssueComment,
11552
11777
  addOrReplaceProjectFile,
@@ -11559,6 +11784,7 @@ export {
11559
11784
  addToRecentIssues,
11560
11785
  addUserForm,
11561
11786
  addUserFormRevision,
11787
+ addUserFormRevisionAttachment,
11562
11788
  addUserFormRevisions,
11563
11789
  addUserFormSubmission,
11564
11790
  addUserFormSubmissionAttachment,
@@ -11645,8 +11871,6 @@ export {
11645
11871
  issueReducer,
11646
11872
  issueSlice,
11647
11873
  issueToSearchResult,
11648
- licenseReducer,
11649
- licenseSlice,
11650
11874
  literalToCoordinates,
11651
11875
  logOnlyOnce,
11652
11876
  makeClient,
@@ -11713,20 +11937,17 @@ export {
11713
11937
  searchIssues,
11714
11938
  selectAccessToken,
11715
11939
  selectActiveIssueId,
11716
- selectActiveLicense,
11717
11940
  selectActiveOrganization,
11718
11941
  selectActiveOrganizationAccess,
11719
11942
  selectActiveOrganizationId,
11720
- selectActiveOrganizationLicenses,
11721
- selectActiveOrganizationProjects,
11722
11943
  selectActiveProject,
11723
11944
  selectActiveProjectAccess,
11724
11945
  selectActiveProjectFileId,
11725
11946
  selectActiveProjectId,
11726
- selectActiveStatusLicenses,
11727
11947
  selectActiveWorkspace,
11728
11948
  selectActiveWorkspaceId,
11729
11949
  selectAllAttachments,
11950
+ selectAllRevisionAttachmentsByLatestRevisionId,
11730
11951
  selectAppearance,
11731
11952
  selectCategories,
11732
11953
  selectCategoriesOfWorkspace,
@@ -11768,7 +11989,6 @@ export {
11768
11989
  selectHiddenComponentTypeIds,
11769
11990
  selectIsFetchingInitialData,
11770
11991
  selectIsImportingProjectFile,
11771
- selectIsLoading,
11772
11992
  selectIsLoggedIn,
11773
11993
  selectIssue,
11774
11994
  selectIssueAttachmentMapping,
@@ -11778,10 +11998,6 @@ export {
11778
11998
  selectLatestFormRevision,
11779
11999
  selectLatestRetryTime,
11780
12000
  selectLatestRevisionByFormId,
11781
- selectLicencesMapping,
11782
- selectLicense,
11783
- selectLicenseForProject,
11784
- selectLicenses,
11785
12001
  selectMainWorkspace,
11786
12002
  selectMapStyle,
11787
12003
  selectNumberOfComponentTypesMatchingCaseInsensitiveName,
@@ -11795,7 +12011,6 @@ export {
11795
12011
  selectOrganizationUsersAsMapping,
11796
12012
  selectOrganizationUsersIds,
11797
12013
  selectOrganizations,
11798
- selectOrganizationsMapping,
11799
12014
  selectOrganizationsWithAccess,
11800
12015
  selectPermittedWorkspaceIds,
11801
12016
  selectPhotoAttachmentsOfIssue,
@@ -11813,10 +12028,10 @@ export {
11813
12028
  selectRecentIssuesAsSearchResults,
11814
12029
  selectRecentProjects,
11815
12030
  selectRehydrated,
12031
+ selectRevisionAttachments,
11816
12032
  selectRevisionsForForm,
11817
12033
  selectShowTooltips,
11818
12034
  selectSortedEmailDomains,
11819
- selectSortedOrganizationLicenses,
11820
12035
  selectSortedOrganizationUsers,
11821
12036
  selectSortedProjectUsers,
11822
12037
  selectSortedProjects,
@@ -11859,10 +12074,8 @@ export {
11859
12074
  setEnablePlacementMode,
11860
12075
  setIsFetchingInitialData,
11861
12076
  setIsImportingProjectFile,
11862
- setIsLoading,
11863
12077
  setIssueComments,
11864
12078
  setIssues,
11865
- setLicenses,
11866
12079
  setLoggedIn,
11867
12080
  setMapStyle,
11868
12081
  setOrganizationAccesses,
@@ -11877,6 +12090,7 @@ export {
11877
12090
  setTokens,
11878
12091
  setTourStep,
11879
12092
  setUploadUrl,
12093
+ setUserFormRevisionAttachments,
11880
12094
  setUserFormSubmissionAttachments,
11881
12095
  setUserFormSubmissions,
11882
12096
  setUsers,
@@ -11897,12 +12111,9 @@ export {
11897
12111
  unhideAllCategories,
11898
12112
  unhideCategory,
11899
12113
  updateActiveOrganization,
11900
- updateActiveProjectFormSubmissionsCount,
11901
- updateActiveProjectIssuesCount,
11902
12114
  updateAttachment,
11903
12115
  updateComponent,
11904
12116
  updateIssue,
11905
- updateLicense,
11906
12117
  updateOrCreateProject,
11907
12118
  updateOrganizationAccess,
11908
12119
  updateProjectAccess,