Skip to content

Commit 7236b56

Browse files
authored
better UX (#583)
1 parent 9178803 commit 7236b56

File tree

6 files changed

+203
-4
lines changed

6 files changed

+203
-4
lines changed

changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
- Column sorting and filtering in document type list view
1616
- Column sorting and filtering in custom field list view
1717
- Column sorting and filtering in tags list view
18+
- Minor UX improvements: notification messages on custom field and document type CRUD
19+
operations
1820

1921

2022
## [3.3.1] - 2025-01-19

ui2/src/app/listenerMiddleware.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import {customFieldCRUDListeners} from "@/features/custom-fields/customFieldsSlice"
2+
import {documentTypeCRUDListeners} from "@/features/document-types/documentTypesSlice"
13
import {moveNodesListeners} from "@/features/nodes/nodesSlice"
4+
25
import {addListener, createListenerMiddleware} from "@reduxjs/toolkit"
36
import type {AppDispatch, RootState} from "./types"
47

@@ -14,3 +17,5 @@ export const addAppListener = addListener.withTypes<RootState, AppDispatch>()
1417
export type AppAddListener = typeof addAppListener
1518

1619
moveNodesListeners(startAppListening)
20+
documentTypeCRUDListeners(startAppListening)
21+
customFieldCRUDListeners(startAppListening)

ui2/src/features/custom-fields/customFieldsSlice.ts

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
import {AppStartListening} from "@/app/listenerMiddleware"
2+
import {notifications} from "@mantine/notifications"
13
import {PayloadAction, createSelector, createSlice} from "@reduxjs/toolkit"
24

35
import {RootState} from "@/app/types"
46
import {PAGINATION_DEFAULT_ITEMS_PER_PAGES} from "@/cconstants"
5-
import type {CustomField, Paginated, PaginationType} from "@/types"
7+
import type {
8+
CustomField,
9+
Paginated,
10+
PaginationType,
11+
ServerErrorType
12+
} from "@/types"
613
import {apiSliceWithCustomFields} from "./apiSlice"
714

815
import type {CustomFieldListColumnName, CustomFieldSortByInput} from "./types"
@@ -175,3 +182,82 @@ export const selectReverseSortedByType = (state: RootState) => {
175182
export const selectFilterText = (state: RootState) => {
176183
return state.customFields.listTableSort.filter
177184
}
185+
186+
export const customFieldCRUDListeners = (
187+
startAppListening: AppStartListening
188+
) => {
189+
// Create positive
190+
startAppListening({
191+
matcher:
192+
apiSliceWithCustomFields.endpoints.addNewCustomField.matchFulfilled,
193+
effect: async () => {
194+
notifications.show({
195+
withBorder: true,
196+
message: "Custom Field successfully created"
197+
})
198+
}
199+
})
200+
// Create negative
201+
startAppListening({
202+
matcher: apiSliceWithCustomFields.endpoints.addNewCustomField.matchRejected,
203+
effect: async action => {
204+
const error = action.payload as ServerErrorType
205+
notifications.show({
206+
autoClose: false,
207+
withBorder: true,
208+
color: "red",
209+
title: "Error",
210+
message: error.data.detail
211+
})
212+
}
213+
})
214+
// Update positive
215+
startAppListening({
216+
matcher: apiSliceWithCustomFields.endpoints.editCustomField.matchFulfilled,
217+
effect: async () => {
218+
notifications.show({
219+
withBorder: true,
220+
message: "Custom Field successfully updated"
221+
})
222+
}
223+
})
224+
// Update negative
225+
startAppListening({
226+
matcher: apiSliceWithCustomFields.endpoints.editCustomField.matchRejected,
227+
effect: async action => {
228+
const error = action.payload as ServerErrorType
229+
notifications.show({
230+
autoClose: false,
231+
withBorder: true,
232+
color: "red",
233+
title: "Error",
234+
message: error.data.detail
235+
})
236+
}
237+
})
238+
// Delete positive
239+
startAppListening({
240+
matcher:
241+
apiSliceWithCustomFields.endpoints.deleteCustomField.matchFulfilled,
242+
effect: async () => {
243+
notifications.show({
244+
withBorder: true,
245+
message: "Custom Field successfully deleted"
246+
})
247+
}
248+
})
249+
// Delete negative
250+
startAppListening({
251+
matcher: apiSliceWithCustomFields.endpoints.deleteCustomField.matchRejected,
252+
effect: async action => {
253+
const error = action.payload as ServerErrorType
254+
notifications.show({
255+
autoClose: false,
256+
withBorder: true,
257+
color: "red",
258+
title: "Error",
259+
message: error.data.detail
260+
})
261+
}
262+
})
263+
}

ui2/src/features/document-types/documentTypesSlice.ts

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import {AppStartListening} from "@/app/listenerMiddleware"
2+
import {notifications} from "@mantine/notifications"
13
import {PayloadAction, createSelector, createSlice} from "@reduxjs/toolkit"
24

35
import {RootState} from "@/app/types"
46
import {PAGINATION_DEFAULT_ITEMS_PER_PAGES} from "@/cconstants"
5-
import type {Paginated, PaginationType} from "@/types"
7+
import type {Paginated, PaginationType, ServerErrorType} from "@/types"
8+
69
import {apiSliceWithDocTypes} from "./apiSlice"
710
import type {
811
DocType,
@@ -153,3 +156,80 @@ export const selectTableSortColumns = (state: RootState) =>
153156
export const selectFilterText = (state: RootState) => {
154157
return state.customFields.listTableSort.filter
155158
}
159+
160+
export const documentTypeCRUDListeners = (
161+
startAppListening: AppStartListening
162+
) => {
163+
// Create positive
164+
startAppListening({
165+
matcher: apiSliceWithDocTypes.endpoints.addDocumentType.matchFulfilled,
166+
effect: async () => {
167+
notifications.show({
168+
withBorder: true,
169+
message: "Document Type successfully created"
170+
})
171+
}
172+
})
173+
// Create negative
174+
startAppListening({
175+
matcher: apiSliceWithDocTypes.endpoints.addDocumentType.matchRejected,
176+
effect: async action => {
177+
const error = action.payload as ServerErrorType
178+
notifications.show({
179+
autoClose: false,
180+
withBorder: true,
181+
color: "red",
182+
title: "Error",
183+
message: error.data.detail
184+
})
185+
}
186+
})
187+
// Update positive
188+
startAppListening({
189+
matcher: apiSliceWithDocTypes.endpoints.editDocumentType.matchFulfilled,
190+
effect: async () => {
191+
notifications.show({
192+
withBorder: true,
193+
message: "Document Type successfully updated"
194+
})
195+
}
196+
})
197+
// Update negative
198+
startAppListening({
199+
matcher: apiSliceWithDocTypes.endpoints.editDocumentType.matchRejected,
200+
effect: async action => {
201+
const error = action.payload as ServerErrorType
202+
notifications.show({
203+
autoClose: false,
204+
withBorder: true,
205+
color: "red",
206+
title: "Error",
207+
message: error.data.detail
208+
})
209+
}
210+
})
211+
// Delete positive
212+
startAppListening({
213+
matcher: apiSliceWithDocTypes.endpoints.deleteDocumentType.matchFulfilled,
214+
effect: async () => {
215+
notifications.show({
216+
withBorder: true,
217+
message: "Document Type successfully deleted"
218+
})
219+
}
220+
})
221+
// Delete negative
222+
startAppListening({
223+
matcher: apiSliceWithDocTypes.endpoints.deleteDocumentType.matchRejected,
224+
effect: async action => {
225+
const error = action.payload as ServerErrorType
226+
notifications.show({
227+
autoClose: false,
228+
withBorder: true,
229+
color: "red",
230+
title: "Error",
231+
message: error.data.detail
232+
})
233+
}
234+
})
235+
}

ui2/src/features/document/components/DocumentDetails/DocumentDetails.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ import {useContext} from "react"
1212

1313
import PanelContext from "@/contexts/PanelContext"
1414
import {useGetDocumentQuery} from "@/features/document/apiSlice"
15-
import {selectDocumentVersionOCRLang} from "@/features/document/documentVersSlice"
15+
import {
16+
selectDocumentVersionID,
17+
selectDocumentVersionOCRLang
18+
} from "@/features/document/documentVersSlice"
1619
import {skipToken} from "@reduxjs/toolkit/query"
1720
import {IconEdit} from "@tabler/icons-react"
1821
import classes from "./DocumentDetails.module.css"
1922

23+
import CopyButton from "@/components/CopyButton"
2024
import {EditNodeTagsModal} from "@/components/EditNodeTags"
2125
import {
2226
selectCurrentNodeID,
@@ -34,6 +38,7 @@ export default function DocumentDetails() {
3438
selectDocumentDetailsPanelOpen(s, mode)
3539
)
3640
const ocrLang = useAppSelector(s => selectDocumentVersionOCRLang(s, mode))
41+
const docVerID = useAppSelector(s => selectDocumentVersionID(s, mode))
3742

3843
if (!ocrLang || !docID || isLoading) {
3944
return (
@@ -52,7 +57,18 @@ export default function DocumentDetails() {
5257
return (
5358
<Group align="flex-start" className={classes.documentDetailsOpened}>
5459
<Stack className={classes.documentDetailsContent} justify="flex-start">
55-
<TextInput label="ID" readOnly value={docID} />
60+
<TextInput
61+
label="ID"
62+
readOnly
63+
value={docID}
64+
rightSection={<CopyButton value={docID || ""} />}
65+
/>
66+
<TextInput
67+
label="Version ID"
68+
readOnly
69+
value={docVerID}
70+
rightSection={<CopyButton value={docVerID || ""} />}
71+
/>
5672
<TextInput label="OCR Language" readOnly value={ocrLang} mt="md" />
5773
<Group>
5874
<TagsInput

ui2/src/features/document/documentVersSlice.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,16 @@ export const selectDocumentVersionOCRLang = (
214214
}
215215
}
216216

217+
export const selectDocumentVersionID = (state: RootState, mode: PanelMode) => {
218+
if (mode == "main") {
219+
return state.ui.mainViewerCurrentDocVerID
220+
}
221+
222+
if (mode == "secondary") {
223+
return state.ui.secondaryViewerCurrentDocVerID
224+
}
225+
}
226+
217227
export const selectSelectedPageIDs = (state: RootState, mode: PanelMode) => {
218228
if (mode == "main") {
219229
return state.ui.mainViewerSelectedIDs

0 commit comments

Comments
 (0)