@overmap-ai/core 1.0.49 → 1.0.50-bulk-form-submission.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +888 -454
- package/dist/overmap-core.js.map +1 -1
- package/dist/overmap-core.umd.cjs +888 -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,22 @@ 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
|
+
void this.enqueueRequest({
|
|
4811
|
+
url: presignedUrl.url,
|
|
4812
|
+
description: "Upload file",
|
|
4813
|
+
method: HttpMethod.POST,
|
|
4814
|
+
isExternalUrl: true,
|
|
4815
|
+
isAuthNeeded: false,
|
|
4816
|
+
attachmentHash: sha1,
|
|
4817
|
+
// TODO: can we use the sha1 as the blocker?
|
|
4818
|
+
blockers: [`s3-${sha1}`],
|
|
4819
|
+
blocks: [sha1],
|
|
4820
|
+
s3url: presignedUrl
|
|
4821
|
+
});
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4554
4824
|
fetchAll(projectId) {
|
|
4555
4825
|
const promise = this.enqueueRequest({
|
|
4556
4826
|
description: "Fetch attachments",
|
|
@@ -4564,7 +4834,8 @@ class AttachmentService extends BaseApiService {
|
|
|
4564
4834
|
issue_attachments: Object.values(state.issueReducer.attachments),
|
|
4565
4835
|
component_attachments: Object.values(state.componentReducer.attachments),
|
|
4566
4836
|
component_type_attachments: Object.values(state.componentTypeReducer.attachments),
|
|
4567
|
-
project_attachments: Object.values(state.projectReducer.attachments)
|
|
4837
|
+
project_attachments: Object.values(state.projectReducer.attachments),
|
|
4838
|
+
document_attachments: Object.values(state.documentsReducer.attachments)
|
|
4568
4839
|
};
|
|
4569
4840
|
return [allAttachments, promise];
|
|
4570
4841
|
}
|
|
@@ -4576,6 +4847,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4576
4847
|
}
|
|
4577
4848
|
const offlineAttachment = {
|
|
4578
4849
|
...attachmentPayload,
|
|
4850
|
+
// TODO: just handle creating the objectURL in here, then the front end doesn't need to worry about it
|
|
4579
4851
|
file: attachmentPayload.file.objectURL,
|
|
4580
4852
|
file_name: attachmentPayload.file.name,
|
|
4581
4853
|
file_type: attachmentPayload.file.type,
|
|
@@ -4609,6 +4881,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4609
4881
|
}
|
|
4610
4882
|
const offlineAttachment = {
|
|
4611
4883
|
...attachmentPayload,
|
|
4884
|
+
// TODO: just handle creating the objectURL in here, then the front end doesn't need to worry about it
|
|
4612
4885
|
file: attachmentPayload.file.objectURL,
|
|
4613
4886
|
file_name: attachmentPayload.file.name,
|
|
4614
4887
|
file_type: attachmentPayload.file.type,
|
|
@@ -4642,6 +4915,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4642
4915
|
}
|
|
4643
4916
|
const offlineAttachment = {
|
|
4644
4917
|
...attachmentPayload,
|
|
4918
|
+
// TODO: just handle creating the objectURL in here, then the front end doesn't need to worry about it
|
|
4645
4919
|
file: attachmentPayload.file.objectURL,
|
|
4646
4920
|
file_name: attachmentPayload.file.name,
|
|
4647
4921
|
file_type: attachmentPayload.file.type,
|
|
@@ -4668,8 +4942,8 @@ class AttachmentService extends BaseApiService {
|
|
|
4668
4942
|
});
|
|
4669
4943
|
return [offlineAttachment, promise];
|
|
4670
4944
|
}
|
|
4671
|
-
async
|
|
4672
|
-
const { description: description2,
|
|
4945
|
+
async addDocumentAttachment(attachmentPayload) {
|
|
4946
|
+
const { description: description2, document: document2, file_sha1, offline_id } = attachmentPayload;
|
|
4673
4947
|
if (!attachmentPayload.file.objectURL) {
|
|
4674
4948
|
throw new Error("Expected attachmentPayload.file.objectURL to be defined.");
|
|
4675
4949
|
}
|
|
@@ -4682,24 +4956,24 @@ class AttachmentService extends BaseApiService {
|
|
|
4682
4956
|
created_by: this.client.store.getState().userReducer.currentUser.id
|
|
4683
4957
|
};
|
|
4684
4958
|
await this.client.files.addCache(attachmentPayload.file, file_sha1);
|
|
4685
|
-
this.client.store.dispatch(
|
|
4959
|
+
this.client.store.dispatch(addDocumentAttachment(offlineAttachment));
|
|
4686
4960
|
const [fileProps] = await this.client.files.uploadFileToS3(file_sha1);
|
|
4687
4961
|
const promise = this.enqueueRequest({
|
|
4688
4962
|
description: "Create attachment",
|
|
4689
4963
|
method: HttpMethod.POST,
|
|
4690
|
-
url: `/
|
|
4691
|
-
blocks: [offline_id,
|
|
4964
|
+
url: `/documents/${document2}/attach/`,
|
|
4965
|
+
blocks: [offline_id, document2],
|
|
4692
4966
|
blockers: [file_sha1],
|
|
4693
4967
|
payload: {
|
|
4694
4968
|
offline_id,
|
|
4695
|
-
|
|
4969
|
+
document: document2,
|
|
4696
4970
|
description: description2 ?? "",
|
|
4697
4971
|
submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4698
4972
|
...fileProps
|
|
4699
4973
|
}
|
|
4700
4974
|
});
|
|
4701
4975
|
promise.catch((error2) => {
|
|
4702
|
-
this.client.store.dispatch(
|
|
4976
|
+
this.client.store.dispatch(removeDocumentAttachment(offlineAttachment.offline_id));
|
|
4703
4977
|
throw error2;
|
|
4704
4978
|
});
|
|
4705
4979
|
return [offlineAttachment, promise];
|
|
@@ -4707,26 +4981,54 @@ class AttachmentService extends BaseApiService {
|
|
|
4707
4981
|
/** the outer Promise is needed to await the hashing of each file, which is required before offline use. If wanting to
|
|
4708
4982
|
* attach promise handlers to the request to add the attachment in the backend, apply it on the promise returned from the
|
|
4709
4983
|
* OptimisticModelResult. */
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
};
|
|
4728
|
-
|
|
4984
|
+
// note the method is only marked as async since files needs to be hashed
|
|
4985
|
+
async attachFilesToIssue(files, issueId) {
|
|
4986
|
+
const { store } = this.client;
|
|
4987
|
+
const offlineAttachments = [];
|
|
4988
|
+
const attachmentsPayload = [];
|
|
4989
|
+
const currentUser = store.getState().userReducer.currentUser;
|
|
4990
|
+
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4991
|
+
for (const file of files) {
|
|
4992
|
+
const attachment = offline({
|
|
4993
|
+
file: URL.createObjectURL(file),
|
|
4994
|
+
file_name: file.name,
|
|
4995
|
+
file_type: file.type,
|
|
4996
|
+
file_sha1: await hashFile(file),
|
|
4997
|
+
description: "",
|
|
4998
|
+
submitted_at: submittedAt,
|
|
4999
|
+
created_by: currentUser.id,
|
|
5000
|
+
issue: issueId
|
|
5001
|
+
});
|
|
5002
|
+
attachmentsPayload.push({
|
|
5003
|
+
offline_id: attachment.offline_id,
|
|
5004
|
+
name: attachment.file_name,
|
|
5005
|
+
sha1: attachment.file_sha1,
|
|
5006
|
+
description: attachment.description,
|
|
5007
|
+
created_by: attachment.created_by,
|
|
5008
|
+
issue_id: attachment.issue
|
|
5009
|
+
});
|
|
5010
|
+
offlineAttachments.push(attachment);
|
|
5011
|
+
}
|
|
5012
|
+
store.dispatch(addIssueAttachments(offlineAttachments));
|
|
5013
|
+
const promise = this.enqueueRequest({
|
|
5014
|
+
description: "Attach files to issue",
|
|
5015
|
+
method: HttpMethod.POST,
|
|
5016
|
+
url: `/issues/${issueId}/attach/`,
|
|
5017
|
+
payload: {
|
|
5018
|
+
submitted_at: submittedAt,
|
|
5019
|
+
attachments: attachmentsPayload,
|
|
5020
|
+
files: await constructUploadedFilePayloads(files)
|
|
5021
|
+
},
|
|
5022
|
+
blocks: offlineAttachments.map((attachment) => attachment.offline_id),
|
|
5023
|
+
blockers: offlineAttachments.map((attachment) => attachment.file_sha1)
|
|
5024
|
+
});
|
|
5025
|
+
promise.then(({ attachments, presigned_urls }) => {
|
|
5026
|
+
store.dispatch(updateIssueAttachments(attachments));
|
|
5027
|
+
this.processPresignedUrls(presigned_urls);
|
|
5028
|
+
}).catch(() => {
|
|
5029
|
+
store.dispatch(removeIssueAttachments(offlineAttachments.map((attachment) => attachment.offline_id)));
|
|
4729
5030
|
});
|
|
5031
|
+
return [offlineAttachments, promise.then(({ attachments }) => attachments)];
|
|
4730
5032
|
}
|
|
4731
5033
|
attachFilesToComponent(filesToSubmit, componentId) {
|
|
4732
5034
|
return filesToSubmit.map((file) => {
|
|
@@ -4770,7 +5072,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4770
5072
|
return photoAttachmentPromise(file);
|
|
4771
5073
|
});
|
|
4772
5074
|
}
|
|
4773
|
-
|
|
5075
|
+
attachFilesToDocument(filesToSubmit, documentId) {
|
|
4774
5076
|
return filesToSubmit.map((file) => {
|
|
4775
5077
|
if (!(file instanceof File)) {
|
|
4776
5078
|
throw new Error("Expected a File instance.");
|
|
@@ -4781,12 +5083,12 @@ class AttachmentService extends BaseApiService {
|
|
|
4781
5083
|
file: file2,
|
|
4782
5084
|
file_name: file2.name,
|
|
4783
5085
|
file_type: file2.type,
|
|
4784
|
-
|
|
5086
|
+
document: documentId,
|
|
4785
5087
|
file_sha1: hash,
|
|
4786
5088
|
submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4787
5089
|
created_by: this.client.store.getState().userReducer.currentUser.id
|
|
4788
5090
|
});
|
|
4789
|
-
return this.
|
|
5091
|
+
return this.addDocumentAttachment(attachment);
|
|
4790
5092
|
};
|
|
4791
5093
|
return photoAttachmentPromise(file);
|
|
4792
5094
|
});
|
|
@@ -4966,9 +5268,9 @@ class AttachmentService extends BaseApiService {
|
|
|
4966
5268
|
const promise = performRequest2();
|
|
4967
5269
|
return [offlineAttachment, promise];
|
|
4968
5270
|
}
|
|
4969
|
-
async
|
|
5271
|
+
async replaceDocumentAttachmentFile(attachmentId, newFile) {
|
|
4970
5272
|
const { store } = this.client;
|
|
4971
|
-
const attachment = store.getState().
|
|
5273
|
+
const attachment = store.getState().documentsReducer.attachments[attachmentId];
|
|
4972
5274
|
if (!attachment)
|
|
4973
5275
|
throw new Error(`Attachment ${attachmentId} not found`);
|
|
4974
5276
|
let oldFile = void 0;
|
|
@@ -4982,7 +5284,7 @@ class AttachmentService extends BaseApiService {
|
|
|
4982
5284
|
throw new Error(`newFile["objectURL"] is unexpectedly ${newFile.objectURL}`);
|
|
4983
5285
|
}
|
|
4984
5286
|
store.dispatch(
|
|
4985
|
-
|
|
5287
|
+
updateDocumentAttachment({
|
|
4986
5288
|
...attachment,
|
|
4987
5289
|
file_sha1: newSha1,
|
|
4988
5290
|
file: URL.createObjectURL(newFile)
|
|
@@ -4990,13 +5292,13 @@ class AttachmentService extends BaseApiService {
|
|
|
4990
5292
|
);
|
|
4991
5293
|
await this.client.files.addCache(newFile, newSha1);
|
|
4992
5294
|
const [fileProps] = await this.client.files.uploadFileToS3(newSha1).catch((e) => {
|
|
4993
|
-
store.dispatch(
|
|
5295
|
+
store.dispatch(updateDocumentAttachment(attachment));
|
|
4994
5296
|
throw e;
|
|
4995
5297
|
});
|
|
4996
5298
|
const promise2 = this.enqueueRequest({
|
|
4997
5299
|
description: "Edit attachment",
|
|
4998
5300
|
method: HttpMethod.PATCH,
|
|
4999
|
-
url: `/attachments/
|
|
5301
|
+
url: `/attachments/documents/${attachment.offline_id}/`,
|
|
5000
5302
|
isResponseBlob: false,
|
|
5001
5303
|
payload: fileProps,
|
|
5002
5304
|
blockers: [attachmentId, newSha1],
|
|
@@ -5009,7 +5311,7 @@ class AttachmentService extends BaseApiService {
|
|
|
5009
5311
|
} catch (e) {
|
|
5010
5312
|
if (oldFile) {
|
|
5011
5313
|
store.dispatch(
|
|
5012
|
-
|
|
5314
|
+
updateDocumentAttachment({
|
|
5013
5315
|
...attachment,
|
|
5014
5316
|
file_sha1: attachment.file_sha1,
|
|
5015
5317
|
file: URL.createObjectURL(oldFile)
|
|
@@ -5079,20 +5381,20 @@ class AttachmentService extends BaseApiService {
|
|
|
5079
5381
|
blocks: [componentTypeAttachmentId]
|
|
5080
5382
|
});
|
|
5081
5383
|
}
|
|
5082
|
-
|
|
5384
|
+
deleteDocumentAttachment(documentAttachmentId) {
|
|
5083
5385
|
const { store } = this.client;
|
|
5084
|
-
const attachment =
|
|
5386
|
+
const attachment = store.getState().documentsReducer.attachments[documentAttachmentId];
|
|
5085
5387
|
if (!attachment) {
|
|
5086
|
-
throw new Error(`Attachment ${
|
|
5388
|
+
throw new Error(`Attachment ${documentAttachmentId} not found`);
|
|
5087
5389
|
}
|
|
5088
|
-
store.dispatch(
|
|
5390
|
+
store.dispatch(removeDocumentAttachment(documentAttachmentId));
|
|
5089
5391
|
void this.client.files.removeCache(attachment.file_sha1);
|
|
5090
5392
|
return this.enqueueRequest({
|
|
5091
|
-
description: "Delete attachment",
|
|
5393
|
+
description: "Delete document attachment",
|
|
5092
5394
|
method: HttpMethod.DELETE,
|
|
5093
|
-
url: `/attachments/
|
|
5094
|
-
blockers: [
|
|
5095
|
-
blocks: [
|
|
5395
|
+
url: `/attachments/documents/${documentAttachmentId}/`,
|
|
5396
|
+
blockers: [documentAttachmentId],
|
|
5397
|
+
blocks: [documentAttachmentId]
|
|
5096
5398
|
});
|
|
5097
5399
|
}
|
|
5098
5400
|
}
|
|
@@ -6330,11 +6632,18 @@ class MainService extends BaseApiService {
|
|
|
6330
6632
|
if (currentProjectId) {
|
|
6331
6633
|
const [_offlineAttachments, promise] = this.client.attachments.fetchAll(currentProjectId);
|
|
6332
6634
|
void promise.then((result) => {
|
|
6333
|
-
const {
|
|
6635
|
+
const {
|
|
6636
|
+
issue_attachments,
|
|
6637
|
+
component_type_attachments,
|
|
6638
|
+
component_attachments,
|
|
6639
|
+
project_attachments,
|
|
6640
|
+
document_attachments
|
|
6641
|
+
} = result;
|
|
6334
6642
|
store.dispatch(setIssueAttachments(issue_attachments));
|
|
6335
6643
|
store.dispatch(setComponentAttachments(component_attachments));
|
|
6336
6644
|
store.dispatch(setComponentTypeAttachments(component_type_attachments));
|
|
6337
6645
|
store.dispatch(setProjectAttachments(project_attachments));
|
|
6646
|
+
store.dispatch(setDocumentAttachments(document_attachments));
|
|
6338
6647
|
});
|
|
6339
6648
|
void this.client.documents.refreshStore();
|
|
6340
6649
|
void this.client.issueUpdates.refreshStore();
|
|
@@ -6702,7 +7011,7 @@ class UserFormService extends BaseApiService {
|
|
|
6702
7011
|
...revisionAttachmentPayload,
|
|
6703
7012
|
file: URL.createObjectURL(image)
|
|
6704
7013
|
};
|
|
6705
|
-
store.dispatch(
|
|
7014
|
+
store.dispatch(addFormRevisionAttachment(offlinePayload));
|
|
6706
7015
|
return attach;
|
|
6707
7016
|
});
|
|
6708
7017
|
});
|
|
@@ -6736,8 +7045,8 @@ class UserFormService extends BaseApiService {
|
|
|
6736
7045
|
revision: 0
|
|
6737
7046
|
};
|
|
6738
7047
|
const { store } = this.client;
|
|
6739
|
-
store.dispatch(
|
|
6740
|
-
store.dispatch(
|
|
7048
|
+
store.dispatch(addForm(retForm));
|
|
7049
|
+
store.dispatch(addFormRevision(retRevision));
|
|
6741
7050
|
const formPromise = this.enqueueRequest({
|
|
6742
7051
|
description: "Create form",
|
|
6743
7052
|
method: HttpMethod.POST,
|
|
@@ -6755,8 +7064,8 @@ class UserFormService extends BaseApiService {
|
|
|
6755
7064
|
});
|
|
6756
7065
|
const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
|
|
6757
7066
|
void formPromise.catch((e) => {
|
|
6758
|
-
store.dispatch(
|
|
6759
|
-
store.dispatch(
|
|
7067
|
+
store.dispatch(deleteForm(retForm.offline_id));
|
|
7068
|
+
store.dispatch(deleteFormRevision(retRevision.offline_id));
|
|
6760
7069
|
throw e;
|
|
6761
7070
|
});
|
|
6762
7071
|
const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
|
|
@@ -6798,7 +7107,7 @@ class UserFormService extends BaseApiService {
|
|
|
6798
7107
|
revision: "Pending",
|
|
6799
7108
|
form: formId2
|
|
6800
7109
|
};
|
|
6801
|
-
store.dispatch(
|
|
7110
|
+
store.dispatch(addFormRevision(fullRevision));
|
|
6802
7111
|
const promise = this.enqueueRequest({
|
|
6803
7112
|
description: "Create form revision",
|
|
6804
7113
|
method: HttpMethod.PATCH,
|
|
@@ -6812,9 +7121,9 @@ class UserFormService extends BaseApiService {
|
|
|
6812
7121
|
});
|
|
6813
7122
|
const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
|
|
6814
7123
|
void promise.then((result) => {
|
|
6815
|
-
store.dispatch(
|
|
7124
|
+
store.dispatch(setFormRevision(result));
|
|
6816
7125
|
}).catch(() => {
|
|
6817
|
-
store.dispatch(
|
|
7126
|
+
store.dispatch(deleteFormRevision(fullRevision.offline_id));
|
|
6818
7127
|
});
|
|
6819
7128
|
const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
|
|
6820
7129
|
return [fullRevision, settledPromise];
|
|
@@ -6856,19 +7165,19 @@ class UserFormService extends BaseApiService {
|
|
|
6856
7165
|
async delete(formId2) {
|
|
6857
7166
|
const { store } = this.client;
|
|
6858
7167
|
const state = store.getState();
|
|
6859
|
-
const userForm =
|
|
7168
|
+
const userForm = selectForm(formId2)(state);
|
|
6860
7169
|
if (!userForm) {
|
|
6861
7170
|
throw new Error("Expected userForm to exist");
|
|
6862
7171
|
}
|
|
6863
|
-
const userFormSubmissions =
|
|
7172
|
+
const userFormSubmissions = selectFormSubmissionsOfForm(formId2)(state);
|
|
6864
7173
|
if (userFormSubmissions && userFormSubmissions.length > 0) {
|
|
6865
|
-
store.dispatch(
|
|
7174
|
+
store.dispatch(deleteFormSubmissions(userFormSubmissions.map(({ offline_id }) => offline_id)));
|
|
6866
7175
|
}
|
|
6867
|
-
const userFormRevisions =
|
|
7176
|
+
const userFormRevisions = selectFormRevisionsOfForm(formId2)(state);
|
|
6868
7177
|
if (userFormRevisions && userFormRevisions.length > 0) {
|
|
6869
|
-
store.dispatch(
|
|
7178
|
+
store.dispatch(deleteFormRevisions(userFormRevisions.map(({ offline_id }) => offline_id)));
|
|
6870
7179
|
}
|
|
6871
|
-
store.dispatch(
|
|
7180
|
+
store.dispatch(deleteForm(formId2));
|
|
6872
7181
|
try {
|
|
6873
7182
|
return await this.enqueueRequest({
|
|
6874
7183
|
description: "Delete form",
|
|
@@ -6878,12 +7187,12 @@ class UserFormService extends BaseApiService {
|
|
|
6878
7187
|
blocks: []
|
|
6879
7188
|
});
|
|
6880
7189
|
} catch (e) {
|
|
6881
|
-
store.dispatch(
|
|
7190
|
+
store.dispatch(addForm(userForm));
|
|
6882
7191
|
if (userFormRevisions && userFormRevisions.length > 0) {
|
|
6883
|
-
store.dispatch(
|
|
7192
|
+
store.dispatch(addFormRevisions(userFormRevisions));
|
|
6884
7193
|
}
|
|
6885
7194
|
if (userFormSubmissions && userFormSubmissions.length > 0) {
|
|
6886
|
-
store.dispatch(
|
|
7195
|
+
store.dispatch(addFormSubmissions(userFormSubmissions));
|
|
6887
7196
|
}
|
|
6888
7197
|
throw e;
|
|
6889
7198
|
}
|
|
@@ -6897,16 +7206,15 @@ class UserFormService extends BaseApiService {
|
|
|
6897
7206
|
blockers: [],
|
|
6898
7207
|
blocks: []
|
|
6899
7208
|
});
|
|
6900
|
-
store.dispatch(
|
|
6901
|
-
store.dispatch(
|
|
6902
|
-
store.dispatch(
|
|
7209
|
+
store.dispatch(setForms(Object.values(result.forms)));
|
|
7210
|
+
store.dispatch(setFormRevisions(Object.values(result.revisions)));
|
|
7211
|
+
store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
|
|
6903
7212
|
}
|
|
6904
7213
|
}
|
|
6905
7214
|
const isArrayOfFiles = (value) => {
|
|
6906
7215
|
return Array.isArray(value) && value[0] instanceof File;
|
|
6907
7216
|
};
|
|
6908
|
-
const separateFilesFromValues = (
|
|
6909
|
-
const { values } = payload;
|
|
7217
|
+
const separateFilesFromValues = (values) => {
|
|
6910
7218
|
const files = {};
|
|
6911
7219
|
const newValues = {};
|
|
6912
7220
|
for (const key in values) {
|
|
@@ -6921,17 +7229,13 @@ const separateFilesFromValues = (payload) => {
|
|
|
6921
7229
|
newValues[key] = value;
|
|
6922
7230
|
}
|
|
6923
7231
|
}
|
|
6924
|
-
|
|
6925
|
-
...payload,
|
|
6926
|
-
values: newValues
|
|
6927
|
-
};
|
|
6928
|
-
return { payloadWithoutFiles, files };
|
|
7232
|
+
return { values: newValues, files };
|
|
6929
7233
|
};
|
|
6930
7234
|
class UserFormSubmissionService extends BaseApiService {
|
|
6931
7235
|
constructor() {
|
|
6932
7236
|
super(...arguments);
|
|
6933
7237
|
// Attach files to submission, after uploading them to S3
|
|
6934
|
-
__publicField(this, "getAttachFilesPromises", (files,
|
|
7238
|
+
__publicField(this, "getAttachFilesPromises", (files, submission) => {
|
|
6935
7239
|
const { store } = this.client;
|
|
6936
7240
|
return Object.entries(files).map(async ([key, fileArray]) => {
|
|
6937
7241
|
const attachResults = [];
|
|
@@ -6941,24 +7245,27 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
6941
7245
|
const [fileProps] = await this.client.files.uploadFileToS3(sha1);
|
|
6942
7246
|
const submissionAttachmentPayload = offline({
|
|
6943
7247
|
...fileProps,
|
|
6944
|
-
submission:
|
|
7248
|
+
submission: submission.offline_id,
|
|
6945
7249
|
field_identifier: key
|
|
6946
7250
|
});
|
|
6947
7251
|
const attach = await this.enqueueRequest({
|
|
6948
7252
|
description: "Attach file to form submission",
|
|
6949
7253
|
method: HttpMethod.POST,
|
|
6950
|
-
url: `/forms/submission/${
|
|
7254
|
+
url: `/forms/submission/${submission.offline_id}/attachments/`,
|
|
6951
7255
|
payload: submissionAttachmentPayload,
|
|
6952
|
-
blockers: [
|
|
6953
|
-
|
|
6954
|
-
|
|
7256
|
+
blockers: [
|
|
7257
|
+
submission.component,
|
|
7258
|
+
submission.component_stage,
|
|
7259
|
+
submission.issue,
|
|
7260
|
+
submission.form_revision
|
|
7261
|
+
].filter((x) => x !== void 0),
|
|
6955
7262
|
blocks: [submissionAttachmentPayload.offline_id]
|
|
6956
7263
|
});
|
|
6957
7264
|
const offlinePayload = {
|
|
6958
7265
|
...submissionAttachmentPayload,
|
|
6959
7266
|
file: URL.createObjectURL(file)
|
|
6960
7267
|
};
|
|
6961
|
-
store.dispatch(
|
|
7268
|
+
store.dispatch(addFormSubmissionAttachment(offlinePayload));
|
|
6962
7269
|
attachResults.push(attach);
|
|
6963
7270
|
}
|
|
6964
7271
|
return attachResults;
|
|
@@ -6972,70 +7279,165 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
6972
7279
|
if (!activeProjectId) {
|
|
6973
7280
|
throw new Error("Expected an active project");
|
|
6974
7281
|
}
|
|
6975
|
-
const {
|
|
7282
|
+
const { values, files } = separateFilesFromValues(payload.values);
|
|
7283
|
+
const offlineSubmission = {
|
|
7284
|
+
...payload,
|
|
7285
|
+
values,
|
|
7286
|
+
created_by: state.userReducer.currentUser.id,
|
|
7287
|
+
submitted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
7288
|
+
};
|
|
6976
7289
|
const promise = this.enqueueRequest({
|
|
6977
7290
|
description: "Respond to form",
|
|
6978
7291
|
method: HttpMethod.POST,
|
|
6979
7292
|
url: `/forms/revisions/${payload.form_revision}/respond/`,
|
|
6980
|
-
payload: { ...
|
|
7293
|
+
payload: { ...offlineSubmission, project: activeProjectId },
|
|
6981
7294
|
blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
|
|
6982
7295
|
(x) => x !== void 0
|
|
6983
7296
|
),
|
|
6984
7297
|
blocks: [payload.offline_id]
|
|
6985
7298
|
});
|
|
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));
|
|
7299
|
+
const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
|
|
7300
|
+
store.dispatch(addFormSubmission(offlineSubmission));
|
|
6999
7301
|
void promise.then((result) => {
|
|
7000
7302
|
store.dispatch(addActiveProjectFormSubmissionsCount(1));
|
|
7001
|
-
store.dispatch(
|
|
7303
|
+
store.dispatch(setFormSubmission(result));
|
|
7002
7304
|
return result;
|
|
7003
7305
|
}).catch(() => {
|
|
7004
|
-
store.dispatch(
|
|
7306
|
+
store.dispatch(deleteFormSubmission(payload.offline_id));
|
|
7005
7307
|
store.dispatch(addActiveProjectFormSubmissionsCount(-1));
|
|
7006
7308
|
});
|
|
7007
7309
|
const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
|
|
7008
|
-
return [
|
|
7310
|
+
return [offlineSubmission, settledPromise];
|
|
7009
7311
|
}
|
|
7010
|
-
|
|
7312
|
+
// Note currently the bulkAdd method is specific to form submissions for components
|
|
7313
|
+
// TODO: adapt the support bulk adding to any model type
|
|
7314
|
+
async bulkAdd(args) {
|
|
7315
|
+
const { form_revision, values: argsValues, componentOfflineIds } = args;
|
|
7011
7316
|
const { store } = this.client;
|
|
7012
|
-
const
|
|
7013
|
-
|
|
7014
|
-
|
|
7317
|
+
const offlineSubmissions = [];
|
|
7318
|
+
const offlineAttachments = [];
|
|
7319
|
+
const submissionOfflineIds = [];
|
|
7320
|
+
const submissionsPayload = [];
|
|
7321
|
+
const attachmentsPayload = [];
|
|
7322
|
+
const { values, files } = separateFilesFromValues(argsValues);
|
|
7323
|
+
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7324
|
+
const createdBy = store.getState().userReducer.currentUser.id;
|
|
7325
|
+
for (const component_id of componentOfflineIds) {
|
|
7326
|
+
const submission = offline({
|
|
7327
|
+
form_revision,
|
|
7328
|
+
values,
|
|
7329
|
+
created_by: createdBy,
|
|
7330
|
+
submitted_at: submittedAt,
|
|
7331
|
+
component: component_id
|
|
7332
|
+
});
|
|
7333
|
+
submissionOfflineIds.push(submission.offline_id);
|
|
7334
|
+
submissionsPayload.push({ offline_id: submission.offline_id, component_id });
|
|
7335
|
+
offlineSubmissions.push(submission);
|
|
7336
|
+
for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
|
|
7337
|
+
for (const file of fileArray) {
|
|
7338
|
+
const sha1 = await hashFile(file);
|
|
7339
|
+
await this.client.files.addCache(file, sha1);
|
|
7340
|
+
const offlineAttachment = offline({
|
|
7341
|
+
file_name: file.name,
|
|
7342
|
+
file_sha1: sha1,
|
|
7343
|
+
file: URL.createObjectURL(file),
|
|
7344
|
+
submission: submission.offline_id,
|
|
7345
|
+
field_identifier: fieldIdentifier
|
|
7346
|
+
});
|
|
7347
|
+
offlineAttachments.push(offlineAttachment);
|
|
7348
|
+
attachmentsPayload.push({
|
|
7349
|
+
offline_id: offlineAttachment.offline_id,
|
|
7350
|
+
submission_id: submission.offline_id,
|
|
7351
|
+
sha1,
|
|
7352
|
+
name: file.name,
|
|
7353
|
+
field_identifier: fieldIdentifier
|
|
7354
|
+
});
|
|
7355
|
+
}
|
|
7356
|
+
}
|
|
7015
7357
|
}
|
|
7358
|
+
const filesRecord = {};
|
|
7359
|
+
for (const file of Object.values(files).flat()) {
|
|
7360
|
+
const sha1 = await hashFile(file);
|
|
7361
|
+
filesRecord[sha1] = {
|
|
7362
|
+
sha1,
|
|
7363
|
+
extension: file.name.split(".").pop() || "",
|
|
7364
|
+
file_type: file.type,
|
|
7365
|
+
size: file.size
|
|
7366
|
+
};
|
|
7367
|
+
}
|
|
7368
|
+
store.dispatch(addFormSubmissions(offlineSubmissions));
|
|
7369
|
+
store.dispatch(addFormSubmissionAttachments(offlineAttachments));
|
|
7370
|
+
const promise = this.enqueueRequest({
|
|
7371
|
+
description: "Bulk add form submissions",
|
|
7372
|
+
method: HttpMethod.POST,
|
|
7373
|
+
url: `/forms/revisions/${form_revision}/bulk-respond/`,
|
|
7374
|
+
payload: {
|
|
7375
|
+
form_data: values,
|
|
7376
|
+
submitted_at: submittedAt,
|
|
7377
|
+
submissions: submissionsPayload,
|
|
7378
|
+
attachments: attachmentsPayload,
|
|
7379
|
+
files: Object.values(filesRecord)
|
|
7380
|
+
},
|
|
7381
|
+
blockers: componentOfflineIds,
|
|
7382
|
+
blocks: submissionOfflineIds
|
|
7383
|
+
});
|
|
7384
|
+
promise.then(({ submissions, attachments, presigned_urls }) => {
|
|
7385
|
+
store.dispatch(updateFormSubmissions(submissions));
|
|
7386
|
+
store.dispatch(updateFormSubmissionAttachments(attachments));
|
|
7387
|
+
for (const [sha1, presigned_url] of Object.entries(presigned_urls)) {
|
|
7388
|
+
const file = filesRecord[sha1];
|
|
7389
|
+
if (!file)
|
|
7390
|
+
continue;
|
|
7391
|
+
void this.enqueueRequest({
|
|
7392
|
+
url: presigned_url.url,
|
|
7393
|
+
description: "Upload file",
|
|
7394
|
+
method: HttpMethod.POST,
|
|
7395
|
+
isExternalUrl: true,
|
|
7396
|
+
isAuthNeeded: false,
|
|
7397
|
+
attachmentHash: sha1,
|
|
7398
|
+
blockers: [`s3-${file.sha1}.${file.extension}`],
|
|
7399
|
+
blocks: [sha1],
|
|
7400
|
+
s3url: presigned_url
|
|
7401
|
+
});
|
|
7402
|
+
}
|
|
7403
|
+
}).catch(() => {
|
|
7404
|
+
store.dispatch(deleteFormSubmissions(submissionOfflineIds));
|
|
7405
|
+
store.dispatch(deleteFormSubmissionAttachments(offlineAttachments.map((x) => x.offline_id)));
|
|
7406
|
+
});
|
|
7407
|
+
return [offlineSubmissions, promise.then(({ submissions }) => submissions)];
|
|
7408
|
+
}
|
|
7409
|
+
update(submission) {
|
|
7410
|
+
const { store } = this.client;
|
|
7411
|
+
const { values, files } = separateFilesFromValues(submission.values);
|
|
7016
7412
|
const attachFilesPromises = this.getAttachFilesPromises(files, submission);
|
|
7017
|
-
const
|
|
7018
|
-
...
|
|
7019
|
-
|
|
7413
|
+
const offlineSubmission = {
|
|
7414
|
+
...submission,
|
|
7415
|
+
values
|
|
7020
7416
|
};
|
|
7021
|
-
store.
|
|
7417
|
+
const submissionToBeUpdated = store.getState().formSubmissionReducer.formSubmissions[submission.offline_id];
|
|
7418
|
+
store.dispatch(updateFormSubmission(offlineSubmission));
|
|
7022
7419
|
const promise = this.enqueueRequest({
|
|
7023
7420
|
description: "Patch form submission",
|
|
7024
7421
|
method: HttpMethod.PATCH,
|
|
7025
7422
|
url: `/forms/submissions/${submission.offline_id}/`,
|
|
7026
|
-
payload:
|
|
7027
|
-
blockers: [
|
|
7423
|
+
payload: offlineSubmission,
|
|
7424
|
+
blockers: [offlineSubmission.issue, offlineSubmission.component, offlineSubmission.component_stage].filter(
|
|
7028
7425
|
(x) => x !== void 0
|
|
7029
7426
|
),
|
|
7030
|
-
blocks: [
|
|
7427
|
+
blocks: [offlineSubmission.offline_id]
|
|
7428
|
+
});
|
|
7429
|
+
promise.then((createdSubmission) => {
|
|
7430
|
+
store.dispatch(setFormSubmission(createdSubmission));
|
|
7431
|
+
}).catch(() => {
|
|
7432
|
+
store.dispatch(setFormSubmission(submissionToBeUpdated));
|
|
7031
7433
|
});
|
|
7032
|
-
return Promise.all([promise, ...attachFilesPromises]).then(() => promise);
|
|
7434
|
+
return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
|
|
7033
7435
|
}
|
|
7034
7436
|
async delete(submissionId) {
|
|
7035
7437
|
const { store } = this.client;
|
|
7036
7438
|
const state = store.getState();
|
|
7037
|
-
const submission = state.
|
|
7038
|
-
store.dispatch(
|
|
7439
|
+
const submission = state.formSubmissionReducer.formSubmissions[submissionId];
|
|
7440
|
+
store.dispatch(deleteFormSubmission(submissionId));
|
|
7039
7441
|
store.dispatch(addActiveProjectFormSubmissionsCount(-1));
|
|
7040
7442
|
try {
|
|
7041
7443
|
return await this.enqueueRequest({
|
|
@@ -7046,10 +7448,8 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7046
7448
|
blocks: []
|
|
7047
7449
|
});
|
|
7048
7450
|
} catch (e) {
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
store.dispatch(updateOrCreateUserFormSubmission(submission));
|
|
7052
|
-
}
|
|
7451
|
+
store.dispatch(addActiveProjectFormSubmissionsCount(1));
|
|
7452
|
+
store.dispatch(addFormSubmission(submission));
|
|
7053
7453
|
throw e;
|
|
7054
7454
|
}
|
|
7055
7455
|
}
|
|
@@ -7063,7 +7463,7 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7063
7463
|
blockers: [],
|
|
7064
7464
|
blocks: []
|
|
7065
7465
|
});
|
|
7066
|
-
store.dispatch(
|
|
7466
|
+
store.dispatch(setFormSubmissions(submissions));
|
|
7067
7467
|
const attachments = await this.enqueueRequest({
|
|
7068
7468
|
description: "Fetch form attachments",
|
|
7069
7469
|
method: HttpMethod.GET,
|
|
@@ -7071,7 +7471,7 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7071
7471
|
blockers: [],
|
|
7072
7472
|
blocks: []
|
|
7073
7473
|
});
|
|
7074
|
-
store.dispatch(
|
|
7474
|
+
store.dispatch(setFormSubmissionAttachments(attachments));
|
|
7075
7475
|
}
|
|
7076
7476
|
}
|
|
7077
7477
|
class WorkspaceService extends BaseApiService {
|
|
@@ -13930,7 +14330,7 @@ const initialFormValues = (fields, values) => {
|
|
|
13930
14330
|
};
|
|
13931
14331
|
const useAttachImagesToFormRevisionFields = (revision) => {
|
|
13932
14332
|
const { sdk } = useSDK();
|
|
13933
|
-
const attachments = useAppSelector(
|
|
14333
|
+
const attachments = useAppSelector(selectAttachmentsOfFormRevision((revision == null ? void 0 : revision.offline_id) ?? ""));
|
|
13934
14334
|
return useMemo(() => {
|
|
13935
14335
|
if (!revision || !attachments)
|
|
13936
14336
|
return revision;
|
|
@@ -14027,7 +14427,7 @@ const FormSubmissionViewer = memo(
|
|
|
14027
14427
|
return formRevisionToSchema(revisionWithImages, { readonly: true });
|
|
14028
14428
|
}, [revisionWithImages]);
|
|
14029
14429
|
const submissionValuesWithAttachments = useMemo(() => {
|
|
14030
|
-
const attachments =
|
|
14430
|
+
const attachments = selectAttachmentsOfFormSubmission(submission.offline_id)(sdk.store.getState()) ?? [];
|
|
14031
14431
|
const downloadedAttachments = {};
|
|
14032
14432
|
for (const attachment of attachments) {
|
|
14033
14433
|
const promise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
|
|
@@ -14077,8 +14477,8 @@ const FormBrowser = memo(
|
|
|
14077
14477
|
}
|
|
14078
14478
|
return ret;
|
|
14079
14479
|
}, [filter, maxResults, ownerFilter]);
|
|
14080
|
-
const userForms = useAppSelector(
|
|
14081
|
-
const userFormMapping = useAppSelector(
|
|
14480
|
+
const userForms = useAppSelector(selectFilteredForms(ownerFilterOptions)) ?? [];
|
|
14481
|
+
const userFormMapping = useAppSelector(selectFormMapping);
|
|
14082
14482
|
const attachableUserForms = userForms.filter((form) => !form.component_type);
|
|
14083
14483
|
const attachableUserFormMapping = Object.values(userFormMapping).filter(
|
|
14084
14484
|
(form) => !form.component_type
|
|
@@ -14111,7 +14511,7 @@ const FormBrowser = memo(
|
|
|
14111
14511
|
const handleChange = useCallback((e) => {
|
|
14112
14512
|
setFilter(e.currentTarget.value);
|
|
14113
14513
|
}, []);
|
|
14114
|
-
const numberOfForms = useAppSelector(
|
|
14514
|
+
const numberOfForms = useAppSelector(selectGeneralFormCount) || 0;
|
|
14115
14515
|
const numberOfHiddenForms = numberOfForms - attachableUserForms.length;
|
|
14116
14516
|
const overflowMessage = attachableUserForms.length == maxResults && numberOfHiddenForms > 0 ? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)` : numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`;
|
|
14117
14517
|
return /* @__PURE__ */ jsxs(Flex$1, { ref, direction: "column", gap: "2", children: [
|
|
@@ -14205,16 +14605,13 @@ const FormSubmissionBrowserEntry = memo((props) => {
|
|
|
14205
14605
|
const { submission, onSubmissionClick, compact, labelType, rowDecorator } = props;
|
|
14206
14606
|
const currentUser = useAppSelector(selectCurrentUser);
|
|
14207
14607
|
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);
|
|
14608
|
+
const dateToUse = submission.submitted_at;
|
|
14609
|
+
const formattedDateTime = getLocalDateString(dateToUse);
|
|
14213
14610
|
const revision = useAppSelector(selectFormRevision(submission.form_revision));
|
|
14214
14611
|
if (!revision) {
|
|
14215
14612
|
throw new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`);
|
|
14216
14613
|
}
|
|
14217
|
-
const latestRevisionNumber = (_a2 = useAppSelector(
|
|
14614
|
+
const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevisionOfForm(revision.form))) == null ? void 0 : _a2.revision;
|
|
14218
14615
|
const creatorProfileSrc = useFileSrc({
|
|
14219
14616
|
file: (createdBy == null ? void 0 : createdBy.profile.file) ?? null,
|
|
14220
14617
|
fileSha1: (createdBy == null ? void 0 : createdBy.profile.file_sha1) ?? null
|
|
@@ -14245,10 +14642,6 @@ const FormSubmissionBrowserEntry = memo((props) => {
|
|
|
14245
14642
|
return row;
|
|
14246
14643
|
});
|
|
14247
14644
|
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
14645
|
const FormSubmissionBrowser = memo((props) => {
|
|
14253
14646
|
const {
|
|
14254
14647
|
formId: formId2,
|
|
@@ -14262,10 +14655,10 @@ const FormSubmissionBrowser = memo((props) => {
|
|
|
14262
14655
|
if (!!formId2 === !!propSubmissions) {
|
|
14263
14656
|
throw new Error("Either formId or submissions must be provided, but not both.");
|
|
14264
14657
|
}
|
|
14265
|
-
const submissions = useAppSelector(propSubmissions ? () => propSubmissions :
|
|
14658
|
+
const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectFormSubmissionsOfForm(formId2));
|
|
14266
14659
|
const sortedSubmissions = useMemo(
|
|
14267
14660
|
() => submissions == null ? void 0 : submissions.sort((a, b) => {
|
|
14268
|
-
return
|
|
14661
|
+
return a.submitted_at.localeCompare(b.submitted_at);
|
|
14269
14662
|
}),
|
|
14270
14663
|
[submissions]
|
|
14271
14664
|
);
|
|
@@ -15583,6 +15976,7 @@ export {
|
|
|
15583
15976
|
VerificationCodeType,
|
|
15584
15977
|
WorkspaceService,
|
|
15585
15978
|
YELLOW,
|
|
15979
|
+
_selectLatestFormRevision,
|
|
15586
15980
|
_setLatestRetryTime,
|
|
15587
15981
|
acceptProjectInvite,
|
|
15588
15982
|
addActiveProjectFormSubmissionsCount,
|
|
@@ -15595,9 +15989,21 @@ export {
|
|
|
15595
15989
|
addComponentTypeAttachment,
|
|
15596
15990
|
addComponentTypeAttachments,
|
|
15597
15991
|
addComponentsInBatches,
|
|
15992
|
+
addDocumentAttachment,
|
|
15993
|
+
addDocumentAttachments,
|
|
15598
15994
|
addDocuments,
|
|
15599
15995
|
addEmailDomain,
|
|
15600
15996
|
addFavouriteProjectId,
|
|
15997
|
+
addForm,
|
|
15998
|
+
addFormRevision,
|
|
15999
|
+
addFormRevisionAttachment,
|
|
16000
|
+
addFormRevisionAttachments,
|
|
16001
|
+
addFormRevisions,
|
|
16002
|
+
addFormSubmission,
|
|
16003
|
+
addFormSubmissionAttachment,
|
|
16004
|
+
addFormSubmissionAttachments,
|
|
16005
|
+
addFormSubmissions,
|
|
16006
|
+
addForms,
|
|
15601
16007
|
addIssue,
|
|
15602
16008
|
addIssueAttachment,
|
|
15603
16009
|
addIssueAttachments,
|
|
@@ -15618,13 +16024,6 @@ export {
|
|
|
15618
16024
|
addStageCompletions,
|
|
15619
16025
|
addStages,
|
|
15620
16026
|
addToRecentIssues,
|
|
15621
|
-
addUserForm,
|
|
15622
|
-
addUserFormRevision,
|
|
15623
|
-
addUserFormRevisionAttachment,
|
|
15624
|
-
addUserFormRevisions,
|
|
15625
|
-
addUserFormSubmissionAttachment,
|
|
15626
|
-
addUserFormSubmissions,
|
|
15627
|
-
addUserForms,
|
|
15628
16027
|
addUsers,
|
|
15629
16028
|
addWorkspace,
|
|
15630
16029
|
areArraysEqual,
|
|
@@ -15645,6 +16044,7 @@ export {
|
|
|
15645
16044
|
componentStageSlice,
|
|
15646
16045
|
componentTypeReducer,
|
|
15647
16046
|
componentTypeSlice,
|
|
16047
|
+
constructUploadedFilePayloads,
|
|
15648
16048
|
coordinatesAreEqual,
|
|
15649
16049
|
coordinatesToLiteral,
|
|
15650
16050
|
coordinatesToPointGeometry,
|
|
@@ -15655,12 +16055,16 @@ export {
|
|
|
15655
16055
|
defaultBadgeColor,
|
|
15656
16056
|
defaultStore,
|
|
15657
16057
|
deleteComponentType,
|
|
16058
|
+
deleteForm,
|
|
16059
|
+
deleteFormRevision,
|
|
16060
|
+
deleteFormRevisionAttachment,
|
|
16061
|
+
deleteFormRevisionAttachments,
|
|
16062
|
+
deleteFormRevisions,
|
|
16063
|
+
deleteFormSubmission,
|
|
16064
|
+
deleteFormSubmissionAttachment,
|
|
16065
|
+
deleteFormSubmissionAttachments,
|
|
16066
|
+
deleteFormSubmissions,
|
|
15658
16067
|
deleteProject,
|
|
15659
|
-
deleteUserForm,
|
|
15660
|
-
deleteUserFormRevision,
|
|
15661
|
-
deleteUserFormRevisions,
|
|
15662
|
-
deleteUserFormSubmission,
|
|
15663
|
-
deleteUserFormSubmissions,
|
|
15664
16068
|
dequeue,
|
|
15665
16069
|
deserialize,
|
|
15666
16070
|
deserializeField,
|
|
@@ -15689,7 +16093,13 @@ export {
|
|
|
15689
16093
|
fileSlice,
|
|
15690
16094
|
fileToBlob,
|
|
15691
16095
|
flipCoordinates,
|
|
16096
|
+
formReducer,
|
|
16097
|
+
formRevisionReducer,
|
|
15692
16098
|
formRevisionToSchema,
|
|
16099
|
+
formRevisionsSlice,
|
|
16100
|
+
formSlice,
|
|
16101
|
+
formSubmissionReducer,
|
|
16102
|
+
formSubmissionSlice,
|
|
15693
16103
|
index as forms,
|
|
15694
16104
|
fullComponentMarkerSize,
|
|
15695
16105
|
generateBadgeColors,
|
|
@@ -15758,11 +16168,14 @@ export {
|
|
|
15758
16168
|
removeComponentAttachments,
|
|
15759
16169
|
removeComponentTypeAttachment,
|
|
15760
16170
|
removeComponentTypeAttachments,
|
|
16171
|
+
removeDocumentAttachment,
|
|
16172
|
+
removeDocumentAttachments,
|
|
15761
16173
|
removeDocuments,
|
|
15762
16174
|
removeEmailDomain,
|
|
15763
16175
|
removeFavouriteProjectId,
|
|
15764
16176
|
removeIssue,
|
|
15765
16177
|
removeIssueAttachment,
|
|
16178
|
+
removeIssueAttachments,
|
|
15766
16179
|
removeIssueComment,
|
|
15767
16180
|
removeIssueComments,
|
|
15768
16181
|
removeIssueUpdate,
|
|
@@ -15805,6 +16218,7 @@ export {
|
|
|
15805
16218
|
selectAllAttachments,
|
|
15806
16219
|
selectAllComponentAttachments,
|
|
15807
16220
|
selectAllComponentTypeAttachments,
|
|
16221
|
+
selectAllDocumentAttachments,
|
|
15808
16222
|
selectAllProjectAttachments,
|
|
15809
16223
|
selectAncestorIdsOfDocument,
|
|
15810
16224
|
selectAppearance,
|
|
@@ -15812,6 +16226,10 @@ export {
|
|
|
15812
16226
|
selectAttachmentsOfComponentByType,
|
|
15813
16227
|
selectAttachmentsOfComponentType,
|
|
15814
16228
|
selectAttachmentsOfComponentTypeByType,
|
|
16229
|
+
selectAttachmentsOfDocument,
|
|
16230
|
+
selectAttachmentsOfDocumentByType,
|
|
16231
|
+
selectAttachmentsOfFormRevision,
|
|
16232
|
+
selectAttachmentsOfFormSubmission,
|
|
15815
16233
|
selectAttachmentsOfIssue,
|
|
15816
16234
|
selectAttachmentsOfIssueByType,
|
|
15817
16235
|
selectAttachmentsOfProject,
|
|
@@ -15827,11 +16245,11 @@ export {
|
|
|
15827
16245
|
selectCompletedStageIdsForComponent,
|
|
15828
16246
|
selectCompletedStages,
|
|
15829
16247
|
selectComponent,
|
|
16248
|
+
selectComponentAttachment,
|
|
15830
16249
|
selectComponentAttachmentMapping,
|
|
15831
|
-
selectComponentSubmissionMapping,
|
|
15832
16250
|
selectComponentType,
|
|
16251
|
+
selectComponentTypeAttachment,
|
|
15833
16252
|
selectComponentTypeAttachmentMapping,
|
|
15834
|
-
selectComponentTypeForm,
|
|
15835
16253
|
selectComponentTypeFromComponent,
|
|
15836
16254
|
selectComponentTypeFromComponents,
|
|
15837
16255
|
selectComponentTypeStagesMapping,
|
|
@@ -15847,6 +16265,8 @@ export {
|
|
|
15847
16265
|
selectCurrentUser,
|
|
15848
16266
|
selectDeletedRequests,
|
|
15849
16267
|
selectDocument,
|
|
16268
|
+
selectDocumentAttachment,
|
|
16269
|
+
selectDocumentAttachmentMapping,
|
|
15850
16270
|
selectDocuments,
|
|
15851
16271
|
selectDocumentsMapping,
|
|
15852
16272
|
selectEmailDomainsAsMapping,
|
|
@@ -15859,8 +16279,24 @@ export {
|
|
|
15859
16279
|
selectExpandedSections,
|
|
15860
16280
|
selectFavouriteProjects,
|
|
15861
16281
|
selectFileAttachmentsOfIssue,
|
|
15862
|
-
|
|
16282
|
+
selectFilteredForms,
|
|
16283
|
+
selectForm,
|
|
16284
|
+
selectFormMapping,
|
|
16285
|
+
selectFormOfComponentType,
|
|
15863
16286
|
selectFormRevision,
|
|
16287
|
+
selectFormRevisionMapping,
|
|
16288
|
+
selectFormRevisions,
|
|
16289
|
+
selectFormRevisionsOfForm,
|
|
16290
|
+
selectFormSubmission,
|
|
16291
|
+
selectFormSubmissionAttachmentsMapping,
|
|
16292
|
+
selectFormSubmissions,
|
|
16293
|
+
selectFormSubmissionsByComponents,
|
|
16294
|
+
selectFormSubmissionsMapping,
|
|
16295
|
+
selectFormSubmissionsOfComponent,
|
|
16296
|
+
selectFormSubmissionsOfForm,
|
|
16297
|
+
selectFormSubmissionsOfIssue,
|
|
16298
|
+
selectFormsCount,
|
|
16299
|
+
selectGeneralFormCount,
|
|
15864
16300
|
selectHiddenCategoryCount,
|
|
15865
16301
|
selectHiddenComponentTypeIds,
|
|
15866
16302
|
selectIsFetchingInitialData,
|
|
@@ -15868,16 +16304,17 @@ export {
|
|
|
15868
16304
|
selectIsLoading,
|
|
15869
16305
|
selectIsLoggedIn,
|
|
15870
16306
|
selectIssue,
|
|
16307
|
+
selectIssueAttachment,
|
|
15871
16308
|
selectIssueAttachmentMapping,
|
|
15872
16309
|
selectIssueAttachments,
|
|
15873
16310
|
selectIssueMapping,
|
|
15874
16311
|
selectIssueUpdateMapping,
|
|
15875
16312
|
selectIssueUpdatesOfIssue,
|
|
15876
16313
|
selectIssues,
|
|
15877
|
-
|
|
16314
|
+
selectLatestFormRevisionByForm,
|
|
16315
|
+
selectLatestFormRevisionOfForm,
|
|
16316
|
+
selectLatestFormRevisionsOfComponentTypes,
|
|
15878
16317
|
selectLatestRetryTime,
|
|
15879
|
-
selectLatestRevisionByFormId,
|
|
15880
|
-
selectLatestRevisionsFromComponentTypeIds,
|
|
15881
16318
|
selectLicense,
|
|
15882
16319
|
selectLicenseForProject,
|
|
15883
16320
|
selectLicenses,
|
|
@@ -15886,8 +16323,6 @@ export {
|
|
|
15886
16323
|
selectMapStyle,
|
|
15887
16324
|
selectNumberOfComponentTypesMatchingCaseInsensitiveName,
|
|
15888
16325
|
selectNumberOfComponentsOfComponentType,
|
|
15889
|
-
selectNumberOfGeneralUserForms,
|
|
15890
|
-
selectNumberOfUserForms,
|
|
15891
16326
|
selectOrganization,
|
|
15892
16327
|
selectOrganizationAccess,
|
|
15893
16328
|
selectOrganizationAccessForUser,
|
|
@@ -15915,8 +16350,6 @@ export {
|
|
|
15915
16350
|
selectRecentIssuesAsSearchResults,
|
|
15916
16351
|
selectRecentProjects,
|
|
15917
16352
|
selectRehydrated,
|
|
15918
|
-
selectRevisionAttachments,
|
|
15919
|
-
selectRevisionsForForm,
|
|
15920
16353
|
selectRootDocuments,
|
|
15921
16354
|
selectShowTooltips,
|
|
15922
16355
|
selectSortedEmailDomains,
|
|
@@ -15931,16 +16364,10 @@ export {
|
|
|
15931
16364
|
selectStagesFromComponentType,
|
|
15932
16365
|
selectStagesFromComponentTypeIds,
|
|
15933
16366
|
selectStagesFromStageIds,
|
|
15934
|
-
selectSubmissionAttachments,
|
|
15935
|
-
selectSubmissionsForComponent,
|
|
15936
|
-
selectSubmissionsForForm,
|
|
15937
|
-
selectSubmissionsForIssue,
|
|
15938
16367
|
selectUploadUrl,
|
|
15939
16368
|
selectUsedColors,
|
|
15940
16369
|
selectUser,
|
|
15941
|
-
|
|
15942
|
-
selectUserFormMapping,
|
|
15943
|
-
selectUserFormSubmission,
|
|
16370
|
+
selectUserFormRevisionAttachmentsMapping,
|
|
15944
16371
|
selectUsersAsMapping,
|
|
15945
16372
|
selectVisibleStatuses,
|
|
15946
16373
|
selectVisibleUserIds,
|
|
@@ -15961,11 +16388,19 @@ export {
|
|
|
15961
16388
|
setComponents,
|
|
15962
16389
|
setCreateProjectType,
|
|
15963
16390
|
setCurrentUser,
|
|
16391
|
+
setDocumentAttachments,
|
|
15964
16392
|
setDocuments,
|
|
15965
16393
|
setEmailDomains,
|
|
15966
16394
|
setEnableClustering,
|
|
15967
16395
|
setEnableDuplicateIssues,
|
|
15968
16396
|
setEnablePlacementMode,
|
|
16397
|
+
setFormRevision,
|
|
16398
|
+
setFormRevisionAttachments,
|
|
16399
|
+
setFormRevisions,
|
|
16400
|
+
setFormSubmission,
|
|
16401
|
+
setFormSubmissionAttachments,
|
|
16402
|
+
setFormSubmissions,
|
|
16403
|
+
setForms,
|
|
15969
16404
|
setIsFetchingInitialData,
|
|
15970
16405
|
setIsImportingProjectFile,
|
|
15971
16406
|
setIsLoading,
|
|
@@ -15990,9 +16425,6 @@ export {
|
|
|
15990
16425
|
setTokens,
|
|
15991
16426
|
setTourStep,
|
|
15992
16427
|
setUploadUrl,
|
|
15993
|
-
setUserFormRevisionAttachments,
|
|
15994
|
-
setUserFormSubmissionAttachments,
|
|
15995
|
-
setUserFormSubmissions,
|
|
15996
16428
|
setUsers,
|
|
15997
16429
|
setVisibleStatuses,
|
|
15998
16430
|
setVisibleUserIds,
|
|
@@ -16015,12 +16447,16 @@ export {
|
|
|
16015
16447
|
updateComponent,
|
|
16016
16448
|
updateComponentAttachment,
|
|
16017
16449
|
updateComponentTypeAttachment,
|
|
16450
|
+
updateDocumentAttachment,
|
|
16018
16451
|
updateDocuments,
|
|
16452
|
+
updateFormSubmission,
|
|
16453
|
+
updateFormSubmissionAttachments,
|
|
16454
|
+
updateFormSubmissions,
|
|
16019
16455
|
updateIssue,
|
|
16020
16456
|
updateIssueAttachment,
|
|
16457
|
+
updateIssueAttachments,
|
|
16021
16458
|
updateLicense,
|
|
16022
16459
|
updateOrCreateProject,
|
|
16023
|
-
updateOrCreateUserFormSubmission,
|
|
16024
16460
|
updateOrganizationAccess,
|
|
16025
16461
|
updateProjectAccess,
|
|
16026
16462
|
updateProjectAttachment,
|
|
@@ -16034,8 +16470,6 @@ export {
|
|
|
16034
16470
|
useFormikInput,
|
|
16035
16471
|
useMemoCompare,
|
|
16036
16472
|
useSDK,
|
|
16037
|
-
userFormReducer,
|
|
16038
|
-
userFormSlice,
|
|
16039
16473
|
userReducer,
|
|
16040
16474
|
userSlice,
|
|
16041
16475
|
valueIsFile,
|