feat: ability to create a task #14
@ -3,17 +3,9 @@
|
||||
<database-model serializer="dbm" dbms="POSTGRES" family-id="POSTGRES" format-version="4.53">
|
||||
<root id="1">
|
||||
<DateStyle>mdy</DateStyle>
|
||||
<Grants>1||-9223372036854775808|c|G
|
||||
1||10|c|G
|
||||
1||10|C|G
|
||||
1||10|T|G
|
||||
4||-9223372036854775808|c|G
|
||||
4||10|c|G
|
||||
4||10|C|G
|
||||
4||10|T|G</Grants>
|
||||
<IntrospectionStateNumber>767</IntrospectionStateNumber>
|
||||
<IntrospectionStateNumber>785</IntrospectionStateNumber>
|
||||
<ServerVersion>16.4</ServerVersion>
|
||||
<StartupTime>1723847104</StartupTime>
|
||||
<StartupTime>1724062819</StartupTime>
|
||||
<TimeZones>true ACDT
|
||||
true ACSST
|
||||
false ACST
|
||||
@ -1412,7 +1404,7 @@ true posixrules
|
||||
13212||10|C|G
|
||||
13212||-9223372036854775808|U|G
|
||||
13212||10|U|G</Grants>
|
||||
<IntrospectionStateNumber>767</IntrospectionStateNumber>
|
||||
<IntrospectionStateNumber>785</IntrospectionStateNumber>
|
||||
<ObjectId>16384</ObjectId>
|
||||
<OwnerName>app</OwnerName>
|
||||
</database>
|
||||
@ -4831,8 +4823,8 @@ true posixrules
|
||||
<schema id="264" parent="3" name="public">
|
||||
<Comment>standard public schema</Comment>
|
||||
<Current>1</Current>
|
||||
<IntrospectionStateNumber>767</IntrospectionStateNumber>
|
||||
<LastIntrospectionLocalTimestamp>2024-08-16.22:33:41</LastIntrospectionLocalTimestamp>
|
||||
<IntrospectionStateNumber>785</IntrospectionStateNumber>
|
||||
<LastIntrospectionLocalTimestamp>2024-08-19.17:09:45</LastIntrospectionLocalTimestamp>
|
||||
<ObjectId>2200</ObjectId>
|
||||
<StateNumber>524</StateNumber>
|
||||
<OwnerName>pg_database_owner</OwnerName>
|
||||
@ -4873,30 +4865,36 @@ true posixrules
|
||||
</table>
|
||||
<table id="269" parent="264" name="projects">
|
||||
<ObjectId>16425</ObjectId>
|
||||
<StateNumber>762</StateNumber>
|
||||
<StateNumber>781</StateNumber>
|
||||
<AccessMethodId>2</AccessMethodId>
|
||||
<OwnerName>app</OwnerName>
|
||||
</table>
|
||||
<argument id="270" parent="265">
|
||||
<table id="270" parent="264" name="tasks">
|
||||
<ObjectId>16446</ObjectId>
|
||||
<StateNumber>783</StateNumber>
|
||||
<AccessMethodId>2</AccessMethodId>
|
||||
<OwnerName>app</OwnerName>
|
||||
</table>
|
||||
<argument id="271" parent="265">
|
||||
<ArgumentDirection>R</ArgumentDirection>
|
||||
<StoredType>void|0s</StoredType>
|
||||
</argument>
|
||||
<argument id="271" parent="265" name="_tbl">
|
||||
<argument id="272" parent="265" name="_tbl">
|
||||
<Position>1</Position>
|
||||
<StoredType>regclass|0s</StoredType>
|
||||
</argument>
|
||||
<argument id="272" parent="266">
|
||||
<argument id="273" parent="266">
|
||||
<ArgumentDirection>R</ArgumentDirection>
|
||||
<StoredType>trigger|0s</StoredType>
|
||||
</argument>
|
||||
<column id="273" parent="268" name="version">
|
||||
<column id="274" parent="268" name="version">
|
||||
<NotNull>1</NotNull>
|
||||
<Position>1</Position>
|
||||
<StateNumber>743</StateNumber>
|
||||
<StoredType>varchar(50)|0s</StoredType>
|
||||
<TypeId>1043</TypeId>
|
||||
</column>
|
||||
<column id="274" parent="268" name="run_on">
|
||||
<column id="275" parent="268" name="run_on">
|
||||
<DefaultExpression>CURRENT_TIMESTAMP</DefaultExpression>
|
||||
<NotNull>1</NotNull>
|
||||
<Position>2</Position>
|
||||
@ -4904,7 +4902,7 @@ true posixrules
|
||||
<StoredType>timestamp|0s</StoredType>
|
||||
<TypeId>1114</TypeId>
|
||||
</column>
|
||||
<index id="275" parent="268" name="__diesel_schema_migrations_pkey">
|
||||
<index id="276" parent="268" name="__diesel_schema_migrations_pkey">
|
||||
<ColNames>version</ColNames>
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ObjectId>16393</ObjectId>
|
||||
@ -4916,14 +4914,14 @@ true posixrules
|
||||
<CollationIds>100</CollationIds>
|
||||
<CollationParentNames>pg_catalog</CollationParentNames>
|
||||
</index>
|
||||
<key id="276" parent="268" name="__diesel_schema_migrations_pkey">
|
||||
<key id="277" parent="268" name="__diesel_schema_migrations_pkey">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ObjectId>16394</ObjectId>
|
||||
<Primary>1</Primary>
|
||||
<StateNumber>743</StateNumber>
|
||||
<UnderlyingIndexId>16393</UnderlyingIndexId>
|
||||
</key>
|
||||
<column id="277" parent="269" name="id">
|
||||
<column id="278" parent="269" name="id">
|
||||
<DefaultExpression>nextval('projects_id_seq'::regclass)</DefaultExpression>
|
||||
<NotNull>1</NotNull>
|
||||
<Position>1</Position>
|
||||
@ -4932,14 +4930,14 @@ true posixrules
|
||||
<SequenceId>16424</SequenceId>
|
||||
<TypeId>23</TypeId>
|
||||
</column>
|
||||
<column id="278" parent="269" name="title">
|
||||
<column id="279" parent="269" name="title">
|
||||
<NotNull>1</NotNull>
|
||||
<Position>2</Position>
|
||||
<StateNumber>762</StateNumber>
|
||||
<StoredType>text|0s</StoredType>
|
||||
<TypeId>25</TypeId>
|
||||
</column>
|
||||
<index id="279" parent="269" name="projects_pkey">
|
||||
<index id="280" parent="269" name="projects_pkey">
|
||||
<ColNames>id</ColNames>
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ObjectId>16431</ObjectId>
|
||||
@ -4948,12 +4946,69 @@ true posixrules
|
||||
<Unique>1</Unique>
|
||||
<AccessMethodId>403</AccessMethodId>
|
||||
</index>
|
||||
<key id="280" parent="269" name="projects_pkey">
|
||||
<key id="281" parent="269" name="projects_pkey">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ObjectId>16432</ObjectId>
|
||||
<Primary>1</Primary>
|
||||
<StateNumber>762</StateNumber>
|
||||
<UnderlyingIndexId>16431</UnderlyingIndexId>
|
||||
</key>
|
||||
<column id="282" parent="270" name="id">
|
||||
<NotNull>1</NotNull>
|
||||
<Position>1</Position>
|
||||
<StateNumber>783</StateNumber>
|
||||
<StoredType>integer|0s</StoredType>
|
||||
<TypeId>23</TypeId>
|
||||
</column>
|
||||
<column id="283" parent="270" name="title">
|
||||
<NotNull>1</NotNull>
|
||||
<Position>2</Position>
|
||||
<StateNumber>783</StateNumber>
|
||||
<StoredType>text|0s</StoredType>
|
||||
<TypeId>25</TypeId>
|
||||
</column>
|
||||
<column id="284" parent="270" name="deadline">
|
||||
<Position>3</Position>
|
||||
<StateNumber>783</StateNumber>
|
||||
<StoredType>date|0s</StoredType>
|
||||
<TypeId>1082</TypeId>
|
||||
</column>
|
||||
<column id="285" parent="270" name="category">
|
||||
<NotNull>1</NotNull>
|
||||
<Position>4</Position>
|
||||
<StateNumber>783</StateNumber>
|
||||
<StoredType>jsonb|0s</StoredType>
|
||||
<TypeId>3802</TypeId>
|
||||
</column>
|
||||
<column id="286" parent="270" name="project_id">
|
||||
<Position>5</Position>
|
||||
<StateNumber>783</StateNumber>
|
||||
<StoredType>integer|0s</StoredType>
|
||||
<TypeId>23</TypeId>
|
||||
</column>
|
||||
<foreign-key id="287" parent="270" name="tasks_project_id_fkey">
|
||||
<ColNames>project_id</ColNames>
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ObjectId>16453</ObjectId>
|
||||
<StateNumber>783</StateNumber>
|
||||
<RefKeyColPositions>1</RefKeyColPositions>
|
||||
<RefTableId>16425</RefTableId>
|
||||
</foreign-key>
|
||||
<index id="288" parent="270" name="tasks_pkey">
|
||||
<ColNames>id</ColNames>
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ObjectId>16451</ObjectId>
|
||||
<Primary>1</Primary>
|
||||
<StateNumber>783</StateNumber>
|
||||
<Unique>1</Unique>
|
||||
<AccessMethodId>403</AccessMethodId>
|
||||
</index>
|
||||
<key id="289" parent="270" name="tasks_pkey">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ObjectId>16452</ObjectId>
|
||||
<Primary>1</Primary>
|
||||
<StateNumber>783</StateNumber>
|
||||
<UnderlyingIndexId>16451</UnderlyingIndexId>
|
||||
</key>
|
||||
</database-model>
|
||||
</dataSource>
|
@ -1,2 +1,2 @@
|
||||
#n:public
|
||||
!<md> [767, 0, null, null, -2147483648, -2147483648]
|
||||
!<md> [785, 0, null, null, -2147483648, -2147483648]
|
||||
|
4
.idea/vcs.xml
generated
@ -2,8 +2,8 @@
|
||||
<project version="4">
|
||||
<component name="CommitMessageInspectionProfile">
|
||||
<profile version="1.0">
|
||||
<inspection_tool class="CommitFormat" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="CommitNamingConvention" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="CommitFormat" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="CommitNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
<component name="VcsDirectoryMappings">
|
||||
|
137
Cargo.lock
generated
@ -127,7 +127,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"axum-macros",
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
@ -211,6 +211,12 @@ version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@ -335,6 +341,7 @@ dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
@ -499,7 +506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.5",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
@ -511,6 +518,16 @@ version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel"
|
||||
version = "2.2.2"
|
||||
@ -519,9 +536,11 @@ checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"diesel_derives",
|
||||
"itoa",
|
||||
"pq-sys",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -647,7 +666,7 @@ dependencies = [
|
||||
"anymap",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"ciborium",
|
||||
"dioxus-cli-config",
|
||||
@ -1400,6 +1419,12 @@ dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
@ -1428,6 +1453,12 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
@ -1564,6 +1595,17 @@ dependencies = [
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.4.0"
|
||||
@ -1571,7 +1613,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1580,7 +1623,7 @@ version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04e8e537b529b8674e97e9fb82c10ff168a290ac3867a0295f112061ffbca1ef"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.5",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
@ -1695,7 +1738,7 @@ version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1780,6 +1823,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@ -1861,7 +1910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap",
|
||||
"indexmap 2.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1907,6 +1956,12 @@ dependencies = [
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
@ -2199,6 +2254,36 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.4.0",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"serde_with_macros",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "server_fn"
|
||||
version = "0.6.14"
|
||||
@ -2442,6 +2527,37 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.8.0"
|
||||
@ -2467,11 +2583,16 @@ checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8"
|
||||
name = "todo-baggins"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"diesel",
|
||||
"dioxus",
|
||||
"dioxus-logger",
|
||||
"dotenvy",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"tracing",
|
||||
"tracing-wasm",
|
||||
"validator",
|
||||
]
|
||||
|
||||
@ -2538,7 +2659,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.5",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
@ -7,7 +7,8 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
diesel = { version = "2.2.2", features = ["postgres"] }
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
diesel = { version = "2.2.2", features = ["chrono", "postgres", "postgres_backend", "serde_json"] }
|
||||
|
||||
dioxus = { version = "0.5", features = ["fullstack", "router"] }
|
||||
|
||||
@ -16,6 +17,10 @@ dioxus-logger = "0.5.1"
|
||||
dotenvy = "0.15.7"
|
||||
serde = "1.0.208"
|
||||
validator = { version = "0.18.1", features = ["derive"] }
|
||||
serde_json = "1.0.125"
|
||||
tracing = "0.1.40"
|
||||
tracing-wasm = "0.2.1"
|
||||
serde_with = { version = "3.9.0", features = ["chrono_0_4"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
3
migrations/2024-08-19-105140_create_tasks/down.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
|
||||
DROP TABLE IF EXISTS "tasks";
|
11
migrations/2024-08-19-105140_create_tasks/up.sql
Normal file
@ -0,0 +1,11 @@
|
||||
-- Your SQL goes here
|
||||
|
||||
CREATE TABLE "tasks"(
|
||||
"id" SERIAL NOT NULL PRIMARY KEY,
|
||||
"title" TEXT NOT NULL,
|
||||
"deadline" DATE,
|
||||
"category" JSONB NOT NULL,
|
||||
"project_id" INT4,
|
||||
FOREIGN KEY ("project_id") REFERENCES "projects"("id")
|
||||
);
|
||||
|
||||
|
@ -6,6 +6,9 @@ use dioxus::prelude::*;
|
||||
#[component]
|
||||
pub(crate) fn App() -> Element {
|
||||
rsx! {
|
||||
Router::<Route> {}
|
||||
div {
|
||||
class: "min-h-screen text-white bg-neutral-800",
|
||||
Router::<Route> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,12 @@ use crate::components::project_form::ProjectForm;
|
||||
use dioxus::core_macro::rsx;
|
||||
use dioxus::dioxus_core::Element;
|
||||
use dioxus::prelude::*;
|
||||
use crate::components::task_form::TaskForm;
|
||||
|
||||
#[component]
|
||||
pub(crate) fn Home() -> Element {
|
||||
rsx! {
|
||||
ProjectForm {}
|
||||
TaskForm {}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub(crate) mod app;
|
||||
pub(crate) mod home;
|
||||
pub(crate) mod project_form;
|
||||
pub(crate) mod task_form;
|
||||
|
@ -19,6 +19,7 @@ pub(crate) fn ProjectForm() -> Element {
|
||||
input {
|
||||
r#type: "text",
|
||||
name: "title",
|
||||
required: true,
|
||||
placeholder: "title"
|
||||
}
|
||||
button {
|
||||
|
221
src/components/task_form.rs
Normal file
@ -0,0 +1,221 @@
|
||||
use chrono::Duration;
|
||||
use crate::models::category::{CalendarTime, Category};
|
||||
use crate::models::task::NewTask;
|
||||
use crate::server::projects::get_projects;
|
||||
use crate::server::tasks::create_task;
|
||||
use dioxus::core_macro::{component, rsx};
|
||||
use dioxus::dioxus_core::Element;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub(crate) fn TaskForm() -> Element {
|
||||
let categories = vec![
|
||||
Category::Inbox,
|
||||
Category::SomedayMaybe,
|
||||
Category::WaitingFor(String::new()),
|
||||
Category::NextSteps,
|
||||
Category::Calendar {
|
||||
date: chrono::Local::now().date_naive(),
|
||||
reoccurance_interval: None,
|
||||
time: None,
|
||||
},
|
||||
Category::LongTerm,
|
||||
];
|
||||
let projects = use_server_future(get_projects)?.unwrap().unwrap();
|
||||
|
||||
let mut selected_category_index = use_signal::<usize>(|| 0);
|
||||
let mut category_calendar_is_reoccurring = use_signal::<bool>(|| false);
|
||||
let mut category_calendar_has_time = use_signal::<bool>(|| false);
|
||||
let mut category_calendar_has_reminder = use_signal::<bool>(|| false);
|
||||
|
||||
rsx! {
|
||||
form {
|
||||
onsubmit: move |event| {
|
||||
let categories = categories.clone();
|
||||
async move {
|
||||
let new_task = NewTask::new(
|
||||
event.values().get("title").unwrap().as_value(),
|
||||
event.values().get("deadline").unwrap().as_value().parse().ok(),
|
||||
match &categories[
|
||||
event.values().get("category_index").unwrap()
|
||||
.as_value().parse::<usize>().unwrap()
|
||||
] {
|
||||
Category::WaitingFor(_) => Category::WaitingFor(
|
||||
event.values().get("category_waiting_for").unwrap()
|
||||
.as_value()
|
||||
),
|
||||
Category::Calendar { .. } => Category::Calendar {
|
||||
date: event.values().get("category_calendar_date").unwrap()
|
||||
.as_value().parse().unwrap(),
|
||||
reoccurance_interval:
|
||||
event.values().get("category_calendar_is_reoccurring").map(
|
||||
|_| Duration::days(
|
||||
event.values().get("category_calendar_reoccurance_interval")
|
||||
.unwrap().as_value().parse().unwrap()
|
||||
)
|
||||
),
|
||||
time: event.values().get("category_calendar_time").unwrap()
|
||||
.as_value().parse().ok().map(|time|
|
||||
CalendarTime::new(
|
||||
time,
|
||||
event.values().get("category_calendar_has_reminder").map(
|
||||
|_| Duration::minutes(
|
||||
event.values()
|
||||
.get("category_calendar_reminder_offset").unwrap()
|
||||
.as_value().parse().unwrap()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
},
|
||||
category => category.clone()
|
||||
},
|
||||
event.values().get("project_id").unwrap()
|
||||
.as_value().parse::<i32>().ok().filter(|&id| id > 0),
|
||||
);
|
||||
let _ = create_task(new_task).await;
|
||||
}
|
||||
},
|
||||
![]() Consider adding error handling for form submission. The form submission logic is well-implemented, but it lacks error handling. Consider handling potential errors from
**Consider adding error handling for form submission.**
The form submission logic is well-implemented, but it lacks error handling. Consider handling potential errors from `create_task`.
```rust
let result = create_task(new_task).await;
if let Err(e) = result {
// Handle error, e.g., display a message to the user
}
```
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
class: "p-4 flex flex-col gap-4",
|
||||
input {
|
||||
r#type: "text",
|
||||
name: "title",
|
||||
required: true,
|
||||
placeholder: "title",
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
},
|
||||
select {
|
||||
name: "category_index",
|
||||
oninput: move |event| {
|
||||
selected_category_index.set(event.value().parse().unwrap());
|
||||
},
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
option {
|
||||
value: 0,
|
||||
"inbox"
|
||||
},
|
||||
option {
|
||||
value: 1,
|
||||
"someday maybe"
|
||||
},
|
||||
option {
|
||||
value: 2,
|
||||
"waiting for"
|
||||
},
|
||||
option {
|
||||
value: 3,
|
||||
"next steps"
|
||||
},
|
||||
option {
|
||||
value: 4,
|
||||
"calendar"
|
||||
},
|
||||
option {
|
||||
value: 5,
|
||||
"long term"
|
||||
},
|
||||
},
|
||||
match categories[selected_category_index()] {
|
||||
Category::WaitingFor(_) => rsx !{
|
||||
input {
|
||||
r#type: "text",
|
||||
name: "category_waiting_for",
|
||||
required: true,
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
},
|
||||
},
|
||||
Category::Calendar { .. } => rsx !{
|
||||
input {
|
||||
r#type: "date",
|
||||
name: "category_calendar_date",
|
||||
required: true,
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
},
|
||||
div {
|
||||
input {
|
||||
r#type: "checkbox",
|
||||
name: "category_calendar_is_reoccurring",
|
||||
id: "category_calendar_is_reoccurring",
|
||||
onchange: move |event| {
|
||||
category_calendar_is_reoccurring.set(event.checked());
|
||||
}
|
||||
},
|
||||
label {
|
||||
r#for: "category_calendar_is_reoccurring",
|
||||
" is reoccurring"
|
||||
}
|
||||
},
|
||||
if category_calendar_is_reoccurring() {
|
||||
input {
|
||||
r#type: "number",
|
||||
name: "category_calendar_reoccurance_interval",
|
||||
required: true,
|
||||
min: 1,
|
||||
placeholder: "reoccurance interval (days)",
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
}
|
||||
},
|
||||
input {
|
||||
r#type: "time",
|
||||
name: "category_calendar_time",
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
oninput: move |event| {
|
||||
category_calendar_has_time.set(!event.value().is_empty());
|
||||
}
|
||||
},
|
||||
if category_calendar_has_time() {
|
||||
div {
|
||||
input {
|
||||
r#type: "checkbox",
|
||||
name: "category_calendar_has_reminder",
|
||||
value: 0,
|
||||
id: "category_calendar_has_reminder",
|
||||
onchange: move |event| {
|
||||
category_calendar_has_reminder.set(event.checked());
|
||||
}
|
||||
},
|
||||
label {
|
||||
r#for: "category_calendar_has_reminder",
|
||||
" set a reminder"
|
||||
}
|
||||
}
|
||||
}
|
||||
if category_calendar_has_reminder() {
|
||||
input {
|
||||
r#type: "number",
|
||||
name: "category_calendar_reminder_offset",
|
||||
required: true,
|
||||
min: 0,
|
||||
placeholder: "reminder offset (minutes)",
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
},
|
||||
input {
|
||||
r#type: "date",
|
||||
name: "deadline",
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
},
|
||||
select {
|
||||
name: "project_id",
|
||||
class: "p-2 bg-neutral-700 rounded",
|
||||
option {
|
||||
value: 0,
|
||||
"none"
|
||||
},
|
||||
for project in projects {
|
||||
option {
|
||||
value: project.id().to_string(),
|
||||
{project.title()}
|
||||
}
|
||||
}
|
||||
},
|
||||
button {
|
||||
r#type: "submit",
|
||||
"create"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub enum Error {
|
||||
ServerInternal,
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use serde::Deserialize;
|
||||
use serde_with::serde_derive::Serialize;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct ErrorVec<T> {
|
||||
errors: Vec<T>,
|
||||
}
|
||||
@ -37,7 +39,7 @@ impl<T: Display> Display for ErrorVec<T> {
|
||||
impl<T> FromStr for ErrorVec<T> {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
fn from_str(_: &str) -> Result<Self, Self::Err> {
|
||||
Ok(ErrorVec { errors: Vec::new() })
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub(crate) mod error;
|
||||
pub(crate) mod error_vec;
|
||||
pub(crate) mod project_create_error;
|
||||
pub(crate) mod task_create_error;
|
||||
|
@ -12,8 +12,8 @@ pub enum ProjectCreateError {
|
||||
}
|
||||
|
||||
impl From<ValidationErrors> for ErrorVec<ProjectCreateError> {
|
||||
fn from(e: ValidationErrors) -> Self {
|
||||
e.errors()
|
||||
fn from(validation_errors: ValidationErrors) -> Self {
|
||||
validation_errors.errors()
|
||||
.iter()
|
||||
.flat_map(|(&field, error_kind)| match field {
|
||||
"title" => match error_kind {
|
||||
@ -22,30 +22,30 @@ impl From<ValidationErrors> for ErrorVec<ProjectCreateError> {
|
||||
.map(|validation_error| validation_error.code.as_ref())
|
||||
.map(|code| match code {
|
||||
"title_length" => ProjectCreateError::TitleLengthInvalid,
|
||||
_ => panic!("unexpected validation error code: {code}"),
|
||||
_ => panic!("Unexpected validation error code: `{code}`."),
|
||||
})
|
||||
.collect::<Vec<ProjectCreateError>>(),
|
||||
_ => panic!("unexpected validation error kind"),
|
||||
_ => panic!("Unexpected validation error kind."),
|
||||
},
|
||||
_ => panic!("unexpected validation field name: {field}"),
|
||||
_ => panic!("Unexpected validation field name: `{field}`."),
|
||||
})
|
||||
.collect::<Vec<ProjectCreateError>>()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
// has to be implemented for Dioxus server functions
|
||||
// Has to be implemented for Dioxus server functions.
|
||||
impl Display for ProjectCreateError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
// has to be implemented for Dioxus server functions
|
||||
// Has to be implemented for Dioxus server functions.
|
||||
![]() Consider alternatives to panic for unexpected validation errors. Using panic for unexpected validation errors may not be ideal in production code. Consider logging the error and returning a default error variant or using a custom error type. **Consider alternatives to panic for unexpected validation errors.**
Using panic for unexpected validation errors may not be ideal in production code. Consider logging the error and returning a default error variant or using a custom error type.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
impl FromStr for ProjectCreateError {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(_: &str) -> Result<Self, Self::Err> {
|
||||
Ok(ProjectCreateError::TitleLengthInvalid)
|
||||
Ok(ProjectCreateError::Error(Error::ServerInternal))
|
||||
}
|
||||
}
|
||||
|
52
src/errors/task_create_error.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::errors::error::Error;
|
||||
use crate::errors::error_vec::ErrorVec;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use validator::{ValidationErrors, ValidationErrorsKind};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum TaskCreateError {
|
||||
TitleLengthInvalid,
|
||||
ProjectNotFound,
|
||||
Error(Error),
|
||||
}
|
||||
|
||||
impl From<ValidationErrors> for ErrorVec<TaskCreateError> {
|
||||
fn from(validation_errors: ValidationErrors) -> Self {
|
||||
validation_errors.errors()
|
||||
.iter()
|
||||
.flat_map(|(&field, error_kind)| match field {
|
||||
"title" => match error_kind {
|
||||
ValidationErrorsKind::Field(validation_errors) => validation_errors
|
||||
.iter()
|
||||
.map(|validation_error| validation_error.code.as_ref())
|
||||
.map(|code| match code {
|
||||
"title_length" => TaskCreateError::TitleLengthInvalid,
|
||||
_ => panic!("Unexpected validation error code: `{code}`."),
|
||||
})
|
||||
.collect::<Vec<TaskCreateError>>(),
|
||||
_ => panic!("Unexpected validation error kind."),
|
||||
},
|
||||
_ => panic!("Unexpected validation field name: `{field}`."),
|
||||
![]() Consider alternatives to panic for unexpected validation errors. Using panic for unexpected validation errors may not be ideal in production code. Consider logging the error and returning a default error variant or using a custom error type. **Consider alternatives to panic for unexpected validation errors.**
Using panic for unexpected validation errors may not be ideal in production code. Consider logging the error and returning a default error variant or using a custom error type.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
})
|
||||
.collect::<Vec<TaskCreateError>>()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
// Has to be implemented for Dioxus server functions.
|
||||
impl Display for TaskCreateError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
// Has to be implemented for Dioxus server functions.
|
||||
impl FromStr for TaskCreateError {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(_: &str) -> Result<Self, Self::Err> {
|
||||
Ok(TaskCreateError::Error(Error::ServerInternal))
|
||||
}
|
||||
}
|
65
src/models/category.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use chrono::{Duration, NaiveDate, NaiveTime};
|
||||
use diesel::deserialize::FromSql;
|
||||
use diesel::pg::{Pg, PgValue};
|
||||
use diesel::serialize::{Output, ToSql};
|
||||
use diesel::sql_types::Jsonb;
|
||||
use diesel::{AsExpression, FromSqlRow};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::DurationSeconds;
|
||||
use std::io::Write;
|
||||
|
||||
#[serde_with::serde_as]
|
||||
#[derive(AsExpression, FromSqlRow, Serialize, Deserialize, Clone, Debug)]
|
||||
#[diesel(sql_type = Jsonb)]
|
||||
pub enum Category {
|
||||
Inbox,
|
||||
SomedayMaybe,
|
||||
WaitingFor(String),
|
||||
NextSteps,
|
||||
Calendar {
|
||||
date: NaiveDate,
|
||||
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
||||
reoccurance_interval: Option<Duration>,
|
||||
time: Option<CalendarTime>,
|
||||
},
|
||||
LongTerm,
|
||||
Done,
|
||||
Trash,
|
||||
}
|
||||
|
||||
#[serde_with::serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct CalendarTime {
|
||||
time: NaiveTime,
|
||||
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
||||
reminder_offset: Option<Duration>,
|
||||
}
|
||||
|
||||
impl CalendarTime {
|
||||
pub fn new(time: NaiveTime, reminder_offset: Option<Duration>) -> Self {
|
||||
Self { time, reminder_offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql<Jsonb, Pg> for Category {
|
||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> diesel::serialize::Result {
|
||||
let json = serde_json::to_string(self)?;
|
||||
|
||||
// Prepend the JSONB version byte.
|
||||
out.write_all(&[1])?;
|
||||
out.write_all(json.as_bytes())?;
|
||||
|
||||
Ok(diesel::serialize::IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql<Jsonb, Pg> for Category {
|
||||
fn from_sql(bytes: PgValue) -> diesel::deserialize::Result<Self> {
|
||||
let bytes = bytes.as_bytes();
|
||||
if bytes.is_empty() {
|
||||
return Err("Unexpected empty bytes (missing the JSONB version number).".into());
|
||||
}
|
||||
let str = std::str::from_utf8(&bytes[1..])?;
|
||||
serde_json::from_str(str).map_err(Into::into)
|
||||
}
|
||||
}
|
@ -1 +1,3 @@
|
||||
pub(crate) mod project;
|
||||
pub(crate) mod category;
|
||||
pub(crate) mod task;
|
||||
|
@ -6,7 +6,7 @@ use validator::Validate;
|
||||
const TITLE_LENGTH_MIN: u64 = 1;
|
||||
const TITLE_LENGTH_MAX: u64 = 255;
|
||||
|
||||
#[derive(Queryable, Selectable, Serialize, Deserialize, Debug)]
|
||||
#[derive(Queryable, Selectable, Serialize, Deserialize, Clone, Debug)]
|
||||
#[diesel(table_name = crate::schema::projects)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct Project {
|
||||
|
60
src/models/task.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
use crate::models::category::Category;
|
||||
use crate::schema::tasks;
|
||||
|
||||
const TITLE_LENGTH_MIN: u64 = 1;
|
||||
const TITLE_LENGTH_MAX: u64 = 255;
|
||||
|
||||
#[derive(Queryable, Selectable, Serialize, Deserialize, Clone, Debug)]
|
||||
#[diesel(table_name = crate::schema::tasks)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct Task {
|
||||
id: i32,
|
||||
title: String,
|
||||
deadline: Option<chrono::NaiveDate>,
|
||||
category: Category,
|
||||
project_id: Option<i32>,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub fn id(&self) -> i32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn title(&self) -> &str {
|
||||
&self.title
|
||||
}
|
||||
|
||||
pub fn deadline(&self) -> Option<chrono::NaiveDate> {
|
||||
self.deadline
|
||||
}
|
||||
|
||||
pub fn category(&self) -> &Category {
|
||||
&self.category
|
||||
}
|
||||
|
||||
pub fn project_id(&self) -> Option<i32> {
|
||||
self.project_id
|
||||
}
|
||||
}
|
||||
![]() Consider improving encapsulation and method naming. The getter methods are straightforward, but consider using Rust's idiomatic approach by implementing the **Consider improving encapsulation and method naming.**
The getter methods are straightforward, but consider using Rust's idiomatic approach by implementing the `Deref` trait or using public fields if appropriate. Additionally, method names could be more descriptive, such as `get_id` instead of `id`.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
|
||||
#[derive(Insertable, Serialize, Deserialize, Validate, Clone, Debug)]
|
||||
#[diesel(table_name = tasks)]
|
||||
pub struct NewTask {
|
||||
#[validate(length(min = "TITLE_LENGTH_MIN", max = "TITLE_LENGTH_MAX", code = "title_length"))]
|
||||
pub title: String,
|
||||
pub deadline: Option<chrono::NaiveDate>,
|
||||
pub category: Category,
|
||||
pub project_id: Option<i32>,
|
||||
}
|
||||
|
||||
impl NewTask {
|
||||
pub fn new(
|
||||
title: String, deadline: Option<chrono::NaiveDate>,
|
||||
category: Category, project_id: Option<i32>,
|
||||
) -> Self {
|
||||
Self { title, deadline, category, project_id }
|
||||
}
|
||||
![]() Consider enhancing validation error handling. While the validation logic is clear, consider implementing custom error handling to provide more informative feedback to the user when validation fails. **Consider enhancing validation error handling.**
While the validation logic is clear, consider implementing custom error handling to provide more informative feedback to the user when validation fails.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
}
|
@ -6,3 +6,20 @@ diesel::table! {
|
||||
title -> Text,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
tasks (id) {
|
||||
id -> Int4,
|
||||
title -> Text,
|
||||
deadline -> Nullable<Date>,
|
||||
category -> Jsonb,
|
||||
project_id -> Nullable<Int4>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(tasks -> projects (project_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
projects,
|
||||
tasks,
|
||||
);
|
||||
|
@ -1,2 +1,3 @@
|
||||
mod database_connection;
|
||||
pub(crate) mod projects;
|
||||
pub(crate) mod tasks;
|
||||
|
@ -3,23 +3,21 @@ use crate::errors::error_vec::ErrorVec;
|
||||
use crate::errors::project_create_error::ProjectCreateError;
|
||||
use crate::models::project::{NewProject, Project};
|
||||
use crate::server::database_connection::establish_database_connection;
|
||||
use diesel::{RunQueryDsl, SelectableHelper};
|
||||
use diesel::{QueryDsl, RunQueryDsl, SelectableHelper};
|
||||
use dioxus::prelude::*;
|
||||
use validator::Validate;
|
||||
|
||||
#[server]
|
||||
pub(crate) async fn create_project(
|
||||
new_project: NewProject,
|
||||
) -> Result<Project, ServerFnError<ErrorVec<ProjectCreateError>>> {
|
||||
pub(crate) async fn create_project(new_project: NewProject)
|
||||
-> Result<Project, ServerFnError<ErrorVec<ProjectCreateError>>> {
|
||||
use crate::schema::projects;
|
||||
|
||||
new_project
|
||||
.validate()
|
||||
new_project.validate()
|
||||
.map_err::<ErrorVec<ProjectCreateError>, _>(|errors| errors.into())?;
|
||||
|
||||
let mut connection = establish_database_connection()
|
||||
.map_err::<ErrorVec<ProjectCreateError>, _>(
|
||||
|_| vec![ProjectCreateError::Error(Error::ServerInternal), ].into()
|
||||
|_| vec![ProjectCreateError::Error(Error::ServerInternal)].into()
|
||||
)?;
|
||||
|
||||
let new_project = diesel::insert_into(projects::table)
|
||||
@ -27,8 +25,28 @@ pub(crate) async fn create_project(
|
||||
.returning(Project::as_returning())
|
||||
.get_result(&mut connection)
|
||||
.map_err::<ErrorVec<ProjectCreateError>, _>(
|
||||
|_| vec![ProjectCreateError::Error(Error::ServerInternal), ].into()
|
||||
|_| vec![ProjectCreateError::Error(Error::ServerInternal)].into()
|
||||
)?;
|
||||
|
||||
Ok(new_project)
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub(crate) async fn get_projects()
|
||||
-> Result<Vec<Project>, ServerFnError<ErrorVec<Error>>> {
|
||||
use crate::schema::projects::dsl::*;
|
||||
|
||||
let mut connection = establish_database_connection()
|
||||
.map_err::<ErrorVec<Error>, _>(
|
||||
|_| vec![Error::ServerInternal].into()
|
||||
)?;
|
||||
|
||||
let results = projects
|
||||
.select(Project::as_select())
|
||||
.load::<Project>(&mut connection)
|
||||
.map_err::<ErrorVec<Error>, _>(
|
||||
|_| vec![Error::ServerInternal].into()
|
||||
)?;
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
45
src/server/tasks.rs
Normal file
@ -0,0 +1,45 @@
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use crate::errors::error::Error;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use crate::errors::error_vec::ErrorVec;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use crate::models::task::{NewTask, Task};
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use crate::server::database_connection::establish_database_connection;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use diesel::{RunQueryDsl, SelectableHelper};
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use dioxus::prelude::*;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use validator::Validate;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use crate::errors::task_create_error::TaskCreateError;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
#[server]
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
pub(crate) async fn create_task(new_task: NewTask)
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
-> Result<Task, ServerFnError<ErrorVec<TaskCreateError>>> {
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
use crate::schema::tasks;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
new_task.validate()
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
.map_err::<ErrorVec<TaskCreateError>, _>(|errors| errors.into())?;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
let mut connection = establish_database_connection()
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
.map_err::<ErrorVec<TaskCreateError>, _>(
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
|_| vec![TaskCreateError::Error(Error::ServerInternal)].into()
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
)?;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
![]() Consider adding logging for database connection errors. While the error handling for database connection is appropriate, consider logging the error for better traceability.
**Consider adding logging for database connection errors.**
While the error handling for database connection is appropriate, consider logging the error for better traceability.
```rust
.map_err::<ErrorVec<TaskCreateError>, _>(
|e| {
log::error!("Database connection error: {:?}", e);
vec![TaskCreateError::Error(Error::ServerInternal)].into()
}
)?;
```
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
let new_task = diesel::insert_into(tasks::table)
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
.values(&new_task)
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
.returning(Task::as_returning())
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
.get_result(&mut connection)
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
.map_err::<ErrorVec<TaskCreateError>, _>(|error| {
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
let error = match error {
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
diesel::result::Error::DatabaseError(
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
diesel::result::DatabaseErrorKind::ForeignKeyViolation, info
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
) => {
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
match info.constraint_name() {
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
Some("tasks_project_id_fkey") => TaskCreateError::ProjectNotFound,
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
_ => TaskCreateError::Error(Error::ServerInternal)
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
}
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
},
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
_ => {
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
TaskCreateError::Error(Error::ServerInternal)
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
}
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
};
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
vec![error].into()
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
})?;
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
Ok(new_task)
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
}
|
||||
![]() Avoid using Using Replace **Avoid using `unwrap()` for database operations.**
Using `unwrap()` can lead to panics if the database operation fails. Consider handling the error with `map_err` or `expect` with a meaningful message.
Replace `unwrap()` with proper error handling to prevent potential panics.
<!-- This is an auto-generated comment by CodeRabbit -->
|
@ -1,8 +1,15 @@
|
||||
/* stylelint-disable */
|
||||
|
||||
/* noinspection CssInvalidAtRule */
|
||||
@tailwind base;
|
||||
/* noinspection CssInvalidAtRule */
|
||||
@tailwind components;
|
||||
/* noinspection CssInvalidAtRule */
|
||||
@tailwind utilities;
|
||||
|
||||
html, body, #main {
|
||||
/* noinspection CssInvalidAtRule */
|
||||
@apply min-h-screen;
|
||||
}
|
||||
|
||||
/* stylelint-enable */
|
||||
|
Ensure proper indexing and constraints.
The
tasks
table is created with a primary key and a foreign key. Consider adding an index onproject_id
to improve query performance if you frequently query tasks by project. Additionally, ensure that thecategory
JSONB column is used correctly, as it can store complex data structures.If you need further assistance with indexing strategies or JSONB usage, let me know!