@overmap-ai/core 1.0.51-add-submitted-at-to-form-revisions.0 → 1.0.51-attachment-creation-flows.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 +1235 -503
- package/dist/overmap-core.js.map +1 -1
- package/dist/overmap-core.umd.cjs +1235 -503
- package/dist/overmap-core.umd.cjs.map +1 -1
- package/dist/sdk/sdk.d.ts +6 -1
- package/dist/sdk/services/BaseAttachmentService.d.ts +31 -0
- package/dist/sdk/services/ComponentAttachmentService.d.ts +10 -0
- package/dist/sdk/services/ComponentTypeAttachmentService.d.ts +10 -0
- package/dist/sdk/services/DocumentAttachmentService.d.ts +10 -0
- package/dist/sdk/services/IssueAttachmentService.d.ts +10 -0
- package/dist/sdk/services/ProjectAttachmentService.d.ts +10 -0
- package/dist/sdk/services/UserFormSubmissionService.d.ts +9 -2
- package/dist/sdk/services/index.d.ts +5 -0
- package/dist/store/slices/categorySlice.d.ts +3 -1
- package/dist/store/slices/componentSlice.d.ts +15 -7
- package/dist/store/slices/componentTypeSlice.d.ts +16 -8
- package/dist/store/slices/documentSlice.d.ts +13 -3
- package/dist/store/slices/formRevisionSlice.d.ts +65 -0
- package/dist/store/slices/formSlice.d.ts +110 -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 +36 -22
- package/dist/store/slices/projectFileSlice.d.ts +3 -1
- package/dist/store/slices/projectSlice.d.ts +12 -3
- package/dist/store/slices/utils.d.ts +4 -2
- 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 +15 -11
- 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/dist/utils/forms.d.ts +2 -0
- package/package.json +1 -1
- package/dist/store/slices/userFormSlice.d.ts +0 -145
package/dist/overmap-core.js
CHANGED
|
@@ -677,15 +677,15 @@ const wrapMigration = (migrator) => (state) => {
|
|
|
677
677
|
};
|
|
678
678
|
const migrations = [initialVersioning, signOut, signOut, createOutboxState];
|
|
679
679
|
const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
|
|
680
|
-
const initialState$
|
|
680
|
+
const initialState$p = {
|
|
681
681
|
accessToken: "",
|
|
682
682
|
refreshToken: "",
|
|
683
683
|
isLoggedIn: false
|
|
684
684
|
};
|
|
685
685
|
const authSlice = createSlice({
|
|
686
686
|
name: "auth",
|
|
687
|
-
initialState: initialState$
|
|
688
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
687
|
+
initialState: initialState$p,
|
|
688
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$p)),
|
|
689
689
|
reducers: {
|
|
690
690
|
setTokens: (state, action) => {
|
|
691
691
|
state.accessToken = action.payload.accessToken;
|
|
@@ -850,6 +850,19 @@ function downloadInMemoryFile(filename, text) {
|
|
|
850
850
|
element.click();
|
|
851
851
|
document.body.removeChild(element);
|
|
852
852
|
}
|
|
853
|
+
const constructUploadedFilePayloads = async (files) => {
|
|
854
|
+
const filePayloads = {};
|
|
855
|
+
for (const file of files) {
|
|
856
|
+
const sha1 = await hashFile(file);
|
|
857
|
+
filePayloads[sha1] = {
|
|
858
|
+
sha1,
|
|
859
|
+
extension: file.name.split(".").pop() || "",
|
|
860
|
+
file_type: file.type,
|
|
861
|
+
size: file.size
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
return Object.values(filePayloads);
|
|
865
|
+
};
|
|
853
866
|
const fileToBlob = async (dataUrl) => {
|
|
854
867
|
return (await fetch(dataUrl)).blob();
|
|
855
868
|
};
|
|
@@ -1416,7 +1429,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
|
|
|
1416
1429
|
return getLocalDateString(date);
|
|
1417
1430
|
return relative.format(days, "days");
|
|
1418
1431
|
});
|
|
1419
|
-
const initialState$
|
|
1432
|
+
const initialState$o = {
|
|
1420
1433
|
categories: {},
|
|
1421
1434
|
usedCategoryColors: [],
|
|
1422
1435
|
categoryVisibility: {
|
|
@@ -1426,8 +1439,8 @@ const initialState$m = {
|
|
|
1426
1439
|
};
|
|
1427
1440
|
const categorySlice = createSlice({
|
|
1428
1441
|
name: "categories",
|
|
1429
|
-
initialState: initialState$
|
|
1430
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1442
|
+
initialState: initialState$o,
|
|
1443
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$o)),
|
|
1431
1444
|
reducers: {
|
|
1432
1445
|
setCategories: (state, action) => {
|
|
1433
1446
|
if (!Array.isArray(action.payload))
|
|
@@ -1560,6 +1573,9 @@ const selectHiddenCategoryCount = (state) => {
|
|
|
1560
1573
|
return hiddenCategoryCount;
|
|
1561
1574
|
};
|
|
1562
1575
|
const categoryReducer = categorySlice.reducer;
|
|
1576
|
+
function setAttachment(state, action) {
|
|
1577
|
+
state.attachments[action.payload.offline_id] = action.payload;
|
|
1578
|
+
}
|
|
1563
1579
|
function setAttachments(state, action) {
|
|
1564
1580
|
state.attachments = {};
|
|
1565
1581
|
for (const attachment of action.payload) {
|
|
@@ -1584,6 +1600,15 @@ function updateAttachment(state, action) {
|
|
|
1584
1600
|
throw new Error(`Attachment ${action.payload.offline_id} does not exist.`);
|
|
1585
1601
|
}
|
|
1586
1602
|
}
|
|
1603
|
+
function updateAttachments(state, action) {
|
|
1604
|
+
for (const attachment of action.payload) {
|
|
1605
|
+
if (attachment.offline_id in state.attachments) {
|
|
1606
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
1607
|
+
} else {
|
|
1608
|
+
throw new Error(`Attachment ${attachment.offline_id} does not exist.`);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1587
1612
|
function removeAttachment(state, action) {
|
|
1588
1613
|
if (action.payload in state.attachments) {
|
|
1589
1614
|
delete state.attachments[action.payload];
|
|
@@ -1596,14 +1621,14 @@ function removeAttachments(state, action) {
|
|
|
1596
1621
|
delete state.attachments[attachmentId];
|
|
1597
1622
|
}
|
|
1598
1623
|
}
|
|
1599
|
-
const initialState$
|
|
1624
|
+
const initialState$n = {
|
|
1600
1625
|
components: {},
|
|
1601
1626
|
attachments: {}
|
|
1602
1627
|
};
|
|
1603
1628
|
const componentSlice = createSlice({
|
|
1604
1629
|
name: "components",
|
|
1605
|
-
initialState: initialState$
|
|
1606
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1630
|
+
initialState: initialState$n,
|
|
1631
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
|
|
1607
1632
|
reducers: {
|
|
1608
1633
|
addComponent: (state, action) => {
|
|
1609
1634
|
state.components[action.payload.offline_id] = action.payload;
|
|
@@ -1617,12 +1642,6 @@ const componentSlice = createSlice({
|
|
|
1617
1642
|
state.components = toOfflineIdRecord(action.payload);
|
|
1618
1643
|
prevComponents = null;
|
|
1619
1644
|
},
|
|
1620
|
-
setComponentAttachments: setAttachments,
|
|
1621
|
-
addComponentAttachment: addAttachment,
|
|
1622
|
-
addComponentAttachments: addAttachments,
|
|
1623
|
-
updateComponentAttachment: updateAttachment,
|
|
1624
|
-
removeComponentAttachment: removeAttachment,
|
|
1625
|
-
removeComponentAttachments: removeAttachments,
|
|
1626
1645
|
updateComponent: (state, action) => {
|
|
1627
1646
|
if (action.payload.offline_id in state.components) {
|
|
1628
1647
|
state.components[action.payload.offline_id] = action.payload;
|
|
@@ -1647,9 +1666,35 @@ const componentSlice = createSlice({
|
|
|
1647
1666
|
}
|
|
1648
1667
|
}
|
|
1649
1668
|
prevComponents = null;
|
|
1650
|
-
}
|
|
1669
|
+
},
|
|
1670
|
+
// Attachments
|
|
1671
|
+
setComponentAttachment: setAttachment,
|
|
1672
|
+
setComponentAttachments: setAttachments,
|
|
1673
|
+
addComponentAttachment: addAttachment,
|
|
1674
|
+
addComponentAttachments: addAttachments,
|
|
1675
|
+
updateComponentAttachment: updateAttachment,
|
|
1676
|
+
updateComponentAttachments: updateAttachments,
|
|
1677
|
+
removeComponentAttachment: removeAttachment,
|
|
1678
|
+
removeComponentAttachments: removeAttachments
|
|
1651
1679
|
}
|
|
1652
1680
|
});
|
|
1681
|
+
const {
|
|
1682
|
+
addComponent,
|
|
1683
|
+
updateComponent,
|
|
1684
|
+
removeComponent,
|
|
1685
|
+
addComponentsInBatches,
|
|
1686
|
+
setComponents,
|
|
1687
|
+
removeAllComponentsOfType,
|
|
1688
|
+
// Attachments
|
|
1689
|
+
setComponentAttachment,
|
|
1690
|
+
setComponentAttachments,
|
|
1691
|
+
addComponentAttachment,
|
|
1692
|
+
addComponentAttachments,
|
|
1693
|
+
updateComponentAttachment,
|
|
1694
|
+
updateComponentAttachments,
|
|
1695
|
+
removeComponentAttachment,
|
|
1696
|
+
removeComponentAttachments
|
|
1697
|
+
} = componentSlice.actions;
|
|
1653
1698
|
let prevComponents = null;
|
|
1654
1699
|
const selectComponents = (state) => {
|
|
1655
1700
|
if (!prevComponents) {
|
|
@@ -1744,28 +1789,14 @@ const selectAttachmentsOfComponentByType = restructureCreateSelectorWithArgs(
|
|
|
1744
1789
|
}
|
|
1745
1790
|
)
|
|
1746
1791
|
);
|
|
1747
|
-
const {
|
|
1748
|
-
addComponent,
|
|
1749
|
-
updateComponent,
|
|
1750
|
-
removeComponent,
|
|
1751
|
-
addComponentsInBatches,
|
|
1752
|
-
setComponents,
|
|
1753
|
-
setComponentAttachments,
|
|
1754
|
-
addComponentAttachment,
|
|
1755
|
-
addComponentAttachments,
|
|
1756
|
-
updateComponentAttachment,
|
|
1757
|
-
removeComponentAttachment,
|
|
1758
|
-
removeComponentAttachments,
|
|
1759
|
-
removeAllComponentsOfType
|
|
1760
|
-
} = componentSlice.actions;
|
|
1761
1792
|
const componentReducer = componentSlice.reducer;
|
|
1762
|
-
const initialState$
|
|
1793
|
+
const initialState$m = {
|
|
1763
1794
|
completionsByComponentId: {}
|
|
1764
1795
|
};
|
|
1765
1796
|
const componentStageCompletionSlice = createSlice({
|
|
1766
1797
|
name: "componentStageCompletions",
|
|
1767
|
-
initialState: initialState$
|
|
1768
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1798
|
+
initialState: initialState$m,
|
|
1799
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
|
|
1769
1800
|
reducers: {
|
|
1770
1801
|
addStageCompletion: (state, action) => {
|
|
1771
1802
|
let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
|
|
@@ -1816,13 +1847,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
|
|
|
1816
1847
|
return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
|
|
1817
1848
|
};
|
|
1818
1849
|
const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
|
|
1819
|
-
const initialState$
|
|
1850
|
+
const initialState$l = {
|
|
1820
1851
|
stages: {}
|
|
1821
1852
|
};
|
|
1822
1853
|
const componentStageSlice = createSlice({
|
|
1823
1854
|
name: "componentStages",
|
|
1824
|
-
initialState: initialState$
|
|
1825
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1855
|
+
initialState: initialState$l,
|
|
1856
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
|
|
1826
1857
|
reducers: {
|
|
1827
1858
|
addStages: (state, action) => {
|
|
1828
1859
|
Object.assign(state.stages, toOfflineIdRecord(action.payload));
|
|
@@ -1932,15 +1963,15 @@ const selectStageFormIdsFromStageIds = restructureCreateSelectorWithArgs(
|
|
|
1932
1963
|
);
|
|
1933
1964
|
const { addStages, updateStages, removeStages, linkStageToForm, unlinkStageToForm } = componentStageSlice.actions;
|
|
1934
1965
|
const componentStageReducer = componentStageSlice.reducer;
|
|
1935
|
-
const initialState$
|
|
1966
|
+
const initialState$k = {
|
|
1936
1967
|
componentTypes: {},
|
|
1937
1968
|
hiddenComponentTypeIds: {},
|
|
1938
1969
|
attachments: {}
|
|
1939
1970
|
};
|
|
1940
1971
|
const componentTypeSlice = createSlice({
|
|
1941
1972
|
name: "componentTypes",
|
|
1942
|
-
initialState: initialState$
|
|
1943
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
1973
|
+
initialState: initialState$k,
|
|
1974
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
|
|
1944
1975
|
reducers: {
|
|
1945
1976
|
addComponentType: (state, action) => {
|
|
1946
1977
|
state.componentTypes[action.payload.offline_id] = action.payload;
|
|
@@ -1948,20 +1979,38 @@ const componentTypeSlice = createSlice({
|
|
|
1948
1979
|
setComponentTypes: (state, action) => {
|
|
1949
1980
|
state.componentTypes = toOfflineIdRecord(action.payload);
|
|
1950
1981
|
},
|
|
1951
|
-
setComponentTypeAttachments: setAttachments,
|
|
1952
|
-
addComponentTypeAttachment: addAttachment,
|
|
1953
|
-
addComponentTypeAttachments: addAttachments,
|
|
1954
|
-
updateComponentTypeAttachment: updateAttachment,
|
|
1955
|
-
removeComponentTypeAttachment: removeAttachment,
|
|
1956
|
-
removeComponentTypeAttachments: removeAttachments,
|
|
1957
1982
|
toggleComponentTypeVisibility: (state, action) => {
|
|
1958
1983
|
state.hiddenComponentTypeIds[action.payload] = !state.hiddenComponentTypeIds[action.payload];
|
|
1959
1984
|
},
|
|
1960
1985
|
deleteComponentType: (state, action) => {
|
|
1961
1986
|
delete state.componentTypes[action.payload];
|
|
1962
|
-
}
|
|
1987
|
+
},
|
|
1988
|
+
// Attachments
|
|
1989
|
+
setComponentTypeAttachment: setAttachment,
|
|
1990
|
+
setComponentTypeAttachments: setAttachments,
|
|
1991
|
+
addComponentTypeAttachment: addAttachment,
|
|
1992
|
+
addComponentTypeAttachments: addAttachments,
|
|
1993
|
+
updateComponentTypeAttachment: updateAttachment,
|
|
1994
|
+
updateComponentTypeAttachments: updateAttachments,
|
|
1995
|
+
removeComponentTypeAttachment: removeAttachment,
|
|
1996
|
+
removeComponentTypeAttachments: removeAttachments
|
|
1963
1997
|
}
|
|
1964
1998
|
});
|
|
1999
|
+
const {
|
|
2000
|
+
addComponentType,
|
|
2001
|
+
setComponentTypes,
|
|
2002
|
+
toggleComponentTypeVisibility,
|
|
2003
|
+
deleteComponentType,
|
|
2004
|
+
// Attachmet
|
|
2005
|
+
setComponentTypeAttachment,
|
|
2006
|
+
setComponentTypeAttachments,
|
|
2007
|
+
addComponentTypeAttachment,
|
|
2008
|
+
addComponentTypeAttachments,
|
|
2009
|
+
updateComponentTypeAttachment,
|
|
2010
|
+
updateComponentTypeAttachments,
|
|
2011
|
+
removeComponentTypeAttachment,
|
|
2012
|
+
removeComponentTypeAttachments
|
|
2013
|
+
} = componentTypeSlice.actions;
|
|
1965
2014
|
const selectComponentTypesMapping = (state) => state.componentTypeReducer.componentTypes;
|
|
1966
2015
|
const selectComponentTypes = createSelector(
|
|
1967
2016
|
[selectComponentTypesMapping],
|
|
@@ -2038,26 +2087,14 @@ const selectAttachmentsOfComponentTypeByType = restructureCreateSelectorWithArgs
|
|
|
2038
2087
|
}
|
|
2039
2088
|
)
|
|
2040
2089
|
);
|
|
2041
|
-
const {
|
|
2042
|
-
addComponentType,
|
|
2043
|
-
setComponentTypes,
|
|
2044
|
-
setComponentTypeAttachments,
|
|
2045
|
-
addComponentTypeAttachment,
|
|
2046
|
-
addComponentTypeAttachments,
|
|
2047
|
-
updateComponentTypeAttachment,
|
|
2048
|
-
removeComponentTypeAttachment,
|
|
2049
|
-
removeComponentTypeAttachments,
|
|
2050
|
-
toggleComponentTypeVisibility,
|
|
2051
|
-
deleteComponentType
|
|
2052
|
-
} = componentTypeSlice.actions;
|
|
2053
2090
|
const componentTypeReducer = componentTypeSlice.reducer;
|
|
2054
|
-
const initialState$
|
|
2091
|
+
const initialState$j = {
|
|
2055
2092
|
workspaces: {},
|
|
2056
2093
|
activeWorkspaceId: null
|
|
2057
2094
|
};
|
|
2058
2095
|
const workspaceSlice = createSlice({
|
|
2059
2096
|
name: "workspace",
|
|
2060
|
-
initialState: initialState$
|
|
2097
|
+
initialState: initialState$j,
|
|
2061
2098
|
// The `reducers` field lets us define reducers and generate associated actions
|
|
2062
2099
|
reducers: {
|
|
2063
2100
|
setWorkspaces: (state, action) => {
|
|
@@ -2114,7 +2151,7 @@ const selectPermittedWorkspaceIds = createSelector(
|
|
|
2114
2151
|
);
|
|
2115
2152
|
const workspaceReducer = workspaceSlice.reducer;
|
|
2116
2153
|
const maxRecentIssues = 10;
|
|
2117
|
-
const initialState$
|
|
2154
|
+
const initialState$i = {
|
|
2118
2155
|
issues: {},
|
|
2119
2156
|
attachments: {},
|
|
2120
2157
|
comments: {},
|
|
@@ -2126,9 +2163,9 @@ const initialState$g = {
|
|
|
2126
2163
|
};
|
|
2127
2164
|
const issueSlice = createSlice({
|
|
2128
2165
|
name: "issues",
|
|
2129
|
-
initialState: initialState$
|
|
2166
|
+
initialState: initialState$i,
|
|
2130
2167
|
extraReducers: (builder) => builder.addCase("RESET", (state) => {
|
|
2131
|
-
Object.assign(state, initialState$
|
|
2168
|
+
Object.assign(state, initialState$i);
|
|
2132
2169
|
}),
|
|
2133
2170
|
reducers: {
|
|
2134
2171
|
setIssues: (state, action) => {
|
|
@@ -2139,7 +2176,6 @@ const issueSlice = createSlice({
|
|
|
2139
2176
|
state.issues[issue.offline_id] = issue;
|
|
2140
2177
|
});
|
|
2141
2178
|
},
|
|
2142
|
-
setIssueAttachments: setAttachments,
|
|
2143
2179
|
setIssueUpdates: (state, action) => {
|
|
2144
2180
|
if (action.payload.filter(onlyUniqueOfflineIds).length !== action.payload.length) {
|
|
2145
2181
|
throw new Error("Tried to use setIssues reducer with duplicate ID's");
|
|
@@ -2159,8 +2195,6 @@ const issueSlice = createSlice({
|
|
|
2159
2195
|
}
|
|
2160
2196
|
state.issues[action.payload.offline_id] = action.payload;
|
|
2161
2197
|
},
|
|
2162
|
-
addIssueAttachment: addAttachment,
|
|
2163
|
-
addIssueAttachments: addAttachments,
|
|
2164
2198
|
addIssueUpdate: (state, action) => {
|
|
2165
2199
|
if (action.payload.offline_id in state.updates) {
|
|
2166
2200
|
throw new Error(`Tried to add duplicate issue update with offline_id: ${action.payload.offline_id}`);
|
|
@@ -2182,7 +2216,6 @@ const issueSlice = createSlice({
|
|
|
2182
2216
|
throw new Error(`Tried to update issue with ID that doesn't exist: ${action.payload.offline_id}`);
|
|
2183
2217
|
}
|
|
2184
2218
|
},
|
|
2185
|
-
updateIssueAttachment: updateAttachment,
|
|
2186
2219
|
removeIssue: (state, action) => {
|
|
2187
2220
|
if (action.payload in state.issues) {
|
|
2188
2221
|
delete state.issues[action.payload];
|
|
@@ -2190,7 +2223,6 @@ const issueSlice = createSlice({
|
|
|
2190
2223
|
throw new Error(`Failed to remove issue because ID doesn't exist: ${action.payload}`);
|
|
2191
2224
|
}
|
|
2192
2225
|
},
|
|
2193
|
-
removeIssueAttachment: removeAttachment,
|
|
2194
2226
|
removeIssueUpdate: (state, action) => {
|
|
2195
2227
|
if (action.payload in state.updates) {
|
|
2196
2228
|
delete state.updates[action.payload];
|
|
@@ -2287,19 +2319,25 @@ const issueSlice = createSlice({
|
|
|
2287
2319
|
if (indexToRemove !== -1) {
|
|
2288
2320
|
state.recentIssueIds.splice(indexToRemove, 1);
|
|
2289
2321
|
}
|
|
2290
|
-
}
|
|
2322
|
+
},
|
|
2323
|
+
// Attachments
|
|
2324
|
+
setIssueAttachment: setAttachment,
|
|
2325
|
+
setIssueAttachments: setAttachments,
|
|
2326
|
+
addIssueAttachment: addAttachment,
|
|
2327
|
+
addIssueAttachments: addAttachments,
|
|
2328
|
+
updateIssueAttachment: updateAttachment,
|
|
2329
|
+
updateIssueAttachments: updateAttachments,
|
|
2330
|
+
removeIssueAttachment: removeAttachment,
|
|
2331
|
+
removeIssueAttachments: removeAttachments
|
|
2291
2332
|
}
|
|
2292
2333
|
});
|
|
2293
2334
|
const {
|
|
2294
|
-
addIssueAttachment,
|
|
2295
|
-
addIssueAttachments,
|
|
2296
2335
|
addIssue,
|
|
2297
2336
|
addIssueUpdate,
|
|
2298
2337
|
addIssueUpdates,
|
|
2299
2338
|
addOrReplaceIssueComment,
|
|
2300
2339
|
addToRecentIssues,
|
|
2301
2340
|
cleanRecentIssues,
|
|
2302
|
-
removeIssueAttachment,
|
|
2303
2341
|
removeAttachmentsOfIssue,
|
|
2304
2342
|
removeIssue,
|
|
2305
2343
|
removeIssueUpdate,
|
|
@@ -2307,13 +2345,20 @@ const {
|
|
|
2307
2345
|
removeRecentIssue,
|
|
2308
2346
|
resetRecentIssues,
|
|
2309
2347
|
setActiveIssueId,
|
|
2310
|
-
setIssueAttachments,
|
|
2311
2348
|
setIssueUpdates,
|
|
2312
2349
|
setIssues,
|
|
2313
2350
|
setVisibleStatuses,
|
|
2314
2351
|
setVisibleUserIds,
|
|
2315
|
-
updateIssueAttachment,
|
|
2316
2352
|
updateIssue,
|
|
2353
|
+
// Attachments
|
|
2354
|
+
setIssueAttachment,
|
|
2355
|
+
setIssueAttachments,
|
|
2356
|
+
addIssueAttachment,
|
|
2357
|
+
addIssueAttachments,
|
|
2358
|
+
updateIssueAttachment,
|
|
2359
|
+
updateIssueAttachments,
|
|
2360
|
+
removeIssueAttachment,
|
|
2361
|
+
removeIssueAttachments,
|
|
2317
2362
|
// Commments
|
|
2318
2363
|
addIssueComment,
|
|
2319
2364
|
addIssueComments,
|
|
@@ -2536,15 +2581,15 @@ const selectRecentIssuesAsSearchResults = createSelector(
|
|
|
2536
2581
|
}
|
|
2537
2582
|
);
|
|
2538
2583
|
const issueReducer = issueSlice.reducer;
|
|
2539
|
-
const initialState$
|
|
2584
|
+
const initialState$h = {
|
|
2540
2585
|
s3Urls: {}
|
|
2541
2586
|
};
|
|
2542
2587
|
const msPerHour = 1e3 * 60 * 60;
|
|
2543
2588
|
const msPerWeek = msPerHour * 24 * 7;
|
|
2544
2589
|
const fileSlice = createSlice({
|
|
2545
2590
|
name: "file",
|
|
2546
|
-
initialState: initialState$
|
|
2547
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2591
|
+
initialState: initialState$h,
|
|
2592
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
|
|
2548
2593
|
reducers: {
|
|
2549
2594
|
setUploadUrl: (state, action) => {
|
|
2550
2595
|
const { url, fields, sha1 } = action.payload;
|
|
@@ -2571,7 +2616,7 @@ const selectUploadUrl = (sha1) => (state) => {
|
|
|
2571
2616
|
return url;
|
|
2572
2617
|
};
|
|
2573
2618
|
const fileReducer = fileSlice.reducer;
|
|
2574
|
-
const initialState$
|
|
2619
|
+
const initialState$g = {
|
|
2575
2620
|
// TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
|
|
2576
2621
|
mapStyle: MapStyle.SATELLITE,
|
|
2577
2622
|
showTooltips: false,
|
|
@@ -2579,8 +2624,8 @@ const initialState$e = {
|
|
|
2579
2624
|
};
|
|
2580
2625
|
const mapSlice = createSlice({
|
|
2581
2626
|
name: "map",
|
|
2582
|
-
initialState: initialState$
|
|
2583
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2627
|
+
initialState: initialState$g,
|
|
2628
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
|
|
2584
2629
|
reducers: {
|
|
2585
2630
|
setMapStyle: (state, action) => {
|
|
2586
2631
|
state.mapStyle = action.payload;
|
|
@@ -2608,6 +2653,14 @@ var OrganizationAccessLevel = /* @__PURE__ */ ((OrganizationAccessLevel2) => {
|
|
|
2608
2653
|
OrganizationAccessLevel2[OrganizationAccessLevel2["ADMIN"] = 2] = "ADMIN";
|
|
2609
2654
|
return OrganizationAccessLevel2;
|
|
2610
2655
|
})(OrganizationAccessLevel || {});
|
|
2656
|
+
var AttachmentModel = /* @__PURE__ */ ((AttachmentModel2) => {
|
|
2657
|
+
AttachmentModel2["Issue"] = "issue";
|
|
2658
|
+
AttachmentModel2["Component"] = "component";
|
|
2659
|
+
AttachmentModel2["ComponentType"] = "component_type";
|
|
2660
|
+
AttachmentModel2["Project"] = "project";
|
|
2661
|
+
AttachmentModel2["Document"] = "document";
|
|
2662
|
+
return AttachmentModel2;
|
|
2663
|
+
})(AttachmentModel || {});
|
|
2611
2664
|
var IssueUpdateChange = /* @__PURE__ */ ((IssueUpdateChange2) => {
|
|
2612
2665
|
IssueUpdateChange2["STATUS"] = "status";
|
|
2613
2666
|
IssueUpdateChange2["PRIORITY"] = "priority";
|
|
@@ -2649,7 +2702,7 @@ var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
|
|
|
2649
2702
|
LicenseStatus2[LicenseStatus2["PAST_DUE"] = 8] = "PAST_DUE";
|
|
2650
2703
|
return LicenseStatus2;
|
|
2651
2704
|
})(LicenseStatus || {});
|
|
2652
|
-
const initialState$
|
|
2705
|
+
const initialState$f = {
|
|
2653
2706
|
users: {},
|
|
2654
2707
|
currentUser: {
|
|
2655
2708
|
id: 0,
|
|
@@ -2660,8 +2713,8 @@ const initialState$d = {
|
|
|
2660
2713
|
};
|
|
2661
2714
|
const userSlice = createSlice({
|
|
2662
2715
|
name: "users",
|
|
2663
|
-
initialState: initialState$
|
|
2664
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2716
|
+
initialState: initialState$f,
|
|
2717
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
|
|
2665
2718
|
reducers: {
|
|
2666
2719
|
setUsers: (state, action) => {
|
|
2667
2720
|
const usersMapping = {};
|
|
@@ -2723,13 +2776,13 @@ const selectUser = (userId) => (state) => {
|
|
|
2723
2776
|
const selectUsersAsMapping = (state) => state.userReducer.users;
|
|
2724
2777
|
const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
|
|
2725
2778
|
const userReducer = userSlice.reducer;
|
|
2726
|
-
const initialState$
|
|
2779
|
+
const initialState$e = {
|
|
2727
2780
|
organizationAccesses: {}
|
|
2728
2781
|
};
|
|
2729
2782
|
const organizationAccessSlice = createSlice({
|
|
2730
2783
|
name: "organizationAccess",
|
|
2731
|
-
initialState: initialState$
|
|
2732
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2784
|
+
initialState: initialState$e,
|
|
2785
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
|
|
2733
2786
|
reducers: {
|
|
2734
2787
|
setOrganizationAccesses: (state, action) => {
|
|
2735
2788
|
if (!Array.isArray(action.payload))
|
|
@@ -2792,13 +2845,13 @@ const selectOrganizationAccessUserMapping = (state) => {
|
|
|
2792
2845
|
return organizationAccesses;
|
|
2793
2846
|
};
|
|
2794
2847
|
const organizationAccessReducer = organizationAccessSlice.reducer;
|
|
2795
|
-
const initialState$
|
|
2848
|
+
const initialState$d = {
|
|
2796
2849
|
licenses: {}
|
|
2797
2850
|
};
|
|
2798
2851
|
const licenseSlice = createSlice({
|
|
2799
2852
|
name: "license",
|
|
2800
|
-
initialState: initialState$
|
|
2801
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2853
|
+
initialState: initialState$d,
|
|
2854
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
|
|
2802
2855
|
reducers: {
|
|
2803
2856
|
setLicenses: (state, action) => {
|
|
2804
2857
|
if (!Array.isArray(action.payload))
|
|
@@ -2843,13 +2896,13 @@ const selectLicensesForProjectsMapping = createSelector(
|
|
|
2843
2896
|
(licenses) => Object.values(licenses).filter((license) => license.project).reduce((accum, license) => ({ ...accum, [license.project]: license }), {})
|
|
2844
2897
|
);
|
|
2845
2898
|
const licenseReducer = licenseSlice.reducer;
|
|
2846
|
-
const initialState$
|
|
2899
|
+
const initialState$c = {
|
|
2847
2900
|
projectAccesses: {}
|
|
2848
2901
|
};
|
|
2849
2902
|
const projectAccessSlice = createSlice({
|
|
2850
2903
|
name: "projectAccess",
|
|
2851
|
-
initialState: initialState$
|
|
2852
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
2904
|
+
initialState: initialState$c,
|
|
2905
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
|
|
2853
2906
|
reducers: {
|
|
2854
2907
|
setProjectAccesses: (state, action) => {
|
|
2855
2908
|
if (!Array.isArray(action.payload))
|
|
@@ -2917,7 +2970,7 @@ const selectProjectAccessUserMapping = (state) => {
|
|
|
2917
2970
|
return projectAccesses;
|
|
2918
2971
|
};
|
|
2919
2972
|
const projectAccessReducer = projectAccessSlice.reducer;
|
|
2920
|
-
const initialState$
|
|
2973
|
+
const initialState$b = {
|
|
2921
2974
|
projects: {},
|
|
2922
2975
|
activeProjectId: null,
|
|
2923
2976
|
recentProjectIds: [],
|
|
@@ -2927,7 +2980,7 @@ const initialState$9 = {
|
|
|
2927
2980
|
};
|
|
2928
2981
|
const projectSlice = createSlice({
|
|
2929
2982
|
name: "projects",
|
|
2930
|
-
initialState: initialState$
|
|
2983
|
+
initialState: initialState$b,
|
|
2931
2984
|
reducers: {
|
|
2932
2985
|
setProjects: (state, action) => {
|
|
2933
2986
|
const projectsMap = {};
|
|
@@ -2995,11 +3048,13 @@ const projectSlice = createSlice({
|
|
|
2995
3048
|
throw new Error("Update form submissions count: no active project");
|
|
2996
3049
|
}
|
|
2997
3050
|
},
|
|
2998
|
-
//
|
|
3051
|
+
// Attachments
|
|
3052
|
+
setProjectAttachment: setAttachment,
|
|
2999
3053
|
setProjectAttachments: setAttachments,
|
|
3000
3054
|
addProjectAttachment: addAttachment,
|
|
3001
3055
|
addProjectAttachments: addAttachments,
|
|
3002
3056
|
updateProjectAttachment: updateAttachment,
|
|
3057
|
+
updateProjectAttachments: updateAttachments,
|
|
3003
3058
|
removeProjectAttachment: removeAttachment,
|
|
3004
3059
|
removeProjectAttachments: removeAttachments
|
|
3005
3060
|
}
|
|
@@ -3014,11 +3069,13 @@ const {
|
|
|
3014
3069
|
acceptProjectInvite,
|
|
3015
3070
|
addActiveProjectIssuesCount,
|
|
3016
3071
|
addActiveProjectFormSubmissionsCount,
|
|
3017
|
-
//
|
|
3072
|
+
// Attachments
|
|
3073
|
+
setProjectAttachment,
|
|
3018
3074
|
setProjectAttachments,
|
|
3019
3075
|
addProjectAttachment,
|
|
3020
3076
|
addProjectAttachments,
|
|
3021
3077
|
updateProjectAttachment,
|
|
3078
|
+
updateProjectAttachments,
|
|
3022
3079
|
removeProjectAttachment,
|
|
3023
3080
|
removeProjectAttachments
|
|
3024
3081
|
} = projectSlice.actions;
|
|
@@ -3089,6 +3146,9 @@ const selectAllProjectAttachments = createSelector(
|
|
|
3089
3146
|
[selectProjectAttachmentMapping],
|
|
3090
3147
|
(mapping) => Object.values(mapping)
|
|
3091
3148
|
);
|
|
3149
|
+
const selectProjectAttachment = (attachmentId) => (state) => {
|
|
3150
|
+
return state.projectReducer.attachments[attachmentId];
|
|
3151
|
+
};
|
|
3092
3152
|
const selectAttachmentsOfProject = restructureCreateSelectorWithArgs(
|
|
3093
3153
|
createSelector(
|
|
3094
3154
|
[selectAllProjectAttachments, (_state, projectId) => projectId],
|
|
@@ -3114,14 +3174,14 @@ const selectAttachmentsOfProjectByType = restructureCreateSelectorWithArgs(
|
|
|
3114
3174
|
}
|
|
3115
3175
|
)
|
|
3116
3176
|
);
|
|
3117
|
-
const initialState$
|
|
3177
|
+
const initialState$a = {
|
|
3118
3178
|
organizations: {},
|
|
3119
3179
|
activeOrganizationId: null
|
|
3120
3180
|
};
|
|
3121
3181
|
const organizationSlice = createSlice({
|
|
3122
3182
|
name: "organizations",
|
|
3123
|
-
initialState: initialState$
|
|
3124
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
3183
|
+
initialState: initialState$a,
|
|
3184
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
|
|
3125
3185
|
reducers: {
|
|
3126
3186
|
setOrganizations: (state, action) => {
|
|
3127
3187
|
for (const org of action.payload) {
|
|
@@ -3240,14 +3300,14 @@ const createOfflineAction = (request2, baseUrl) => {
|
|
|
3240
3300
|
}
|
|
3241
3301
|
};
|
|
3242
3302
|
};
|
|
3243
|
-
const initialState$
|
|
3303
|
+
const initialState$9 = {
|
|
3244
3304
|
deletedRequests: [],
|
|
3245
3305
|
latestRetryTime: 0
|
|
3246
3306
|
};
|
|
3247
3307
|
const outboxSlice = createSlice({
|
|
3248
3308
|
name: "outbox",
|
|
3249
|
-
initialState: initialState$
|
|
3250
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
3309
|
+
initialState: initialState$9,
|
|
3310
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
|
|
3251
3311
|
reducers: {
|
|
3252
3312
|
// enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
|
|
3253
3313
|
// Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
|
|
@@ -3279,7 +3339,7 @@ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
|
|
|
3279
3339
|
const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
|
|
3280
3340
|
const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
|
|
3281
3341
|
const outboxReducer = outboxSlice.reducer;
|
|
3282
|
-
const initialState$
|
|
3342
|
+
const initialState$8 = {
|
|
3283
3343
|
projectFiles: {},
|
|
3284
3344
|
activeProjectFileId: null,
|
|
3285
3345
|
isImportingProjectFile: false,
|
|
@@ -3287,8 +3347,8 @@ const initialState$6 = {
|
|
|
3287
3347
|
};
|
|
3288
3348
|
const projectFileSlice = createSlice({
|
|
3289
3349
|
name: "projectFiles",
|
|
3290
|
-
initialState: initialState$
|
|
3291
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
3350
|
+
initialState: initialState$8,
|
|
3351
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
|
|
3292
3352
|
reducers: {
|
|
3293
3353
|
addOrReplaceProjectFiles: (state, action) => {
|
|
3294
3354
|
for (let fileObj of action.payload) {
|
|
@@ -3389,12 +3449,12 @@ const selectProjectFiles = createSelector(
|
|
|
3389
3449
|
const selectActiveProjectFileId = (state) => state.projectFileReducer.activeProjectFileId;
|
|
3390
3450
|
const selectIsImportingProjectFile = (state) => state.projectFileReducer.isImportingProjectFile;
|
|
3391
3451
|
const projectFileReducer = projectFileSlice.reducer;
|
|
3392
|
-
const initialState$
|
|
3452
|
+
const initialState$7 = {
|
|
3393
3453
|
isRehydrated: false
|
|
3394
3454
|
};
|
|
3395
3455
|
const rehydratedSlice = createSlice({
|
|
3396
3456
|
name: "rehydrated",
|
|
3397
|
-
initialState: initialState$
|
|
3457
|
+
initialState: initialState$7,
|
|
3398
3458
|
// The `reducers` field lets us define reducers and generate associated actions
|
|
3399
3459
|
reducers: {
|
|
3400
3460
|
setRehydrated: (state, action) => {
|
|
@@ -3404,7 +3464,7 @@ const rehydratedSlice = createSlice({
|
|
|
3404
3464
|
});
|
|
3405
3465
|
const selectRehydrated = (state) => state.rehydratedReducer.isRehydrated;
|
|
3406
3466
|
const rehydratedReducer = rehydratedSlice.reducer;
|
|
3407
|
-
const initialState$
|
|
3467
|
+
const initialState$6 = {
|
|
3408
3468
|
useIssueTemplate: false,
|
|
3409
3469
|
placementMode: false,
|
|
3410
3470
|
enableClustering: false,
|
|
@@ -3421,8 +3481,8 @@ const initialState$4 = {
|
|
|
3421
3481
|
};
|
|
3422
3482
|
const settingSlice = createSlice({
|
|
3423
3483
|
name: "settings",
|
|
3424
|
-
initialState: initialState$
|
|
3425
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$
|
|
3484
|
+
initialState: initialState$6,
|
|
3485
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
|
|
3426
3486
|
reducers: {
|
|
3427
3487
|
setEnableDuplicateIssues: (state, action) => {
|
|
3428
3488
|
state.useIssueTemplate = action.payload;
|
|
@@ -3468,146 +3528,231 @@ const selectAppearance = (state) => state.settingReducer.appearance;
|
|
|
3468
3528
|
const settingReducer = settingSlice.reducer;
|
|
3469
3529
|
const selectIsFetchingInitialData = (state) => state.settingReducer.isFetchingInitialData;
|
|
3470
3530
|
const selectIsLoading = (state) => state.settingReducer.isLoading;
|
|
3471
|
-
const
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
if (
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
return;
|
|
3483
|
-
}
|
|
3484
|
-
if (revision.revision === "Pending") {
|
|
3485
|
-
if (preferPending) {
|
|
3486
|
-
LATEST_REVISION_CACHE[revision.form] = revision;
|
|
3487
|
-
}
|
|
3488
|
-
return;
|
|
3489
|
-
}
|
|
3490
|
-
const cachedRevision = (_a2 = LATEST_REVISION_CACHE[revision.form]) == null ? void 0 : _a2.revision;
|
|
3491
|
-
if (revision.revision > (typeof cachedRevision === "number" ? cachedRevision : -1)) {
|
|
3492
|
-
LATEST_REVISION_CACHE[revision.form] = revision;
|
|
3531
|
+
const formRevisionSortFn = (formRevisionA, formRevisionB) => {
|
|
3532
|
+
const revisionA = formRevisionA.revision;
|
|
3533
|
+
const revisionB = formRevisionB.revision;
|
|
3534
|
+
if (revisionA === "Pending" && revisionB === "Pending") {
|
|
3535
|
+
return formRevisionA.submitted_at < formRevisionB.submitted_at ? -1 : 1;
|
|
3536
|
+
} else if (revisionA === "Pending") {
|
|
3537
|
+
return 1;
|
|
3538
|
+
} else if (revisionB === "Pending") {
|
|
3539
|
+
return -1;
|
|
3540
|
+
} else {
|
|
3541
|
+
return revisionA < revisionB ? -1 : 1;
|
|
3493
3542
|
}
|
|
3494
|
-
}
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
}
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
revisionAttachments: {}
|
|
3504
|
-
};
|
|
3505
|
-
const userFormSlice = createSlice({
|
|
3506
|
-
name: "userForms",
|
|
3507
|
-
initialState: initialState$3,
|
|
3508
|
-
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
|
|
3543
|
+
};
|
|
3544
|
+
const initialState$5 = {
|
|
3545
|
+
formRevisions: {},
|
|
3546
|
+
attachments: {}
|
|
3547
|
+
};
|
|
3548
|
+
const formRevisionsSlice = createSlice({
|
|
3549
|
+
name: "formRevisions",
|
|
3550
|
+
initialState: initialState$5,
|
|
3551
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
|
|
3509
3552
|
reducers: {
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
action.payload.
|
|
3513
|
-
state.userForms[userForm.offline_id] = userForm;
|
|
3514
|
-
});
|
|
3515
|
-
},
|
|
3516
|
-
addUserForm: (state, action) => {
|
|
3517
|
-
state.userForms[action.payload.offline_id] = action.payload;
|
|
3518
|
-
},
|
|
3519
|
-
addUserForms: (state, action) => {
|
|
3520
|
-
action.payload.forEach((userForm) => {
|
|
3521
|
-
state.userForms[userForm.offline_id] = userForm;
|
|
3522
|
-
});
|
|
3523
|
-
},
|
|
3524
|
-
addUserFormRevisions: (state, action) => {
|
|
3525
|
-
action.payload.forEach((userFormRevision) => {
|
|
3526
|
-
state.revisions[userFormRevision.offline_id] = userFormRevision;
|
|
3527
|
-
considerCachingRevision(userFormRevision);
|
|
3528
|
-
});
|
|
3553
|
+
// revision related actions
|
|
3554
|
+
setFormRevision: (state, action) => {
|
|
3555
|
+
state.formRevisions[action.payload.offline_id] = action.payload;
|
|
3529
3556
|
},
|
|
3530
|
-
|
|
3531
|
-
state.
|
|
3532
|
-
|
|
3557
|
+
setFormRevisions: (state, action) => {
|
|
3558
|
+
state.formRevisions = {};
|
|
3559
|
+
for (const revision of action.payload) {
|
|
3560
|
+
state.formRevisions[revision.offline_id] = revision;
|
|
3561
|
+
}
|
|
3533
3562
|
},
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3563
|
+
addFormRevision: (state, action) => {
|
|
3564
|
+
if (state.formRevisions[action.payload.offline_id] !== void 0) {
|
|
3565
|
+
throw new Error(`Revision with offline_id ${action.payload.offline_id} already exists`);
|
|
3566
|
+
}
|
|
3567
|
+
state.formRevisions[action.payload.offline_id] = action.payload;
|
|
3537
3568
|
},
|
|
3538
|
-
|
|
3569
|
+
addFormRevisions: (state, action) => {
|
|
3539
3570
|
for (const userFormRevision of action.payload) {
|
|
3540
|
-
|
|
3541
|
-
|
|
3571
|
+
if (state.formRevisions[userFormRevision.offline_id] !== void 0) {
|
|
3572
|
+
throw new Error(`Revision with offline_id ${userFormRevision.offline_id} already exists`);
|
|
3573
|
+
}
|
|
3542
3574
|
}
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
state.submissions[action.payload.offline_id] = action.payload;
|
|
3546
|
-
},
|
|
3547
|
-
addUserFormSubmissionAttachment: (state, action) => {
|
|
3548
|
-
const submissionId = action.payload.submission;
|
|
3549
|
-
const submissionAttachments = state.submissionAttachments[submissionId];
|
|
3550
|
-
if (submissionAttachments) {
|
|
3551
|
-
submissionAttachments.push(action.payload);
|
|
3552
|
-
} else {
|
|
3553
|
-
state.submissionAttachments[submissionId] = [action.payload];
|
|
3575
|
+
for (const userFormRevision of action.payload) {
|
|
3576
|
+
state.formRevisions[userFormRevision.offline_id] = userFormRevision;
|
|
3554
3577
|
}
|
|
3555
3578
|
},
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
revisionAttachments.push(action.payload);
|
|
3561
|
-
} else {
|
|
3562
|
-
state.revisionAttachments[revisionId] = [action.payload];
|
|
3579
|
+
// UserFormRevisions do not get updated
|
|
3580
|
+
deleteFormRevision: (state, action) => {
|
|
3581
|
+
if (state.formRevisions[action.payload] === void 0) {
|
|
3582
|
+
throw new Error(`Revision with offline_id ${action.payload} does not exist`);
|
|
3563
3583
|
}
|
|
3584
|
+
delete state.formRevisions[action.payload];
|
|
3564
3585
|
},
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
const submissionAttachments = state.submissionAttachments[submissionId];
|
|
3570
|
-
if (submissionAttachments) {
|
|
3571
|
-
submissionAttachments.push(attachment);
|
|
3572
|
-
} else {
|
|
3573
|
-
state.submissionAttachments[submissionId] = [attachment];
|
|
3586
|
+
deleteFormRevisions: (state, action) => {
|
|
3587
|
+
for (const offlineId of action.payload) {
|
|
3588
|
+
if (state.formRevisions[offlineId] === void 0) {
|
|
3589
|
+
throw new Error(`Revision with offline_id ${offlineId} does not exist`);
|
|
3574
3590
|
}
|
|
3575
3591
|
}
|
|
3592
|
+
for (const offlineId of action.payload) {
|
|
3593
|
+
delete state.formRevisions[offlineId];
|
|
3594
|
+
}
|
|
3576
3595
|
},
|
|
3577
|
-
|
|
3578
|
-
|
|
3596
|
+
// attachment related actions
|
|
3597
|
+
setFormRevisionAttachments: (state, action) => {
|
|
3598
|
+
state.attachments = {};
|
|
3579
3599
|
for (const attachment of action.payload) {
|
|
3580
|
-
|
|
3581
|
-
const revisionAttachments = state.revisionAttachments[revisionId];
|
|
3582
|
-
if (revisionAttachments) {
|
|
3583
|
-
revisionAttachments.push(attachment);
|
|
3584
|
-
} else {
|
|
3585
|
-
state.revisionAttachments[revisionId] = [attachment];
|
|
3586
|
-
}
|
|
3600
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3587
3601
|
}
|
|
3588
3602
|
},
|
|
3589
|
-
|
|
3590
|
-
|
|
3603
|
+
addFormRevisionAttachment: (state, action) => {
|
|
3604
|
+
if (state.attachments[action.payload.offline_id] !== void 0) {
|
|
3605
|
+
throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
|
|
3606
|
+
}
|
|
3607
|
+
state.attachments[action.payload.offline_id] = action.payload;
|
|
3591
3608
|
},
|
|
3592
|
-
|
|
3593
|
-
for (const
|
|
3594
|
-
|
|
3609
|
+
addFormRevisionAttachments: (state, action) => {
|
|
3610
|
+
for (const attachment of action.payload) {
|
|
3611
|
+
if (state.attachments[attachment.offline_id] !== void 0) {
|
|
3612
|
+
throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
for (const attachment of action.payload) {
|
|
3616
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3595
3617
|
}
|
|
3596
3618
|
},
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3619
|
+
deleteFormRevisionAttachment: (state, action) => {
|
|
3620
|
+
if (state.attachments[action.payload] === void 0) {
|
|
3621
|
+
throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
|
|
3600
3622
|
}
|
|
3623
|
+
delete state.attachments[action.payload];
|
|
3601
3624
|
},
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3625
|
+
deleteFormRevisionAttachments: (state, action) => {
|
|
3626
|
+
for (const offlineId of action.payload) {
|
|
3627
|
+
if (state.attachments[offlineId] === void 0) {
|
|
3628
|
+
throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
for (const offlineId of action.payload) {
|
|
3632
|
+
delete state.attachments[offlineId];
|
|
3633
|
+
}
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
});
|
|
3637
|
+
const {
|
|
3638
|
+
setFormRevision,
|
|
3639
|
+
setFormRevisions,
|
|
3640
|
+
addFormRevision,
|
|
3641
|
+
addFormRevisions,
|
|
3642
|
+
deleteFormRevision,
|
|
3643
|
+
deleteFormRevisions,
|
|
3644
|
+
setFormRevisionAttachments,
|
|
3645
|
+
addFormRevisionAttachment,
|
|
3646
|
+
addFormRevisionAttachments,
|
|
3647
|
+
deleteFormRevisionAttachment,
|
|
3648
|
+
deleteFormRevisionAttachments
|
|
3649
|
+
} = formRevisionsSlice.actions;
|
|
3650
|
+
const selectFormRevisionMapping = (state) => state.formRevisionReducer.formRevisions;
|
|
3651
|
+
const selectFormRevisions = createSelector(
|
|
3652
|
+
[selectFormRevisionMapping],
|
|
3653
|
+
(formRevisions) => Object.values(formRevisions)
|
|
3654
|
+
);
|
|
3655
|
+
const selectFormRevision = (formRevisionId) => (state) => {
|
|
3656
|
+
return state.formRevisionReducer.formRevisions[formRevisionId];
|
|
3657
|
+
};
|
|
3658
|
+
const _selectLatestFormRevision = (formRevisions, formId2) => {
|
|
3659
|
+
let ret = null;
|
|
3660
|
+
for (const candidate of Object.values(formRevisions)) {
|
|
3661
|
+
if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
|
|
3662
|
+
ret = candidate;
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
if (!ret) {
|
|
3666
|
+
throw new Error("No form revision found for form " + formId2);
|
|
3667
|
+
}
|
|
3668
|
+
return ret;
|
|
3669
|
+
};
|
|
3670
|
+
const selectLatestFormRevisionOfForm = restructureCreateSelectorWithArgs(
|
|
3671
|
+
createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
|
|
3672
|
+
return revisions.filter((revision) => revision.form === formId2).sort(formRevisionSortFn).pop();
|
|
3673
|
+
})
|
|
3674
|
+
);
|
|
3675
|
+
const selectFormRevisionsOfForm = restructureCreateSelectorWithArgs(
|
|
3676
|
+
createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
|
|
3677
|
+
return revisions.filter((revision) => {
|
|
3678
|
+
return revision.form === formId2;
|
|
3679
|
+
});
|
|
3680
|
+
})
|
|
3681
|
+
);
|
|
3682
|
+
const selectLatestFormRevisionsOfComponentTypes = restructureCreateSelectorWithArgs(
|
|
3683
|
+
createSelector(
|
|
3684
|
+
[
|
|
3685
|
+
(state) => state.formReducer.forms,
|
|
3686
|
+
selectFormRevisionMapping,
|
|
3687
|
+
(_state, componentTypeIds) => componentTypeIds
|
|
3688
|
+
],
|
|
3689
|
+
(userForms, revisions, componentTypeIds) => {
|
|
3690
|
+
const componentTypeIdsSet = new Set(componentTypeIds);
|
|
3691
|
+
const formsOfComponentTypes = {};
|
|
3692
|
+
const ret = {};
|
|
3693
|
+
for (const form of Object.values(userForms)) {
|
|
3694
|
+
if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
|
|
3695
|
+
formsOfComponentTypes[form.offline_id] = form;
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
for (const revision of Object.values(revisions)) {
|
|
3699
|
+
const form = formsOfComponentTypes[revision.form];
|
|
3700
|
+
if (!form || !form.component_type || ret[form.component_type] && formRevisionSortFn(ret[form.component_type], revision) > 0)
|
|
3701
|
+
continue;
|
|
3702
|
+
ret[form.component_type] = revision;
|
|
3703
|
+
}
|
|
3704
|
+
return ret;
|
|
3705
|
+
}
|
|
3706
|
+
)
|
|
3707
|
+
);
|
|
3708
|
+
const selectLatestFormRevisionByForm = createSelector([selectFormRevisionMapping], (revisions) => {
|
|
3709
|
+
const latestRevisions = {};
|
|
3710
|
+
for (const revision of Object.values(revisions)) {
|
|
3711
|
+
const formId2 = revision.form;
|
|
3712
|
+
const currentLatestRevision = latestRevisions[formId2];
|
|
3713
|
+
if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
|
|
3714
|
+
latestRevisions[formId2] = revision;
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
return latestRevisions;
|
|
3718
|
+
});
|
|
3719
|
+
const selectUserFormRevisionAttachmentsMapping = (state) => {
|
|
3720
|
+
return state.formRevisionReducer.attachments;
|
|
3721
|
+
};
|
|
3722
|
+
const selectAttachmentsOfFormRevision = restructureCreateSelectorWithArgs(
|
|
3723
|
+
createSelector(
|
|
3724
|
+
[selectUserFormRevisionAttachmentsMapping, (_state, revisionId) => revisionId],
|
|
3725
|
+
(attachments, revisionId) => {
|
|
3726
|
+
return Object.values(attachments).filter((attachment) => attachment.revision === revisionId);
|
|
3727
|
+
}
|
|
3728
|
+
)
|
|
3729
|
+
);
|
|
3730
|
+
const formRevisionReducer = formRevisionsSlice.reducer;
|
|
3731
|
+
const initialState$4 = {
|
|
3732
|
+
forms: {}
|
|
3733
|
+
};
|
|
3734
|
+
const formSlice = createSlice({
|
|
3735
|
+
name: "forms",
|
|
3736
|
+
initialState: initialState$4,
|
|
3737
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
|
|
3738
|
+
reducers: {
|
|
3739
|
+
setForms: (state, action) => {
|
|
3740
|
+
state.forms = {};
|
|
3741
|
+
action.payload.forEach((userForm) => {
|
|
3742
|
+
state.forms[userForm.offline_id] = userForm;
|
|
3606
3743
|
});
|
|
3607
3744
|
},
|
|
3745
|
+
addForm: (state, action) => {
|
|
3746
|
+
state.forms[action.payload.offline_id] = action.payload;
|
|
3747
|
+
},
|
|
3748
|
+
addForms: (state, action) => {
|
|
3749
|
+
for (const userForm of action.payload) {
|
|
3750
|
+
state.forms[userForm.offline_id] = userForm;
|
|
3751
|
+
}
|
|
3752
|
+
},
|
|
3608
3753
|
favoriteForm: (state, action) => {
|
|
3609
3754
|
const { formId: formId2 } = action.payload;
|
|
3610
|
-
const form = state.
|
|
3755
|
+
const form = state.forms[formId2];
|
|
3611
3756
|
if (!form) {
|
|
3612
3757
|
throw new Error("No form exists with the id " + formId2);
|
|
3613
3758
|
}
|
|
@@ -3615,48 +3760,23 @@ const userFormSlice = createSlice({
|
|
|
3615
3760
|
},
|
|
3616
3761
|
unfavoriteForm: (state, action) => {
|
|
3617
3762
|
const { formId: formId2 } = action.payload;
|
|
3618
|
-
const form = state.
|
|
3763
|
+
const form = state.forms[formId2];
|
|
3619
3764
|
if (!form) {
|
|
3620
3765
|
throw new Error("No form exists with the id " + formId2);
|
|
3621
3766
|
}
|
|
3622
3767
|
form.favorite = false;
|
|
3623
3768
|
},
|
|
3624
|
-
|
|
3625
|
-
delete state.
|
|
3769
|
+
deleteForm: (state, action) => {
|
|
3770
|
+
delete state.forms[action.payload];
|
|
3626
3771
|
}
|
|
3627
3772
|
}
|
|
3628
3773
|
});
|
|
3629
|
-
const {
|
|
3630
|
-
|
|
3631
|
-
addUserForms,
|
|
3632
|
-
addUserFormRevisions,
|
|
3633
|
-
updateOrCreateUserFormSubmission,
|
|
3634
|
-
addUserFormSubmissions,
|
|
3635
|
-
deleteUserFormSubmission,
|
|
3636
|
-
deleteUserFormSubmissions,
|
|
3637
|
-
favoriteForm,
|
|
3638
|
-
unfavoriteForm,
|
|
3639
|
-
deleteUserForm,
|
|
3640
|
-
deleteUserFormRevision,
|
|
3641
|
-
deleteUserFormRevisions,
|
|
3642
|
-
setUserFormSubmissions,
|
|
3643
|
-
addUserFormRevision,
|
|
3644
|
-
addUserFormSubmissionAttachment,
|
|
3645
|
-
addUserFormRevisionAttachment,
|
|
3646
|
-
setUserFormSubmissionAttachments,
|
|
3647
|
-
setUserFormRevisionAttachments
|
|
3648
|
-
} = userFormSlice.actions;
|
|
3649
|
-
const selectSubmissionAttachments = (submissionId) => (state) => {
|
|
3650
|
-
return state.userFormReducer.submissionAttachments[submissionId] || [];
|
|
3651
|
-
};
|
|
3652
|
-
const selectRevisionAttachments = (revisionId) => (state) => {
|
|
3653
|
-
return state.userFormReducer.revisionAttachments[revisionId] || [];
|
|
3654
|
-
};
|
|
3655
|
-
const selectFilteredUserForms = restructureCreateSelectorWithArgs(
|
|
3774
|
+
const { setForms, addForm, addForms, favoriteForm, unfavoriteForm, deleteForm } = formSlice.actions;
|
|
3775
|
+
const selectFilteredForms = restructureCreateSelectorWithArgs(
|
|
3656
3776
|
createSelector(
|
|
3657
3777
|
[
|
|
3658
|
-
(state) => state.
|
|
3659
|
-
(state) => state.
|
|
3778
|
+
(state) => state.formReducer.forms,
|
|
3779
|
+
(state) => state.formRevisionReducer.formRevisions,
|
|
3660
3780
|
(_state, search) => search
|
|
3661
3781
|
],
|
|
3662
3782
|
(userForms, revisions, search) => {
|
|
@@ -3683,70 +3803,195 @@ const selectFilteredUserForms = restructureCreateSelectorWithArgs(
|
|
|
3683
3803
|
break;
|
|
3684
3804
|
}
|
|
3685
3805
|
}
|
|
3686
|
-
const maxRegularMatches = maxResults - favoriteMatches.length;
|
|
3687
|
-
return [...favoriteMatches, ...regularMatches.slice(0, maxRegularMatches)];
|
|
3806
|
+
const maxRegularMatches = maxResults - favoriteMatches.length;
|
|
3807
|
+
return [...favoriteMatches, ...regularMatches.slice(0, maxRegularMatches)];
|
|
3808
|
+
},
|
|
3809
|
+
// as the argument is an object, we check the first level of properties for equality
|
|
3810
|
+
{ memoizeOptions: { equalityCheck: shallowEqual$1 } }
|
|
3811
|
+
)
|
|
3812
|
+
);
|
|
3813
|
+
const selectForm = (formId2) => (state) => {
|
|
3814
|
+
return state.formReducer.forms[formId2];
|
|
3815
|
+
};
|
|
3816
|
+
const selectFormMapping = (state) => {
|
|
3817
|
+
return state.formReducer.forms;
|
|
3818
|
+
};
|
|
3819
|
+
const selectFormOfComponentType = restructureCreateSelectorWithArgs(
|
|
3820
|
+
createSelector(
|
|
3821
|
+
[selectFormMapping, (_state, componentTypeId) => componentTypeId],
|
|
3822
|
+
(userForms, componentTypeId) => {
|
|
3823
|
+
return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
|
|
3824
|
+
}
|
|
3825
|
+
)
|
|
3826
|
+
);
|
|
3827
|
+
const selectFormsCount = createSelector([selectFormMapping], (userForms) => {
|
|
3828
|
+
return Object.keys(userForms).length;
|
|
3829
|
+
});
|
|
3830
|
+
const selectGeneralFormCount = createSelector([selectFormMapping], (userForms) => {
|
|
3831
|
+
return Object.values(userForms).filter((form) => !form.component_type).length;
|
|
3832
|
+
});
|
|
3833
|
+
const formReducer = formSlice.reducer;
|
|
3834
|
+
const initialState$3 = {
|
|
3835
|
+
formSubmissions: {},
|
|
3836
|
+
attachments: {}
|
|
3837
|
+
};
|
|
3838
|
+
const formSubmissionSlice = createSlice({
|
|
3839
|
+
name: "formSubmissions",
|
|
3840
|
+
initialState: initialState$3,
|
|
3841
|
+
extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
|
|
3842
|
+
reducers: {
|
|
3843
|
+
setFormSubmission: (state, action) => {
|
|
3844
|
+
state.formSubmissions[action.payload.offline_id] = action.payload;
|
|
3845
|
+
},
|
|
3846
|
+
setFormSubmissions: (state, action) => {
|
|
3847
|
+
state.formSubmissions = {};
|
|
3848
|
+
for (const submission of action.payload) {
|
|
3849
|
+
state.formSubmissions[submission.offline_id] = submission;
|
|
3850
|
+
}
|
|
3851
|
+
},
|
|
3852
|
+
addFormSubmission: (state, action) => {
|
|
3853
|
+
if (action.payload.offline_id in state.formSubmissions) {
|
|
3854
|
+
throw new Error(`Submission with offline_id ${action.payload.offline_id} already exists`);
|
|
3855
|
+
}
|
|
3856
|
+
state.formSubmissions[action.payload.offline_id] = action.payload;
|
|
3857
|
+
},
|
|
3858
|
+
addFormSubmissions: (state, action) => {
|
|
3859
|
+
for (const submission of action.payload) {
|
|
3860
|
+
if (state.formSubmissions[submission.offline_id] !== void 0) {
|
|
3861
|
+
throw new Error(`Submission with offline_id ${submission.offline_id} already exists`);
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3864
|
+
for (const submission of action.payload) {
|
|
3865
|
+
state.formSubmissions[submission.offline_id] = submission;
|
|
3866
|
+
}
|
|
3867
|
+
},
|
|
3868
|
+
updateFormSubmission: (state, action) => {
|
|
3869
|
+
if (state.formSubmissions[action.payload.offline_id] === void 0) {
|
|
3870
|
+
throw new Error(`Submission with offline_id ${action.payload.offline_id} does not exist`);
|
|
3871
|
+
}
|
|
3872
|
+
state.formSubmissions[action.payload.offline_id] = action.payload;
|
|
3873
|
+
},
|
|
3874
|
+
updateFormSubmissions: (state, action) => {
|
|
3875
|
+
for (const submission of action.payload) {
|
|
3876
|
+
if (state.formSubmissions[submission.offline_id] === void 0) {
|
|
3877
|
+
throw new Error(`Submission with offline_id ${submission.offline_id} does not exist`);
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
for (const submission of action.payload) {
|
|
3881
|
+
state.formSubmissions[submission.offline_id] = submission;
|
|
3882
|
+
}
|
|
3883
|
+
},
|
|
3884
|
+
deleteFormSubmission: (state, action) => {
|
|
3885
|
+
if (state.formSubmissions[action.payload] === void 0) {
|
|
3886
|
+
throw new Error(`Submission with offline_id ${action.payload} does not exist`);
|
|
3887
|
+
}
|
|
3888
|
+
delete state.formSubmissions[action.payload];
|
|
3889
|
+
},
|
|
3890
|
+
deleteFormSubmissions: (state, action) => {
|
|
3891
|
+
for (const offlineId of action.payload) {
|
|
3892
|
+
if (state.formSubmissions[offlineId] === void 0) {
|
|
3893
|
+
throw new Error(`Submission with offline_id ${offlineId} does not exist`);
|
|
3894
|
+
}
|
|
3895
|
+
delete state.formSubmissions[offlineId];
|
|
3896
|
+
}
|
|
3897
|
+
for (const offlineId of action.payload) {
|
|
3898
|
+
delete state.formSubmissions[offlineId];
|
|
3899
|
+
}
|
|
3900
|
+
},
|
|
3901
|
+
// Attachments
|
|
3902
|
+
addFormSubmissionAttachment: (state, action) => {
|
|
3903
|
+
if (state.attachments[action.payload.offline_id] !== void 0) {
|
|
3904
|
+
throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
|
|
3905
|
+
}
|
|
3906
|
+
state.attachments[action.payload.offline_id] = action.payload;
|
|
3907
|
+
},
|
|
3908
|
+
addFormSubmissionAttachments: (state, action) => {
|
|
3909
|
+
for (const attachment of action.payload) {
|
|
3910
|
+
if (state.attachments[attachment.offline_id] !== void 0) {
|
|
3911
|
+
throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
for (const attachment of action.payload) {
|
|
3915
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3916
|
+
}
|
|
3917
|
+
},
|
|
3918
|
+
// We only need a multi set for attachments because they are not updated, only added and deleted
|
|
3919
|
+
setFormSubmissionAttachments: (state, action) => {
|
|
3920
|
+
state.attachments = {};
|
|
3921
|
+
for (const attachment of action.payload) {
|
|
3922
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3923
|
+
}
|
|
3924
|
+
},
|
|
3925
|
+
updateFormSubmissionAttachments: (state, action) => {
|
|
3926
|
+
for (const attachment of action.payload) {
|
|
3927
|
+
if (state.attachments[attachment.offline_id] === void 0) {
|
|
3928
|
+
throw new Error(`Attachment with offline_id ${attachment.offline_id} does not exist`);
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
for (const attachment of action.payload) {
|
|
3932
|
+
state.attachments[attachment.offline_id] = attachment;
|
|
3933
|
+
}
|
|
3688
3934
|
},
|
|
3689
|
-
//
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
)
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3935
|
+
// The delete actions for UserFormSubmissionAttachments are not used in the app, but are included for completeness
|
|
3936
|
+
// Could be used if editing a submission is ever supported, will be applicable for supporting tip tap content in submissions
|
|
3937
|
+
deleteFormSubmissionAttachment: (state, action) => {
|
|
3938
|
+
if (state.attachments[action.payload] === void 0) {
|
|
3939
|
+
throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
|
|
3940
|
+
}
|
|
3941
|
+
delete state.attachments[action.payload];
|
|
3942
|
+
},
|
|
3943
|
+
deleteFormSubmissionAttachments: (state, action) => {
|
|
3944
|
+
for (const offlineId of action.payload) {
|
|
3945
|
+
if (state.attachments[offlineId] === void 0) {
|
|
3946
|
+
throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
|
|
3947
|
+
}
|
|
3948
|
+
delete state.attachments[offlineId];
|
|
3949
|
+
}
|
|
3701
3950
|
}
|
|
3702
3951
|
}
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3952
|
+
});
|
|
3953
|
+
const {
|
|
3954
|
+
setFormSubmission,
|
|
3955
|
+
setFormSubmissions,
|
|
3956
|
+
addFormSubmission,
|
|
3957
|
+
addFormSubmissions,
|
|
3958
|
+
updateFormSubmission,
|
|
3959
|
+
updateFormSubmissions,
|
|
3960
|
+
deleteFormSubmission,
|
|
3961
|
+
deleteFormSubmissions,
|
|
3962
|
+
addFormSubmissionAttachment,
|
|
3963
|
+
addFormSubmissionAttachments,
|
|
3964
|
+
setFormSubmissionAttachments,
|
|
3965
|
+
updateFormSubmissionAttachments,
|
|
3966
|
+
deleteFormSubmissionAttachment,
|
|
3967
|
+
deleteFormSubmissionAttachments
|
|
3968
|
+
} = formSubmissionSlice.actions;
|
|
3969
|
+
const selectFormSubmissionsMapping = (state) => {
|
|
3970
|
+
return state.formSubmissionReducer.formSubmissions;
|
|
3707
3971
|
};
|
|
3708
|
-
const
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
(
|
|
3712
|
-
|
|
3713
|
-
throw new Error("formId is required");
|
|
3714
|
-
}
|
|
3715
|
-
return _selectLatestFormRevision(revisions, formId2);
|
|
3716
|
-
}
|
|
3717
|
-
)
|
|
3718
|
-
);
|
|
3719
|
-
const selectUserForm = (formId2) => (state) => {
|
|
3720
|
-
return state.userFormReducer.userForms[formId2];
|
|
3721
|
-
};
|
|
3722
|
-
const selectSubmissionMapping = (state) => state.userFormReducer.submissions;
|
|
3723
|
-
const selectUserFormSubmission = (submissionId) => (state) => {
|
|
3724
|
-
return state.userFormReducer.submissions[submissionId];
|
|
3725
|
-
};
|
|
3726
|
-
const selectSubmissions = createSelector([selectSubmissionMapping], (submissions) => Object.values(submissions));
|
|
3727
|
-
const selectRevisionMapping = (state) => state.userFormReducer.revisions;
|
|
3728
|
-
const selectRevisions = createSelector([selectRevisionMapping], (revisions) => Object.values(revisions));
|
|
3729
|
-
const selectRevisionsForForm = restructureCreateSelectorWithArgs(
|
|
3730
|
-
createSelector([selectRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
|
|
3731
|
-
return revisions.filter((revision) => {
|
|
3732
|
-
return revision.form === formId2;
|
|
3733
|
-
});
|
|
3734
|
-
})
|
|
3972
|
+
const selectFormSubmissions = createSelector(
|
|
3973
|
+
[selectFormSubmissionsMapping],
|
|
3974
|
+
(submissions) => {
|
|
3975
|
+
return Object.values(submissions);
|
|
3976
|
+
}
|
|
3735
3977
|
);
|
|
3736
|
-
const
|
|
3978
|
+
const selectFormSubmission = (submissionId) => (state) => {
|
|
3979
|
+
return state.formSubmissionReducer.formSubmissions[submissionId];
|
|
3980
|
+
};
|
|
3981
|
+
const selectFormSubmissionsOfForm = restructureCreateSelectorWithArgs(
|
|
3737
3982
|
createSelector(
|
|
3738
|
-
[
|
|
3983
|
+
[selectFormSubmissions, selectFormRevisionMapping, (_state, formId2) => formId2],
|
|
3739
3984
|
(submissions, revisionMapping, formId2) => {
|
|
3740
|
-
return
|
|
3985
|
+
return submissions.filter((submission) => {
|
|
3741
3986
|
const revision = revisionMapping[submission.form_revision];
|
|
3742
3987
|
return (revision == null ? void 0 : revision.form) === formId2;
|
|
3743
3988
|
});
|
|
3744
3989
|
}
|
|
3745
3990
|
)
|
|
3746
3991
|
);
|
|
3747
|
-
const
|
|
3992
|
+
const selectFormSubmissionsOfIssue = restructureCreateSelectorWithArgs(
|
|
3748
3993
|
createSelector(
|
|
3749
|
-
[
|
|
3994
|
+
[selectFormSubmissions, (_state, issueId) => issueId],
|
|
3750
3995
|
(submissions, issueId) => {
|
|
3751
3996
|
return Object.values(submissions).filter((submission) => {
|
|
3752
3997
|
return submission.issue === issueId;
|
|
@@ -3754,9 +3999,9 @@ const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
|
|
|
3754
3999
|
}
|
|
3755
4000
|
)
|
|
3756
4001
|
);
|
|
3757
|
-
const
|
|
4002
|
+
const selectFormSubmissionsOfComponent = restructureCreateSelectorWithArgs(
|
|
3758
4003
|
createSelector(
|
|
3759
|
-
[
|
|
4004
|
+
[selectFormSubmissions, (_state, componentId) => componentId],
|
|
3760
4005
|
(submissions, componentId) => {
|
|
3761
4006
|
return submissions.filter((submission) => {
|
|
3762
4007
|
return submission.component === componentId;
|
|
@@ -3764,8 +4009,8 @@ const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
|
|
|
3764
4009
|
}
|
|
3765
4010
|
)
|
|
3766
4011
|
);
|
|
3767
|
-
const
|
|
3768
|
-
[
|
|
4012
|
+
const selectFormSubmissionsByComponents = createSelector(
|
|
4013
|
+
[selectFormSubmissionsMapping, selectComponentsMapping],
|
|
3769
4014
|
(submissions, components) => {
|
|
3770
4015
|
var _a2;
|
|
3771
4016
|
const componentSubmissionMapping = {};
|
|
@@ -3781,54 +4026,18 @@ const selectComponentSubmissionMapping = createSelector(
|
|
|
3781
4026
|
return componentSubmissionMapping;
|
|
3782
4027
|
}
|
|
3783
4028
|
);
|
|
3784
|
-
const
|
|
3785
|
-
return state.
|
|
4029
|
+
const selectFormSubmissionAttachmentsMapping = (state) => {
|
|
4030
|
+
return state.formSubmissionReducer.attachments;
|
|
3786
4031
|
};
|
|
3787
|
-
const
|
|
3788
|
-
createSelector(
|
|
3789
|
-
[selectUserFormMapping, (_state, componentTypeId) => componentTypeId],
|
|
3790
|
-
(userForms, componentTypeId) => {
|
|
3791
|
-
return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
|
|
3792
|
-
}
|
|
3793
|
-
)
|
|
3794
|
-
);
|
|
3795
|
-
const selectLatestRevisionsFromComponentTypeIds = restructureCreateSelectorWithArgs(
|
|
4032
|
+
const selectAttachmentsOfFormSubmission = restructureCreateSelectorWithArgs(
|
|
3796
4033
|
createSelector(
|
|
3797
|
-
[
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
(_state, componentTypeIds) => componentTypeIds
|
|
3801
|
-
],
|
|
3802
|
-
(userForms, revisions, componentTypeIds) => {
|
|
3803
|
-
const componentTypeIdsSet = new Set(componentTypeIds);
|
|
3804
|
-
const ret = {};
|
|
3805
|
-
for (const form of Object.values(userForms)) {
|
|
3806
|
-
if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
|
|
3807
|
-
ret[form.component_type] = _selectLatestFormRevision(revisions, form.offline_id);
|
|
3808
|
-
}
|
|
3809
|
-
}
|
|
3810
|
-
return ret;
|
|
4034
|
+
[selectFormSubmissionAttachmentsMapping, (_state, submissionId) => submissionId],
|
|
4035
|
+
(attachmentsMapping, submissionId) => {
|
|
4036
|
+
return Object.values(attachmentsMapping).filter((attachment) => attachment.submission === submissionId);
|
|
3811
4037
|
}
|
|
3812
4038
|
)
|
|
3813
4039
|
);
|
|
3814
|
-
const
|
|
3815
|
-
const latestRevisions = {};
|
|
3816
|
-
for (const revision of Object.values(revisions)) {
|
|
3817
|
-
const formId2 = revision.form;
|
|
3818
|
-
const currentLatestRevision = latestRevisions[formId2];
|
|
3819
|
-
if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
|
|
3820
|
-
latestRevisions[formId2] = revision;
|
|
3821
|
-
}
|
|
3822
|
-
}
|
|
3823
|
-
return latestRevisions;
|
|
3824
|
-
});
|
|
3825
|
-
const selectNumberOfUserForms = createSelector([selectUserFormMapping], (userForms) => {
|
|
3826
|
-
return Object.keys(userForms).length;
|
|
3827
|
-
});
|
|
3828
|
-
const selectNumberOfGeneralUserForms = createSelector([selectUserFormMapping], (userForms) => {
|
|
3829
|
-
return Object.values(userForms).filter((form) => !form.component_type).length;
|
|
3830
|
-
});
|
|
3831
|
-
const userFormReducer = userFormSlice.reducer;
|
|
4040
|
+
const formSubmissionReducer = formSubmissionSlice.reducer;
|
|
3832
4041
|
const initialState$2 = {
|
|
3833
4042
|
emailDomains: {}
|
|
3834
4043
|
};
|
|
@@ -4001,10 +4210,13 @@ const documentSlice = createSlice({
|
|
|
4001
4210
|
delete state.documents[documentId];
|
|
4002
4211
|
}
|
|
4003
4212
|
},
|
|
4213
|
+
// Attachments
|
|
4214
|
+
setDocumentAttachment: setAttachment,
|
|
4004
4215
|
setDocumentAttachments: setAttachments,
|
|
4005
4216
|
addDocumentAttachment: addAttachment,
|
|
4006
4217
|
addDocumentAttachments: addAttachments,
|
|
4007
4218
|
updateDocumentAttachment: updateAttachment,
|
|
4219
|
+
updateDocumentAttachments: updateAttachments,
|
|
4008
4220
|
removeDocumentAttachment: removeAttachment,
|
|
4009
4221
|
removeDocumentAttachments: removeAttachments
|
|
4010
4222
|
}
|
|
@@ -4015,10 +4227,13 @@ const {
|
|
|
4015
4227
|
updateDocuments,
|
|
4016
4228
|
moveDocument,
|
|
4017
4229
|
removeDocuments,
|
|
4230
|
+
// Attachments
|
|
4231
|
+
setDocumentAttachment,
|
|
4018
4232
|
setDocumentAttachments,
|
|
4019
4233
|
addDocumentAttachment,
|
|
4020
4234
|
addDocumentAttachments,
|
|
4021
4235
|
updateDocumentAttachment,
|
|
4236
|
+
updateDocumentAttachments,
|
|
4022
4237
|
removeDocumentAttachment,
|
|
4023
4238
|
removeDocumentAttachments
|
|
4024
4239
|
} = documentSlice.actions;
|
|
@@ -4126,7 +4341,9 @@ const overmapReducers = {
|
|
|
4126
4341
|
projectFileReducer,
|
|
4127
4342
|
rehydratedReducer,
|
|
4128
4343
|
settingReducer,
|
|
4129
|
-
|
|
4344
|
+
formReducer,
|
|
4345
|
+
formRevisionReducer,
|
|
4346
|
+
formSubmissionReducer,
|
|
4130
4347
|
userReducer,
|
|
4131
4348
|
workspaceReducer,
|
|
4132
4349
|
emailDomainsReducer,
|
|
@@ -4179,9 +4396,7 @@ function handleWorkspaceRemoval(draft, action) {
|
|
|
4179
4396
|
throw new Error(`Failed to update index_workspace of issue ${issue.offline_id} to main workspace`);
|
|
4180
4397
|
}
|
|
4181
4398
|
}
|
|
4182
|
-
const indexedForms = Object.values(draft.
|
|
4183
|
-
(form) => form.index_workspace === workspaceId
|
|
4184
|
-
);
|
|
4399
|
+
const indexedForms = Object.values(draft.formReducer.forms).filter((form) => form.index_workspace === workspaceId);
|
|
4185
4400
|
for (const form of indexedForms) {
|
|
4186
4401
|
form.index_workspace = mainWorkspace.offline_id;
|
|
4187
4402
|
}
|
|
@@ -5888,6 +6103,221 @@ class ComponentStageService extends BaseApiService {
|
|
|
5888
6103
|
store.dispatch(addStages(result));
|
|
5889
6104
|
}
|
|
5890
6105
|
}
|
|
6106
|
+
const AttachmentModelMeta = {
|
|
6107
|
+
[AttachmentModel.Issue]: {
|
|
6108
|
+
name: "issue",
|
|
6109
|
+
attachUrlPrefix: "/issues",
|
|
6110
|
+
deleteUrlPrefix: "/issues",
|
|
6111
|
+
fetchUrlPostfix: "/issue-attachments"
|
|
6112
|
+
},
|
|
6113
|
+
[AttachmentModel.Component]: {
|
|
6114
|
+
name: "component",
|
|
6115
|
+
attachUrlPrefix: "/components",
|
|
6116
|
+
deleteUrlPrefix: "/components",
|
|
6117
|
+
fetchUrlPostfix: "/component-attachments"
|
|
6118
|
+
},
|
|
6119
|
+
[AttachmentModel.ComponentType]: {
|
|
6120
|
+
name: "component type",
|
|
6121
|
+
attachUrlPrefix: "/components/types",
|
|
6122
|
+
deleteUrlPrefix: "/components/types",
|
|
6123
|
+
fetchUrlPostfix: "/component-type-attachments"
|
|
6124
|
+
},
|
|
6125
|
+
[AttachmentModel.Project]: {
|
|
6126
|
+
name: "component project",
|
|
6127
|
+
attachUrlPrefix: "/projects",
|
|
6128
|
+
deleteUrlPrefix: "/projects",
|
|
6129
|
+
fetchUrlPostfix: "/attachments"
|
|
6130
|
+
},
|
|
6131
|
+
[AttachmentModel.Document]: {
|
|
6132
|
+
name: "document",
|
|
6133
|
+
attachUrlPrefix: "/documents",
|
|
6134
|
+
deleteUrlPrefix: "/documents",
|
|
6135
|
+
fetchUrlPostfix: "/document-attachments"
|
|
6136
|
+
}
|
|
6137
|
+
};
|
|
6138
|
+
class BaseAttachmentService extends BaseApiService {
|
|
6139
|
+
getNumberOfAttachmentsWithSha1(sha1) {
|
|
6140
|
+
const {
|
|
6141
|
+
issueReducer: issueReducer2,
|
|
6142
|
+
componentReducer: componentReducer2,
|
|
6143
|
+
componentTypeReducer: componentTypeReducer2,
|
|
6144
|
+
documentsReducer: documentsReducer2,
|
|
6145
|
+
projectReducer: projectReducer2,
|
|
6146
|
+
formSubmissionReducer: formSubmissionReducer2,
|
|
6147
|
+
formRevisionReducer: formRevisionReducer2
|
|
6148
|
+
} = this.client.store.getState();
|
|
6149
|
+
const objectsWithSha1 = [].concat(
|
|
6150
|
+
Object.values(issueReducer2.attachments),
|
|
6151
|
+
Object.values(componentReducer2.attachments),
|
|
6152
|
+
Object.values(componentTypeReducer2.attachments),
|
|
6153
|
+
Object.values(documentsReducer2.attachments),
|
|
6154
|
+
Object.values(projectReducer2.attachments),
|
|
6155
|
+
Object.values(formRevisionReducer2.attachments),
|
|
6156
|
+
Object.values(formSubmissionReducer2.attachments)
|
|
6157
|
+
);
|
|
6158
|
+
return objectsWithSha1.filter((object) => object.file_sha1 === sha1).length;
|
|
6159
|
+
}
|
|
6160
|
+
processPresignedUrls(presignedUrls) {
|
|
6161
|
+
for (const [sha1, presignedUrl] of Object.entries(presignedUrls)) {
|
|
6162
|
+
void this.enqueueRequest({
|
|
6163
|
+
url: presignedUrl.url,
|
|
6164
|
+
description: "Upload file to S3",
|
|
6165
|
+
method: HttpMethod.POST,
|
|
6166
|
+
isExternalUrl: true,
|
|
6167
|
+
isAuthNeeded: false,
|
|
6168
|
+
attachmentHash: sha1,
|
|
6169
|
+
// TODO: can we use the sha1 as the blocker?
|
|
6170
|
+
blockers: [`s3-${presignedUrl.fields.key}`],
|
|
6171
|
+
blocks: [sha1],
|
|
6172
|
+
s3url: presignedUrl
|
|
6173
|
+
});
|
|
6174
|
+
}
|
|
6175
|
+
}
|
|
6176
|
+
// Note that currently the fetching of attachments for all models dependds on the active projectId. This may change in the future. And
|
|
6177
|
+
// so for some attachment model services, this method will have to be overridden.
|
|
6178
|
+
async getAttachments(actions) {
|
|
6179
|
+
const { store } = this.client;
|
|
6180
|
+
const activeProjectId = store.getState().projectReducer.activeProjectId;
|
|
6181
|
+
const meta = AttachmentModelMeta[this.attachmentModel];
|
|
6182
|
+
const result = await this.enqueueRequest({
|
|
6183
|
+
description: `Get ${meta.name} attachments`,
|
|
6184
|
+
method: HttpMethod.GET,
|
|
6185
|
+
url: `/projects/${activeProjectId}${meta.fetchUrlPostfix}/`,
|
|
6186
|
+
blocks: [],
|
|
6187
|
+
blockers: []
|
|
6188
|
+
});
|
|
6189
|
+
store.dispatch(actions.setAttachments(result));
|
|
6190
|
+
}
|
|
6191
|
+
async attachFiles(files, modelId, buildOfflineAttachment, actions) {
|
|
6192
|
+
const { store } = this.client;
|
|
6193
|
+
const currentUser = store.getState().userReducer.currentUser;
|
|
6194
|
+
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6195
|
+
const offlineAttachments = [];
|
|
6196
|
+
const attachmentPayloads = [];
|
|
6197
|
+
const filePayloads = {};
|
|
6198
|
+
for (const file of files) {
|
|
6199
|
+
const sha1 = await hashFile(file);
|
|
6200
|
+
if (!(sha1 in filePayloads)) {
|
|
6201
|
+
filePayloads[sha1] = {
|
|
6202
|
+
sha1,
|
|
6203
|
+
file_type: file.type,
|
|
6204
|
+
extension: file.name.split(".").pop(),
|
|
6205
|
+
size: file.size
|
|
6206
|
+
};
|
|
6207
|
+
await this.client.files.addCache(file, sha1);
|
|
6208
|
+
}
|
|
6209
|
+
const offlineAttachment = buildOfflineAttachment({
|
|
6210
|
+
file,
|
|
6211
|
+
sha1,
|
|
6212
|
+
submittedAt,
|
|
6213
|
+
createdBy: currentUser.id,
|
|
6214
|
+
description: "",
|
|
6215
|
+
modelId
|
|
6216
|
+
});
|
|
6217
|
+
offlineAttachments.push(offlineAttachment);
|
|
6218
|
+
attachmentPayloads.push({
|
|
6219
|
+
offline_id: offlineAttachment.offline_id,
|
|
6220
|
+
name: offlineAttachment.file_name,
|
|
6221
|
+
sha1: offlineAttachment.file_sha1,
|
|
6222
|
+
description: offlineAttachment.description
|
|
6223
|
+
});
|
|
6224
|
+
}
|
|
6225
|
+
store.dispatch(actions.addAttachments(offlineAttachments));
|
|
6226
|
+
const meta = AttachmentModelMeta[this.attachmentModel];
|
|
6227
|
+
const promise = this.enqueueRequest({
|
|
6228
|
+
description: `Attach files to ${meta.name}`,
|
|
6229
|
+
method: HttpMethod.POST,
|
|
6230
|
+
url: `${meta.attachUrlPrefix}/${modelId}/attach/`,
|
|
6231
|
+
payload: {
|
|
6232
|
+
submitted_at: submittedAt,
|
|
6233
|
+
attachments: attachmentPayloads,
|
|
6234
|
+
files: Object.values(filePayloads)
|
|
6235
|
+
},
|
|
6236
|
+
blocks: offlineAttachments.map((attachment) => attachment.offline_id),
|
|
6237
|
+
blockers: offlineAttachments.map((attachment) => attachment.file_sha1)
|
|
6238
|
+
});
|
|
6239
|
+
promise.then(({ attachments, presigned_urls }) => {
|
|
6240
|
+
store.dispatch(actions.updateAttachments(attachments));
|
|
6241
|
+
this.processPresignedUrls(presigned_urls);
|
|
6242
|
+
}).catch(() => {
|
|
6243
|
+
store.dispatch(actions.removeAttachments(offlineAttachments.map((attachment) => attachment.offline_id)));
|
|
6244
|
+
});
|
|
6245
|
+
return [offlineAttachments, promise.then(({ attachments }) => attachments)];
|
|
6246
|
+
}
|
|
6247
|
+
async deleteAttachment(attachmendId, actions, selectors) {
|
|
6248
|
+
const { store } = this.client;
|
|
6249
|
+
const attachment = selectors.selectAttachment(attachmendId)(store.getState());
|
|
6250
|
+
if (!attachment) {
|
|
6251
|
+
throw new Error(
|
|
6252
|
+
`Attempting to delete attachment with offline_id ${attachmendId} that does not exist in the store`
|
|
6253
|
+
);
|
|
6254
|
+
}
|
|
6255
|
+
store.dispatch(actions.removeAttachment(attachment.offline_id));
|
|
6256
|
+
const meta = AttachmentModelMeta[this.attachmentModel];
|
|
6257
|
+
const promise = this.enqueueRequest({
|
|
6258
|
+
description: "Delete attachment",
|
|
6259
|
+
method: HttpMethod.DELETE,
|
|
6260
|
+
url: `${meta.deleteUrlPrefix}/attachments/${attachmendId}/`,
|
|
6261
|
+
blockers: [attachmendId],
|
|
6262
|
+
blocks: []
|
|
6263
|
+
});
|
|
6264
|
+
promise.then(() => {
|
|
6265
|
+
if (this.getNumberOfAttachmentsWithSha1(attachment.file_sha1) === 0) {
|
|
6266
|
+
void this.client.files.removeCache(attachment.file_sha1);
|
|
6267
|
+
}
|
|
6268
|
+
}).catch(() => {
|
|
6269
|
+
store.dispatch(actions.setAttachment(attachment));
|
|
6270
|
+
});
|
|
6271
|
+
return promise;
|
|
6272
|
+
}
|
|
6273
|
+
}
|
|
6274
|
+
class ComponentAttachmentService extends BaseAttachmentService {
|
|
6275
|
+
constructor() {
|
|
6276
|
+
super(...arguments);
|
|
6277
|
+
__publicField(this, "attachmentModel", AttachmentModel.Component);
|
|
6278
|
+
}
|
|
6279
|
+
buildOfflineAttachment(data) {
|
|
6280
|
+
return offline({
|
|
6281
|
+
file: URL.createObjectURL(data.file),
|
|
6282
|
+
file_sha1: data.sha1,
|
|
6283
|
+
created_by: data.createdBy,
|
|
6284
|
+
file_name: data.file.name,
|
|
6285
|
+
file_type: data.file.type,
|
|
6286
|
+
submitted_at: data.submittedAt,
|
|
6287
|
+
description: data.description,
|
|
6288
|
+
component: data.modelId
|
|
6289
|
+
});
|
|
6290
|
+
}
|
|
6291
|
+
async attachFilesToComponent(files, componentId) {
|
|
6292
|
+
return this.attachFiles(
|
|
6293
|
+
files,
|
|
6294
|
+
componentId,
|
|
6295
|
+
this.buildOfflineAttachment.bind(this),
|
|
6296
|
+
{
|
|
6297
|
+
addAttachments: addComponentAttachments,
|
|
6298
|
+
updateAttachments: updateComponentAttachments,
|
|
6299
|
+
removeAttachments: removeComponentAttachments
|
|
6300
|
+
}
|
|
6301
|
+
);
|
|
6302
|
+
}
|
|
6303
|
+
deleteComponentAttachment(attachmentId) {
|
|
6304
|
+
return this.deleteAttachment(
|
|
6305
|
+
attachmentId,
|
|
6306
|
+
{
|
|
6307
|
+
setAttachment: setComponentAttachment,
|
|
6308
|
+
removeAttachment: removeComponentAttachment
|
|
6309
|
+
},
|
|
6310
|
+
{
|
|
6311
|
+
selectAttachment: selectComponentAttachment
|
|
6312
|
+
}
|
|
6313
|
+
);
|
|
6314
|
+
}
|
|
6315
|
+
async refreshStore() {
|
|
6316
|
+
return this.getAttachments({
|
|
6317
|
+
setAttachments: setComponentAttachments
|
|
6318
|
+
});
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
5891
6321
|
class ComponentTypeService extends BaseApiService {
|
|
5892
6322
|
add(componentType) {
|
|
5893
6323
|
const offlineComponentType = offline(componentType);
|
|
@@ -5960,6 +6390,53 @@ class ComponentTypeService extends BaseApiService {
|
|
|
5960
6390
|
store.dispatch(setComponentTypes(result));
|
|
5961
6391
|
}
|
|
5962
6392
|
}
|
|
6393
|
+
class ComponentTypeAttachmentService extends BaseAttachmentService {
|
|
6394
|
+
constructor() {
|
|
6395
|
+
super(...arguments);
|
|
6396
|
+
__publicField(this, "attachmentModel", AttachmentModel.ComponentType);
|
|
6397
|
+
}
|
|
6398
|
+
buildOfflineAttachment(data) {
|
|
6399
|
+
return offline({
|
|
6400
|
+
file: URL.createObjectURL(data.file),
|
|
6401
|
+
file_sha1: data.sha1,
|
|
6402
|
+
created_by: data.createdBy,
|
|
6403
|
+
file_name: data.file.name,
|
|
6404
|
+
file_type: data.file.type,
|
|
6405
|
+
submitted_at: data.submittedAt,
|
|
6406
|
+
description: data.description,
|
|
6407
|
+
component_type: data.modelId
|
|
6408
|
+
});
|
|
6409
|
+
}
|
|
6410
|
+
async attachFilesToComponentType(files, componentTypeId) {
|
|
6411
|
+
return this.attachFiles(
|
|
6412
|
+
files,
|
|
6413
|
+
componentTypeId,
|
|
6414
|
+
this.buildOfflineAttachment.bind(this),
|
|
6415
|
+
{
|
|
6416
|
+
addAttachments: addComponentTypeAttachments,
|
|
6417
|
+
updateAttachments: updateComponentTypeAttachments,
|
|
6418
|
+
removeAttachments: removeComponentTypeAttachments
|
|
6419
|
+
}
|
|
6420
|
+
);
|
|
6421
|
+
}
|
|
6422
|
+
deleteComponentTypeAttachment(attachmentId) {
|
|
6423
|
+
return this.deleteAttachment(
|
|
6424
|
+
attachmentId,
|
|
6425
|
+
{
|
|
6426
|
+
setAttachment: setComponentTypeAttachment,
|
|
6427
|
+
removeAttachment: removeComponentTypeAttachment
|
|
6428
|
+
},
|
|
6429
|
+
{
|
|
6430
|
+
selectAttachment: selectComponentTypeAttachment
|
|
6431
|
+
}
|
|
6432
|
+
);
|
|
6433
|
+
}
|
|
6434
|
+
async refreshStore() {
|
|
6435
|
+
return this.getAttachments({
|
|
6436
|
+
setAttachments: setComponentTypeAttachments
|
|
6437
|
+
});
|
|
6438
|
+
}
|
|
6439
|
+
}
|
|
5963
6440
|
class IssueCommentService extends BaseApiService {
|
|
5964
6441
|
// Omit author and submitted_at since these will always be set internally
|
|
5965
6442
|
add(comment) {
|
|
@@ -6056,6 +6533,48 @@ class IssueUpdateService extends BaseApiService {
|
|
|
6056
6533
|
store.dispatch(setIssueUpdates(filteredResult));
|
|
6057
6534
|
}
|
|
6058
6535
|
}
|
|
6536
|
+
class IssueAttachmentService extends BaseAttachmentService {
|
|
6537
|
+
constructor() {
|
|
6538
|
+
super(...arguments);
|
|
6539
|
+
__publicField(this, "attachmentModel", AttachmentModel.Issue);
|
|
6540
|
+
}
|
|
6541
|
+
buildOfflineAttachment(data) {
|
|
6542
|
+
return offline({
|
|
6543
|
+
file: URL.createObjectURL(data.file),
|
|
6544
|
+
file_sha1: data.sha1,
|
|
6545
|
+
created_by: data.createdBy,
|
|
6546
|
+
file_name: data.file.name,
|
|
6547
|
+
file_type: data.file.type,
|
|
6548
|
+
submitted_at: data.submittedAt,
|
|
6549
|
+
description: data.description,
|
|
6550
|
+
issue: data.modelId
|
|
6551
|
+
});
|
|
6552
|
+
}
|
|
6553
|
+
async attachFilesToIssue(files, issueId) {
|
|
6554
|
+
return this.attachFiles(files, issueId, this.buildOfflineAttachment.bind(this), {
|
|
6555
|
+
addAttachments: addIssueAttachments,
|
|
6556
|
+
updateAttachments: updateIssueAttachments,
|
|
6557
|
+
removeAttachments: removeIssueAttachments
|
|
6558
|
+
});
|
|
6559
|
+
}
|
|
6560
|
+
deleteIssueAttachment(attachmentId) {
|
|
6561
|
+
return this.deleteAttachment(
|
|
6562
|
+
attachmentId,
|
|
6563
|
+
{
|
|
6564
|
+
setAttachment: setIssueAttachment,
|
|
6565
|
+
removeAttachment: removeIssueAttachment
|
|
6566
|
+
},
|
|
6567
|
+
{
|
|
6568
|
+
selectAttachment: selectIssueAttachment
|
|
6569
|
+
}
|
|
6570
|
+
);
|
|
6571
|
+
}
|
|
6572
|
+
async refreshStore() {
|
|
6573
|
+
return this.getAttachments({
|
|
6574
|
+
setAttachments: setIssueAttachments
|
|
6575
|
+
});
|
|
6576
|
+
}
|
|
6577
|
+
}
|
|
6059
6578
|
class IssueService extends BaseApiService {
|
|
6060
6579
|
// Basic CRUD functions
|
|
6061
6580
|
// TODO: Once all models are represented in `Created<TModel>`, use `Created` in `OptimisticModelResult`, so we don't
|
|
@@ -6401,6 +6920,7 @@ class MainService extends BaseApiService {
|
|
|
6401
6920
|
const usersResult = await usersResultPromise;
|
|
6402
6921
|
await projectAccessRefreshPromise;
|
|
6403
6922
|
store.dispatch(addUsers(usersResult));
|
|
6923
|
+
void this.client.projectAttachments.refreshStore();
|
|
6404
6924
|
}
|
|
6405
6925
|
let currentWorkspaceId;
|
|
6406
6926
|
const oldWorkspaceId = this.client.store.getState().workspaceReducer.activeWorkspaceId;
|
|
@@ -6413,38 +6933,30 @@ class MainService extends BaseApiService {
|
|
|
6413
6933
|
store.dispatch(setActiveWorkspaceId(currentWorkspaceId));
|
|
6414
6934
|
void this.client.categories.refreshStore().then(() => {
|
|
6415
6935
|
void this.client.issues.refreshStore().then(() => {
|
|
6936
|
+
void this.client.issueAttachments.refreshStore().then();
|
|
6416
6937
|
void this.client.issueComments.refreshStore().then();
|
|
6938
|
+
void this.client.issueUpdates.refreshStore().then();
|
|
6417
6939
|
});
|
|
6418
6940
|
});
|
|
6419
6941
|
void this.client.projectFiles.refreshStore().then();
|
|
6420
6942
|
void this.client.componentTypes.refreshStore().then(() => {
|
|
6421
|
-
void this.client.
|
|
6422
|
-
void this.client.
|
|
6943
|
+
void this.client.componentTypeAttachments.refreshStore().then(() => {
|
|
6944
|
+
void this.client.componentStages.refreshStore().then(() => {
|
|
6945
|
+
void this.client.components.refreshStore(overwrite).then(() => {
|
|
6946
|
+
void this.client.componentAttachments.refreshStore().then();
|
|
6947
|
+
});
|
|
6948
|
+
});
|
|
6949
|
+
void this.client.componentStageCompletions.refreshStore().then();
|
|
6423
6950
|
});
|
|
6424
|
-
void this.client.componentStageCompletions.refreshStore().then();
|
|
6425
6951
|
});
|
|
6426
6952
|
void this.client.userForms.refreshStore().then(() => {
|
|
6427
6953
|
void this.client.userFormSubmissions.refreshStore().then();
|
|
6428
6954
|
});
|
|
6429
6955
|
}
|
|
6430
6956
|
if (currentProjectId) {
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
const {
|
|
6434
|
-
issue_attachments,
|
|
6435
|
-
component_type_attachments,
|
|
6436
|
-
component_attachments,
|
|
6437
|
-
project_attachments,
|
|
6438
|
-
document_attachments
|
|
6439
|
-
} = result;
|
|
6440
|
-
store.dispatch(setIssueAttachments(issue_attachments));
|
|
6441
|
-
store.dispatch(setComponentAttachments(component_attachments));
|
|
6442
|
-
store.dispatch(setComponentTypeAttachments(component_type_attachments));
|
|
6443
|
-
store.dispatch(setProjectAttachments(project_attachments));
|
|
6444
|
-
store.dispatch(setDocumentAttachments(document_attachments));
|
|
6957
|
+
void this.client.documents.refreshStore().then(() => {
|
|
6958
|
+
void this.client.documentAttachments.refreshStore().then();
|
|
6445
6959
|
});
|
|
6446
|
-
void this.client.documents.refreshStore();
|
|
6447
|
-
void this.client.issueUpdates.refreshStore();
|
|
6448
6960
|
}
|
|
6449
6961
|
store.dispatch(setIsFetchingInitialData(false));
|
|
6450
6962
|
if (overwrite) {
|
|
@@ -6608,6 +7120,48 @@ class ProjectFileService extends BaseApiService {
|
|
|
6608
7120
|
});
|
|
6609
7121
|
}
|
|
6610
7122
|
}
|
|
7123
|
+
class ProjectAttachmentService extends BaseAttachmentService {
|
|
7124
|
+
constructor() {
|
|
7125
|
+
super(...arguments);
|
|
7126
|
+
__publicField(this, "attachmentModel", AttachmentModel.Project);
|
|
7127
|
+
}
|
|
7128
|
+
buildOfflineAttachment(data) {
|
|
7129
|
+
return offline({
|
|
7130
|
+
file: URL.createObjectURL(data.file),
|
|
7131
|
+
file_sha1: data.sha1,
|
|
7132
|
+
created_by: data.createdBy,
|
|
7133
|
+
file_name: data.file.name,
|
|
7134
|
+
file_type: data.file.type,
|
|
7135
|
+
submitted_at: data.submittedAt,
|
|
7136
|
+
description: data.description,
|
|
7137
|
+
project: data.modelId
|
|
7138
|
+
});
|
|
7139
|
+
}
|
|
7140
|
+
async attachFilesToProject(files, projectId) {
|
|
7141
|
+
return this.attachFiles(files, projectId, this.buildOfflineAttachment.bind(this), {
|
|
7142
|
+
addAttachments: addProjectAttachments,
|
|
7143
|
+
updateAttachments: updateProjectAttachments,
|
|
7144
|
+
removeAttachments: removeProjectAttachments
|
|
7145
|
+
});
|
|
7146
|
+
}
|
|
7147
|
+
deleteProjectAttachment(attachmentId) {
|
|
7148
|
+
return this.deleteAttachment(
|
|
7149
|
+
attachmentId,
|
|
7150
|
+
{
|
|
7151
|
+
setAttachment: setProjectAttachment,
|
|
7152
|
+
removeAttachment: removeProjectAttachment
|
|
7153
|
+
},
|
|
7154
|
+
{
|
|
7155
|
+
selectAttachment: selectProjectAttachment
|
|
7156
|
+
}
|
|
7157
|
+
);
|
|
7158
|
+
}
|
|
7159
|
+
async refreshStore() {
|
|
7160
|
+
return this.getAttachments({
|
|
7161
|
+
setAttachments: setProjectAttachments
|
|
7162
|
+
});
|
|
7163
|
+
}
|
|
7164
|
+
}
|
|
6611
7165
|
class ProjectService extends BaseApiService {
|
|
6612
7166
|
/**
|
|
6613
7167
|
* Creates a new project. Due to the nature of project creation,
|
|
@@ -6809,7 +7363,7 @@ class UserFormService extends BaseApiService {
|
|
|
6809
7363
|
...revisionAttachmentPayload,
|
|
6810
7364
|
file: URL.createObjectURL(image)
|
|
6811
7365
|
};
|
|
6812
|
-
store.dispatch(
|
|
7366
|
+
store.dispatch(addFormRevisionAttachment(offlinePayload));
|
|
6813
7367
|
return attach;
|
|
6814
7368
|
});
|
|
6815
7369
|
});
|
|
@@ -6824,13 +7378,14 @@ class UserFormService extends BaseApiService {
|
|
|
6824
7378
|
};
|
|
6825
7379
|
const currentUser = state.userReducer.currentUser;
|
|
6826
7380
|
const activeWorkspaceId = state.workspaceReducer.activeWorkspaceId;
|
|
7381
|
+
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6827
7382
|
const offlineFormPayload = offline({});
|
|
6828
|
-
const offlineRevisionPayload = offline(initialRevision);
|
|
7383
|
+
const offlineRevisionPayload = offline({ ...initialRevision, submitted_at: submittedAt });
|
|
6829
7384
|
const retForm = {
|
|
6830
7385
|
...offlineFormPayload,
|
|
6831
7386
|
index_workspace: activeWorkspaceId,
|
|
6832
7387
|
favorite: true,
|
|
6833
|
-
submitted_at:
|
|
7388
|
+
submitted_at: submittedAt,
|
|
6834
7389
|
created_by: currentUser.id,
|
|
6835
7390
|
...componentTypeId && { component_type: componentTypeId },
|
|
6836
7391
|
...ownerAttrs
|
|
@@ -6841,11 +7396,11 @@ class UserFormService extends BaseApiService {
|
|
|
6841
7396
|
created_by: currentUser.id,
|
|
6842
7397
|
form: retForm.offline_id,
|
|
6843
7398
|
revision: 0,
|
|
6844
|
-
submitted_at:
|
|
7399
|
+
submitted_at: submittedAt
|
|
6845
7400
|
};
|
|
6846
7401
|
const { store } = this.client;
|
|
6847
|
-
store.dispatch(
|
|
6848
|
-
store.dispatch(
|
|
7402
|
+
store.dispatch(addForm(retForm));
|
|
7403
|
+
store.dispatch(addFormRevision(retRevision));
|
|
6849
7404
|
const formPromise = this.enqueueRequest({
|
|
6850
7405
|
description: "Create form",
|
|
6851
7406
|
method: HttpMethod.POST,
|
|
@@ -6863,8 +7418,8 @@ class UserFormService extends BaseApiService {
|
|
|
6863
7418
|
});
|
|
6864
7419
|
const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
|
|
6865
7420
|
void formPromise.catch((e) => {
|
|
6866
|
-
store.dispatch(
|
|
6867
|
-
store.dispatch(
|
|
7421
|
+
store.dispatch(deleteForm(retForm.offline_id));
|
|
7422
|
+
store.dispatch(deleteFormRevision(retRevision.offline_id));
|
|
6868
7423
|
throw e;
|
|
6869
7424
|
});
|
|
6870
7425
|
const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
|
|
@@ -6907,7 +7462,7 @@ class UserFormService extends BaseApiService {
|
|
|
6907
7462
|
form: formId2,
|
|
6908
7463
|
submitted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
6909
7464
|
};
|
|
6910
|
-
store.dispatch(
|
|
7465
|
+
store.dispatch(addFormRevision(fullRevision));
|
|
6911
7466
|
const promise = this.enqueueRequest({
|
|
6912
7467
|
description: "Create form revision",
|
|
6913
7468
|
method: HttpMethod.PATCH,
|
|
@@ -6921,9 +7476,9 @@ class UserFormService extends BaseApiService {
|
|
|
6921
7476
|
});
|
|
6922
7477
|
const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
|
|
6923
7478
|
void promise.then((result) => {
|
|
6924
|
-
store.dispatch(
|
|
7479
|
+
store.dispatch(setFormRevision(result));
|
|
6925
7480
|
}).catch(() => {
|
|
6926
|
-
store.dispatch(
|
|
7481
|
+
store.dispatch(deleteFormRevision(fullRevision.offline_id));
|
|
6927
7482
|
});
|
|
6928
7483
|
const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
|
|
6929
7484
|
return [fullRevision, settledPromise];
|
|
@@ -6965,19 +7520,19 @@ class UserFormService extends BaseApiService {
|
|
|
6965
7520
|
async delete(formId2) {
|
|
6966
7521
|
const { store } = this.client;
|
|
6967
7522
|
const state = store.getState();
|
|
6968
|
-
const userForm =
|
|
7523
|
+
const userForm = selectForm(formId2)(state);
|
|
6969
7524
|
if (!userForm) {
|
|
6970
7525
|
throw new Error("Expected userForm to exist");
|
|
6971
7526
|
}
|
|
6972
|
-
const userFormSubmissions =
|
|
7527
|
+
const userFormSubmissions = selectFormSubmissionsOfForm(formId2)(state);
|
|
6973
7528
|
if (userFormSubmissions && userFormSubmissions.length > 0) {
|
|
6974
|
-
store.dispatch(
|
|
7529
|
+
store.dispatch(deleteFormSubmissions(userFormSubmissions.map(({ offline_id }) => offline_id)));
|
|
6975
7530
|
}
|
|
6976
|
-
const userFormRevisions =
|
|
7531
|
+
const userFormRevisions = selectFormRevisionsOfForm(formId2)(state);
|
|
6977
7532
|
if (userFormRevisions && userFormRevisions.length > 0) {
|
|
6978
|
-
store.dispatch(
|
|
7533
|
+
store.dispatch(deleteFormRevisions(userFormRevisions.map(({ offline_id }) => offline_id)));
|
|
6979
7534
|
}
|
|
6980
|
-
store.dispatch(
|
|
7535
|
+
store.dispatch(deleteForm(formId2));
|
|
6981
7536
|
try {
|
|
6982
7537
|
return await this.enqueueRequest({
|
|
6983
7538
|
description: "Delete form",
|
|
@@ -6987,12 +7542,12 @@ class UserFormService extends BaseApiService {
|
|
|
6987
7542
|
blocks: []
|
|
6988
7543
|
});
|
|
6989
7544
|
} catch (e) {
|
|
6990
|
-
store.dispatch(
|
|
7545
|
+
store.dispatch(addForm(userForm));
|
|
6991
7546
|
if (userFormRevisions && userFormRevisions.length > 0) {
|
|
6992
|
-
store.dispatch(
|
|
7547
|
+
store.dispatch(addFormRevisions(userFormRevisions));
|
|
6993
7548
|
}
|
|
6994
7549
|
if (userFormSubmissions && userFormSubmissions.length > 0) {
|
|
6995
|
-
store.dispatch(
|
|
7550
|
+
store.dispatch(addFormSubmissions(userFormSubmissions));
|
|
6996
7551
|
}
|
|
6997
7552
|
throw e;
|
|
6998
7553
|
}
|
|
@@ -7006,16 +7561,15 @@ class UserFormService extends BaseApiService {
|
|
|
7006
7561
|
blockers: [],
|
|
7007
7562
|
blocks: []
|
|
7008
7563
|
});
|
|
7009
|
-
store.dispatch(
|
|
7010
|
-
store.dispatch(
|
|
7011
|
-
store.dispatch(
|
|
7564
|
+
store.dispatch(setForms(Object.values(result.forms)));
|
|
7565
|
+
store.dispatch(setFormRevisions(Object.values(result.revisions)));
|
|
7566
|
+
store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
|
|
7012
7567
|
}
|
|
7013
7568
|
}
|
|
7014
7569
|
const isArrayOfFiles = (value) => {
|
|
7015
7570
|
return Array.isArray(value) && value[0] instanceof File;
|
|
7016
7571
|
};
|
|
7017
|
-
const separateFilesFromValues = (
|
|
7018
|
-
const { values } = payload;
|
|
7572
|
+
const separateFilesFromValues = (values) => {
|
|
7019
7573
|
const files = {};
|
|
7020
7574
|
const newValues = {};
|
|
7021
7575
|
for (const key in values) {
|
|
@@ -7030,17 +7584,13 @@ const separateFilesFromValues = (payload) => {
|
|
|
7030
7584
|
newValues[key] = value;
|
|
7031
7585
|
}
|
|
7032
7586
|
}
|
|
7033
|
-
|
|
7034
|
-
...payload,
|
|
7035
|
-
values: newValues
|
|
7036
|
-
};
|
|
7037
|
-
return { payloadWithoutFiles, files };
|
|
7587
|
+
return { values: newValues, files };
|
|
7038
7588
|
};
|
|
7039
7589
|
class UserFormSubmissionService extends BaseApiService {
|
|
7040
7590
|
constructor() {
|
|
7041
7591
|
super(...arguments);
|
|
7042
7592
|
// Attach files to submission, after uploading them to S3
|
|
7043
|
-
__publicField(this, "getAttachFilesPromises", (files,
|
|
7593
|
+
__publicField(this, "getAttachFilesPromises", (files, submission) => {
|
|
7044
7594
|
const { store } = this.client;
|
|
7045
7595
|
return Object.entries(files).map(async ([key, fileArray]) => {
|
|
7046
7596
|
const attachResults = [];
|
|
@@ -7050,24 +7600,27 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7050
7600
|
const [fileProps] = await this.client.files.uploadFileToS3(sha1);
|
|
7051
7601
|
const submissionAttachmentPayload = offline({
|
|
7052
7602
|
...fileProps,
|
|
7053
|
-
submission:
|
|
7603
|
+
submission: submission.offline_id,
|
|
7054
7604
|
field_identifier: key
|
|
7055
7605
|
});
|
|
7056
7606
|
const attach = await this.enqueueRequest({
|
|
7057
7607
|
description: "Attach file to form submission",
|
|
7058
7608
|
method: HttpMethod.POST,
|
|
7059
|
-
url: `/forms/submission/${
|
|
7609
|
+
url: `/forms/submission/${submission.offline_id}/attachments/`,
|
|
7060
7610
|
payload: submissionAttachmentPayload,
|
|
7061
|
-
blockers: [
|
|
7062
|
-
|
|
7063
|
-
|
|
7611
|
+
blockers: [
|
|
7612
|
+
submission.component,
|
|
7613
|
+
submission.component_stage,
|
|
7614
|
+
submission.issue,
|
|
7615
|
+
submission.form_revision
|
|
7616
|
+
].filter((x) => x !== void 0),
|
|
7064
7617
|
blocks: [submissionAttachmentPayload.offline_id]
|
|
7065
7618
|
});
|
|
7066
7619
|
const offlinePayload = {
|
|
7067
7620
|
...submissionAttachmentPayload,
|
|
7068
7621
|
file: URL.createObjectURL(file)
|
|
7069
7622
|
};
|
|
7070
|
-
store.dispatch(
|
|
7623
|
+
store.dispatch(addFormSubmissionAttachment(offlinePayload));
|
|
7071
7624
|
attachResults.push(attach);
|
|
7072
7625
|
}
|
|
7073
7626
|
return attachResults;
|
|
@@ -7081,71 +7634,168 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7081
7634
|
if (!activeProjectId) {
|
|
7082
7635
|
throw new Error("Expected an active project");
|
|
7083
7636
|
}
|
|
7084
|
-
const {
|
|
7637
|
+
const { values, files } = separateFilesFromValues(payload.values);
|
|
7638
|
+
const offlineSubmission = {
|
|
7639
|
+
...payload,
|
|
7640
|
+
values,
|
|
7641
|
+
created_by: state.userReducer.currentUser.id,
|
|
7642
|
+
submitted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
7643
|
+
};
|
|
7085
7644
|
const promise = this.enqueueRequest({
|
|
7086
7645
|
description: "Respond to form",
|
|
7087
7646
|
method: HttpMethod.POST,
|
|
7088
7647
|
url: `/forms/revisions/${payload.form_revision}/respond/`,
|
|
7089
|
-
payload: { ...
|
|
7648
|
+
payload: { ...offlineSubmission, project: activeProjectId },
|
|
7090
7649
|
blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
|
|
7091
7650
|
(x) => x !== void 0
|
|
7092
7651
|
),
|
|
7093
7652
|
blocks: [payload.offline_id]
|
|
7094
7653
|
});
|
|
7095
|
-
const attachFilesPromises = this.getAttachFilesPromises(files,
|
|
7096
|
-
|
|
7097
|
-
const fullOfflineResult = {
|
|
7098
|
-
...payload,
|
|
7099
|
-
created_by: state.userReducer.currentUser.id,
|
|
7100
|
-
created_at: now,
|
|
7101
|
-
updated_at: now
|
|
7102
|
-
};
|
|
7103
|
-
const offlineResultWithoutFiles = {
|
|
7104
|
-
...fullOfflineResult,
|
|
7105
|
-
...payloadWithoutFiles
|
|
7106
|
-
};
|
|
7107
|
-
store.dispatch(updateOrCreateUserFormSubmission(offlineResultWithoutFiles));
|
|
7654
|
+
const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
|
|
7655
|
+
store.dispatch(addFormSubmission(offlineSubmission));
|
|
7108
7656
|
void promise.then((result) => {
|
|
7109
7657
|
store.dispatch(addActiveProjectFormSubmissionsCount(1));
|
|
7110
|
-
store.dispatch(
|
|
7658
|
+
store.dispatch(setFormSubmission(result));
|
|
7111
7659
|
return result;
|
|
7112
7660
|
}).catch(() => {
|
|
7113
|
-
store.dispatch(
|
|
7661
|
+
store.dispatch(deleteFormSubmission(payload.offline_id));
|
|
7114
7662
|
store.dispatch(addActiveProjectFormSubmissionsCount(-1));
|
|
7115
7663
|
});
|
|
7116
7664
|
const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
|
|
7117
|
-
return [
|
|
7665
|
+
return [offlineSubmission, settledPromise];
|
|
7118
7666
|
}
|
|
7119
|
-
|
|
7667
|
+
// Note currently the bulkAdd method is specific to form submissions for components
|
|
7668
|
+
// TODO: adapt the support bulk adding to any model type
|
|
7669
|
+
async bulkAdd(args) {
|
|
7670
|
+
const { formRevision, values: argsValues, componentOfflineIds } = args;
|
|
7120
7671
|
const { store } = this.client;
|
|
7121
|
-
const
|
|
7122
|
-
|
|
7123
|
-
|
|
7672
|
+
const offlineSubmissions = [];
|
|
7673
|
+
const offlineAttachments = [];
|
|
7674
|
+
const submissionOfflineIds = [];
|
|
7675
|
+
const submissionsPayload = [];
|
|
7676
|
+
const attachmentsPayload = [];
|
|
7677
|
+
const { values, files } = separateFilesFromValues(argsValues);
|
|
7678
|
+
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7679
|
+
const createdBy = store.getState().userReducer.currentUser.id;
|
|
7680
|
+
for (const component_id of componentOfflineIds) {
|
|
7681
|
+
const submission = offline({
|
|
7682
|
+
form_revision: formRevision,
|
|
7683
|
+
values,
|
|
7684
|
+
created_by: createdBy,
|
|
7685
|
+
submitted_at: submittedAt,
|
|
7686
|
+
component: component_id
|
|
7687
|
+
});
|
|
7688
|
+
submissionOfflineIds.push(submission.offline_id);
|
|
7689
|
+
submissionsPayload.push({ offline_id: submission.offline_id, component_id });
|
|
7690
|
+
offlineSubmissions.push(submission);
|
|
7691
|
+
for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
|
|
7692
|
+
for (const file of fileArray) {
|
|
7693
|
+
const sha1 = await hashFile(file);
|
|
7694
|
+
await this.client.files.addCache(file, sha1);
|
|
7695
|
+
const offlineAttachment = offline({
|
|
7696
|
+
file_name: file.name,
|
|
7697
|
+
file_sha1: sha1,
|
|
7698
|
+
file: URL.createObjectURL(file),
|
|
7699
|
+
submission: submission.offline_id,
|
|
7700
|
+
field_identifier: fieldIdentifier
|
|
7701
|
+
});
|
|
7702
|
+
offlineAttachments.push(offlineAttachment);
|
|
7703
|
+
attachmentsPayload.push({
|
|
7704
|
+
offline_id: offlineAttachment.offline_id,
|
|
7705
|
+
submission_id: submission.offline_id,
|
|
7706
|
+
sha1,
|
|
7707
|
+
name: file.name,
|
|
7708
|
+
field_identifier: fieldIdentifier
|
|
7709
|
+
});
|
|
7710
|
+
}
|
|
7711
|
+
}
|
|
7712
|
+
}
|
|
7713
|
+
const filesRecord = {};
|
|
7714
|
+
for (const file of Object.values(files).flat()) {
|
|
7715
|
+
const sha1 = await hashFile(file);
|
|
7716
|
+
filesRecord[sha1] = {
|
|
7717
|
+
sha1,
|
|
7718
|
+
extension: file.name.split(".").pop() || "",
|
|
7719
|
+
file_type: file.type,
|
|
7720
|
+
size: file.size
|
|
7721
|
+
};
|
|
7124
7722
|
}
|
|
7723
|
+
store.dispatch(addFormSubmissions(offlineSubmissions));
|
|
7724
|
+
store.dispatch(addFormSubmissionAttachments(offlineAttachments));
|
|
7725
|
+
const promise = this.enqueueRequest({
|
|
7726
|
+
description: "Bulk add form submissions",
|
|
7727
|
+
method: HttpMethod.POST,
|
|
7728
|
+
url: `/forms/revisions/${formRevision}/bulk-respond/`,
|
|
7729
|
+
payload: {
|
|
7730
|
+
form_data: values,
|
|
7731
|
+
submitted_at: submittedAt,
|
|
7732
|
+
submissions: submissionsPayload,
|
|
7733
|
+
attachments: attachmentsPayload,
|
|
7734
|
+
files: Object.values(filesRecord)
|
|
7735
|
+
},
|
|
7736
|
+
blockers: componentOfflineIds,
|
|
7737
|
+
blocks: submissionOfflineIds
|
|
7738
|
+
});
|
|
7739
|
+
promise.then(({ submissions, attachments, presigned_urls }) => {
|
|
7740
|
+
store.dispatch(updateFormSubmissions(submissions));
|
|
7741
|
+
store.dispatch(updateFormSubmissionAttachments(attachments));
|
|
7742
|
+
for (const [sha1, presigned_url] of Object.entries(presigned_urls)) {
|
|
7743
|
+
const file = filesRecord[sha1];
|
|
7744
|
+
if (!file)
|
|
7745
|
+
continue;
|
|
7746
|
+
void this.enqueueRequest({
|
|
7747
|
+
url: presigned_url.url,
|
|
7748
|
+
description: "Upload file",
|
|
7749
|
+
method: HttpMethod.POST,
|
|
7750
|
+
isExternalUrl: true,
|
|
7751
|
+
isAuthNeeded: false,
|
|
7752
|
+
attachmentHash: sha1,
|
|
7753
|
+
blockers: [`s3-${file.sha1}.${file.extension}`],
|
|
7754
|
+
blocks: [sha1],
|
|
7755
|
+
s3url: presigned_url
|
|
7756
|
+
});
|
|
7757
|
+
}
|
|
7758
|
+
}).catch(() => {
|
|
7759
|
+
store.dispatch(deleteFormSubmissions(submissionOfflineIds));
|
|
7760
|
+
store.dispatch(deleteFormSubmissionAttachments(offlineAttachments.map((x) => x.offline_id)));
|
|
7761
|
+
});
|
|
7762
|
+
return [offlineSubmissions, promise.then(({ submissions }) => submissions)];
|
|
7763
|
+
}
|
|
7764
|
+
update(submission) {
|
|
7765
|
+
const { store } = this.client;
|
|
7766
|
+
const { values, files } = separateFilesFromValues(submission.values);
|
|
7125
7767
|
const attachFilesPromises = this.getAttachFilesPromises(files, submission);
|
|
7126
|
-
const
|
|
7127
|
-
...
|
|
7128
|
-
|
|
7768
|
+
const offlineSubmission = {
|
|
7769
|
+
...submission,
|
|
7770
|
+
values
|
|
7129
7771
|
};
|
|
7130
|
-
store.
|
|
7772
|
+
const submissionToBeUpdated = store.getState().formSubmissionReducer.formSubmissions[submission.offline_id];
|
|
7773
|
+
store.dispatch(updateFormSubmission(offlineSubmission));
|
|
7131
7774
|
const promise = this.enqueueRequest({
|
|
7132
7775
|
description: "Patch form submission",
|
|
7133
7776
|
method: HttpMethod.PATCH,
|
|
7134
7777
|
url: `/forms/submissions/${submission.offline_id}/`,
|
|
7135
|
-
payload:
|
|
7136
|
-
blockers: [
|
|
7778
|
+
payload: offlineSubmission,
|
|
7779
|
+
blockers: [offlineSubmission.issue, offlineSubmission.component, offlineSubmission.component_stage].filter(
|
|
7137
7780
|
(x) => x !== void 0
|
|
7138
7781
|
),
|
|
7139
|
-
blocks: [
|
|
7782
|
+
blocks: [offlineSubmission.offline_id]
|
|
7783
|
+
});
|
|
7784
|
+
promise.then((createdSubmission) => {
|
|
7785
|
+
store.dispatch(setFormSubmission(createdSubmission));
|
|
7786
|
+
}).catch(() => {
|
|
7787
|
+
store.dispatch(setFormSubmission(submissionToBeUpdated));
|
|
7140
7788
|
});
|
|
7141
|
-
return Promise.all([promise, ...attachFilesPromises]).then(() => promise);
|
|
7789
|
+
return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
|
|
7142
7790
|
}
|
|
7143
7791
|
async delete(submissionId) {
|
|
7144
7792
|
const { store } = this.client;
|
|
7145
7793
|
const state = store.getState();
|
|
7146
|
-
const submission = state.
|
|
7147
|
-
|
|
7794
|
+
const submission = state.formSubmissionReducer.formSubmissions[submissionId];
|
|
7795
|
+
const submissionAttachments = selectAttachmentsOfFormSubmission(submissionId)(state);
|
|
7796
|
+
store.dispatch(deleteFormSubmission(submissionId));
|
|
7148
7797
|
store.dispatch(addActiveProjectFormSubmissionsCount(-1));
|
|
7798
|
+
store.dispatch(deleteFormSubmissionAttachments(submissionAttachments.map((x) => x.offline_id)));
|
|
7149
7799
|
try {
|
|
7150
7800
|
return await this.enqueueRequest({
|
|
7151
7801
|
description: "Delete user form submissions",
|
|
@@ -7155,10 +7805,9 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7155
7805
|
blocks: []
|
|
7156
7806
|
});
|
|
7157
7807
|
} catch (e) {
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
}
|
|
7808
|
+
store.dispatch(addActiveProjectFormSubmissionsCount(1));
|
|
7809
|
+
store.dispatch(addFormSubmission(submission));
|
|
7810
|
+
store.dispatch(addFormSubmissionAttachments(submissionAttachments));
|
|
7162
7811
|
throw e;
|
|
7163
7812
|
}
|
|
7164
7813
|
}
|
|
@@ -7172,7 +7821,7 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7172
7821
|
blockers: [],
|
|
7173
7822
|
blocks: []
|
|
7174
7823
|
});
|
|
7175
|
-
store.dispatch(
|
|
7824
|
+
store.dispatch(setFormSubmissions(submissions));
|
|
7176
7825
|
const attachments = await this.enqueueRequest({
|
|
7177
7826
|
description: "Fetch form attachments",
|
|
7178
7827
|
method: HttpMethod.GET,
|
|
@@ -7180,7 +7829,7 @@ class UserFormSubmissionService extends BaseApiService {
|
|
|
7180
7829
|
blockers: [],
|
|
7181
7830
|
blocks: []
|
|
7182
7831
|
});
|
|
7183
|
-
store.dispatch(
|
|
7832
|
+
store.dispatch(setFormSubmissionAttachments(attachments));
|
|
7184
7833
|
}
|
|
7185
7834
|
}
|
|
7186
7835
|
class WorkspaceService extends BaseApiService {
|
|
@@ -7872,6 +8521,48 @@ class DocumentService extends BaseApiService {
|
|
|
7872
8521
|
store.dispatch(setDocuments(result));
|
|
7873
8522
|
}
|
|
7874
8523
|
}
|
|
8524
|
+
class DocumentAttachmentService extends BaseAttachmentService {
|
|
8525
|
+
constructor() {
|
|
8526
|
+
super(...arguments);
|
|
8527
|
+
__publicField(this, "attachmentModel", AttachmentModel.Document);
|
|
8528
|
+
}
|
|
8529
|
+
buildOfflineAttachment(data) {
|
|
8530
|
+
return offline({
|
|
8531
|
+
file: URL.createObjectURL(data.file),
|
|
8532
|
+
file_sha1: data.sha1,
|
|
8533
|
+
created_by: data.createdBy,
|
|
8534
|
+
file_name: data.file.name,
|
|
8535
|
+
file_type: data.file.type,
|
|
8536
|
+
submitted_at: data.submittedAt,
|
|
8537
|
+
description: data.description,
|
|
8538
|
+
document: data.modelId
|
|
8539
|
+
});
|
|
8540
|
+
}
|
|
8541
|
+
async attachFilesToDocument(files, documentId) {
|
|
8542
|
+
return this.attachFiles(files, documentId, this.buildOfflineAttachment.bind(this), {
|
|
8543
|
+
addAttachments: addDocumentAttachments,
|
|
8544
|
+
updateAttachments: updateDocumentAttachments,
|
|
8545
|
+
removeAttachments: removeDocumentAttachments
|
|
8546
|
+
});
|
|
8547
|
+
}
|
|
8548
|
+
deleteDocumentAttachment(attachmentId) {
|
|
8549
|
+
return this.deleteAttachment(
|
|
8550
|
+
attachmentId,
|
|
8551
|
+
{
|
|
8552
|
+
setAttachment: setDocumentAttachment,
|
|
8553
|
+
removeAttachment: removeDocumentAttachment
|
|
8554
|
+
},
|
|
8555
|
+
{
|
|
8556
|
+
selectAttachment: selectDocumentAttachment
|
|
8557
|
+
}
|
|
8558
|
+
);
|
|
8559
|
+
}
|
|
8560
|
+
async refreshStore() {
|
|
8561
|
+
return this.getAttachments({
|
|
8562
|
+
setAttachments: setDocumentAttachments
|
|
8563
|
+
});
|
|
8564
|
+
}
|
|
8565
|
+
}
|
|
7875
8566
|
class AgentService extends BaseApiService {
|
|
7876
8567
|
/**
|
|
7877
8568
|
* Prompt the agent with a message.
|
|
@@ -7919,20 +8610,25 @@ class OvermapSDK {
|
|
|
7919
8610
|
__publicField(this, "issues", new IssueService(this));
|
|
7920
8611
|
__publicField(this, "issueComments", new IssueCommentService(this));
|
|
7921
8612
|
__publicField(this, "issueUpdates", new IssueUpdateService(this));
|
|
8613
|
+
__publicField(this, "issueAttachments", new IssueAttachmentService(this));
|
|
7922
8614
|
__publicField(this, "workspaces", new WorkspaceService(this));
|
|
7923
8615
|
__publicField(this, "main", new MainService(this));
|
|
7924
8616
|
__publicField(this, "components", new ComponentService(this));
|
|
8617
|
+
__publicField(this, "componentAttachments", new ComponentAttachmentService(this));
|
|
7925
8618
|
__publicField(this, "componentTypes", new ComponentTypeService(this));
|
|
8619
|
+
__publicField(this, "componentTypeAttachments", new ComponentTypeAttachmentService(this));
|
|
7926
8620
|
__publicField(this, "componentStages", new ComponentStageService(this));
|
|
7927
8621
|
__publicField(this, "componentStageCompletions", new ComponentStageCompletionService(this));
|
|
7928
8622
|
__publicField(this, "userForms", new UserFormService(this));
|
|
7929
8623
|
__publicField(this, "userFormSubmissions", new UserFormSubmissionService(this));
|
|
7930
8624
|
__publicField(this, "projects", new ProjectService(this));
|
|
7931
8625
|
__publicField(this, "projectFiles", new ProjectFileService(this));
|
|
8626
|
+
__publicField(this, "projectAttachments", new ProjectAttachmentService(this));
|
|
7932
8627
|
__publicField(this, "emailVerification", new EmailVerificationService(this));
|
|
7933
8628
|
__publicField(this, "emailDomains", new EmailDomainsService(this));
|
|
7934
8629
|
__publicField(this, "licenses", new LicenseService(this));
|
|
7935
8630
|
__publicField(this, "documents", new DocumentService(this));
|
|
8631
|
+
__publicField(this, "documentAttachments", new DocumentAttachmentService(this));
|
|
7936
8632
|
this.API_URL = apiUrl;
|
|
7937
8633
|
this.store = store;
|
|
7938
8634
|
}
|
|
@@ -14038,7 +14734,7 @@ const initialFormValues = (fields, values) => {
|
|
|
14038
14734
|
};
|
|
14039
14735
|
const useAttachImagesToFormRevisionFields = (revision) => {
|
|
14040
14736
|
const { sdk } = useSDK();
|
|
14041
|
-
const attachments = useAppSelector(
|
|
14737
|
+
const attachments = useAppSelector(selectAttachmentsOfFormRevision((revision == null ? void 0 : revision.offline_id) ?? ""));
|
|
14042
14738
|
return useMemo(() => {
|
|
14043
14739
|
if (!revision || !attachments)
|
|
14044
14740
|
return revision;
|
|
@@ -14135,7 +14831,7 @@ const FormSubmissionViewer = memo(
|
|
|
14135
14831
|
return formRevisionToSchema(revisionWithImages, { readonly: true });
|
|
14136
14832
|
}, [revisionWithImages]);
|
|
14137
14833
|
const submissionValuesWithAttachments = useMemo(() => {
|
|
14138
|
-
const attachments =
|
|
14834
|
+
const attachments = selectAttachmentsOfFormSubmission(submission.offline_id)(sdk.store.getState()) ?? [];
|
|
14139
14835
|
const downloadedAttachments = {};
|
|
14140
14836
|
for (const attachment of attachments) {
|
|
14141
14837
|
const promise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
|
|
@@ -14185,8 +14881,8 @@ const FormBrowser = memo(
|
|
|
14185
14881
|
}
|
|
14186
14882
|
return ret;
|
|
14187
14883
|
}, [filter, maxResults, ownerFilter]);
|
|
14188
|
-
const userForms = useAppSelector(
|
|
14189
|
-
const userFormMapping = useAppSelector(
|
|
14884
|
+
const userForms = useAppSelector(selectFilteredForms(ownerFilterOptions)) ?? [];
|
|
14885
|
+
const userFormMapping = useAppSelector(selectFormMapping);
|
|
14190
14886
|
const attachableUserForms = userForms.filter((form) => !form.component_type);
|
|
14191
14887
|
const attachableUserFormMapping = Object.values(userFormMapping).filter(
|
|
14192
14888
|
(form) => !form.component_type
|
|
@@ -14219,7 +14915,7 @@ const FormBrowser = memo(
|
|
|
14219
14915
|
const handleChange = useCallback((e) => {
|
|
14220
14916
|
setFilter(e.currentTarget.value);
|
|
14221
14917
|
}, []);
|
|
14222
|
-
const numberOfForms = useAppSelector(
|
|
14918
|
+
const numberOfForms = useAppSelector(selectGeneralFormCount) || 0;
|
|
14223
14919
|
const numberOfHiddenForms = numberOfForms - attachableUserForms.length;
|
|
14224
14920
|
const overflowMessage = attachableUserForms.length == maxResults && numberOfHiddenForms > 0 ? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)` : numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`;
|
|
14225
14921
|
return /* @__PURE__ */ jsxs(Flex$1, { ref, direction: "column", gap: "2", children: [
|
|
@@ -14313,16 +15009,13 @@ const FormSubmissionBrowserEntry = memo((props) => {
|
|
|
14313
15009
|
const { submission, onSubmissionClick, compact, labelType, rowDecorator } = props;
|
|
14314
15010
|
const currentUser = useAppSelector(selectCurrentUser);
|
|
14315
15011
|
const createdBy = useAppSelector(selectUser("created_by" in submission ? submission.created_by : currentUser.id));
|
|
14316
|
-
const dateToUse =
|
|
14317
|
-
const formattedDateTime =
|
|
14318
|
-
hour: "2-digit",
|
|
14319
|
-
minute: "2-digit"
|
|
14320
|
-
}) : getLocalDateString(dateToUse);
|
|
15012
|
+
const dateToUse = submission.submitted_at;
|
|
15013
|
+
const formattedDateTime = getLocalDateString(dateToUse);
|
|
14321
15014
|
const revision = useAppSelector(selectFormRevision(submission.form_revision));
|
|
14322
15015
|
if (!revision) {
|
|
14323
15016
|
throw new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`);
|
|
14324
15017
|
}
|
|
14325
|
-
const latestRevisionNumber = (_a2 = useAppSelector(
|
|
15018
|
+
const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevisionOfForm(revision.form))) == null ? void 0 : _a2.revision;
|
|
14326
15019
|
const creatorProfileSrc = useFileSrc({
|
|
14327
15020
|
file: (createdBy == null ? void 0 : createdBy.profile.file) ?? null,
|
|
14328
15021
|
fileSha1: (createdBy == null ? void 0 : createdBy.profile.file_sha1) ?? null
|
|
@@ -14353,10 +15046,6 @@ const FormSubmissionBrowserEntry = memo((props) => {
|
|
|
14353
15046
|
return row;
|
|
14354
15047
|
});
|
|
14355
15048
|
FormSubmissionBrowserEntry.displayName = "FormSubmissionBrowserEntry";
|
|
14356
|
-
const getCreatedAtOrSubmittedAtDate = (submission) => {
|
|
14357
|
-
const date = "created_at" in submission ? submission.created_at : submission.submitted_at;
|
|
14358
|
-
return new Date(date);
|
|
14359
|
-
};
|
|
14360
15049
|
const FormSubmissionBrowser = memo((props) => {
|
|
14361
15050
|
const {
|
|
14362
15051
|
formId: formId2,
|
|
@@ -14370,10 +15059,10 @@ const FormSubmissionBrowser = memo((props) => {
|
|
|
14370
15059
|
if (!!formId2 === !!propSubmissions) {
|
|
14371
15060
|
throw new Error("Either formId or submissions must be provided, but not both.");
|
|
14372
15061
|
}
|
|
14373
|
-
const submissions = useAppSelector(propSubmissions ? () => propSubmissions :
|
|
15062
|
+
const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectFormSubmissionsOfForm(formId2));
|
|
14374
15063
|
const sortedSubmissions = useMemo(
|
|
14375
15064
|
() => submissions == null ? void 0 : submissions.sort((a, b) => {
|
|
14376
|
-
return
|
|
15065
|
+
return a.submitted_at.localeCompare(b.submitted_at);
|
|
14377
15066
|
}),
|
|
14378
15067
|
[submissions]
|
|
14379
15068
|
);
|
|
@@ -15597,6 +16286,7 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
15597
16286
|
export {
|
|
15598
16287
|
APIError,
|
|
15599
16288
|
AgentService,
|
|
16289
|
+
AttachmentModel,
|
|
15600
16290
|
AttachmentService,
|
|
15601
16291
|
AuthService,
|
|
15602
16292
|
BaseApiService,
|
|
@@ -15608,15 +16298,18 @@ export {
|
|
|
15608
16298
|
ColorPicker,
|
|
15609
16299
|
Colors,
|
|
15610
16300
|
ColorsToString,
|
|
16301
|
+
ComponentAttachmentService,
|
|
15611
16302
|
ComponentService,
|
|
15612
16303
|
ComponentStageColors,
|
|
15613
16304
|
ComponentStageCompletionService,
|
|
15614
16305
|
ComponentStageService,
|
|
16306
|
+
ComponentTypeAttachmentService,
|
|
15615
16307
|
ComponentTypeService,
|
|
15616
16308
|
DEFAULT_ISSUE_PRIORITY,
|
|
15617
16309
|
DEFAULT_ISSUE_STATUS,
|
|
15618
16310
|
DateField,
|
|
15619
16311
|
DateInput,
|
|
16312
|
+
DocumentAttachmentService,
|
|
15620
16313
|
DocumentService,
|
|
15621
16314
|
EmailDomainsService,
|
|
15622
16315
|
EmailVerificationService,
|
|
@@ -15640,6 +16333,7 @@ export {
|
|
|
15640
16333
|
InputWithHelpText,
|
|
15641
16334
|
InputWithLabel,
|
|
15642
16335
|
InputWithLabelAndHelpText,
|
|
16336
|
+
IssueAttachmentService,
|
|
15643
16337
|
IssueCommentService,
|
|
15644
16338
|
IssuePriority,
|
|
15645
16339
|
IssueService,
|
|
@@ -15671,6 +16365,7 @@ export {
|
|
|
15671
16365
|
PatchFormProvider,
|
|
15672
16366
|
ProjectAccessLevel,
|
|
15673
16367
|
ProjectAccessService,
|
|
16368
|
+
ProjectAttachmentService,
|
|
15674
16369
|
ProjectFileService,
|
|
15675
16370
|
ProjectService,
|
|
15676
16371
|
ProjectType,
|
|
@@ -15691,6 +16386,7 @@ export {
|
|
|
15691
16386
|
VerificationCodeType,
|
|
15692
16387
|
WorkspaceService,
|
|
15693
16388
|
YELLOW,
|
|
16389
|
+
_selectLatestFormRevision,
|
|
15694
16390
|
_setLatestRetryTime,
|
|
15695
16391
|
acceptProjectInvite,
|
|
15696
16392
|
addActiveProjectFormSubmissionsCount,
|
|
@@ -15708,6 +16404,16 @@ export {
|
|
|
15708
16404
|
addDocuments,
|
|
15709
16405
|
addEmailDomain,
|
|
15710
16406
|
addFavouriteProjectId,
|
|
16407
|
+
addForm,
|
|
16408
|
+
addFormRevision,
|
|
16409
|
+
addFormRevisionAttachment,
|
|
16410
|
+
addFormRevisionAttachments,
|
|
16411
|
+
addFormRevisions,
|
|
16412
|
+
addFormSubmission,
|
|
16413
|
+
addFormSubmissionAttachment,
|
|
16414
|
+
addFormSubmissionAttachments,
|
|
16415
|
+
addFormSubmissions,
|
|
16416
|
+
addForms,
|
|
15711
16417
|
addIssue,
|
|
15712
16418
|
addIssueAttachment,
|
|
15713
16419
|
addIssueAttachments,
|
|
@@ -15728,13 +16434,6 @@ export {
|
|
|
15728
16434
|
addStageCompletions,
|
|
15729
16435
|
addStages,
|
|
15730
16436
|
addToRecentIssues,
|
|
15731
|
-
addUserForm,
|
|
15732
|
-
addUserFormRevision,
|
|
15733
|
-
addUserFormRevisionAttachment,
|
|
15734
|
-
addUserFormRevisions,
|
|
15735
|
-
addUserFormSubmissionAttachment,
|
|
15736
|
-
addUserFormSubmissions,
|
|
15737
|
-
addUserForms,
|
|
15738
16437
|
addUsers,
|
|
15739
16438
|
addWorkspace,
|
|
15740
16439
|
areArraysEqual,
|
|
@@ -15755,6 +16454,7 @@ export {
|
|
|
15755
16454
|
componentStageSlice,
|
|
15756
16455
|
componentTypeReducer,
|
|
15757
16456
|
componentTypeSlice,
|
|
16457
|
+
constructUploadedFilePayloads,
|
|
15758
16458
|
coordinatesAreEqual,
|
|
15759
16459
|
coordinatesToLiteral,
|
|
15760
16460
|
coordinatesToPointGeometry,
|
|
@@ -15765,12 +16465,16 @@ export {
|
|
|
15765
16465
|
defaultBadgeColor,
|
|
15766
16466
|
defaultStore,
|
|
15767
16467
|
deleteComponentType,
|
|
16468
|
+
deleteForm,
|
|
16469
|
+
deleteFormRevision,
|
|
16470
|
+
deleteFormRevisionAttachment,
|
|
16471
|
+
deleteFormRevisionAttachments,
|
|
16472
|
+
deleteFormRevisions,
|
|
16473
|
+
deleteFormSubmission,
|
|
16474
|
+
deleteFormSubmissionAttachment,
|
|
16475
|
+
deleteFormSubmissionAttachments,
|
|
16476
|
+
deleteFormSubmissions,
|
|
15768
16477
|
deleteProject,
|
|
15769
|
-
deleteUserForm,
|
|
15770
|
-
deleteUserFormRevision,
|
|
15771
|
-
deleteUserFormRevisions,
|
|
15772
|
-
deleteUserFormSubmission,
|
|
15773
|
-
deleteUserFormSubmissions,
|
|
15774
16478
|
dequeue,
|
|
15775
16479
|
deserialize,
|
|
15776
16480
|
deserializeField,
|
|
@@ -15799,7 +16503,13 @@ export {
|
|
|
15799
16503
|
fileSlice,
|
|
15800
16504
|
fileToBlob,
|
|
15801
16505
|
flipCoordinates,
|
|
16506
|
+
formReducer,
|
|
16507
|
+
formRevisionReducer,
|
|
15802
16508
|
formRevisionToSchema,
|
|
16509
|
+
formRevisionsSlice,
|
|
16510
|
+
formSlice,
|
|
16511
|
+
formSubmissionReducer,
|
|
16512
|
+
formSubmissionSlice,
|
|
15803
16513
|
index as forms,
|
|
15804
16514
|
fullComponentMarkerSize,
|
|
15805
16515
|
generateBadgeColors,
|
|
@@ -15875,6 +16585,7 @@ export {
|
|
|
15875
16585
|
removeFavouriteProjectId,
|
|
15876
16586
|
removeIssue,
|
|
15877
16587
|
removeIssueAttachment,
|
|
16588
|
+
removeIssueAttachments,
|
|
15878
16589
|
removeIssueComment,
|
|
15879
16590
|
removeIssueComments,
|
|
15880
16591
|
removeIssueUpdate,
|
|
@@ -15927,6 +16638,8 @@ export {
|
|
|
15927
16638
|
selectAttachmentsOfComponentTypeByType,
|
|
15928
16639
|
selectAttachmentsOfDocument,
|
|
15929
16640
|
selectAttachmentsOfDocumentByType,
|
|
16641
|
+
selectAttachmentsOfFormRevision,
|
|
16642
|
+
selectAttachmentsOfFormSubmission,
|
|
15930
16643
|
selectAttachmentsOfIssue,
|
|
15931
16644
|
selectAttachmentsOfIssueByType,
|
|
15932
16645
|
selectAttachmentsOfProject,
|
|
@@ -15944,11 +16657,9 @@ export {
|
|
|
15944
16657
|
selectComponent,
|
|
15945
16658
|
selectComponentAttachment,
|
|
15946
16659
|
selectComponentAttachmentMapping,
|
|
15947
|
-
selectComponentSubmissionMapping,
|
|
15948
16660
|
selectComponentType,
|
|
15949
16661
|
selectComponentTypeAttachment,
|
|
15950
16662
|
selectComponentTypeAttachmentMapping,
|
|
15951
|
-
selectComponentTypeForm,
|
|
15952
16663
|
selectComponentTypeFromComponent,
|
|
15953
16664
|
selectComponentTypeFromComponents,
|
|
15954
16665
|
selectComponentTypeStagesMapping,
|
|
@@ -15978,8 +16689,24 @@ export {
|
|
|
15978
16689
|
selectExpandedSections,
|
|
15979
16690
|
selectFavouriteProjects,
|
|
15980
16691
|
selectFileAttachmentsOfIssue,
|
|
15981
|
-
|
|
16692
|
+
selectFilteredForms,
|
|
16693
|
+
selectForm,
|
|
16694
|
+
selectFormMapping,
|
|
16695
|
+
selectFormOfComponentType,
|
|
15982
16696
|
selectFormRevision,
|
|
16697
|
+
selectFormRevisionMapping,
|
|
16698
|
+
selectFormRevisions,
|
|
16699
|
+
selectFormRevisionsOfForm,
|
|
16700
|
+
selectFormSubmission,
|
|
16701
|
+
selectFormSubmissionAttachmentsMapping,
|
|
16702
|
+
selectFormSubmissions,
|
|
16703
|
+
selectFormSubmissionsByComponents,
|
|
16704
|
+
selectFormSubmissionsMapping,
|
|
16705
|
+
selectFormSubmissionsOfComponent,
|
|
16706
|
+
selectFormSubmissionsOfForm,
|
|
16707
|
+
selectFormSubmissionsOfIssue,
|
|
16708
|
+
selectFormsCount,
|
|
16709
|
+
selectGeneralFormCount,
|
|
15983
16710
|
selectHiddenCategoryCount,
|
|
15984
16711
|
selectHiddenComponentTypeIds,
|
|
15985
16712
|
selectIsFetchingInitialData,
|
|
@@ -15994,10 +16721,10 @@ export {
|
|
|
15994
16721
|
selectIssueUpdateMapping,
|
|
15995
16722
|
selectIssueUpdatesOfIssue,
|
|
15996
16723
|
selectIssues,
|
|
15997
|
-
|
|
16724
|
+
selectLatestFormRevisionByForm,
|
|
16725
|
+
selectLatestFormRevisionOfForm,
|
|
16726
|
+
selectLatestFormRevisionsOfComponentTypes,
|
|
15998
16727
|
selectLatestRetryTime,
|
|
15999
|
-
selectLatestRevisionByFormId,
|
|
16000
|
-
selectLatestRevisionsFromComponentTypeIds,
|
|
16001
16728
|
selectLicense,
|
|
16002
16729
|
selectLicenseForProject,
|
|
16003
16730
|
selectLicenses,
|
|
@@ -16006,8 +16733,6 @@ export {
|
|
|
16006
16733
|
selectMapStyle,
|
|
16007
16734
|
selectNumberOfComponentTypesMatchingCaseInsensitiveName,
|
|
16008
16735
|
selectNumberOfComponentsOfComponentType,
|
|
16009
|
-
selectNumberOfGeneralUserForms,
|
|
16010
|
-
selectNumberOfUserForms,
|
|
16011
16736
|
selectOrganization,
|
|
16012
16737
|
selectOrganizationAccess,
|
|
16013
16738
|
selectOrganizationAccessForUser,
|
|
@@ -16024,6 +16749,7 @@ export {
|
|
|
16024
16749
|
selectProjectAccessForUser,
|
|
16025
16750
|
selectProjectAccessUserMapping,
|
|
16026
16751
|
selectProjectAccesses,
|
|
16752
|
+
selectProjectAttachment,
|
|
16027
16753
|
selectProjectAttachmentMapping,
|
|
16028
16754
|
selectProjectFileVisibility,
|
|
16029
16755
|
selectProjectFiles,
|
|
@@ -16035,8 +16761,6 @@ export {
|
|
|
16035
16761
|
selectRecentIssuesAsSearchResults,
|
|
16036
16762
|
selectRecentProjects,
|
|
16037
16763
|
selectRehydrated,
|
|
16038
|
-
selectRevisionAttachments,
|
|
16039
|
-
selectRevisionsForForm,
|
|
16040
16764
|
selectRootDocuments,
|
|
16041
16765
|
selectShowTooltips,
|
|
16042
16766
|
selectSortedEmailDomains,
|
|
@@ -16051,16 +16775,10 @@ export {
|
|
|
16051
16775
|
selectStagesFromComponentType,
|
|
16052
16776
|
selectStagesFromComponentTypeIds,
|
|
16053
16777
|
selectStagesFromStageIds,
|
|
16054
|
-
selectSubmissionAttachments,
|
|
16055
|
-
selectSubmissionsForComponent,
|
|
16056
|
-
selectSubmissionsForForm,
|
|
16057
|
-
selectSubmissionsForIssue,
|
|
16058
16778
|
selectUploadUrl,
|
|
16059
16779
|
selectUsedColors,
|
|
16060
16780
|
selectUser,
|
|
16061
|
-
|
|
16062
|
-
selectUserFormMapping,
|
|
16063
|
-
selectUserFormSubmission,
|
|
16781
|
+
selectUserFormRevisionAttachmentsMapping,
|
|
16064
16782
|
selectUsersAsMapping,
|
|
16065
16783
|
selectVisibleStatuses,
|
|
16066
16784
|
selectVisibleUserIds,
|
|
@@ -16075,21 +16793,32 @@ export {
|
|
|
16075
16793
|
setAppearance,
|
|
16076
16794
|
setCategories,
|
|
16077
16795
|
setCenterMapToProject,
|
|
16796
|
+
setComponentAttachment,
|
|
16078
16797
|
setComponentAttachments,
|
|
16798
|
+
setComponentTypeAttachment,
|
|
16079
16799
|
setComponentTypeAttachments,
|
|
16080
16800
|
setComponentTypes,
|
|
16081
16801
|
setComponents,
|
|
16082
16802
|
setCreateProjectType,
|
|
16083
16803
|
setCurrentUser,
|
|
16804
|
+
setDocumentAttachment,
|
|
16084
16805
|
setDocumentAttachments,
|
|
16085
16806
|
setDocuments,
|
|
16086
16807
|
setEmailDomains,
|
|
16087
16808
|
setEnableClustering,
|
|
16088
16809
|
setEnableDuplicateIssues,
|
|
16089
16810
|
setEnablePlacementMode,
|
|
16811
|
+
setFormRevision,
|
|
16812
|
+
setFormRevisionAttachments,
|
|
16813
|
+
setFormRevisions,
|
|
16814
|
+
setFormSubmission,
|
|
16815
|
+
setFormSubmissionAttachments,
|
|
16816
|
+
setFormSubmissions,
|
|
16817
|
+
setForms,
|
|
16090
16818
|
setIsFetchingInitialData,
|
|
16091
16819
|
setIsImportingProjectFile,
|
|
16092
16820
|
setIsLoading,
|
|
16821
|
+
setIssueAttachment,
|
|
16093
16822
|
setIssueAttachments,
|
|
16094
16823
|
setIssueComment,
|
|
16095
16824
|
setIssueComments,
|
|
@@ -16102,6 +16831,7 @@ export {
|
|
|
16102
16831
|
setOrganizations,
|
|
16103
16832
|
setProfilePicture,
|
|
16104
16833
|
setProjectAccesses,
|
|
16834
|
+
setProjectAttachment,
|
|
16105
16835
|
setProjectAttachments,
|
|
16106
16836
|
setProjectFileVisible,
|
|
16107
16837
|
setProjects,
|
|
@@ -16111,9 +16841,6 @@ export {
|
|
|
16111
16841
|
setTokens,
|
|
16112
16842
|
setTourStep,
|
|
16113
16843
|
setUploadUrl,
|
|
16114
|
-
setUserFormRevisionAttachments,
|
|
16115
|
-
setUserFormSubmissionAttachments,
|
|
16116
|
-
setUserFormSubmissions,
|
|
16117
16844
|
setUsers,
|
|
16118
16845
|
setVisibleStatuses,
|
|
16119
16846
|
setVisibleUserIds,
|
|
@@ -16135,17 +16862,24 @@ export {
|
|
|
16135
16862
|
updateActiveOrganization,
|
|
16136
16863
|
updateComponent,
|
|
16137
16864
|
updateComponentAttachment,
|
|
16865
|
+
updateComponentAttachments,
|
|
16138
16866
|
updateComponentTypeAttachment,
|
|
16867
|
+
updateComponentTypeAttachments,
|
|
16139
16868
|
updateDocumentAttachment,
|
|
16869
|
+
updateDocumentAttachments,
|
|
16140
16870
|
updateDocuments,
|
|
16871
|
+
updateFormSubmission,
|
|
16872
|
+
updateFormSubmissionAttachments,
|
|
16873
|
+
updateFormSubmissions,
|
|
16141
16874
|
updateIssue,
|
|
16142
16875
|
updateIssueAttachment,
|
|
16876
|
+
updateIssueAttachments,
|
|
16143
16877
|
updateLicense,
|
|
16144
16878
|
updateOrCreateProject,
|
|
16145
|
-
updateOrCreateUserFormSubmission,
|
|
16146
16879
|
updateOrganizationAccess,
|
|
16147
16880
|
updateProjectAccess,
|
|
16148
16881
|
updateProjectAttachment,
|
|
16882
|
+
updateProjectAttachments,
|
|
16149
16883
|
updateStages,
|
|
16150
16884
|
useAppDispatch,
|
|
16151
16885
|
useAppSelector,
|
|
@@ -16156,8 +16890,6 @@ export {
|
|
|
16156
16890
|
useFormikInput,
|
|
16157
16891
|
useMemoCompare,
|
|
16158
16892
|
useSDK,
|
|
16159
|
-
userFormReducer,
|
|
16160
|
-
userFormSlice,
|
|
16161
16893
|
userReducer,
|
|
16162
16894
|
userSlice,
|
|
16163
16895
|
valueIsFile,
|