@overmap-ai/core 1.0.49 → 1.0.50-bulk-form-submission.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/forms/renderer/FormSubmissionBrowser/FormSubmissionBrowser.d.ts +5 -5
- package/dist/forms/renderer/FormSubmissionViewer/FormSubmissionViewer.d.ts +3 -3
- package/dist/overmap-core.js +889 -454
- package/dist/overmap-core.js.map +1 -1
- package/dist/overmap-core.umd.cjs +889 -454
- package/dist/overmap-core.umd.cjs.map +1 -1
- package/dist/sdk/services/AttachmentService.d.ts +9 -7
- package/dist/sdk/services/UserFormSubmissionService.d.ts +9 -2
- package/dist/store/slices/categorySlice.d.ts +3 -1
- package/dist/store/slices/componentSlice.d.ts +1 -0
- package/dist/store/slices/componentTypeSlice.d.ts +1 -0
- package/dist/store/slices/documentSlice.d.ts +38 -3
- package/dist/store/slices/formRevisionSlice.d.ts +73 -0
- package/dist/store/slices/formSlice.d.ts +118 -0
- package/dist/store/slices/formSubmissionSlice.d.ts +47 -0
- package/dist/store/slices/index.d.ts +3 -1
- package/dist/store/slices/issueSlice.d.ts +13 -2
- package/dist/store/slices/projectFileSlice.d.ts +3 -1
- package/dist/store/slices/utils.d.ts +1 -0
- package/dist/store/slices/workspaceSlice.d.ts +3 -1
- package/dist/store/store.d.ts +10 -4
- package/dist/typings/files.d.ts +11 -1
- package/dist/typings/models/attachments.d.ts +11 -10
- package/dist/typings/models/base.d.ts +7 -0
- package/dist/typings/models/forms.d.ts +6 -11
- package/dist/utils/file.d.ts +2 -0
- package/package.json +1 -1
- package/dist/store/slices/userFormSlice.d.ts +0 -145
package/dist/overmap-core.js
CHANGED
|
@@ -631,15 +631,15 @@ const wrapMigration = (migrator) => (state) => {
|
|
|
631
631
|
};
|
|
632
632
|
const migrations = [initialVersioning, signOut, signOut, createOutboxState];
|
|
633
633
|
const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
|
|
634
|
-
const initialState$
|
|
634
|
+
const initialState$p = {
|
|
635
635
|
accessToken: "",
|
|
636
636
|
refreshToken: "",
|
|
637
637
|
isLoggedIn: false
|
|
638
638
|
};
|
|
639
639
|
const authSlice = createSlice({
|
|
640
640
|
name: "auth",
|
|
641
|
-
initialState: initialState$
|
|
642
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
641
|
+
initialState: initialState$p,
|
|
642
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$p)),
|
|
643
643
|
reducers: {
|
|
644
644
|
setTokens: (state, action) => {
|
|
645
645
|
state.accessToken = action.payload.accessToken;
|
|
@@ -804,6 +804,19 @@ function downloadInMemoryFile(filename, text) {
|
|
|
804
804
|
element.click();
|
|
805
805
|
document.body.removeChild(element);
|
|
806
806
|
}
|
|
807
|
+
const constructUploadedFilePayloads = async (files) => {
|
|
808
|
+
const filePayloads = {};
|
|
809
|
+
for (const file of files) {
|
|
810
|
+
const sha1 = await hashFile(file);
|
|
811
|
+
filePayloads[sha1] = {
|
|
812
|
+
sha1,
|
|
813
|
+
extension: file.name.split(".").pop() || "",
|
|
814
|
+
file_type: file.type,
|
|
815
|
+
size: file.size
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
return Object.values(filePayloads);
|
|
819
|
+
};
|
|
807
820
|
const fileToBlob = async (dataUrl) => {
|
|
808
821
|
return (await fetch(dataUrl)).blob();
|
|
809
822
|
};
|
|
@@ -1370,7 +1383,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
|
|
|
1370
1383
|
return getLocalDateString(date);
|
|
1371
1384
|
return relative.format(days, "days");
|
|
1372
1385
|
});
|
|
1373
|
-
const initialState$
|
|
1386
|
+
const initialState$o = {
|
|
1374
1387
|
categories: {},
|
|
1375
1388
|
usedCategoryColors: [],
|
|
1376
1389
|
categoryVisibility: {
|
|
@@ -1380,8 +1393,8 @@ const initialState$m = {
|
|
|
1380
1393
|
};
|
|
1381
1394
|
const categorySlice = createSlice({
|
|
1382
1395
|
name: "categories",
|
|
1383
|
-
initialState: initialState$
|
|
1384
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1396
|
+
initialState: initialState$o,
|
|
1397
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$o)),
|
|
1385
1398
|
reducers: {
|
|
1386
1399
|
setCategories: (state, action) => {
|
|
1387
1400
|
if (!Array.isArray(action.payload))
|
|
@@ -1515,6 +1528,7 @@ const selectHiddenCategoryCount = (state) => {
|
|
|
1515
1528
|
};
|
|
1516
1529
|
const categoryReducer = categorySlice.reducer;
|
|
1517
1530
|
function setAttachments(state, action) {
|
|
1531
|
+
state.attachments = {};
|
|
1518
1532
|
for (const attachment of action.payload) {
|
|
1519
1533
|
state.attachments[attachment.offline_id] = attachment;
|
|
1520
1534
|
}
|
|
@@ -1537,6 +1551,15 @@ function updateAttachment(state, action) {
|
|
|
1537
1551
|
throw new Error(`Attachment ${action.payload.offline_id} does not exist.`);
|
|
1538
1552
|
}
|
|
1539
1553
|
}
|
|
1554
|
+
function updateAttachments(state, action) {
|
|
1555
|
+
for (const attachment of action.payload) {
|
|
1556
|
+
if (attachment.offline_id in state.attachments) {
|
|
1557
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
1558
|
+
} else {
|
|
1559
|
+
throw new Error(`Attachment ${attachment.offline_id} does not exist.`);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1540
1563
|
function removeAttachment(state, action) {
|
|
1541
1564
|
if (action.payload in state.attachments) {
|
|
1542
1565
|
delete state.attachments[action.payload];
|
|
@@ -1549,14 +1572,14 @@ function removeAttachments(state, action) {
|
|
|
1549
1572
|
delete state.attachments[attachmentId];
|
|
1550
1573
|
}
|
|
1551
1574
|
}
|
|
1552
|
-
const initialState$
|
|
1575
|
+
const initialState$n = {
|
|
1553
1576
|
components: {},
|
|
1554
1577
|
attachments: {}
|
|
1555
1578
|
};
|
|
1556
1579
|
const componentSlice = createSlice({
|
|
1557
1580
|
name: "components",
|
|
1558
|
-
initialState: initialState$
|
|
1559
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1581
|
+
initialState: initialState$n,
|
|
1582
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
|
|
1560
1583
|
reducers: {
|
|
1561
1584
|
addComponent: (state, action) => {
|
|
1562
1585
|
state.components[action.payload.offline_id] = action.payload;
|
|
@@ -1669,6 +1692,9 @@ const selectAllComponentAttachments = createSelector(
|
|
|
1669
1692
|
[selectComponentAttachmentMapping],
|
|
1670
1693
|
(mapping) => Object.values(mapping)
|
|
1671
1694
|
);
|
|
1695
|
+
const selectComponentAttachment = (attachmentId) => (state) => {
|
|
1696
|
+
return state.componentReducer.attachments[attachmentId];
|
|
1697
|
+
};
|
|
1672
1698
|
const selectAttachmentsOfComponent = restructureCreateSelectorWithArgs(
|
|
1673
1699
|
createSelector(
|
|
1674
1700
|
[selectAllComponentAttachments, (_state, componentId) => componentId],
|
|
@@ -1709,13 +1735,13 @@ const {
|
|
|
1709
1735
|
removeAllComponentsOfType
|
|
1710
1736
|
} = componentSlice.actions;
|
|
1711
1737
|
const componentReducer = componentSlice.reducer;
|
|
1712
|
-
const initialState$
|
|
1738
|
+
const initialState$m = {
|
|
1713
1739
|
completionsByComponentId: {}
|
|
1714
1740
|
};
|
|
1715
1741
|
const componentStageCompletionSlice = createSlice({
|
|
1716
1742
|
name: "componentStageCompletions",
|
|
1717
|
-
initialState: initialState$
|
|
1718
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1743
|
+
initialState: initialState$m,
|
|
1744
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
|
|
1719
1745
|
reducers: {
|
|
1720
1746
|
addStageCompletion: (state, action) => {
|
|
1721
1747
|
let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
|
|
@@ -1766,13 +1792,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
|
|
|
1766
1792
|
return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
|
|
1767
1793
|
};
|
|
1768
1794
|
const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
|
|
1769
|
-
const initialState$
|
|
1795
|
+
const initialState$l = {
|
|
1770
1796
|
stages: {}
|
|
1771
1797
|
};
|
|
1772
1798
|
const componentStageSlice = createSlice({
|
|
1773
1799
|
name: "componentStages",
|
|
1774
|
-
initialState: initialState$
|
|
1775
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1800
|
+
initialState: initialState$l,
|
|
1801
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
|
|
1776
1802
|
reducers: {
|
|
1777
1803
|
addStages: (state, action) => {
|
|
1778
1804
|
Object.assign(state.stages, toOfflineIdRecord(action.payload));
|
|
@@ -1882,15 +1908,15 @@ const selectStageFormIdsFromStageIds = restructureCreateSelectorWithArgs(
|
|
|
1882
1908
|
);
|
|
1883
1909
|
const { addStages, updateStages, removeStages, linkStageToForm, unlinkStageToForm } = componentStageSlice.actions;
|
|
1884
1910
|
const componentStageReducer = componentStageSlice.reducer;
|
|
1885
|
-
const initialState$
|
|
1911
|
+
const initialState$k = {
|
|
1886
1912
|
componentTypes: {},
|
|
1887
1913
|
hiddenComponentTypeIds: {},
|
|
1888
1914
|
attachments: {}
|
|
1889
1915
|
};
|
|
1890
1916
|
const componentTypeSlice = createSlice({
|
|
1891
1917
|
name: "componentTypes",
|
|
1892
|
-
initialState: initialState$
|
|
1893
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1918
|
+
initialState: initialState$k,
|
|
1919
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
|
|
1894
1920
|
reducers: {
|
|
1895
1921
|
addComponentType: (state, action) => {
|
|
1896
1922
|
state.componentTypes[action.payload.offline_id] = action.payload;
|
|
@@ -1958,6 +1984,9 @@ const selectAllComponentTypeAttachments = createSelector(
|
|
|
1958
1984
|
[selectComponentTypeAttachmentMapping],
|
|
1959
1985
|
(mapping) => Object.values(mapping)
|
|
1960
1986
|
);
|
|
1987
|
+
const selectComponentTypeAttachment = (attachmentId) => (state) => {
|
|
1988
|
+
return state.componentTypeReducer.attachments[attachmentId];
|
|
1989
|
+
};
|
|
1961
1990
|
const selectAttachmentsOfComponentType = restructureCreateSelectorWithArgs(
|
|
1962
1991
|
createSelector(
|
|
1963
1992
|
[selectAllComponentTypeAttachments, (_state, componentTypeId) => componentTypeId],
|
|
@@ -1998,13 +2027,13 @@ const {
|
|
|
1998
2027
|
deleteComponentType
|
|
1999
2028
|
} = componentTypeSlice.actions;
|
|
2000
2029
|
const componentTypeReducer = componentTypeSlice.reducer;
|
|
2001
|
-
const initialState$
|
|
2030
|
+
const initialState$j = {
|
|
2002
2031
|
workspaces: {},
|
|
2003
2032
|
activeWorkspaceId: null
|
|
2004
2033
|
};
|
|
2005
2034
|
const workspaceSlice = createSlice({
|
|
2006
2035
|
name: "workspace",
|
|
2007
|
-
initialState: initialState$
|
|
2036
|
+
initialState: initialState$j,
|
|
2008
2037
|
// The `reducers` field lets us define reducers and generate associated actions
|
|
2009
2038
|
reducers: {
|
|
2010
2039
|
setWorkspaces: (state, action) => {
|
|
@@ -2061,7 +2090,7 @@ const selectPermittedWorkspaceIds = createSelector(
|
|
|
2061
2090
|
);
|
|
2062
2091
|
const workspaceReducer = workspaceSlice.reducer;
|
|
2063
2092
|
const maxRecentIssues = 10;
|
|
2064
|
-
const initialState$
|
|
2093
|
+
const initialState$i = {
|
|
2065
2094
|
issues: {},
|
|
2066
2095
|
attachments: {},
|
|
2067
2096
|
comments: {},
|
|
@@ -2073,9 +2102,9 @@ const initialState$g = {
|
|
|
2073
2102
|
};
|
|
2074
2103
|
const issueSlice = createSlice({
|
|
2075
2104
|
name: "issues",
|
|
2076
|
-
initialState: initialState$
|
|
2105
|
+
initialState: initialState$i,
|
|
2077
2106
|
extraReducers: (builder) => builder.addCase("RESET", (state) => {
|
|
2078
|
-
Object.assign(state, initialState$
|
|
2107
|
+
Object.assign(state, initialState$i);
|
|
2079
2108
|
}),
|
|
2080
2109
|
reducers: {
|
|
2081
2110
|
setIssues: (state, action) => {
|
|
@@ -2130,6 +2159,7 @@ const issueSlice = createSlice({
|
|
|
2130
2159
|
}
|
|
2131
2160
|
},
|
|
2132
2161
|
updateIssueAttachment: updateAttachment,
|
|
2162
|
+
updateIssueAttachments: updateAttachments,
|
|
2133
2163
|
removeIssue: (state, action) => {
|
|
2134
2164
|
if (action.payload in state.issues) {
|
|
2135
2165
|
delete state.issues[action.payload];
|
|
@@ -2138,6 +2168,7 @@ const issueSlice = createSlice({
|
|
|
2138
2168
|
}
|
|
2139
2169
|
},
|
|
2140
2170
|
removeIssueAttachment: removeAttachment,
|
|
2171
|
+
removeIssueAttachments: removeAttachments,
|
|
2141
2172
|
removeIssueUpdate: (state, action) => {
|
|
2142
2173
|
if (action.payload in state.updates) {
|
|
2143
2174
|
delete state.updates[action.payload];
|
|
@@ -2247,6 +2278,7 @@ const {
|
|
|
2247
2278
|
addToRecentIssues,
|
|
2248
2279
|
cleanRecentIssues,
|
|
2249
2280
|
removeIssueAttachment,
|
|
2281
|
+
removeIssueAttachments,
|
|
2250
2282
|
removeAttachmentsOfIssue,
|
|
2251
2283
|
removeIssue,
|
|
2252
2284
|
removeIssueUpdate,
|
|
@@ -2260,6 +2292,7 @@ const {
|
|
|
2260
2292
|
setVisibleStatuses,
|
|
2261
2293
|
setVisibleUserIds,
|
|
2262
2294
|
updateIssueAttachment,
|
|
2295
|
+
updateIssueAttachments,
|
|
2263
2296
|
updateIssue,
|
|
2264
2297
|
// Commments
|
|
2265
2298
|
addIssueComment,
|
|
@@ -2352,6 +2385,9 @@ const selectAttachmentsOfIssue = restructureCreateSelectorWithArgs(
|
|
|
2352
2385
|
}
|
|
2353
2386
|
)
|
|
2354
2387
|
);
|
|
2388
|
+
const selectIssueAttachment = (attachmentId) => (root) => {
|
|
2389
|
+
return root.issueReducer.attachments[attachmentId];
|
|
2390
|
+
};
|
|
2355
2391
|
const selectAttachmentsOfIssueByType = restructureCreateSelectorWithArgs(
|
|
2356
2392
|
createSelector(
|
|
2357
2393
|
[selectIssueAttachments, (_state, issueId) => issueId],
|
|
@@ -2480,15 +2516,15 @@ const selectRecentIssuesAsSearchResults = createSelector(
|
|
|
2480
2516
|
}
|
|
2481
2517
|
);
|
|
2482
2518
|
const issueReducer = issueSlice.reducer;
|
|
2483
|
-
const initialState$
|
|
2519
|
+
const initialState$h = {
|
|
2484
2520
|
s3Urls: {}
|
|
2485
2521
|
};
|
|
2486
2522
|
const msPerHour = 1e3 * 60 * 60;
|
|
2487
2523
|
const msPerWeek = msPerHour * 24 * 7;
|
|
2488
2524
|
const fileSlice = createSlice({
|
|
2489
2525
|
name: "file",
|
|
2490
|
-
initialState: initialState$
|
|
2491
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2526
|
+
initialState: initialState$h,
|
|
2527
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
|
|
2492
2528
|
reducers: {
|
|
2493
2529
|
setUploadUrl: (state, action) => {
|
|
2494
2530
|
const { url, fields, sha1 } = action.payload;
|
|
@@ -2515,7 +2551,7 @@ const selectUploadUrl = (sha1) => (state) => {
|
|
|
2515
2551
|
return url;
|
|
2516
2552
|
};
|
|
2517
2553
|
const fileReducer = fileSlice.reducer;
|
|
2518
|
-
const initialState$
|
|
2554
|
+
const initialState$g = {
|
|
2519
2555
|
// TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
|
|
2520
2556
|
mapStyle: MapStyle.SATELLITE,
|
|
2521
2557
|
showTooltips: false,
|
|
@@ -2523,8 +2559,8 @@ const initialState$e = {
|
|
|
2523
2559
|
};
|
|
2524
2560
|
const mapSlice = createSlice({
|
|
2525
2561
|
name: "map",
|
|
2526
|
-
initialState: initialState$
|
|
2527
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2562
|
+
initialState: initialState$g,
|
|
2563
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
|
|
2528
2564
|
reducers: {
|
|
2529
2565
|
setMapStyle: (state, action) => {
|
|
2530
2566
|
state.mapStyle = action.payload;
|
|
@@ -2593,7 +2629,7 @@ var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
|
|
|
2593
2629
|
LicenseStatus2[LicenseStatus2["PAST_DUE"] = 8] = "PAST_DUE";
|
|
2594
2630
|
return LicenseStatus2;
|
|
2595
2631
|
})(LicenseStatus || {});
|
|
2596
|
-
const initialState$
|
|
2632
|
+
const initialState$f = {
|
|
2597
2633
|
users: {},
|
|
2598
2634
|
currentUser: {
|
|
2599
2635
|
id: 0,
|
|
@@ -2604,8 +2640,8 @@ const initialState$d = {
|
|
|
2604
2640
|
};
|
|
2605
2641
|
const userSlice = createSlice({
|
|
2606
2642
|
name: "users",
|
|
2607
|
-
initialState: initialState$
|
|
2608
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2643
|
+
initialState: initialState$f,
|
|
2644
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
|
|
2609
2645
|
reducers: {
|
|
2610
2646
|
setUsers: (state, action) => {
|
|
2611
2647
|
const usersMapping = {};
|
|
@@ -2667,13 +2703,13 @@ const selectUser = (userId) => (state) => {
|
|
|
2667
2703
|
const selectUsersAsMapping = (state) => state.userReducer.users;
|
|
2668
2704
|
const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
|
|
2669
2705
|
const userReducer = userSlice.reducer;
|
|
2670
|
-
const initialState$
|
|
2706
|
+
const initialState$e = {
|
|
2671
2707
|
organizationAccesses: {}
|
|
2672
2708
|
};
|
|
2673
2709
|
const organizationAccessSlice = createSlice({
|
|
2674
2710
|
name: "organizationAccess",
|
|
2675
|
-
initialState: initialState$
|
|
2676
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2711
|
+
initialState: initialState$e,
|
|
2712
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
|
|
2677
2713
|
reducers: {
|
|
2678
2714
|
setOrganizationAccesses: (state, action) => {
|
|
2679
2715
|
if (!Array.isArray(action.payload))
|
|
@@ -2736,13 +2772,13 @@ const selectOrganizationAccessUserMapping = (state) => {
|
|
|
2736
2772
|
return organizationAccesses;
|
|
2737
2773
|
};
|
|
2738
2774
|
const organizationAccessReducer = organizationAccessSlice.reducer;
|
|
2739
|
-
const initialState$
|
|
2775
|
+
const initialState$d = {
|
|
2740
2776
|
licenses: {}
|
|
2741
2777
|
};
|
|
2742
2778
|
const licenseSlice = createSlice({
|
|
2743
2779
|
name: "license",
|
|
2744
|
-
initialState: initialState$
|
|
2745
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2780
|
+
initialState: initialState$d,
|
|
2781
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
|
|
2746
2782
|
reducers: {
|
|
2747
2783
|
setLicenses: (state, action) => {
|
|
2748
2784
|
if (!Array.isArray(action.payload))
|
|
@@ -2787,13 +2823,13 @@ const selectLicensesForProjectsMapping = createSelector(
|
|
|
2787
2823
|
(licenses) => Object.values(licenses).filter((license) => license.project).reduce((accum, license) => ({ ...accum, [license.project]: license }), {})
|
|
2788
2824
|
);
|
|
2789
2825
|
const licenseReducer = licenseSlice.reducer;
|
|
2790
|
-
const initialState$
|
|
2826
|
+
const initialState$c = {
|
|
2791
2827
|
projectAccesses: {}
|
|
2792
2828
|
};
|
|
2793
2829
|
const projectAccessSlice = createSlice({
|
|
2794
2830
|
name: "projectAccess",
|
|
2795
|
-
initialState: initialState$
|
|
2796
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2831
|
+
initialState: initialState$c,
|
|
2832
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
|
|
2797
2833
|
reducers: {
|
|
2798
2834
|
setProjectAccesses: (state, action) => {
|
|
2799
2835
|
if (!Array.isArray(action.payload))
|
|
@@ -2861,7 +2897,7 @@ const selectProjectAccessUserMapping = (state) => {
|
|
|
2861
2897
|
return projectAccesses;
|
|
2862
2898
|
};
|
|
2863
2899
|
const projectAccessReducer = projectAccessSlice.reducer;
|
|
2864
|
-
const initialState$
|
|
2900
|
+
const initialState$b = {
|
|
2865
2901
|
projects: {},
|
|
2866
2902
|
activeProjectId: null,
|
|
2867
2903
|
recentProjectIds: [],
|
|
@@ -2871,7 +2907,7 @@ const initialState$9 = {
|
|
|
2871
2907
|
};
|
|
2872
2908
|
const projectSlice = createSlice({
|
|
2873
2909
|
name: "projects",
|
|
2874
|
-
initialState: initialState$
|
|
2910
|
+
initialState: initialState$b,
|
|
2875
2911
|
reducers: {
|
|
2876
2912
|
setProjects: (state, action) => {
|
|
2877
2913
|
const projectsMap = {};
|
|
@@ -3058,14 +3094,14 @@ const selectAttachmentsOfProjectByType = restructureCreateSelectorWithArgs(
|
|
|
3058
3094
|
}
|
|
3059
3095
|
)
|
|
3060
3096
|
);
|
|
3061
|
-
const initialState$
|
|
3097
|
+
const initialState$a = {
|
|
3062
3098
|
organizations: {},
|
|
3063
3099
|
activeOrganizationId: null
|
|
3064
3100
|
};
|
|
3065
3101
|
const organizationSlice = createSlice({
|
|
3066
3102
|
name: "organizations",
|
|
3067
|
-
initialState: initialState$
|
|
3068
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
3103
|
+
initialState: initialState$a,
|
|
3104
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
|
|
3069
3105
|
reducers: {
|
|
3070
3106
|
setOrganizations: (state, action) => {
|
|
3071
3107
|
for (const org of action.payload) {
|
|
@@ -3184,14 +3220,14 @@ const createOfflineAction = (request2, baseUrl) => {
|
|
|
3184
3220
|
}
|
|
3185
3221
|
};
|
|
3186
3222
|
};
|
|
3187
|
-
const initialState$
|
|
3223
|
+
const initialState$9 = {
|
|
3188
3224
|
deletedRequests: [],
|
|
3189
3225
|
latestRetryTime: 0
|
|
3190
3226
|
};
|
|
3191
3227
|
const outboxSlice = createSlice({
|
|
3192
3228
|
name: "outbox",
|
|
3193
|
-
initialState: initialState$
|
|
3194
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
3229
|
+
initialState: initialState$9,
|
|
3230
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
|
|
3195
3231
|
reducers: {
|
|
3196
3232
|
// enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
|
|
3197
3233
|
// Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
|
|
@@ -3223,7 +3259,7 @@ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
|
|
|
3223
3259
|
const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
|
|
3224
3260
|
const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
|
|
3225
3261
|
const outboxReducer = outboxSlice.reducer;
|
|
3226
|
-
const initialState$
|
|
3262
|
+
const initialState$8 = {
|
|
3227
3263
|
projectFiles: {},
|
|
3228
3264
|
activeProjectFileId: null,
|
|
3229
3265
|
isImportingProjectFile: false,
|
|
@@ -3231,8 +3267,8 @@ const initialState$6 = {
|
|
|
3231
3267
|
};
|
|
3232
3268
|
const projectFileSlice = createSlice({
|
|
3233
3269
|
name: "projectFiles",
|
|
3234
|
-
initialState: initialState$
|
|
3235
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
3270
|
+
initialState: initialState$8,
|
|
3271
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
|
|
3236
3272
|
reducers: {
|
|
3237
3273
|
addOrReplaceProjectFiles: (state, action) => {
|
|
3238
3274
|
for (let fileObj of action.payload) {
|
|
@@ -3333,12 +3369,12 @@ const selectProjectFiles = createSelector(
|
|
|
3333
3369
|
const selectActiveProjectFileId = (state) => state.projectFileReducer.activeProjectFileId;
|
|
3334
3370
|
const selectIsImportingProjectFile = (state) => state.projectFileReducer.isImportingProjectFile;
|
|
3335
3371
|
const projectFileReducer = projectFileSlice.reducer;
|
|
3336
|
-
const initialState$
|
|
3372
|
+
const initialState$7 = {
|
|
3337
3373
|
isRehydrated: false
|
|
3338
3374
|
};
|
|
3339
3375
|
const rehydratedSlice = createSlice({
|
|
3340
3376
|
name: "rehydrated",
|
|
3341
|
-
initialState: initialState$
|
|
3377
|
+
initialState: initialState$7,
|
|
3342
3378
|
// The `reducers` field lets us define reducers and generate associated actions
|
|
3343
3379
|
reducers: {
|
|
3344
3380
|
setRehydrated: (state, action) => {
|
|
@@ -3348,7 +3384,7 @@ const rehydratedSlice = createSlice({
|
|
|
3348
3384
|
});
|
|
3349
3385
|
const selectRehydrated = (state) => state.rehydratedReducer.isRehydrated;
|
|
3350
3386
|
const rehydratedReducer = rehydratedSlice.reducer;
|
|
3351
|
-
const initialState$
|
|
3387
|
+
const initialState$6 = {
|
|
3352
3388
|
useIssueTemplate: false,
|
|
3353
3389
|
placementMode: false,
|
|
3354
3390
|
enableClustering: false,
|
|
@@ -3365,8 +3401,8 @@ const initialState$4 = {
|
|
|
3365
3401
|
};
|
|
3366
3402
|
const settingSlice = createSlice({
|
|
3367
3403
|
name: "settings",
|
|
3368
|
-
initialState: initialState$
|
|
3369
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
3404
|
+
initialState: initialState$6,
|
|
3405
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
|
|
3370
3406
|
reducers: {
|
|
3371
3407
|
setEnableDuplicateIssues: (state, action) => {
|
|
3372
3408
|
state.useIssueTemplate = action.payload;
|
|
@@ -3412,146 +3448,248 @@ const selectAppearance = (state) => state.settingReducer.appearance;
|
|
|
3412
3448
|
const settingReducer = settingSlice.reducer;
|
|
3413
3449
|
const selectIsFetchingInitialData = (state) => state.settingReducer.isFetchingInitialData;
|
|
3414
3450
|
const selectIsLoading = (state) => state.settingReducer.isLoading;
|
|
3415
|
-
const
|
|
3416
|
-
function
|
|
3451
|
+
const LATEST_FORM_REVISION_CACHE = {};
|
|
3452
|
+
function considerCachingFormRevision(formRevision, formId2, preferPending = false) {
|
|
3417
3453
|
var _a2;
|
|
3418
|
-
if (!
|
|
3454
|
+
if (!formRevision) {
|
|
3419
3455
|
if (!formId2) {
|
|
3420
|
-
throw new Error("If revision is null, formId is required.");
|
|
3456
|
+
throw new Error("If form revision is null, formId is required.");
|
|
3421
3457
|
}
|
|
3422
|
-
const
|
|
3423
|
-
if (
|
|
3458
|
+
const currentLatestFormRevision = getLatestFormRevisionFromCache(formId2);
|
|
3459
|
+
if (currentLatestFormRevision)
|
|
3424
3460
|
return;
|
|
3425
|
-
|
|
3461
|
+
LATEST_FORM_REVISION_CACHE[formId2] = null;
|
|
3426
3462
|
return;
|
|
3427
3463
|
}
|
|
3428
|
-
if (
|
|
3464
|
+
if (formRevision.revision === "Pending") {
|
|
3429
3465
|
if (preferPending) {
|
|
3430
|
-
|
|
3466
|
+
LATEST_FORM_REVISION_CACHE[formRevision.form] = formRevision;
|
|
3431
3467
|
}
|
|
3432
3468
|
return;
|
|
3433
3469
|
}
|
|
3434
|
-
const
|
|
3435
|
-
if (
|
|
3436
|
-
|
|
3470
|
+
const cachedFormRevision = (_a2 = LATEST_FORM_REVISION_CACHE[formRevision.form]) == null ? void 0 : _a2.revision;
|
|
3471
|
+
if (formRevision.revision > (typeof cachedFormRevision === "number" ? cachedFormRevision : -1)) {
|
|
3472
|
+
LATEST_FORM_REVISION_CACHE[formRevision.form] = formRevision;
|
|
3437
3473
|
}
|
|
3438
3474
|
}
|
|
3439
|
-
function
|
|
3440
|
-
return
|
|
3475
|
+
function getLatestFormRevisionFromCache(formId2) {
|
|
3476
|
+
return LATEST_FORM_REVISION_CACHE[formId2];
|
|
3441
3477
|
}
|
|
3442
|
-
const initialState$
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
name: "userForms",
|
|
3451
|
-
initialState: initialState$3,
|
|
3452
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
|
|
3478
|
+
const initialState$5 = {
|
|
3479
|
+
formRevisions: {},
|
|
3480
|
+
attachments: {}
|
|
3481
|
+
};
|
|
3482
|
+
const formRevisionsSlice = createSlice({
|
|
3483
|
+
name: "formRevisions",
|
|
3484
|
+
initialState: initialState$5,
|
|
3485
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
|
|
3453
3486
|
reducers: {
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
action.payload.
|
|
3457
|
-
|
|
3458
|
-
});
|
|
3459
|
-
},
|
|
3460
|
-
addUserForm: (state, action) => {
|
|
3461
|
-
state.userForms[action.payload.offline_id] = action.payload;
|
|
3462
|
-
},
|
|
3463
|
-
addUserForms: (state, action) => {
|
|
3464
|
-
action.payload.forEach((userForm) => {
|
|
3465
|
-
state.userForms[userForm.offline_id] = userForm;
|
|
3466
|
-
});
|
|
3487
|
+
// revision related actions
|
|
3488
|
+
setFormRevision: (state, action) => {
|
|
3489
|
+
state.formRevisions[action.payload.offline_id] = action.payload;
|
|
3490
|
+
considerCachingFormRevision(action.payload);
|
|
3467
3491
|
},
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
addUserFormRevision: (state, action) => {
|
|
3475
|
-
state.revisions[action.payload.offline_id] = action.payload;
|
|
3476
|
-
considerCachingRevision(action.payload);
|
|
3492
|
+
setFormRevisions: (state, action) => {
|
|
3493
|
+
state.formRevisions = {};
|
|
3494
|
+
for (const revision of action.payload) {
|
|
3495
|
+
state.formRevisions[revision.offline_id] = revision;
|
|
3496
|
+
considerCachingFormRevision(revision);
|
|
3497
|
+
}
|
|
3477
3498
|
},
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3499
|
+
addFormRevision: (state, action) => {
|
|
3500
|
+
if (state.formRevisions[action.payload.offline_id] !== void 0) {
|
|
3501
|
+
throw new Error(`Revision with offline_id ${action.payload.offline_id} already exists`);
|
|
3502
|
+
}
|
|
3503
|
+
state.formRevisions[action.payload.offline_id] = action.payload;
|
|
3504
|
+
considerCachingFormRevision(action.payload);
|
|
3481
3505
|
},
|
|
3482
|
-
|
|
3506
|
+
// TODO: @Audiopolis / Magnus - do we want to standardize using PayloadAction?
|
|
3507
|
+
addFormRevisions: (state, action) => {
|
|
3483
3508
|
for (const userFormRevision of action.payload) {
|
|
3484
|
-
|
|
3485
|
-
|
|
3509
|
+
if (state.formRevisions[userFormRevision.offline_id] !== void 0) {
|
|
3510
|
+
throw new Error(`Revision with offline_id ${userFormRevision.offline_id} already exists`);
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
for (const userFormRevision of action.payload) {
|
|
3514
|
+
state.formRevisions[userFormRevision.offline_id] = userFormRevision;
|
|
3515
|
+
considerCachingFormRevision(userFormRevision);
|
|
3486
3516
|
}
|
|
3487
3517
|
},
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
const submissionId = action.payload.submission;
|
|
3493
|
-
const submissionAttachments = state.submissionAttachments[submissionId];
|
|
3494
|
-
if (submissionAttachments) {
|
|
3495
|
-
submissionAttachments.push(action.payload);
|
|
3496
|
-
} else {
|
|
3497
|
-
state.submissionAttachments[submissionId] = [action.payload];
|
|
3518
|
+
// UserFormRevisions do not get updated
|
|
3519
|
+
deleteFormRevision: (state, action) => {
|
|
3520
|
+
if (state.formRevisions[action.payload] === void 0) {
|
|
3521
|
+
throw new Error(`Revision with offline_id ${action.payload} does not exist`);
|
|
3498
3522
|
}
|
|
3523
|
+
delete state.formRevisions[action.payload];
|
|
3524
|
+
delete LATEST_FORM_REVISION_CACHE[action.payload];
|
|
3499
3525
|
},
|
|
3500
|
-
|
|
3501
|
-
const
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
}
|
|
3506
|
-
|
|
3526
|
+
deleteFormRevisions: (state, action) => {
|
|
3527
|
+
for (const offlineId of action.payload) {
|
|
3528
|
+
if (state.formRevisions[offlineId] === void 0) {
|
|
3529
|
+
throw new Error(`Revision with offline_id ${offlineId} does not exist`);
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
for (const offlineId of action.payload) {
|
|
3533
|
+
delete state.formRevisions[offlineId];
|
|
3534
|
+
delete LATEST_FORM_REVISION_CACHE[offlineId];
|
|
3507
3535
|
}
|
|
3508
3536
|
},
|
|
3509
|
-
|
|
3510
|
-
|
|
3537
|
+
// attachment related actions
|
|
3538
|
+
setFormRevisionAttachments: (state, action) => {
|
|
3539
|
+
state.attachments = {};
|
|
3511
3540
|
for (const attachment of action.payload) {
|
|
3512
|
-
|
|
3513
|
-
const submissionAttachments = state.submissionAttachments[submissionId];
|
|
3514
|
-
if (submissionAttachments) {
|
|
3515
|
-
submissionAttachments.push(attachment);
|
|
3516
|
-
} else {
|
|
3517
|
-
state.submissionAttachments[submissionId] = [attachment];
|
|
3518
|
-
}
|
|
3541
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3519
3542
|
}
|
|
3520
3543
|
},
|
|
3521
|
-
|
|
3522
|
-
state.
|
|
3544
|
+
addFormRevisionAttachment: (state, action) => {
|
|
3545
|
+
if (state.attachments[action.payload.offline_id] !== void 0) {
|
|
3546
|
+
throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
|
|
3547
|
+
}
|
|
3548
|
+
state.attachments[action.payload.offline_id] = action.payload;
|
|
3549
|
+
},
|
|
3550
|
+
addFormRevisionAttachments: (state, action) => {
|
|
3523
3551
|
for (const attachment of action.payload) {
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
if (revisionAttachments) {
|
|
3527
|
-
revisionAttachments.push(attachment);
|
|
3528
|
-
} else {
|
|
3529
|
-
state.revisionAttachments[revisionId] = [attachment];
|
|
3552
|
+
if (state.attachments[attachment.offline_id] !== void 0) {
|
|
3553
|
+
throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
|
|
3530
3554
|
}
|
|
3531
3555
|
}
|
|
3556
|
+
for (const attachment of action.payload) {
|
|
3557
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3558
|
+
}
|
|
3532
3559
|
},
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
deleteUserFormSubmissions: (state, action) => {
|
|
3537
|
-
for (const userFormSubmission of action.payload) {
|
|
3538
|
-
delete state.submissions[userFormSubmission.offline_id];
|
|
3560
|
+
deleteFormRevisionAttachment: (state, action) => {
|
|
3561
|
+
if (state.attachments[action.payload] === void 0) {
|
|
3562
|
+
throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
|
|
3539
3563
|
}
|
|
3564
|
+
delete state.attachments[action.payload];
|
|
3540
3565
|
},
|
|
3541
|
-
|
|
3542
|
-
for (const
|
|
3543
|
-
state.
|
|
3566
|
+
deleteFormRevisionAttachments: (state, action) => {
|
|
3567
|
+
for (const offlineId of action.payload) {
|
|
3568
|
+
if (state.attachments[offlineId] === void 0) {
|
|
3569
|
+
throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
for (const offlineId of action.payload) {
|
|
3573
|
+
delete state.attachments[offlineId];
|
|
3544
3574
|
}
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
});
|
|
3578
|
+
const {
|
|
3579
|
+
setFormRevision,
|
|
3580
|
+
setFormRevisions,
|
|
3581
|
+
addFormRevision,
|
|
3582
|
+
addFormRevisions,
|
|
3583
|
+
deleteFormRevision,
|
|
3584
|
+
deleteFormRevisions,
|
|
3585
|
+
setFormRevisionAttachments,
|
|
3586
|
+
addFormRevisionAttachment,
|
|
3587
|
+
addFormRevisionAttachments,
|
|
3588
|
+
deleteFormRevisionAttachment,
|
|
3589
|
+
deleteFormRevisionAttachments
|
|
3590
|
+
} = formRevisionsSlice.actions;
|
|
3591
|
+
const selectFormRevisionMapping = (state) => state.formRevisionReducer.formRevisions;
|
|
3592
|
+
const selectFormRevisions = createSelector(
|
|
3593
|
+
[selectFormRevisionMapping],
|
|
3594
|
+
(formRevisions) => Object.values(formRevisions)
|
|
3595
|
+
);
|
|
3596
|
+
const selectFormRevision = (formRevisionId) => (state) => {
|
|
3597
|
+
return state.formRevisionReducer.formRevisions[formRevisionId];
|
|
3598
|
+
};
|
|
3599
|
+
const _selectLatestFormRevision = (formRevisions, formId2) => {
|
|
3600
|
+
let ret = null;
|
|
3601
|
+
for (const candidate of Object.values(formRevisions)) {
|
|
3602
|
+
if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
|
|
3603
|
+
ret = candidate;
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
if (!ret) {
|
|
3607
|
+
throw new Error("No form revision found for form " + formId2);
|
|
3608
|
+
}
|
|
3609
|
+
return ret;
|
|
3610
|
+
};
|
|
3611
|
+
const selectLatestFormRevisionOfForm = restructureCreateSelectorWithArgs(
|
|
3612
|
+
createSelector([selectFormRevisionMapping, (_state, formId2) => formId2], (revisions, formId2) => {
|
|
3613
|
+
if (!formId2) {
|
|
3614
|
+
throw new Error("formId is required");
|
|
3615
|
+
}
|
|
3616
|
+
return _selectLatestFormRevision(revisions, formId2);
|
|
3617
|
+
})
|
|
3618
|
+
);
|
|
3619
|
+
const selectFormRevisionsOfForm = restructureCreateSelectorWithArgs(
|
|
3620
|
+
createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
|
|
3621
|
+
return revisions.filter((revision) => {
|
|
3622
|
+
return revision.form === formId2;
|
|
3623
|
+
});
|
|
3624
|
+
})
|
|
3625
|
+
);
|
|
3626
|
+
const selectLatestFormRevisionsOfComponentTypes = restructureCreateSelectorWithArgs(
|
|
3627
|
+
createSelector(
|
|
3628
|
+
[
|
|
3629
|
+
(state) => state.formReducer.forms,
|
|
3630
|
+
selectFormRevisionMapping,
|
|
3631
|
+
(_state, componentTypeIds) => componentTypeIds
|
|
3632
|
+
],
|
|
3633
|
+
(userForms, revisions, componentTypeIds) => {
|
|
3634
|
+
const componentTypeIdsSet = new Set(componentTypeIds);
|
|
3635
|
+
const ret = {};
|
|
3636
|
+
for (const form of Object.values(userForms)) {
|
|
3637
|
+
if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
|
|
3638
|
+
ret[form.component_type] = _selectLatestFormRevision(revisions, form.offline_id);
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
return ret;
|
|
3642
|
+
}
|
|
3643
|
+
)
|
|
3644
|
+
);
|
|
3645
|
+
const selectLatestFormRevisionByForm = createSelector([selectFormRevisionMapping], (revisions) => {
|
|
3646
|
+
const latestRevisions = {};
|
|
3647
|
+
for (const revision of Object.values(revisions)) {
|
|
3648
|
+
const formId2 = revision.form;
|
|
3649
|
+
const currentLatestRevision = latestRevisions[formId2];
|
|
3650
|
+
if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
|
|
3651
|
+
latestRevisions[formId2] = revision;
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
return latestRevisions;
|
|
3655
|
+
});
|
|
3656
|
+
const selectUserFormRevisionAttachmentsMapping = (state) => {
|
|
3657
|
+
return state.formRevisionReducer.attachments;
|
|
3658
|
+
};
|
|
3659
|
+
const selectAttachmentsOfFormRevision = restructureCreateSelectorWithArgs(
|
|
3660
|
+
createSelector(
|
|
3661
|
+
[selectUserFormRevisionAttachmentsMapping, (_state, revisionId) => revisionId],
|
|
3662
|
+
(attachments, revisionId) => {
|
|
3663
|
+
return Object.values(attachments).filter((attachment) => attachment.revision === revisionId);
|
|
3664
|
+
}
|
|
3665
|
+
)
|
|
3666
|
+
);
|
|
3667
|
+
const formRevisionReducer = formRevisionsSlice.reducer;
|
|
3668
|
+
const initialState$4 = {
|
|
3669
|
+
forms: {}
|
|
3670
|
+
};
|
|
3671
|
+
const formSlice = createSlice({
|
|
3672
|
+
name: "forms",
|
|
3673
|
+
initialState: initialState$4,
|
|
3674
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
|
|
3675
|
+
reducers: {
|
|
3676
|
+
setForms: (state, action) => {
|
|
3677
|
+
state.forms = {};
|
|
3678
|
+
action.payload.forEach((userForm) => {
|
|
3679
|
+
state.forms[userForm.offline_id] = userForm;
|
|
3680
|
+
});
|
|
3681
|
+
},
|
|
3682
|
+
addForm: (state, action) => {
|
|
3683
|
+
state.forms[action.payload.offline_id] = action.payload;
|
|
3545
3684
|
},
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
state.submissions[submission.offline_id] = submission;
|
|
3685
|
+
addForms: (state, action) => {
|
|
3686
|
+
action.payload.forEach((userForm) => {
|
|
3687
|
+
state.forms[userForm.offline_id] = userForm;
|
|
3550
3688
|
});
|
|
3551
3689
|
},
|
|
3552
3690
|
favoriteForm: (state, action) => {
|
|
3553
3691
|
const { formId: formId2 } = action.payload;
|
|
3554
|
-
const form = state.
|
|
3692
|
+
const form = state.forms[formId2];
|
|
3555
3693
|
if (!form) {
|
|
3556
3694
|
throw new Error("No form exists with the id " + formId2);
|
|
3557
3695
|
}
|
|
@@ -3559,48 +3697,23 @@ const userFormSlice = createSlice({
|
|
|
3559
3697
|
},
|
|
3560
3698
|
unfavoriteForm: (state, action) => {
|
|
3561
3699
|
const { formId: formId2 } = action.payload;
|
|
3562
|
-
const form = state.
|
|
3700
|
+
const form = state.forms[formId2];
|
|
3563
3701
|
if (!form) {
|
|
3564
3702
|
throw new Error("No form exists with the id " + formId2);
|
|
3565
3703
|
}
|
|
3566
3704
|
form.favorite = false;
|
|
3567
3705
|
},
|
|
3568
|
-
|
|
3569
|
-
delete state.
|
|
3706
|
+
deleteForm: (state, action) => {
|
|
3707
|
+
delete state.forms[action.payload];
|
|
3570
3708
|
}
|
|
3571
3709
|
}
|
|
3572
3710
|
});
|
|
3573
|
-
const {
|
|
3574
|
-
|
|
3575
|
-
addUserForms,
|
|
3576
|
-
addUserFormRevisions,
|
|
3577
|
-
updateOrCreateUserFormSubmission,
|
|
3578
|
-
addUserFormSubmissions,
|
|
3579
|
-
deleteUserFormSubmission,
|
|
3580
|
-
deleteUserFormSubmissions,
|
|
3581
|
-
favoriteForm,
|
|
3582
|
-
unfavoriteForm,
|
|
3583
|
-
deleteUserForm,
|
|
3584
|
-
deleteUserFormRevision,
|
|
3585
|
-
deleteUserFormRevisions,
|
|
3586
|
-
setUserFormSubmissions,
|
|
3587
|
-
addUserFormRevision,
|
|
3588
|
-
addUserFormSubmissionAttachment,
|
|
3589
|
-
addUserFormRevisionAttachment,
|
|
3590
|
-
setUserFormSubmissionAttachments,
|
|
3591
|
-
setUserFormRevisionAttachments
|
|
3592
|
-
} = userFormSlice.actions;
|
|
3593
|
-
const selectSubmissionAttachments = (submissionId) => (state) => {
|
|
3594
|
-
return state.userFormReducer.submissionAttachments[submissionId] || [];
|
|
3595
|
-
};
|
|
3596
|
-
const selectRevisionAttachments = (revisionId) => (state) => {
|
|
3597
|
-
return state.userFormReducer.revisionAttachments[revisionId] || [];
|
|
3598
|
-
};
|
|
3599
|
-
const selectFilteredUserForms = restructureCreateSelectorWithArgs(
|
|
3711
|
+
const { setForms, addForm, addForms, favoriteForm, unfavoriteForm, deleteForm } = formSlice.actions;
|
|
3712
|
+
const selectFilteredForms = restructureCreateSelectorWithArgs(
|
|
3600
3713
|
createSelector(
|
|
3601
3714
|
[
|
|
3602
|
-
(state) => state.
|
|
3603
|
-
(state) => state.
|
|
3715
|
+
(state) => state.formReducer.forms,
|
|
3716
|
+
(state) => state.formRevisionReducer.formRevisions,
|
|
3604
3717
|
(_state, search) => search
|
|
3605
3718
|
],
|
|
3606
3719
|
(userForms, revisions, search) => {
|
|
@@ -3634,63 +3747,188 @@ const selectFilteredUserForms = restructureCreateSelectorWithArgs(
|
|
|
3634
3747
|
{ memoizeOptions: { equalityCheck: shallowEqual$1 } }
|
|
3635
3748
|
)
|
|
3636
3749
|
);
|
|
3637
|
-
const
|
|
3638
|
-
return state.
|
|
3750
|
+
const selectForm = (formId2) => (state) => {
|
|
3751
|
+
return state.formReducer.forms[formId2];
|
|
3639
3752
|
};
|
|
3640
|
-
const
|
|
3641
|
-
|
|
3642
|
-
for (const candidate of Object.values(revisions)) {
|
|
3643
|
-
if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
|
|
3644
|
-
ret = candidate;
|
|
3645
|
-
}
|
|
3646
|
-
}
|
|
3647
|
-
if (!ret) {
|
|
3648
|
-
throw new Error("No revision found for form " + formId2);
|
|
3649
|
-
}
|
|
3650
|
-
return ret;
|
|
3753
|
+
const selectFormMapping = (state) => {
|
|
3754
|
+
return state.formReducer.forms;
|
|
3651
3755
|
};
|
|
3652
|
-
const
|
|
3756
|
+
const selectFormOfComponentType = restructureCreateSelectorWithArgs(
|
|
3653
3757
|
createSelector(
|
|
3654
|
-
[
|
|
3655
|
-
(
|
|
3656
|
-
|
|
3657
|
-
throw new Error("formId is required");
|
|
3658
|
-
}
|
|
3659
|
-
return _selectLatestFormRevision(revisions, formId2);
|
|
3758
|
+
[selectFormMapping, (_state, componentTypeId) => componentTypeId],
|
|
3759
|
+
(userForms, componentTypeId) => {
|
|
3760
|
+
return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
|
|
3660
3761
|
}
|
|
3661
3762
|
)
|
|
3662
3763
|
);
|
|
3663
|
-
const
|
|
3664
|
-
return
|
|
3665
|
-
};
|
|
3666
|
-
const
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
const
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3764
|
+
const selectFormsCount = createSelector([selectFormMapping], (userForms) => {
|
|
3765
|
+
return Object.keys(userForms).length;
|
|
3766
|
+
});
|
|
3767
|
+
const selectGeneralFormCount = createSelector([selectFormMapping], (userForms) => {
|
|
3768
|
+
return Object.values(userForms).filter((form) => !form.component_type).length;
|
|
3769
|
+
});
|
|
3770
|
+
const formReducer = formSlice.reducer;
|
|
3771
|
+
const initialState$3 = {
|
|
3772
|
+
formSubmissions: {},
|
|
3773
|
+
attachments: {}
|
|
3774
|
+
};
|
|
3775
|
+
const formSubmissionSlice = createSlice({
|
|
3776
|
+
name: "formSubmissions",
|
|
3777
|
+
initialState: initialState$3,
|
|
3778
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
|
|
3779
|
+
reducers: {
|
|
3780
|
+
setFormSubmission: (state, action) => {
|
|
3781
|
+
state.formSubmissions[action.payload.offline_id] = action.payload;
|
|
3782
|
+
},
|
|
3783
|
+
setFormSubmissions: (state, action) => {
|
|
3784
|
+
state.formSubmissions = {};
|
|
3785
|
+
for (const submission of action.payload) {
|
|
3786
|
+
state.formSubmissions[submission.offline_id] = submission;
|
|
3787
|
+
}
|
|
3788
|
+
},
|
|
3789
|
+
addFormSubmission: (state, action) => {
|
|
3790
|
+
if (state.formSubmissions[action.payload.offline_id] !== void 0) {
|
|
3791
|
+
throw new Error(`Submission with offline_id ${action.payload.offline_id} already exists`);
|
|
3792
|
+
}
|
|
3793
|
+
state.formSubmissions[action.payload.offline_id] = action.payload;
|
|
3794
|
+
},
|
|
3795
|
+
addFormSubmissions: (state, action) => {
|
|
3796
|
+
for (const submission of action.payload) {
|
|
3797
|
+
if (state.formSubmissions[submission.offline_id] !== void 0) {
|
|
3798
|
+
throw new Error(`Submission with offline_id ${submission.offline_id} already exists`);
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
for (const submission of action.payload) {
|
|
3802
|
+
state.formSubmissions[submission.offline_id] = submission;
|
|
3803
|
+
}
|
|
3804
|
+
},
|
|
3805
|
+
updateFormSubmission: (state, action) => {
|
|
3806
|
+
if (state.formSubmissions[action.payload.offline_id] === void 0) {
|
|
3807
|
+
throw new Error(`Submission with offline_id ${action.payload.offline_id} does not exist`);
|
|
3808
|
+
}
|
|
3809
|
+
state.formSubmissions[action.payload.offline_id] = action.payload;
|
|
3810
|
+
},
|
|
3811
|
+
updateFormSubmissions: (state, action) => {
|
|
3812
|
+
for (const submission of action.payload) {
|
|
3813
|
+
if (state.formSubmissions[submission.offline_id] === void 0) {
|
|
3814
|
+
throw new Error(`Submission with offline_id ${submission.offline_id} does not exist`);
|
|
3815
|
+
}
|
|
3816
|
+
}
|
|
3817
|
+
for (const submission of action.payload) {
|
|
3818
|
+
state.formSubmissions[submission.offline_id] = submission;
|
|
3819
|
+
}
|
|
3820
|
+
},
|
|
3821
|
+
deleteFormSubmission: (state, action) => {
|
|
3822
|
+
if (state.formSubmissions[action.payload] === void 0) {
|
|
3823
|
+
throw new Error(`Submission with offline_id ${action.payload} does not exist`);
|
|
3824
|
+
}
|
|
3825
|
+
delete state.formSubmissions[action.payload];
|
|
3826
|
+
},
|
|
3827
|
+
deleteFormSubmissions: (state, action) => {
|
|
3828
|
+
for (const offlineId of action.payload) {
|
|
3829
|
+
if (state.formSubmissions[offlineId] === void 0) {
|
|
3830
|
+
throw new Error(`Submission with offline_id ${offlineId} does not exist`);
|
|
3831
|
+
}
|
|
3832
|
+
delete state.formSubmissions[offlineId];
|
|
3833
|
+
}
|
|
3834
|
+
for (const offlineId of action.payload) {
|
|
3835
|
+
delete state.formSubmissions[offlineId];
|
|
3836
|
+
}
|
|
3837
|
+
},
|
|
3838
|
+
// Attachments
|
|
3839
|
+
addFormSubmissionAttachment: (state, action) => {
|
|
3840
|
+
if (state.attachments[action.payload.offline_id] !== void 0) {
|
|
3841
|
+
throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
|
|
3842
|
+
}
|
|
3843
|
+
state.attachments[action.payload.offline_id] = action.payload;
|
|
3844
|
+
},
|
|
3845
|
+
addFormSubmissionAttachments: (state, action) => {
|
|
3846
|
+
for (const attachment of action.payload) {
|
|
3847
|
+
if (state.attachments[attachment.offline_id] !== void 0) {
|
|
3848
|
+
throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
for (const attachment of action.payload) {
|
|
3852
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3853
|
+
}
|
|
3854
|
+
},
|
|
3855
|
+
// We only need a multi set for attachments because they are not updated, only added and deleted
|
|
3856
|
+
setFormSubmissionAttachments: (state, action) => {
|
|
3857
|
+
state.attachments = {};
|
|
3858
|
+
for (const attachment of action.payload) {
|
|
3859
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3860
|
+
}
|
|
3861
|
+
},
|
|
3862
|
+
updateFormSubmissionAttachments: (state, action) => {
|
|
3863
|
+
for (const attachment of action.payload) {
|
|
3864
|
+
if (state.attachments[attachment.offline_id] === void 0) {
|
|
3865
|
+
throw new Error(`Attachment with offline_id ${attachment.offline_id} does not exist`);
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
for (const attachment of action.payload) {
|
|
3869
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3870
|
+
}
|
|
3871
|
+
},
|
|
3872
|
+
// The delete actions for UserFormSubmissionAttachments are not used in the app, but are included for completeness
|
|
3873
|
+
// Could be used if editing a submission is ever supported, will be applicable for supporting tip tap content in submissions
|
|
3874
|
+
deleteFormSubmissionAttachment: (state, action) => {
|
|
3875
|
+
if (state.attachments[action.payload] === void 0) {
|
|
3876
|
+
throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
|
|
3877
|
+
}
|
|
3878
|
+
delete state.attachments[action.payload];
|
|
3879
|
+
},
|
|
3880
|
+
deleteFormSubmissionAttachments: (state, action) => {
|
|
3881
|
+
for (const offlineId of action.payload) {
|
|
3882
|
+
if (state.attachments[offlineId] === void 0) {
|
|
3883
|
+
throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
|
|
3884
|
+
}
|
|
3885
|
+
delete state.attachments[offlineId];
|
|
3886
|
+
}
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
});
|
|
3890
|
+
const {
|
|
3891
|
+
setFormSubmission,
|
|
3892
|
+
setFormSubmissions,
|
|
3893
|
+
addFormSubmission,
|
|
3894
|
+
addFormSubmissions,
|
|
3895
|
+
updateFormSubmission,
|
|
3896
|
+
updateFormSubmissions,
|
|
3897
|
+
deleteFormSubmission,
|
|
3898
|
+
deleteFormSubmissions,
|
|
3899
|
+
addFormSubmissionAttachment,
|
|
3900
|
+
addFormSubmissionAttachments,
|
|
3901
|
+
setFormSubmissionAttachments,
|
|
3902
|
+
updateFormSubmissionAttachments,
|
|
3903
|
+
deleteFormSubmissionAttachment,
|
|
3904
|
+
deleteFormSubmissionAttachments
|
|
3905
|
+
} = formSubmissionSlice.actions;
|
|
3906
|
+
const selectFormSubmissionsMapping = (state) => {
|
|
3907
|
+
return state.formSubmissionReducer.formSubmissions;
|
|
3908
|
+
};
|
|
3909
|
+
const selectFormSubmissions = createSelector(
|
|
3910
|
+
[selectFormSubmissionsMapping],
|
|
3911
|
+
(submissions) => {
|
|
3912
|
+
return Object.values(submissions);
|
|
3913
|
+
}
|
|
3679
3914
|
);
|
|
3680
|
-
const
|
|
3915
|
+
const selectFormSubmission = (submissionId) => (state) => {
|
|
3916
|
+
return state.formSubmissionReducer.formSubmissions[submissionId];
|
|
3917
|
+
};
|
|
3918
|
+
const selectFormSubmissionsOfForm = restructureCreateSelectorWithArgs(
|
|
3681
3919
|
createSelector(
|
|
3682
|
-
[
|
|
3920
|
+
[selectFormSubmissions, selectFormRevisionMapping, (_state, formId2) => formId2],
|
|
3683
3921
|
(submissions, revisionMapping, formId2) => {
|
|
3684
|
-
return
|
|
3922
|
+
return submissions.filter((submission) => {
|
|
3685
3923
|
const revision = revisionMapping[submission.form_revision];
|
|
3686
3924
|
return (revision == null ? void 0 : revision.form) === formId2;
|
|
3687
3925
|
});
|
|
3688
3926
|
}
|
|
3689
3927
|
)
|
|
3690
3928
|
);
|
|
3691
|
-
const
|
|
3929
|
+
const selectFormSubmissionsOfIssue = restructureCreateSelectorWithArgs(
|
|
3692
3930
|
createSelector(
|
|
3693
|
-
[
|
|
3931
|
+
[selectFormSubmissions, (_state, issueId) => issueId],
|
|
3694
3932
|
(submissions, issueId) => {
|
|
3695
3933
|
return Object.values(submissions).filter((submission) => {
|
|
3696
3934
|
return submission.issue === issueId;
|
|
@@ -3698,9 +3936,9 @@ const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
|
|
|
3698
3936
|
}
|
|
3699
3937
|
)
|
|
3700
3938
|
);
|
|
3701
|
-
const
|
|
3939
|
+
const selectFormSubmissionsOfComponent = restructureCreateSelectorWithArgs(
|
|
3702
3940
|
createSelector(
|
|
3703
|
-
[
|
|
3941
|
+
[selectFormSubmissions, (_state, componentId) => componentId],
|
|
3704
3942
|
(submissions, componentId) => {
|
|
3705
3943
|
return submissions.filter((submission) => {
|
|
3706
3944
|
return submission.component === componentId;
|
|
@@ -3708,8 +3946,8 @@ const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
|
|
|
3708
3946
|
}
|
|
3709
3947
|
)
|
|
3710
3948
|
);
|
|
3711
|
-
const
|
|
3712
|
-
[
|
|
3949
|
+
const selectFormSubmissionsByComponents = createSelector(
|
|
3950
|
+
[selectFormSubmissionsMapping, selectComponentsMapping],
|
|
3713
3951
|
(submissions, components) => {
|
|
3714
3952
|
var _a2;
|
|
3715
3953
|
const componentSubmissionMapping = {};
|
|
@@ -3725,54 +3963,18 @@ const selectComponentSubmissionMapping = createSelector(
|
|
|
3725
3963
|
return componentSubmissionMapping;
|
|
3726
3964
|
}
|
|
3727
3965
|
);
|
|
3728
|
-
const
|
|
3729
|
-
return state.
|
|
3966
|
+
const selectFormSubmissionAttachmentsMapping = (state) => {
|
|
3967
|
+
return state.formSubmissionReducer.attachments;
|
|
3730
3968
|
};
|
|
3731
|
-
const
|
|
3732
|
-
createSelector(
|
|
3733
|
-
[selectUserFormMapping, (_state, componentTypeId) => componentTypeId],
|
|
3734
|
-
(userForms, componentTypeId) => {
|
|
3735
|
-
return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
|
|
3736
|
-
}
|
|
3737
|
-
)
|
|
3738
|
-
);
|
|
3739
|
-
const selectLatestRevisionsFromComponentTypeIds = restructureCreateSelectorWithArgs(
|
|
3969
|
+
const selectAttachmentsOfFormSubmission = restructureCreateSelectorWithArgs(
|
|
3740
3970
|
createSelector(
|
|
3741
|
-
[
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
(_state, componentTypeIds) => componentTypeIds
|
|
3745
|
-
],
|
|
3746
|
-
(userForms, revisions, componentTypeIds) => {
|
|
3747
|
-
const componentTypeIdsSet = new Set(componentTypeIds);
|
|
3748
|
-
const ret = {};
|
|
3749
|
-
for (const form of Object.values(userForms)) {
|
|
3750
|
-
if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
|
|
3751
|
-
ret[form.component_type] = _selectLatestFormRevision(revisions, form.offline_id);
|
|
3752
|
-
}
|
|
3753
|
-
}
|
|
3754
|
-
return ret;
|
|
3971
|
+
[selectFormSubmissionAttachmentsMapping, (_state, submissionId) => submissionId],
|
|
3972
|
+
(attachmentsMapping, submissionId) => {
|
|
3973
|
+
return Object.values(attachmentsMapping).filter((attachment) => attachment.submission === submissionId);
|
|
3755
3974
|
}
|
|
3756
3975
|
)
|
|
3757
3976
|
);
|
|
3758
|
-
const
|
|
3759
|
-
const latestRevisions = {};
|
|
3760
|
-
for (const revision of Object.values(revisions)) {
|
|
3761
|
-
const formId2 = revision.form;
|
|
3762
|
-
const currentLatestRevision = latestRevisions[formId2];
|
|
3763
|
-
if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
|
|
3764
|
-
latestRevisions[formId2] = revision;
|
|
3765
|
-
}
|
|
3766
|
-
}
|
|
3767
|
-
return latestRevisions;
|
|
3768
|
-
});
|
|
3769
|
-
const selectNumberOfUserForms = createSelector([selectUserFormMapping], (userForms) => {
|
|
3770
|
-
return Object.keys(userForms).length;
|
|
3771
|
-
});
|
|
3772
|
-
const selectNumberOfGeneralUserForms = createSelector([selectUserFormMapping], (userForms) => {
|
|
3773
|
-
return Object.values(userForms).filter((form) => !form.component_type).length;
|
|
3774
|
-
});
|
|
3775
|
-
const userFormReducer = userFormSlice.reducer;
|
|
3977
|
+
const formSubmissionReducer = formSubmissionSlice.reducer;
|
|
3776
3978
|
const initialState$2 = {
|
|
3777
3979
|
emailDomains: {}
|
|
3778
3980
|
};
|
|
@@ -3806,7 +4008,8 @@ const selectSortedEmailDomains = (state) => Object.values(state.emailDomainsRedu
|
|
|
3806
4008
|
);
|
|
3807
4009
|
const emailDomainsReducer = emailDomainsSlice.reducer;
|
|
3808
4010
|
const initialState$1 = {
|
|
3809
|
-
documents: {}
|
|
4011
|
+
documents: {},
|
|
4012
|
+
attachments: {}
|
|
3810
4013
|
};
|
|
3811
4014
|
const documentSlice = createSlice({
|
|
3812
4015
|
name: "documents",
|
|
@@ -3943,10 +4146,28 @@ const documentSlice = createSlice({
|
|
|
3943
4146
|
}
|
|
3944
4147
|
delete state.documents[documentId];
|
|
3945
4148
|
}
|
|
3946
|
-
}
|
|
4149
|
+
},
|
|
4150
|
+
setDocumentAttachments: setAttachments,
|
|
4151
|
+
addDocumentAttachment: addAttachment,
|
|
4152
|
+
addDocumentAttachments: addAttachments,
|
|
4153
|
+
updateDocumentAttachment: updateAttachment,
|
|
4154
|
+
removeDocumentAttachment: removeAttachment,
|
|
4155
|
+
removeDocumentAttachments: removeAttachments
|
|
3947
4156
|
}
|
|
3948
4157
|
});
|
|
3949
|
-
const {
|
|
4158
|
+
const {
|
|
4159
|
+
setDocuments,
|
|
4160
|
+
addDocuments,
|
|
4161
|
+
updateDocuments,
|
|
4162
|
+
moveDocument,
|
|
4163
|
+
removeDocuments,
|
|
4164
|
+
setDocumentAttachments,
|
|
4165
|
+
addDocumentAttachment,
|
|
4166
|
+
addDocumentAttachments,
|
|
4167
|
+
updateDocumentAttachment,
|
|
4168
|
+
removeDocumentAttachment,
|
|
4169
|
+
removeDocumentAttachments
|
|
4170
|
+
} = documentSlice.actions;
|
|
3950
4171
|
const selectDocumentsMapping = (state) => state.documentsReducer.documents;
|
|
3951
4172
|
const selectDocuments = createSelector(
|
|
3952
4173
|
[selectDocumentsMapping],
|
|
@@ -3976,6 +4197,39 @@ const selectRootDocuments = createSelector(
|
|
|
3976
4197
|
[selectDocuments],
|
|
3977
4198
|
(documents) => documents.filter((document2) => !document2.parent_document)
|
|
3978
4199
|
);
|
|
4200
|
+
const selectDocumentAttachmentMapping = (state) => state.documentsReducer.attachments;
|
|
4201
|
+
const selectAllDocumentAttachments = createSelector(
|
|
4202
|
+
[selectDocumentAttachmentMapping],
|
|
4203
|
+
(mapping) => Object.values(mapping)
|
|
4204
|
+
);
|
|
4205
|
+
const selectDocumentAttachment = (attachmentId) => (state) => {
|
|
4206
|
+
return state.documentsReducer.attachments[attachmentId];
|
|
4207
|
+
};
|
|
4208
|
+
const selectAttachmentsOfDocument = restructureCreateSelectorWithArgs(
|
|
4209
|
+
createSelector(
|
|
4210
|
+
[selectAllDocumentAttachments, (_state, documentId) => documentId],
|
|
4211
|
+
(attachments, documentId) => {
|
|
4212
|
+
return attachments.filter(({ document: document2 }) => documentId === document2);
|
|
4213
|
+
}
|
|
4214
|
+
)
|
|
4215
|
+
);
|
|
4216
|
+
const selectAttachmentsOfDocumentByType = restructureCreateSelectorWithArgs(
|
|
4217
|
+
createSelector(
|
|
4218
|
+
[selectAllDocumentAttachments, (_state, documentId) => documentId],
|
|
4219
|
+
(attachments, documentId) => {
|
|
4220
|
+
const attachmentsOfProject = attachments.filter(({ document: document2 }) => documentId === document2);
|
|
4221
|
+
const fileAttachments = attachmentsOfProject.filter(
|
|
4222
|
+
// this null check here is necessary, there are cases where file_type is null or undefined
|
|
4223
|
+
({ file_type }) => !file_type || !file_type.startsWith("image/")
|
|
4224
|
+
);
|
|
4225
|
+
const imageAttachments = attachmentsOfProject.filter(
|
|
4226
|
+
// this null check here is necessary, there are cases where file_type is null or undefined
|
|
4227
|
+
({ file_type }) => file_type && file_type.startsWith("image/")
|
|
4228
|
+
);
|
|
4229
|
+
return { fileAttachments, imageAttachments };
|
|
4230
|
+
}
|
|
4231
|
+
)
|
|
4232
|
+
);
|
|
3979
4233
|
const documentsReducer = documentSlice.reducer;
|
|
3980
4234
|
const initialState = {
|
|
3981
4235
|
version: 0
|
|
@@ -4018,7 +4272,9 @@ const overmapReducers = {
|
|
|
4018
4272
|
projectFileReducer,
|
|
4019
4273
|
rehydratedReducer,
|
|
4020
4274
|
settingReducer,
|
|
4021
|
-
|
|
4275
|
+
formReducer,
|
|
4276
|
+
formRevisionReducer,
|
|
4277
|
+
formSubmissionReducer,
|
|
4022
4278
|
userReducer,
|
|
4023
4279
|
workspaceReducer,
|
|
4024
4280
|
emailDomainsReducer,
|
|
@@ -4071,9 +4327,7 @@ function handleWorkspaceRemoval(draft, action) {
|
|
|
4071
4327
|
throw new Error(`Failed to update index_workspace of issue ${issue.offline_id} to main workspace`);
|
|
4072
4328
|
}
|
|
4073
4329
|
}
|
|
4074
|
-
const indexedForms = Object.values(draft.
|
|
4075
|
-
(form) => form.index_workspace === workspaceId
|
|
4076
|
-
);
|
|
4330
|
+
const indexedForms = Object.values(draft.formReducer.forms).filter((form) => form.index_workspace === workspaceId);
|
|
4077
4331
|
for (const form of indexedForms) {
|
|
4078
4332
|
form.index_workspace = mainWorkspace.offline_id;
|
|
4079
4333
|
}
|
|
@@ -4551,6 +4805,23 @@ class BaseApiService {
|
|
|
4551
4805
|
}
|
|
4552
4806
|
}
|
|
4553
4807
|
class AttachmentService extends BaseApiService {
|
|
4808
|
+
processPresignedUrls(presignedUrls) {
|
|
4809
|
+
for (const [sha1, presignedUrl] of Object.entries(presignedUrls)) {
|
|
4810
|
+
console.debug(sha1, presignedUrl);
|
|
4811
|
+
void this.enqueueRequest({
|
|
4812
|
+
url: presignedUrl.url,
|
|
4813
|
+
description: "Upload file to S3",
|
|
4814
|
+
method: HttpMethod.POST,
|
|
4815
|
+
isExternalUrl: true,
|
|
4816
|
+
isAuthNeeded: false,
|
|
4817
|
+
attachmentHash: sha1,
|
|
4818
|
+
// TODO: can we use the sha1 as the blocker?
|
|
4819
|
+
blockers: [`s3-${sha1}`],
|
|
4820
|
+
blocks: [sha1],
|
|
4821
|
+
s3url: presignedUrl
|
|
4822
|
+
});
|
|
4823
|
+
}
|
|
4824
|
+
}
|
|
4554
4825
|
fetchAll(projectId) {
|
|
4555
4826
|
const promise = this.enqueueRequest({
|
|
4556
4827
|
description: "Fetch attachments",
|
|
@@ -4564,7 +4835,8 @@ class AttachmentService extends BaseApiService {
|
|
|
4564
4835
|
issue_attachments: Object.values(state.issueReducer.attachments),
|
|
4565
4836
|
component_attachments: Object.values(state.componentReducer.attachments),
|
|
4566
4837
|
component_type_attachments: Object.values(state.componentTypeReducer.attachments),
|
|
4567
|
-
project_attachments: Object.values(state.projectReducer.attachments)
|
|
4838
|
+
project_attachments: Object.values(state.projectReducer.attachments),
|
|
4839
|
+
document_attachments: Object.values(state.documentsReducer.attachments)
|
|
4568
4840
|
};
|
|
4569
4841
|
return [allAttachments, promise];
|
|
4570
4842
|
}
|
|
@@ -4576,6 +4848,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4576
4848
|
}
|
|
4577
4849
|
const offlineAttachment = {
|
|
4578
4850
|
...attachmentPayload,
|
|
4851
|
+
// TODO: just handle creating the objectURL in here, then the front end doesn't need to worry about it
|
|
4579
4852
|
file: attachmentPayload.file.objectURL,
|
|
4580
4853
|
file_name: attachmentPayload.file.name,
|
|
4581
4854
|
file_type: attachmentPayload.file.type,
|
|
@@ -4609,6 +4882,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4609
4882
|
}
|
|
4610
4883
|
const offlineAttachment = {
|
|
4611
4884
|
...attachmentPayload,
|
|
4885
|
+
// TODO: just handle creating the objectURL in here, then the front end doesn't need to worry about it
|
|
4612
4886
|
file: attachmentPayload.file.objectURL,
|
|
4613
4887
|
file_name: attachmentPayload.file.name,
|
|
4614
4888
|
file_type: attachmentPayload.file.type,
|
|
@@ -4642,6 +4916,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4642
4916
|
}
|
|
4643
4917
|
const offlineAttachment = {
|
|
4644
4918
|
...attachmentPayload,
|
|
4919
|
+
// TODO: just handle creating the objectURL in here, then the front end doesn't need to worry about it
|
|
4645
4920
|
file: attachmentPayload.file.objectURL,
|
|
4646
4921
|
file_name: attachmentPayload.file.name,
|
|
4647
4922
|
file_type: attachmentPayload.file.type,
|
|
@@ -4668,8 +4943,8 @@ class AttachmentService extends BaseApiService {
|
|
|
4668
4943
|
});
|
|
4669
4944
|
return [offlineAttachment, promise];
|
|
4670
4945
|
}
|
|
4671
|
-
async
|
|
4672
|
-
const { description: description2,
|
|
4946
|
+
async addDocumentAttachment(attachmentPayload) {
|
|
4947
|
+
const { description: description2, document: document2, file_sha1, offline_id } = attachmentPayload;
|
|
4673
4948
|
if (!attachmentPayload.file.objectURL) {
|
|
4674
4949
|
throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
|
|
4675
4950
|
}
|
|
@@ -4682,24 +4957,24 @@ class AttachmentService extends BaseApiService {
|
|
|
4682
4957
|
created_by: this.client.store.getState().userReducer.currentUser.id
|
|
4683
4958
|
};
|
|
4684
4959
|
await this.client.files.addCache(attachmentPayload.file, file_sha1);
|
|
4685
|
-
this.client.store.dispatch(
|
|
4960
|
+
this.client.store.dispatch(addDocumentAttachment(offlineAttachment));
|
|
4686
4961
|
const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
|
|
4687
4962
|
const promise = this.enqueueRequest({
|
|
4688
4963
|
description: "Create attachment",
|
|
4689
4964
|
method: HttpMethod.POST,
|
|
4690
|
-
url: `/
|
|
4691
|
-
blocks: [offline_id,
|
|
4965
|
+
url: `/documents/${document2}/attach/`,
|
|
4966
|
+
blocks: [offline_id, document2],
|
|
4692
4967
|
blockers: [file_sha1],
|
|
4693
4968
|
payload: {
|
|
4694
4969
|
offline_id,
|
|
4695
|
-
|
|
4970
|
+
document: document2,
|
|
4696
4971
|
description: description2 ?? "",
|
|
4697
4972
|
submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4698
4973
|
...fileProps
|
|
4699
4974
|
}
|
|
4700
4975
|
});
|
|
4701
4976
|
promise.catch((error2) => {
|
|
4702
|
-
this.client.store.dispatch(
|
|
4977
|
+
this.client.store.dispatch(removeDocumentAttachment(offlineAttachment.offline_id));
|
|
4703
4978
|
throw error2;
|
|
4704
4979
|
});
|
|
4705
4980
|
return [offlineAttachment, promise];
|
|
@@ -4707,26 +4982,54 @@ class AttachmentService extends BaseApiService {
|
|
|
4707
4982
|
/** the outer Promise is needed to await the hashing of each file, which is required before offline use. If wanting to
|
|
4708
4983
|
* attach promise handlers to the request to add the attachment in the backend, apply it on the promise returned from the
|
|
4709
4984
|
* OptimisticModelResult. */
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
};
|
|
4728
|
-
|
|
4985
|
+
// note the method is only marked as async since files needs to be hashed
|
|
4986
|
+
async attachFilesToIssue(files, issueId) {
|
|
4987
|
+
const { store } = this.client;
|
|
4988
|
+
const offlineAttachments = [];
|
|
4989
|
+
const attachmentsPayload = [];
|
|
4990
|
+
const currentUser = store.getState().userReducer.currentUser;
|
|
4991
|
+
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4992
|
+
for (const file of files) {
|
|
4993
|
+
const attachment = offline({
|
|
4994
|
+
file: URL.createObjectURL(file),
|
|
4995
|
+
file_name: file.name,
|
|
4996
|
+
file_type: file.type,
|
|
4997
|
+
file_sha1: await hashFile(file),
|
|
4998
|
+
description: "",
|
|
4999
|
+
submitted_at: submittedAt,
|
|
5000
|
+
created_by: currentUser.id,
|
|
5001
|
+
issue: issueId
|
|
5002
|
+
});
|
|
5003
|
+
attachmentsPayload.push({
|
|
5004
|
+
offline_id: attachment.offline_id,
|
|
5005
|
+
name: attachment.file_name,
|
|
5006
|
+
sha1: attachment.file_sha1,
|
|
5007
|
+
description: attachment.description,
|
|
5008
|
+
created_by: attachment.created_by,
|
|
5009
|
+
issue_id: attachment.issue
|
|
5010
|
+
});
|
|
5011
|
+
offlineAttachments.push(attachment);
|
|
5012
|
+
}
|
|
5013
|
+
store.dispatch(addIssueAttachments(offlineAttachments));
|
|
5014
|
+
const promise = this.enqueueRequest({
|
|
5015
|
+
description: "Attach files to issue",
|
|
5016
|
+
method: HttpMethod.POST,
|
|
5017
|
+
url: `/issues/${issueId}/attach/`,
|
|
5018
|
+
payload: {
|
|
5019
|
+
submitted_at: submittedAt,
|
|
5020
|
+
attachments: attachmentsPayload,
|
|
5021
|
+
files: await constructUploadedFilePayloads(files)
|
|
5022
|
+
},
|
|
5023
|
+
blocks: offlineAttachments.map((attachment) => attachment.offline_id),
|
|
5024
|
+
blockers: offlineAttachments.map((attachment) => attachment.file_sha1)
|
|
5025
|
+
});
|
|
5026
|
+
promise.then(({ attachments, presigned_urls }) => {
|
|
5027
|
+
store.dispatch(updateIssueAttachments(attachments));
|
|
5028
|
+
this.processPresignedUrls(presigned_urls);
|
|
5029
|
+
}).catch(() => {
|
|
5030
|
+
store.dispatch(removeIssueAttachments(offlineAttachments.map((attachment) => attachment.offline_id)));
|
|
4729
5031
|
});
|
|
5032
|
+
return [offlineAttachments, promise.then(({ attachments }) => attachments)];
|
|
4730
5033
|
}
|
|
4731
5034
|
attachFilesToComponent(filesToSubmit, componentId) {
|
|
4732
5035
|
return filesToSubmit.map((file) => {
|
|
@@ -4770,7 +5073,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4770
5073
|
return photoAttachmentPromise(file);
|
|
4771
5074
|
});
|
|
4772
5075
|
}
|
|
4773
|
-
|
|
5076
|
+
attachFilesToDocument(filesToSubmit, documentId) {
|
|
4774
5077
|
return filesToSubmit.map((file) => {
|
|
4775
5078
|
if (!(file instanceof File)) {
|
|
4776
5079
|
throw new Error("Expected a File instance.");
|
|
@@ -4781,12 +5084,12 @@ class AttachmentService extends BaseApiService {
|
|
|
4781
5084
|
file: file2,
|
|
4782
5085
|
file_name: file2.name,
|
|
4783
5086
|
file_type: file2.type,
|
|
4784
|
-
|
|
5087
|
+
document: documentId,
|
|
4785
5088
|
file_sha1: hash,
|
|
4786
5089
|
submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4787
5090
|
created_by: this.client.store.getState().userReducer.currentUser.id
|
|
4788
5091
|
});
|
|
4789
|
-
return this.
|
|
5092
|
+
return this.addDocumentAttachment(attachment);
|
|
4790
5093
|
};
|
|
4791
5094
|
return photoAttachmentPromise(file);
|
|
4792
5095
|
});
|
|
@@ -4966,9 +5269,9 @@ class AttachmentService extends BaseApiService {
|
|
|
4966
5269
|
const promise = performRequest2();
|
|
4967
5270
|
return [offlineAttachment, promise];
|
|
4968
5271
|
}
|
|
4969
|
-
async
|
|
5272
|
+
async replaceDocumentAttachmentFile(attachmentId, newFile) {
|
|
4970
5273
|
const { store } = this.client;
|
|
4971
|
-
const attachment = store.getState().
|
|
5274
|
+
const attachment = store.getState().documentsReducer.attachments[attachmentId];
|
|
4972
5275
|
if (!attachment)
|
|
4973
5276
|
throw new Error(`Attachment ${attachmentId} not found`);
|
|
4974
5277
|
let oldFile = void 0;
|
|
@@ -4982,7 +5285,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4982
5285
|
throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
|
|
4983
5286
|
}
|
|
4984
5287
|
store.dispatch(
|
|
4985
|
-
|
|
5288
|
+
updateDocumentAttachment({
|
|
4986
5289
|
...attachment,
|
|
4987
5290
|
file_sha1: newSha1,
|
|
4988
5291
|
file: URL.createObjectURL(newFile)
|
|
@@ -4990,13 +5293,13 @@ class AttachmentService extends BaseApiService {
|
|
|
4990
5293
|
);
|
|
4991
5294
|
await this.client.files.addCache(newFile, newSha1);
|
|
4992
5295
|
const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
|
|
4993
|
-
store.dispatch(
|
|
5296
|
+
store.dispatch(updateDocumentAttachment(attachment));
|
|
4994
5297
|
throw e;
|
|
4995
5298
|
});
|
|
4996
5299
|
const promise2 = this.enqueueRequest({
|
|
4997
5300
|
description: "Edit attachment",
|
|
4998
5301
|
method: HttpMethod.PATCH,
|
|
4999
|
-
url: `/attachments/
|
|
5302
|
+
url: `/attachments/documents/${attachment.offline_id}/`,
|
|
5000
5303
|
isResponseBlob: false,
|
|
5001
5304
|
payload: fileProps,
|
|
5002
5305
|
blockers: [attachmentId, newSha1],
|
|
@@ -5009,7 +5312,7 @@ class AttachmentService extends BaseApiService {
|
|
|
5009
5312
|
} catch (e) {
|
|
5010
5313
|
if (oldFile) {
|
|
5011
5314
|
store.dispatch(
|
|
5012
|
-
|
|
5315
|
+
updateDocumentAttachment({
|
|
5013
5316
|
...attachment,
|
|
5014
5317
|
file_sha1: attachment.file_sha1,
|
|
5015
5318
|
file: URL.createObjectURL(oldFile)
|
|
@@ -5079,20 +5382,20 @@ class AttachmentService extends BaseApiService {
|
|
|
5079
5382
|
blocks: [componentTypeAttachmentId]
|
|
5080
5383
|
});
|
|
5081
5384
|
}
|
|
5082
|
-
|
|
5385
|
+
deleteDocumentAttachment(documentAttachmentId) {
|
|
5083
5386
|
const { store } = this.client;
|
|
5084
|
-
const attachment =
|
|
5387
|
+
const attachment = store.getState().documentsReducer.attachments[documentAttachmentId];
|
|
5085
5388
|
if (!attachment) {
|
|
5086
|
-
throw new Error(`Attachment ${
|
|
5389
|
+
throw new Error(`Attachment ${documentAttachmentId} not found`);
|
|
5087
5390
|
}
|
|
5088
|
-
store.dispatch(
|
|
5391
|
+
store.dispatch(removeDocumentAttachment(documentAttachmentId));
|
|
5089
5392
|
void this.client.files.removeCache(attachment.file_sha1);
|
|
5090
5393
|
return this.enqueueRequest({
|
|
5091
|
-
description: "Delete attachment",
|
|
5394
|
+
description: "Delete document attachment",
|
|
5092
5395
|
method: HttpMethod.DELETE,
|
|
5093
|
-
url: `/attachments/
|
|
5094
|
-
blockers: [
|
|
5095
|
-
blocks: [
|
|
5396
|
+
url: `/attachments/documents/${documentAttachmentId}/`,
|
|
5397
|
+
blockers: [documentAttachmentId],
|
|
5398
|
+
blocks: [documentAttachmentId]
|
|
5096
5399
|
});
|
|
5097
5400
|
}
|
|
5098
5401
|
}
|
|
@@ -6330,11 +6633,18 @@ class MainService extends BaseApiService {
|
|
|
6330
6633
|
if (currentProjectId) {
|
|
6331
6634
|
const [_offlineAttachments, promise] = this.client.attachments.fetchAll(currentProjectId);
|
|
6332
6635
|
void promise.then((result) => {
|
|
6333
|
-
const {
|
|
6636
|
+
const {
|
|
6637
|
+
issue_attachments,
|
|
6638
|
+
component_type_attachments,
|
|
6639
|
+
component_attachments,
|
|
6640
|
+
project_attachments,
|
|
6641
|
+
document_attachments
|
|
6642
|
+
} = result;
|
|
6334
6643
|
store.dispatch(setIssueAttachments(issue_attachments));
|
|
6335
6644
|
store.dispatch(setComponentAttachments(component_attachments));
|
|
6336
6645
|
store.dispatch(setComponentTypeAttachments(component_type_attachments));
|
|
6337
6646
|
store.dispatch(setProjectAttachments(project_attachments));
|
|
6647
|
+
store.dispatch(setDocumentAttachments(document_attachments));
|
|
6338
6648
|
});
|
|
6339
6649
|
void this.client.documents.refreshStore();
|
|
6340
6650
|
void this.client.issueUpdates.refreshStore();
|
|
@@ -6702,7 +7012,7 @@ class UserFormService extends BaseApiService {
|
|
|
6702
7012
|
...revisionAttachmentPayload,
|
|
6703
7013
|
file: URL.createObjectURL(image)
|
|
6704
7014
|
};
|
|
6705
|
-
store.dispatch(
|
|
7015
|
+
store.dispatch(addFormRevisionAttachment(offlinePayload));
|
|
6706
7016
|
return attach;
|
|
6707
7017
|
});
|
|
6708
7018
|
});
|
|
@@ -6736,8 +7046,8 @@ class UserFormService extends BaseApiService {
|
|
|
6736
7046
|
revision: 0
|
|
6737
7047
|
};
|
|
6738
7048
|
const { store } = this.client;
|
|
6739
|
-
store.dispatch(
|
|
6740
|
-
store.dispatch(
|
|
7049
|
+
store.dispatch(addForm(retForm));
|
|
7050
|
+
store.dispatch(addFormRevision(retRevision));
|
|
6741
7051
|
const formPromise = this.enqueueRequest({
|
|
6742
7052
|
description: "Create form",
|
|
6743
7053
|
method: HttpMethod.POST,
|
|
@@ -6755,8 +7065,8 @@ class UserFormService extends BaseApiService {
|
|
|
6755
7065
|
});
|
|
6756
7066
|
const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
|
|
6757
7067
|
void formPromise.catch((e) => {
|
|
6758
|
-
store.dispatch(
|
|
6759
|
-
store.dispatch(
|
|
7068
|
+
store.dispatch(deleteForm(retForm.offline_id));
|
|
7069
|
+
store.dispatch(deleteFormRevision(retRevision.offline_id));
|
|
6760
7070
|
throw e;
|
|
6761
7071
|
});
|
|
6762
7072
|
const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
|
|
@@ -6798,7 +7108,7 @@ class UserFormService extends BaseApiService {
|
|
|
6798
7108
|
revision: "Pending",
|
|
6799
7109
|
form: formId2
|
|
6800
7110
|
};
|
|
6801
|
-
store.dispatch(
|
|
7111
|
+
store.dispatch(addFormRevision(fullRevision));
|
|
6802
7112
|
const promise = this.enqueueRequest({
|
|
6803
7113
|
description: "Create form revision",
|
|
6804
7114
|
method: HttpMethod.PATCH,
|
|
@@ -6812,9 +7122,9 @@ class UserFormService extends BaseApiService {
|
|
|
6812
7122
|
});
|
|
6813
7123
|
const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
|
|
6814
7124
|
void promise.then((result) => {
|
|
6815
|
-
store.dispatch(
|
|
7125
|
+
store.dispatch(setFormRevision(result));
|
|
6816
7126
|
}).catch(() => {
|
|
6817
|
-
store.dispatch(
|
|
7127
|
+
store.dispatch(deleteFormRevision(fullRevision.offline_id));
|
|
6818
7128
|
});
|
|
6819
7129
|
const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
|
|
6820
7130
|
return [fullRevision, settledPromise];
|
|
@@ -6856,19 +7166,19 @@ class UserFormService extends BaseApiService {
|
|
|
6856
7166
|
async delete(formId2) {
|
|
6857
7167
|
const { store } = this.client;
|
|
6858
7168
|
const state = store.getState();
|
|
6859
|
-
const userForm =
|
|
7169
|
+
const userForm = selectForm(formId2)(state);
|
|
6860
7170
|
if (!userForm) {
|
|
6861
7171
|
throw new Error("Expected userForm to exist");
|
|
6862
7172
|
}
|
|
6863
|
-
const userFormSubmissions =
|
|
7173
|
+
const userFormSubmissions = selectFormSubmissionsOfForm(formId2)(state);
|
|
6864
7174
|
if (userFormSubmissions && userFormSubmissions.length > 0) {
|
|
6865
|
-
store.dispatch(
|
|
7175
|
+
store.dispatch(deleteFormSubmissions(userFormSubmissions.map(({ offline_id }) => offline_id)));
|
|
6866
7176
|
}
|
|
6867
|
-
const userFormRevisions =
|
|
7177
|
+
const userFormRevisions = selectFormRevisionsOfForm(formId2)(state);
|
|
6868
7178
|
if (userFormRevisions && userFormRevisions.length > 0) {
|
|
6869
|
-
store.dispatch(
|
|
7179
|
+
store.dispatch(deleteFormRevisions(userFormRevisions.map(({ offline_id }) => offline_id)));
|
|
6870
7180
|
}
|
|
6871
|
-
store.dispatch(
|
|
7181
|
+
store.dispatch(deleteForm(formId2));
|
|
6872
7182
|
try {
|
|
6873
7183
|
return await this.enqueueRequest({
|
|
6874
7184
|
description: "Delete form",
|
|
@@ -6878,12 +7188,12 @@ class UserFormService extends BaseApiService {
|
|
|
6878
7188
|
blocks: []
|
|
6879
7189
|
});
|
|
6880
7190
|
} catch (e) {
|
|
6881
|
-
store.dispatch(
|
|
7191
|
+
store.dispatch(addForm(userForm));
|
|
6882
7192
|
if (userFormRevisions && userFormRevisions.length > 0) {
|
|
6883
|
-
store.dispatch(
|
|
7193
|
+
store.dispatch(addFormRevisions(userFormRevisions));
|
|
6884
7194
|
}
|
|
6885
7195
|
if (userFormSubmissions && userFormSubmissions.length > 0) {
|
|
6886
|
-
store.dispatch(
|
|
7196
|
+
store.dispatch(addFormSubmissions(userFormSubmissions));
|
|
6887
7197
|
}
|
|
6888
7198
|
throw e;
|
|
6889
7199
|
}
|
|
@@ -6897,16 +7207,15 @@ class UserFormService extends BaseApiService {
|
|
|
6897
7207
|
blockers: [],
|
|
6898
7208
|
blocks: []
|
|
6899
7209
|
});
|
|
6900
|
-
store.dispatch(
|
|
6901
|
-
store.dispatch(
|
|
6902
|
-
store.dispatch(
|
|
7210
|
+
store.dispatch(setForms(Object.values(result.forms)));
|
|
7211
|
+
store.dispatch(setFormRevisions(Object.values(result.revisions)));
|
|
7212
|
+
store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
|
|
6903
7213
|
}
|
|
6904
7214
|
}
|
|
6905
7215
|
const isArrayOfFiles = (value) => {
|
|
6906
7216
|
return Array.isArray(value) && value[0] instanceof File;
|
|
6907
7217
|
};
|
|
6908
|
-
const separateFilesFromValues = (
|
|
6909
|
-
const { values } = payload;
|
|
7218
|
+
const separateFilesFromValues = (values) => {
|
|
6910
7219
|
const files = {};
|
|
6911
7220
|
const newValues = {};
|
|
6912
7221
|
for (const key in values) {
|
|
@@ -6921,17 +7230,13 @@ const separateFilesFromValues = (payload) => {
|
|
|
6921
7230
|
newValues[key] = value;
|
|
6922
7231
|
}
|
|
6923
7232
|
}
|
|
6924
|
-
|
|
6925
|
-
...payload,
|
|
6926
|
-
values: newValues
|
|
6927
|
-
};
|
|
6928
|
-
return { payloadWithoutFiles, files };
|
|
7233
|
+
return { values: newValues, files };
|
|
6929
7234
|
};
|
|
6930
7235
|
class UserFormSubmissionService extends BaseApiService {
|
|
6931
7236
|
constructor() {
|
|
6932
7237
|
super(...arguments);
|
|
6933
7238
|
// Attach files to submission, after uploading them to S3
|
|
6934
|
-
__publicField(this, "getAttachFilesPromises", (files,
|
|
7239
|
+
__publicField(this, "getAttachFilesPromises", (files, submission) => {
|
|
6935
7240
|
const { store } = this.client;
|
|
6936
7241
|
return Object.entries(files).map(async ([key, fileArray]) => {
|
|
6937
7242
|
const attachResults = [];
|
|
@@ -6941,24 +7246,27 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
6941
7246
|
const [fileProps] = await this.client.files.uploadFileToS3(sha1);
|
|
6942
7247
|
const submissionAttachmentPayload = offline({
|
|
6943
7248
|
...fileProps,
|
|
6944
|
-
submission:
|
|
7249
|
+
submission: submission.offline_id,
|
|
6945
7250
|
field_identifier: key
|
|
6946
7251
|
});
|
|
6947
7252
|
const attach = await this.enqueueRequest({
|
|
6948
7253
|
description: "Attach file to form submission",
|
|
6949
7254
|
method: HttpMethod.POST,
|
|
6950
|
-
url: `/forms/submission/${
|
|
7255
|
+
url: `/forms/submission/${submission.offline_id}/attachments/`,
|
|
6951
7256
|
payload: submissionAttachmentPayload,
|
|
6952
|
-
blockers: [
|
|
6953
|
-
|
|
6954
|
-
|
|
7257
|
+
blockers: [
|
|
7258
|
+
submission.component,
|
|
7259
|
+
submission.component_stage,
|
|
7260
|
+
submission.issue,
|
|
7261
|
+
submission.form_revision
|
|
7262
|
+
].filter((x) => x !== void 0),
|
|
6955
7263
|
blocks: [submissionAttachmentPayload.offline_id]
|
|
6956
7264
|
});
|
|
6957
7265
|
const offlinePayload = {
|
|
6958
7266
|
...submissionAttachmentPayload,
|
|
6959
7267
|
file: URL.createObjectURL(file)
|
|
6960
7268
|
};
|
|
6961
|
-
store.dispatch(
|
|
7269
|
+
store.dispatch(addFormSubmissionAttachment(offlinePayload));
|
|
6962
7270
|
attachResults.push(attach);
|
|
6963
7271
|
}
|
|
6964
7272
|
return attachResults;
|
|
@@ -6972,70 +7280,165 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
6972
7280
|
if (!activeProjectId) {
|
|
6973
7281
|
throw new Error("Expected an active project");
|
|
6974
7282
|
}
|
|
6975
|
-
const {
|
|
7283
|
+
const { values, files } = separateFilesFromValues(payload.values);
|
|
7284
|
+
const offlineSubmission = {
|
|
7285
|
+
...payload,
|
|
7286
|
+
values,
|
|
7287
|
+
created_by: state.userReducer.currentUser.id,
|
|
7288
|
+
submitted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
7289
|
+
};
|
|
6976
7290
|
const promise = this.enqueueRequest({
|
|
6977
7291
|
description: "Respond to form",
|
|
6978
7292
|
method: HttpMethod.POST,
|
|
6979
7293
|
url: `/forms/revisions/${payload.form_revision}/respond/`,
|
|
6980
|
-
payload: { ...
|
|
7294
|
+
payload: { ...offlineSubmission, project: activeProjectId },
|
|
6981
7295
|
blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
|
|
6982
7296
|
(x) => x !== void 0
|
|
6983
7297
|
),
|
|
6984
7298
|
blocks: [payload.offline_id]
|
|
6985
7299
|
});
|
|
6986
|
-
const attachFilesPromises = this.getAttachFilesPromises(files,
|
|
6987
|
-
|
|
6988
|
-
const fullOfflineResult = {
|
|
6989
|
-
...payload,
|
|
6990
|
-
created_by: state.userReducer.currentUser.id,
|
|
6991
|
-
created_at: now,
|
|
6992
|
-
updated_at: now
|
|
6993
|
-
};
|
|
6994
|
-
const offlineResultWithoutFiles = {
|
|
6995
|
-
...fullOfflineResult,
|
|
6996
|
-
...payloadWithoutFiles
|
|
6997
|
-
};
|
|
6998
|
-
store.dispatch(updateOrCreateUserFormSubmission(offlineResultWithoutFiles));
|
|
7300
|
+
const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
|
|
7301
|
+
store.dispatch(addFormSubmission(offlineSubmission));
|
|
6999
7302
|
void promise.then((result) => {
|
|
7000
7303
|
store.dispatch(addActiveProjectFormSubmissionsCount(1));
|
|
7001
|
-
store.dispatch(
|
|
7304
|
+
store.dispatch(setFormSubmission(result));
|
|
7002
7305
|
return result;
|
|
7003
7306
|
}).catch(() => {
|
|
7004
|
-
store.dispatch(
|
|
7307
|
+
store.dispatch(deleteFormSubmission(payload.offline_id));
|
|
7005
7308
|
store.dispatch(addActiveProjectFormSubmissionsCount(-1));
|
|
7006
7309
|
});
|
|
7007
7310
|
const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
|
|
7008
|
-
return [
|
|
7311
|
+
return [offlineSubmission, settledPromise];
|
|
7009
7312
|
}
|
|
7010
|
-
|
|
7313
|
+
// Note currently the bulkAdd method is specific to form submissions for components
|
|
7314
|
+
// TODO: adapt the support bulk adding to any model type
|
|
7315
|
+
async bulkAdd(args) {
|
|
7316
|
+
const { form_revision, values: argsValues, componentOfflineIds } = args;
|
|
7011
7317
|
const { store } = this.client;
|
|
7012
|
-
const
|
|
7013
|
-
|
|
7014
|
-
|
|
7318
|
+
const offlineSubmissions = [];
|
|
7319
|
+
const offlineAttachments = [];
|
|
7320
|
+
const submissionOfflineIds = [];
|
|
7321
|
+
const submissionsPayload = [];
|
|
7322
|
+
const attachmentsPayload = [];
|
|
7323
|
+
const { values, files } = separateFilesFromValues(argsValues);
|
|
7324
|
+
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7325
|
+
const createdBy = store.getState().userReducer.currentUser.id;
|
|
7326
|
+
for (const component_id of componentOfflineIds) {
|
|
7327
|
+
const submission = offline({
|
|
7328
|
+
form_revision,
|
|
7329
|
+
values,
|
|
7330
|
+
created_by: createdBy,
|
|
7331
|
+
submitted_at: submittedAt,
|
|
7332
|
+
component: component_id
|
|
7333
|
+
});
|
|
7334
|
+
submissionOfflineIds.push(submission.offline_id);
|
|
7335
|
+
submissionsPayload.push({ offline_id: submission.offline_id, component_id });
|
|
7336
|
+
offlineSubmissions.push(submission);
|
|
7337
|
+
for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
|
|
7338
|
+
for (const file of fileArray) {
|
|
7339
|
+
const sha1 = await hashFile(file);
|
|
7340
|
+
await this.client.files.addCache(file, sha1);
|
|
7341
|
+
const offlineAttachment = offline({
|
|
7342
|
+
file_name: file.name,
|
|
7343
|
+
file_sha1: sha1,
|
|
7344
|
+
file: URL.createObjectURL(file),
|
|
7345
|
+
submission: submission.offline_id,
|
|
7346
|
+
field_identifier: fieldIdentifier
|
|
7347
|
+
});
|
|
7348
|
+
offlineAttachments.push(offlineAttachment);
|
|
7349
|
+
attachmentsPayload.push({
|
|
7350
|
+
offline_id: offlineAttachment.offline_id,
|
|
7351
|
+
submission_id: submission.offline_id,
|
|
7352
|
+
sha1,
|
|
7353
|
+
name: file.name,
|
|
7354
|
+
field_identifier: fieldIdentifier
|
|
7355
|
+
});
|
|
7356
|
+
}
|
|
7357
|
+
}
|
|
7015
7358
|
}
|
|
7359
|
+
const filesRecord = {};
|
|
7360
|
+
for (const file of Object.values(files).flat()) {
|
|
7361
|
+
const sha1 = await hashFile(file);
|
|
7362
|
+
filesRecord[sha1] = {
|
|
7363
|
+
sha1,
|
|
7364
|
+
extension: file.name.split(".").pop() || "",
|
|
7365
|
+
file_type: file.type,
|
|
7366
|
+
size: file.size
|
|
7367
|
+
};
|
|
7368
|
+
}
|
|
7369
|
+
store.dispatch(addFormSubmissions(offlineSubmissions));
|
|
7370
|
+
store.dispatch(addFormSubmissionAttachments(offlineAttachments));
|
|
7371
|
+
const promise = this.enqueueRequest({
|
|
7372
|
+
description: "Bulk add form submissions",
|
|
7373
|
+
method: HttpMethod.POST,
|
|
7374
|
+
url: `/forms/revisions/${form_revision}/bulk-respond/`,
|
|
7375
|
+
payload: {
|
|
7376
|
+
form_data: values,
|
|
7377
|
+
submitted_at: submittedAt,
|
|
7378
|
+
submissions: submissionsPayload,
|
|
7379
|
+
attachments: attachmentsPayload,
|
|
7380
|
+
files: Object.values(filesRecord)
|
|
7381
|
+
},
|
|
7382
|
+
blockers: componentOfflineIds,
|
|
7383
|
+
blocks: submissionOfflineIds
|
|
7384
|
+
});
|
|
7385
|
+
promise.then(({ submissions, attachments, presigned_urls }) => {
|
|
7386
|
+
store.dispatch(updateFormSubmissions(submissions));
|
|
7387
|
+
store.dispatch(updateFormSubmissionAttachments(attachments));
|
|
7388
|
+
for (const [sha1, presigned_url] of Object.entries(presigned_urls)) {
|
|
7389
|
+
const file = filesRecord[sha1];
|
|
7390
|
+
if (!file)
|
|
7391
|
+
continue;
|
|
7392
|
+
void this.enqueueRequest({
|
|
7393
|
+
url: presigned_url.url,
|
|
7394
|
+
description: "Upload file",
|
|
7395
|
+
method: HttpMethod.POST,
|
|
7396
|
+
isExternalUrl: true,
|
|
7397
|
+
isAuthNeeded: false,
|
|
7398
|
+
attachmentHash: sha1,
|
|
7399
|
+
blockers: [`s3-${file.sha1}.${file.extension}`],
|
|
7400
|
+
blocks: [sha1],
|
|
7401
|
+
s3url: presigned_url
|
|
7402
|
+
});
|
|
7403
|
+
}
|
|
7404
|
+
}).catch(() => {
|
|
7405
|
+
store.dispatch(deleteFormSubmissions(submissionOfflineIds));
|
|
7406
|
+
store.dispatch(deleteFormSubmissionAttachments(offlineAttachments.map((x) => x.offline_id)));
|
|
7407
|
+
});
|
|
7408
|
+
return [offlineSubmissions, promise.then(({ submissions }) => submissions)];
|
|
7409
|
+
}
|
|
7410
|
+
update(submission) {
|
|
7411
|
+
const { store } = this.client;
|
|
7412
|
+
const { values, files } = separateFilesFromValues(submission.values);
|
|
7016
7413
|
const attachFilesPromises = this.getAttachFilesPromises(files, submission);
|
|
7017
|
-
const
|
|
7018
|
-
...
|
|
7019
|
-
|
|
7414
|
+
const offlineSubmission = {
|
|
7415
|
+
...submission,
|
|
7416
|
+
values
|
|
7020
7417
|
};
|
|
7021
|
-
store.
|
|
7418
|
+
const submissionToBeUpdated = store.getState().formSubmissionReducer.formSubmissions[submission.offline_id];
|
|
7419
|
+
store.dispatch(updateFormSubmission(offlineSubmission));
|
|
7022
7420
|
const promise = this.enqueueRequest({
|
|
7023
7421
|
description: "Patch form submission",
|
|
7024
7422
|
method: HttpMethod.PATCH,
|
|
7025
7423
|
url: `/forms/submissions/${submission.offline_id}/`,
|
|
7026
|
-
payload:
|
|
7027
|
-
blockers: [
|
|
7424
|
+
payload: offlineSubmission,
|
|
7425
|
+
blockers: [offlineSubmission.issue, offlineSubmission.component, offlineSubmission.component_stage].filter(
|
|
7028
7426
|
(x) => x !== void 0
|
|
7029
7427
|
),
|
|
7030
|
-
blocks: [
|
|
7428
|
+
blocks: [offlineSubmission.offline_id]
|
|
7429
|
+
});
|
|
7430
|
+
promise.then((createdSubmission) => {
|
|
7431
|
+
store.dispatch(setFormSubmission(createdSubmission));
|
|
7432
|
+
}).catch(() => {
|
|
7433
|
+
store.dispatch(setFormSubmission(submissionToBeUpdated));
|
|
7031
7434
|
});
|
|
7032
|
-
return Promise.all([promise, ...attachFilesPromises]).then(() => promise);
|
|
7435
|
+
return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
|
|
7033
7436
|
}
|
|
7034
7437
|
async delete(submissionId) {
|
|
7035
7438
|
const { store } = this.client;
|
|
7036
7439
|
const state = store.getState();
|
|
7037
|
-
const submission = state.
|
|
7038
|
-
store.dispatch(
|
|
7440
|
+
const submission = state.formSubmissionReducer.formSubmissions[submissionId];
|
|
7441
|
+
store.dispatch(deleteFormSubmission(submissionId));
|
|
7039
7442
|
store.dispatch(addActiveProjectFormSubmissionsCount(-1));
|
|
7040
7443
|
try {
|
|
7041
7444
|
return await this.enqueueRequest({
|
|
@@ -7046,10 +7449,8 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7046
7449
|
blocks: []
|
|
7047
7450
|
});
|
|
7048
7451
|
} catch (e) {
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
store.dispatch(updateOrCreateUserFormSubmission(submission));
|
|
7052
|
-
}
|
|
7452
|
+
store.dispatch(addActiveProjectFormSubmissionsCount(1));
|
|
7453
|
+
store.dispatch(addFormSubmission(submission));
|
|
7053
7454
|
throw e;
|
|
7054
7455
|
}
|
|
7055
7456
|
}
|
|
@@ -7063,7 +7464,7 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7063
7464
|
blockers: [],
|
|
7064
7465
|
blocks: []
|
|
7065
7466
|
});
|
|
7066
|
-
store.dispatch(
|
|
7467
|
+
store.dispatch(setFormSubmissions(submissions));
|
|
7067
7468
|
const attachments = await this.enqueueRequest({
|
|
7068
7469
|
description: "Fetch form attachments",
|
|
7069
7470
|
method: HttpMethod.GET,
|
|
@@ -7071,7 +7472,7 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7071
7472
|
blockers: [],
|
|
7072
7473
|
blocks: []
|
|
7073
7474
|
});
|
|
7074
|
-
store.dispatch(
|
|
7475
|
+
store.dispatch(setFormSubmissionAttachments(attachments));
|
|
7075
7476
|
}
|
|
7076
7477
|
}
|
|
7077
7478
|
class WorkspaceService extends BaseApiService {
|
|
@@ -13930,7 +14331,7 @@ const initialFormValues = (fields, values) => {
|
|
|
13930
14331
|
};
|
|
13931
14332
|
const useAttachImagesToFormRevisionFields = (revision) => {
|
|
13932
14333
|
const { sdk } = useSDK();
|
|
13933
|
-
const attachments = useAppSelector(
|
|
14334
|
+
const attachments = useAppSelector(selectAttachmentsOfFormRevision((revision == null ? void 0 : revision.offline_id) ?? ""));
|
|
13934
14335
|
return useMemo(() => {
|
|
13935
14336
|
if (!revision || !attachments)
|
|
13936
14337
|
return revision;
|
|
@@ -14027,7 +14428,7 @@ const FormSubmissionViewer = memo(
|
|
|
14027
14428
|
return formRevisionToSchema(revisionWithImages, { readonly: true });
|
|
14028
14429
|
}, [revisionWithImages]);
|
|
14029
14430
|
const submissionValuesWithAttachments = useMemo(() => {
|
|
14030
|
-
const attachments =
|
|
14431
|
+
const attachments = selectAttachmentsOfFormSubmission(submission.offline_id)(sdk.store.getState()) ?? [];
|
|
14031
14432
|
const downloadedAttachments = {};
|
|
14032
14433
|
for (const attachment of attachments) {
|
|
14033
14434
|
const promise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
|
|
@@ -14077,8 +14478,8 @@ const FormBrowser = memo(
|
|
|
14077
14478
|
}
|
|
14078
14479
|
return ret;
|
|
14079
14480
|
}, [filter, maxResults, ownerFilter]);
|
|
14080
|
-
const userForms = useAppSelector(
|
|
14081
|
-
const userFormMapping = useAppSelector(
|
|
14481
|
+
const userForms = useAppSelector(selectFilteredForms(ownerFilterOptions)) ?? [];
|
|
14482
|
+
const userFormMapping = useAppSelector(selectFormMapping);
|
|
14082
14483
|
const attachableUserForms = userForms.filter((form) => !form.component_type);
|
|
14083
14484
|
const attachableUserFormMapping = Object.values(userFormMapping).filter(
|
|
14084
14485
|
(form) => !form.component_type
|
|
@@ -14111,7 +14512,7 @@ const FormBrowser = memo(
|
|
|
14111
14512
|
const handleChange = useCallback((e) => {
|
|
14112
14513
|
setFilter(e.currentTarget.value);
|
|
14113
14514
|
}, []);
|
|
14114
|
-
const numberOfForms = useAppSelector(
|
|
14515
|
+
const numberOfForms = useAppSelector(selectGeneralFormCount) || 0;
|
|
14115
14516
|
const numberOfHiddenForms = numberOfForms - attachableUserForms.length;
|
|
14116
14517
|
const overflowMessage = attachableUserForms.length == maxResults && numberOfHiddenForms > 0 ? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)` : numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`;
|
|
14117
14518
|
return /* @__PURE__ */ jsxs(Flex$1, { ref, direction: "column", gap: "2", children: [
|
|
@@ -14205,16 +14606,13 @@ const FormSubmissionBrowserEntry = memo((props) => {
|
|
|
14205
14606
|
const { submission, onSubmissionClick, compact, labelType, rowDecorator } = props;
|
|
14206
14607
|
const currentUser = useAppSelector(selectCurrentUser);
|
|
14207
14608
|
const createdBy = useAppSelector(selectUser("created_by" in submission ? submission.created_by : currentUser.id));
|
|
14208
|
-
const dateToUse =
|
|
14209
|
-
const formattedDateTime =
|
|
14210
|
-
hour: "2-digit",
|
|
14211
|
-
minute: "2-digit"
|
|
14212
|
-
}) : getLocalDateString(dateToUse);
|
|
14609
|
+
const dateToUse = submission.submitted_at;
|
|
14610
|
+
const formattedDateTime = getLocalDateString(dateToUse);
|
|
14213
14611
|
const revision = useAppSelector(selectFormRevision(submission.form_revision));
|
|
14214
14612
|
if (!revision) {
|
|
14215
14613
|
throw new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`);
|
|
14216
14614
|
}
|
|
14217
|
-
const latestRevisionNumber = (_a2 = useAppSelector(
|
|
14615
|
+
const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevisionOfForm(revision.form))) == null ? void 0 : _a2.revision;
|
|
14218
14616
|
const creatorProfileSrc = useFileSrc({
|
|
14219
14617
|
file: (createdBy == null ? void 0 : createdBy.profile.file) ?? null,
|
|
14220
14618
|
fileSha1: (createdBy == null ? void 0 : createdBy.profile.file_sha1) ?? null
|
|
@@ -14245,10 +14643,6 @@ const FormSubmissionBrowserEntry = memo((props) => {
|
|
|
14245
14643
|
return row;
|
|
14246
14644
|
});
|
|
14247
14645
|
FormSubmissionBrowserEntry.displayName = "FormSubmissionBrowserEntry";
|
|
14248
|
-
const getCreatedAtOrSubmittedAtDate = (submission) => {
|
|
14249
|
-
const date = "created_at" in submission ? submission.created_at : submission.submitted_at;
|
|
14250
|
-
return new Date(date);
|
|
14251
|
-
};
|
|
14252
14646
|
const FormSubmissionBrowser = memo((props) => {
|
|
14253
14647
|
const {
|
|
14254
14648
|
formId: formId2,
|
|
@@ -14262,10 +14656,10 @@ const FormSubmissionBrowser = memo((props) => {
|
|
|
14262
14656
|
if (!!formId2 === !!propSubmissions) {
|
|
14263
14657
|
throw new Error("Either formId or submissions must be provided, but not both.");
|
|
14264
14658
|
}
|
|
14265
|
-
const submissions = useAppSelector(propSubmissions ? () => propSubmissions :
|
|
14659
|
+
const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectFormSubmissionsOfForm(formId2));
|
|
14266
14660
|
const sortedSubmissions = useMemo(
|
|
14267
14661
|
() => submissions == null ? void 0 : submissions.sort((a, b) => {
|
|
14268
|
-
return
|
|
14662
|
+
return a.submitted_at.localeCompare(b.submitted_at);
|
|
14269
14663
|
}),
|
|
14270
14664
|
[submissions]
|
|
14271
14665
|
);
|
|
@@ -15583,6 +15977,7 @@ export {
|
|
|
15583
15977
|
VerificationCodeType,
|
|
15584
15978
|
WorkspaceService,
|
|
15585
15979
|
YELLOW,
|
|
15980
|
+
_selectLatestFormRevision,
|
|
15586
15981
|
_setLatestRetryTime,
|
|
15587
15982
|
acceptProjectInvite,
|
|
15588
15983
|
addActiveProjectFormSubmissionsCount,
|
|
@@ -15595,9 +15990,21 @@ export {
|
|
|
15595
15990
|
addComponentTypeAttachment,
|
|
15596
15991
|
addComponentTypeAttachments,
|
|
15597
15992
|
addComponentsInBatches,
|
|
15993
|
+
addDocumentAttachment,
|
|
15994
|
+
addDocumentAttachments,
|
|
15598
15995
|
addDocuments,
|
|
15599
15996
|
addEmailDomain,
|
|
15600
15997
|
addFavouriteProjectId,
|
|
15998
|
+
addForm,
|
|
15999
|
+
addFormRevision,
|
|
16000
|
+
addFormRevisionAttachment,
|
|
16001
|
+
addFormRevisionAttachments,
|
|
16002
|
+
addFormRevisions,
|
|
16003
|
+
addFormSubmission,
|
|
16004
|
+
addFormSubmissionAttachment,
|
|
16005
|
+
addFormSubmissionAttachments,
|
|
16006
|
+
addFormSubmissions,
|
|
16007
|
+
addForms,
|
|
15601
16008
|
addIssue,
|
|
15602
16009
|
addIssueAttachment,
|
|
15603
16010
|
addIssueAttachments,
|
|
@@ -15618,13 +16025,6 @@ export {
|
|
|
15618
16025
|
addStageCompletions,
|
|
15619
16026
|
addStages,
|
|
15620
16027
|
addToRecentIssues,
|
|
15621
|
-
addUserForm,
|
|
15622
|
-
addUserFormRevision,
|
|
15623
|
-
addUserFormRevisionAttachment,
|
|
15624
|
-
addUserFormRevisions,
|
|
15625
|
-
addUserFormSubmissionAttachment,
|
|
15626
|
-
addUserFormSubmissions,
|
|
15627
|
-
addUserForms,
|
|
15628
16028
|
addUsers,
|
|
15629
16029
|
addWorkspace,
|
|
15630
16030
|
areArraysEqual,
|
|
@@ -15645,6 +16045,7 @@ export {
|
|
|
15645
16045
|
componentStageSlice,
|
|
15646
16046
|
componentTypeReducer,
|
|
15647
16047
|
componentTypeSlice,
|
|
16048
|
+
constructUploadedFilePayloads,
|
|
15648
16049
|
coordinatesAreEqual,
|
|
15649
16050
|
coordinatesToLiteral,
|
|
15650
16051
|
coordinatesToPointGeometry,
|
|
@@ -15655,12 +16056,16 @@ export {
|
|
|
15655
16056
|
defaultBadgeColor,
|
|
15656
16057
|
defaultStore,
|
|
15657
16058
|
deleteComponentType,
|
|
16059
|
+
deleteForm,
|
|
16060
|
+
deleteFormRevision,
|
|
16061
|
+
deleteFormRevisionAttachment,
|
|
16062
|
+
deleteFormRevisionAttachments,
|
|
16063
|
+
deleteFormRevisions,
|
|
16064
|
+
deleteFormSubmission,
|
|
16065
|
+
deleteFormSubmissionAttachment,
|
|
16066
|
+
deleteFormSubmissionAttachments,
|
|
16067
|
+
deleteFormSubmissions,
|
|
15658
16068
|
deleteProject,
|
|
15659
|
-
deleteUserForm,
|
|
15660
|
-
deleteUserFormRevision,
|
|
15661
|
-
deleteUserFormRevisions,
|
|
15662
|
-
deleteUserFormSubmission,
|
|
15663
|
-
deleteUserFormSubmissions,
|
|
15664
16069
|
dequeue,
|
|
15665
16070
|
deserialize,
|
|
15666
16071
|
deserializeField,
|
|
@@ -15689,7 +16094,13 @@ export {
|
|
|
15689
16094
|
fileSlice,
|
|
15690
16095
|
fileToBlob,
|
|
15691
16096
|
flipCoordinates,
|
|
16097
|
+
formReducer,
|
|
16098
|
+
formRevisionReducer,
|
|
15692
16099
|
formRevisionToSchema,
|
|
16100
|
+
formRevisionsSlice,
|
|
16101
|
+
formSlice,
|
|
16102
|
+
formSubmissionReducer,
|
|
16103
|
+
formSubmissionSlice,
|
|
15693
16104
|
index as forms,
|
|
15694
16105
|
fullComponentMarkerSize,
|
|
15695
16106
|
generateBadgeColors,
|
|
@@ -15758,11 +16169,14 @@ export {
|
|
|
15758
16169
|
removeComponentAttachments,
|
|
15759
16170
|
removeComponentTypeAttachment,
|
|
15760
16171
|
removeComponentTypeAttachments,
|
|
16172
|
+
removeDocumentAttachment,
|
|
16173
|
+
removeDocumentAttachments,
|
|
15761
16174
|
removeDocuments,
|
|
15762
16175
|
removeEmailDomain,
|
|
15763
16176
|
removeFavouriteProjectId,
|
|
15764
16177
|
removeIssue,
|
|
15765
16178
|
removeIssueAttachment,
|
|
16179
|
+
removeIssueAttachments,
|
|
15766
16180
|
removeIssueComment,
|
|
15767
16181
|
removeIssueComments,
|
|
15768
16182
|
removeIssueUpdate,
|
|
@@ -15805,6 +16219,7 @@ export {
|
|
|
15805
16219
|
selectAllAttachments,
|
|
15806
16220
|
selectAllComponentAttachments,
|
|
15807
16221
|
selectAllComponentTypeAttachments,
|
|
16222
|
+
selectAllDocumentAttachments,
|
|
15808
16223
|
selectAllProjectAttachments,
|
|
15809
16224
|
selectAncestorIdsOfDocument,
|
|
15810
16225
|
selectAppearance,
|
|
@@ -15812,6 +16227,10 @@ export {
|
|
|
15812
16227
|
selectAttachmentsOfComponentByType,
|
|
15813
16228
|
selectAttachmentsOfComponentType,
|
|
15814
16229
|
selectAttachmentsOfComponentTypeByType,
|
|
16230
|
+
selectAttachmentsOfDocument,
|
|
16231
|
+
selectAttachmentsOfDocumentByType,
|
|
16232
|
+
selectAttachmentsOfFormRevision,
|
|
16233
|
+
selectAttachmentsOfFormSubmission,
|
|
15815
16234
|
selectAttachmentsOfIssue,
|
|
15816
16235
|
selectAttachmentsOfIssueByType,
|
|
15817
16236
|
selectAttachmentsOfProject,
|
|
@@ -15827,11 +16246,11 @@ export {
|
|
|
15827
16246
|
selectCompletedStageIdsForComponent,
|
|
15828
16247
|
selectCompletedStages,
|
|
15829
16248
|
selectComponent,
|
|
16249
|
+
selectComponentAttachment,
|
|
15830
16250
|
selectComponentAttachmentMapping,
|
|
15831
|
-
selectComponentSubmissionMapping,
|
|
15832
16251
|
selectComponentType,
|
|
16252
|
+
selectComponentTypeAttachment,
|
|
15833
16253
|
selectComponentTypeAttachmentMapping,
|
|
15834
|
-
selectComponentTypeForm,
|
|
15835
16254
|
selectComponentTypeFromComponent,
|
|
15836
16255
|
selectComponentTypeFromComponents,
|
|
15837
16256
|
selectComponentTypeStagesMapping,
|
|
@@ -15847,6 +16266,8 @@ export {
|
|
|
15847
16266
|
selectCurrentUser,
|
|
15848
16267
|
selectDeletedRequests,
|
|
15849
16268
|
selectDocument,
|
|
16269
|
+
selectDocumentAttachment,
|
|
16270
|
+
selectDocumentAttachmentMapping,
|
|
15850
16271
|
selectDocuments,
|
|
15851
16272
|
selectDocumentsMapping,
|
|
15852
16273
|
selectEmailDomainsAsMapping,
|
|
@@ -15859,8 +16280,24 @@ export {
|
|
|
15859
16280
|
selectExpandedSections,
|
|
15860
16281
|
selectFavouriteProjects,
|
|
15861
16282
|
selectFileAttachmentsOfIssue,
|
|
15862
|
-
|
|
16283
|
+
selectFilteredForms,
|
|
16284
|
+
selectForm,
|
|
16285
|
+
selectFormMapping,
|
|
16286
|
+
selectFormOfComponentType,
|
|
15863
16287
|
selectFormRevision,
|
|
16288
|
+
selectFormRevisionMapping,
|
|
16289
|
+
selectFormRevisions,
|
|
16290
|
+
selectFormRevisionsOfForm,
|
|
16291
|
+
selectFormSubmission,
|
|
16292
|
+
selectFormSubmissionAttachmentsMapping,
|
|
16293
|
+
selectFormSubmissions,
|
|
16294
|
+
selectFormSubmissionsByComponents,
|
|
16295
|
+
selectFormSubmissionsMapping,
|
|
16296
|
+
selectFormSubmissionsOfComponent,
|
|
16297
|
+
selectFormSubmissionsOfForm,
|
|
16298
|
+
selectFormSubmissionsOfIssue,
|
|
16299
|
+
selectFormsCount,
|
|
16300
|
+
selectGeneralFormCount,
|
|
15864
16301
|
selectHiddenCategoryCount,
|
|
15865
16302
|
selectHiddenComponentTypeIds,
|
|
15866
16303
|
selectIsFetchingInitialData,
|
|
@@ -15868,16 +16305,17 @@ export {
|
|
|
15868
16305
|
selectIsLoading,
|
|
15869
16306
|
selectIsLoggedIn,
|
|
15870
16307
|
selectIssue,
|
|
16308
|
+
selectIssueAttachment,
|
|
15871
16309
|
selectIssueAttachmentMapping,
|
|
15872
16310
|
selectIssueAttachments,
|
|
15873
16311
|
selectIssueMapping,
|
|
15874
16312
|
selectIssueUpdateMapping,
|
|
15875
16313
|
selectIssueUpdatesOfIssue,
|
|
15876
16314
|
selectIssues,
|
|
15877
|
-
|
|
16315
|
+
selectLatestFormRevisionByForm,
|
|
16316
|
+
selectLatestFormRevisionOfForm,
|
|
16317
|
+
selectLatestFormRevisionsOfComponentTypes,
|
|
15878
16318
|
selectLatestRetryTime,
|
|
15879
|
-
selectLatestRevisionByFormId,
|
|
15880
|
-
selectLatestRevisionsFromComponentTypeIds,
|
|
15881
16319
|
selectLicense,
|
|
15882
16320
|
selectLicenseForProject,
|
|
15883
16321
|
selectLicenses,
|
|
@@ -15886,8 +16324,6 @@ export {
|
|
|
15886
16324
|
selectMapStyle,
|
|
15887
16325
|
selectNumberOfComponentTypesMatchingCaseInsensitiveName,
|
|
15888
16326
|
selectNumberOfComponentsOfComponentType,
|
|
15889
|
-
selectNumberOfGeneralUserForms,
|
|
15890
|
-
selectNumberOfUserForms,
|
|
15891
16327
|
selectOrganization,
|
|
15892
16328
|
selectOrganizationAccess,
|
|
15893
16329
|
selectOrganizationAccessForUser,
|
|
@@ -15915,8 +16351,6 @@ export {
|
|
|
15915
16351
|
selectRecentIssuesAsSearchResults,
|
|
15916
16352
|
selectRecentProjects,
|
|
15917
16353
|
selectRehydrated,
|
|
15918
|
-
selectRevisionAttachments,
|
|
15919
|
-
selectRevisionsForForm,
|
|
15920
16354
|
selectRootDocuments,
|
|
15921
16355
|
selectShowTooltips,
|
|
15922
16356
|
selectSortedEmailDomains,
|
|
@@ -15931,16 +16365,10 @@ export {
|
|
|
15931
16365
|
selectStagesFromComponentType,
|
|
15932
16366
|
selectStagesFromComponentTypeIds,
|
|
15933
16367
|
selectStagesFromStageIds,
|
|
15934
|
-
selectSubmissionAttachments,
|
|
15935
|
-
selectSubmissionsForComponent,
|
|
15936
|
-
selectSubmissionsForForm,
|
|
15937
|
-
selectSubmissionsForIssue,
|
|
15938
16368
|
selectUploadUrl,
|
|
15939
16369
|
selectUsedColors,
|
|
15940
16370
|
selectUser,
|
|
15941
|
-
|
|
15942
|
-
selectUserFormMapping,
|
|
15943
|
-
selectUserFormSubmission,
|
|
16371
|
+
selectUserFormRevisionAttachmentsMapping,
|
|
15944
16372
|
selectUsersAsMapping,
|
|
15945
16373
|
selectVisibleStatuses,
|
|
15946
16374
|
selectVisibleUserIds,
|
|
@@ -15961,11 +16389,19 @@ export {
|
|
|
15961
16389
|
setComponents,
|
|
15962
16390
|
setCreateProjectType,
|
|
15963
16391
|
setCurrentUser,
|
|
16392
|
+
setDocumentAttachments,
|
|
15964
16393
|
setDocuments,
|
|
15965
16394
|
setEmailDomains,
|
|
15966
16395
|
setEnableClustering,
|
|
15967
16396
|
setEnableDuplicateIssues,
|
|
15968
16397
|
setEnablePlacementMode,
|
|
16398
|
+
setFormRevision,
|
|
16399
|
+
setFormRevisionAttachments,
|
|
16400
|
+
setFormRevisions,
|
|
16401
|
+
setFormSubmission,
|
|
16402
|
+
setFormSubmissionAttachments,
|
|
16403
|
+
setFormSubmissions,
|
|
16404
|
+
setForms,
|
|
15969
16405
|
setIsFetchingInitialData,
|
|
15970
16406
|
setIsImportingProjectFile,
|
|
15971
16407
|
setIsLoading,
|
|
@@ -15990,9 +16426,6 @@ export {
|
|
|
15990
16426
|
setTokens,
|
|
15991
16427
|
setTourStep,
|
|
15992
16428
|
setUploadUrl,
|
|
15993
|
-
setUserFormRevisionAttachments,
|
|
15994
|
-
setUserFormSubmissionAttachments,
|
|
15995
|
-
setUserFormSubmissions,
|
|
15996
16429
|
setUsers,
|
|
15997
16430
|
setVisibleStatuses,
|
|
15998
16431
|
setVisibleUserIds,
|
|
@@ -16015,12 +16448,16 @@ export {
|
|
|
16015
16448
|
updateComponent,
|
|
16016
16449
|
updateComponentAttachment,
|
|
16017
16450
|
updateComponentTypeAttachment,
|
|
16451
|
+
updateDocumentAttachment,
|
|
16018
16452
|
updateDocuments,
|
|
16453
|
+
updateFormSubmission,
|
|
16454
|
+
updateFormSubmissionAttachments,
|
|
16455
|
+
updateFormSubmissions,
|
|
16019
16456
|
updateIssue,
|
|
16020
16457
|
updateIssueAttachment,
|
|
16458
|
+
updateIssueAttachments,
|
|
16021
16459
|
updateLicense,
|
|
16022
16460
|
updateOrCreateProject,
|
|
16023
|
-
updateOrCreateUserFormSubmission,
|
|
16024
16461
|
updateOrganizationAccess,
|
|
16025
16462
|
updateProjectAccess,
|
|
16026
16463
|
updateProjectAttachment,
|
|
@@ -16034,8 +16471,6 @@ export {
|
|
|
16034
16471
|
useFormikInput,
|
|
16035
16472
|
useMemoCompare,
|
|
16036
16473
|
useSDK,
|
|
16037
|
-
userFormReducer,
|
|
16038
|
-
userFormSlice,
|
|
16039
16474
|
userReducer,
|
|
16040
16475
|
userSlice,
|
|
16041
16476
|
valueIsFile,
|