Skip to content

Commit

Permalink
add calendar widget to custom field of type date
Browse files Browse the repository at this point in the history
  • Loading branch information
ciur committed Oct 9, 2024
1 parent 73b9a07 commit 52545c8
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 95 deletions.
46 changes: 24 additions & 22 deletions papermerge/core/constants.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
INBOX_TITLE = '.inbox'
HOME_TITLE = '.home'
CTYPE_FOLDER = 'folder'
CTYPE_DOCUMENT = 'document'
INBOX_TITLE = ".inbox"
HOME_TITLE = ".home"
CTYPE_FOLDER = "folder"
CTYPE_DOCUMENT = "document"
DEFAULT_THUMBNAIL_SIZE = 100 # 100 pixels wide
DEFAULT_PAGE_SIZE = 900 # 900 pixels wide
JPG = 'jpg'
PAGES = 'pages'
THUMBNAILS = 'thumbnails'
DOCVERS = 'docvers'
OCR = 'ocr'
DEFAULT_TAG_BG_COLOR = '#c41fff'
DEFAULT_TAG_FG_COLOR = '#ffffff'
INDEX_ADD_NODE = 'index_add_node'
INDEX_ADD_DOCS = 'index_add_docs'
INDEX_ADD_PAGES = 'index_add_pages'
INDEX_REMOVE_NODE = 'index_remove_node'
INDEX_UPDATE = 'index_update'
S3_WORKER_ADD_DOC_VER = 's3_worker_add_doc_vers'
S3_WORKER_REMOVE_DOC_VER = 's3_worker_remove_doc_vers'
S3_WORKER_REMOVE_DOC_THUMBNAIL = 's3_worker_remove_doc_thumbnail'
S3_WORKER_REMOVE_PAGE_THUMBNAIL = 's3_worker_remove_page_thumbnail'
S3_WORKER_GENERATE_PREVIEW = 's3_worker_generate_preview'
WORKER_OCR_DOCUMENT = 'worker_ocr_document'
JPG = "jpg"
PAGES = "pages"
THUMBNAILS = "thumbnails"
DOCVERS = "docvers"
OCR = "ocr"
DEFAULT_TAG_BG_COLOR = "#c41fff"
DEFAULT_TAG_FG_COLOR = "#ffffff"
INDEX_ADD_NODE = "index_add_node"
INDEX_ADD_DOCS = "index_add_docs"
INDEX_ADD_PAGES = "index_add_pages"
INDEX_REMOVE_NODE = "index_remove_node"
INDEX_UPDATE = "index_update"
S3_WORKER_ADD_DOC_VER = "s3_worker_add_doc_vers"
S3_WORKER_REMOVE_DOC_VER = "s3_worker_remove_doc_vers"
S3_WORKER_REMOVE_DOC_THUMBNAIL = "s3_worker_remove_doc_thumbnail"
S3_WORKER_REMOVE_PAGE_THUMBNAIL = "s3_worker_remove_page_thumbnail"
S3_WORKER_GENERATE_PREVIEW = "s3_worker_generate_preview"
WORKER_OCR_DOCUMENT = "worker_ocr_document"
# incoming (from user) date format
INCOMING_DATE_FORMAT = "%Y-%m-%d"
5 changes: 3 additions & 2 deletions papermerge/core/db/doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from sqlalchemy.orm import Session

from papermerge.core import schemas
from papermerge.core.constants import INCOMING_DATE_FORMAT
from papermerge.core.db.models import (
ColoredTag,
CustomField,
Expand Down Expand Up @@ -135,7 +136,7 @@ def update_document_custom_field_values(
if attr_name:
if attr_name == "date":
_dic[f"value_{attr_name}"] = datetime.strptime(
incoming_cf.value, "%d.%m.%Y"
incoming_cf.value, INCOMING_DATE_FORMAT
)
else:
_dic[f"value_{attr_name}"] = incoming_cf.value
Expand Down Expand Up @@ -215,7 +216,7 @@ def add_document_custom_field_values(
value = ""
if attr_name:
if attr_name == "date":
value = datetime.strptime(incoming_cf.value, "%d.%m.%Y")
value = datetime.strptime(incoming_cf.value, INCOMING_DATE_FORMAT)
else:
value = incoming_cf.value
_dic[f"value_{attr_name}"] = value
Expand Down
18 changes: 12 additions & 6 deletions tests/core/models/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def test_document_add_custom_field_value_of_type_date(
document_type_with_one_date_cf: schemas.DocumentType,
):
"""
Custom field of type `date` is set to string "28.10.2024"
Custom field of type `date` is set to string "2024-10-28"
"""
total_cfv_after = db.get_document_custom_field_values(
db_session, id=document.id, user_id=document.user.id
Expand All @@ -280,7 +280,9 @@ def test_document_add_custom_field_value_of_type_date(
cf_add = {
"document_type_id": dtype.id,
"custom_fields": [
{"custom_field_id": dtype.custom_fields[0].id, "value": "28.10.2024"},
# date is expected to be in:
# papermerge.core.constants.INCOMING_DATE_FORMAT
{"custom_field_id": dtype.custom_fields[0].id, "value": "2024-10-28"},
],
}
custom_fields_add = schemas.DocumentCustomFieldsAdd(**cf_add)
Expand Down Expand Up @@ -311,7 +313,9 @@ def test_document_update_same_custom_field_value_multiple_times1(
cf_add = {
"document_type_id": dtype.id,
"custom_fields": [
{"custom_field_id": dtype.custom_fields[0].id, "value": "28.10.2024"},
# date is expected to be in:
# papermerge.core.constants.INCOMING_DATE_FORMAT
{"custom_field_id": dtype.custom_fields[0].id, "value": "2024-10-28"},
],
}
custom_fields_add = schemas.DocumentCustomFieldsAdd(**cf_add)
Expand All @@ -329,7 +333,9 @@ def test_document_update_same_custom_field_value_multiple_times1(
)
assert len(total_cfv_after1) == 1

for value in ["29.10.2024", "30.10.2024"]:
# date is expected to be in:
# papermerge.core.constants.INCOMING_DATE_FORMAT
for value in ["2024-10-29", "2024-10-30"]:
# updating same custom field multiple times should not raise
# exceptions
cf_update = {
Expand Down Expand Up @@ -372,7 +378,7 @@ def test_document_update_same_custom_field_value_multiple_times2(
cf_add = {
"document_type_id": dtype.id,
"custom_fields": [
{"custom_field_id": dtype.custom_fields[0].id, "value": "28.10.2024"},
{"custom_field_id": dtype.custom_fields[0].id, "value": "2024-10-28"},
],
}
custom_fields_add = schemas.DocumentCustomFieldsAdd(**cf_add)
Expand All @@ -395,7 +401,7 @@ def test_document_update_same_custom_field_value_multiple_times2(
cf_update = {
"document_type_id": dtype.id,
"custom_fields": [
{"custom_field_value_id": total_cfv_after1[0].id, "value": "29.10.2024"},
{"custom_field_value_id": total_cfv_after1[0].id, "value": "2024-10-29"},
],
}
custom_fields_update = schemas.DocumentCustomFieldsUpdate(**cf_update)
Expand Down
16 changes: 9 additions & 7 deletions ui2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@
"preview": "vite preview"
},
"dependencies": {
"@mantine/core": "^7.12.2",
"@mantine/form": "^7.12.2",
"@mantine/hooks": "^7.12.2",
"@mantine/notifications": "^7.12.2",
"@reduxjs/toolkit": "^2.2.5",
"@tabler/icons-react": "^3.6.0",
"@mantine/core": "^7.13.2",
"@mantine/dates": "^7.13.2",
"@mantine/form": "^7.13.2",
"@mantine/hooks": "^7.13.2",
"@mantine/notifications": "^7.13.2",
"@reduxjs/toolkit": "^2.2.8",
"@tabler/icons-react": "^3.19.0",
"axios": "^1.7.2",
"dayjs": "^1.11.13",
"js-cookie": "^3.0.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"react-router": "^6.23.1",
"react-router": "^6.26.2",
"react-router-dom": "^6.23.1"
},
"devDependencies": {
Expand Down
22 changes: 11 additions & 11 deletions ui2/src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import {useLocation} from "react-router-dom"
import {useEffect, useRef} from "react"
import "@mantine/core/styles.css"
import {AppShell} from "@mantine/core"
import "@mantine/core/styles.css"
import "@mantine/dates/styles.css"
import {useViewportSize} from "@mantine/hooks"
import {Outlet, useNavigate} from "react-router-dom"
import {useSelector, useDispatch} from "react-redux"
import {useEffect, useRef} from "react"
import {useDispatch, useSelector} from "react-redux"
import {Outlet, useLocation, useNavigate} from "react-router-dom"

import NavBar from "@/components/NavBar"
import Header from "@/components/Header/Header"
import NavBar from "@/components/NavBar"
import {updateOutlet} from "@/features/ui/uiSlice"
import {
selectCurrentUser,
selectCurrentUserError,
selectCurrentUserStatus,
selectCurrentUser
selectCurrentUserStatus
} from "@/slices/currentUser"
import {updateOutlet} from "@/features/ui/uiSlice"

import "./App.css"
import {selectNavBarWidth} from "@/features/ui/uiSlice"
import Uploader from "@/components/Uploader"
import {selectNavBarWidth} from "@/features/ui/uiSlice"
import "./App.css"

function App() {
const {height, width} = useViewportSize()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {useContext, useEffect, useState} from "react"

import PanelContext from "@/contexts/PanelContext"
import {useGetDocumentQuery} from "@/features/document/apiSlice"
import {CustomFieldDate} from "@/features/document/components/customFields"
import {skipToken} from "@reduxjs/toolkit/query"

import {
Expand Down Expand Up @@ -143,7 +144,7 @@ export default function CustomFields() {
}

const onSave = async () => {
if (documentCustomFields && customFieldValues.length > 0) {
if (documentCustomFields && documentCustomFields.length > 0) {
// document already has custom fields associated
// we need to update existing custom field value
const data = {
Expand All @@ -164,7 +165,7 @@ export default function CustomFields() {
body: {
document_type_id: documentTypeID?.value!,
custom_fields: customFieldValues.map(i => {
return {custom_field_id: i.field_id!, value: i.value}
return {custom_field_id: i.id, value: i.value}
})
}
}
Expand Down Expand Up @@ -232,6 +233,10 @@ function GenericCustomField({
return <Skeleton height={"20"} />
}

if (customField.data_type == "date") {
return <CustomFieldDate customField={customField} onChange={onChange} />
}

return (
<TextInput
label={customField.name}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type {DocumentCustomFieldValue} from "@/types"
import {rem} from "@mantine/core"
import {DatePickerInput, DateValue} from "@mantine/dates"
import {IconCalendar} from "@tabler/icons-react"
import dayjs from "dayjs"
import {useEffect, useState} from "react"

type onChangeArgs = {
customField: DocumentCustomFieldValue
value: string
}

type onChangeType = ({customField, value}: onChangeArgs) => void

interface Args {
customField: DocumentCustomFieldValue
onChange: onChangeType
}

export default function CustomFieldDate({customField, onChange}: Args) {
const [value, setValue] = useState<Date | null>(null)
const icon = (
<IconCalendar style={{width: rem(18), height: rem(18)}} stroke={1.5} />
)

useEffect(() => {
if (customField.value && customField.value.length > 0) {
const parts = customField.value.split("-")
const year = Number(parts[0])
const month = Number(parts[1]) - 1
const day = Number(parts[2].substring(0, 2))

const date = new Date(year, month, day)
setValue(date)
}
}, [])

const onLocalChange = (value: DateValue) => {
if (value) {
const d = dayjs(value)
const DATE_FORMAT = "YYYY-MM-DD"
const strValue = d.format(DATE_FORMAT)
onChange({customField, value: strValue})
}
setValue(value)
}

return (
<DatePickerInput
leftSection={icon}
leftSectionPointerEvents="none"
clearable
// `valueFormat` will be retrieved from user preferences
valueFormat="DD.MM.YYYY"
label={customField.name}
placeholder="Pick date"
value={value}
onChange={onLocalChange}
/>
)
}
3 changes: 3 additions & 0 deletions ui2/src/features/document/components/customFields/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import CustomFieldDate from "./CustomFieldDate"

export {CustomFieldDate}
Loading

0 comments on commit 52545c8

Please sign in to comment.