feat: ability to create a project (#9)
This commit is contained in:
		
							
								
								
									
										10
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| /.dioxus/ | ||||
| /.git/ | ||||
| /.github/ | ||||
| /dist/ | ||||
| /debug/ | ||||
| /node_modules/ | ||||
| /static/ | ||||
| /target/ | ||||
| /docker-compose-dev.yml | ||||
| /docker-compose-prod.yml | ||||
							
								
								
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| /target/ | ||||
| /dist/ | ||||
| /static/ | ||||
| /.dioxus/ | ||||
| /node_modules/ | ||||
|  | ||||
| **/*.rs.bk | ||||
|  | ||||
| .env | ||||
| .env.prod | ||||
							
								
								
									
										5
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| # Default ignored files | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
| # Editor-based HTTP Client requests | ||||
| /httpRequests/ | ||||
							
								
								
									
										20
									
								
								.idea/dataSources.local.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.idea/dataSources.local.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="dataSourceStorageLocal" created-in="RR-242.20224.309"> | ||||
|     <data-source name="todo_baggins@localhost" uuid="1658668c-c2b8-426d-a22f-16fbad9eff0b"> | ||||
|       <database-info product="PostgreSQL" version="16.4 (Debian 16.4-1.pgdg120+1)" jdbc-version="4.2" driver-name="PostgreSQL JDBC Driver" driver-version="42.6.0" dbms="POSTGRES" exact-version="16.4" exact-driver-version="42.6"> | ||||
|         <identifier-quote-string>"</identifier-quote-string> | ||||
|       </database-info> | ||||
|       <case-sensitivity plain-identifiers="lower" quoted-identifiers="exact" /> | ||||
|       <secret-storage>master_key</secret-storage> | ||||
|       <user-name>app</user-name> | ||||
|       <schema-mapping> | ||||
|         <introspection-scope> | ||||
|           <node kind="database" qname="@"> | ||||
|             <node kind="schema" qname="@" /> | ||||
|           </node> | ||||
|         </introspection-scope> | ||||
|       </schema-mapping> | ||||
|     </data-source> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										12
									
								
								.idea/dataSources.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.idea/dataSources.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="DataSourceManagerImpl" format="xml" multifile-model="true"> | ||||
|     <data-source source="LOCAL" name="todo_baggins@localhost" uuid="1658668c-c2b8-426d-a22f-16fbad9eff0b"> | ||||
|       <driver-ref>postgresql</driver-ref> | ||||
|       <synchronize>true</synchronize> | ||||
|       <jdbc-driver>org.postgresql.Driver</jdbc-driver> | ||||
|       <jdbc-url>jdbc:postgresql://localhost:5432/todo_baggins</jdbc-url> | ||||
|       <working-dir>$ProjectFileDir$</working-dir> | ||||
|     </data-source> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										4959
									
								
								.idea/dataSources/1658668c-c2b8-426d-a22f-16fbad9eff0b.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										4959
									
								
								.idea/dataSources/1658668c-c2b8-426d-a22f-16fbad9eff0b.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1 @@ | ||||
| #n:todo_baggins | ||||
| @@ -0,0 +1,2 @@ | ||||
| #n:information_schema | ||||
| !<md> [null, 0, null, null, -2147483648, -2147483648] | ||||
| @@ -0,0 +1,2 @@ | ||||
| #n:pg_catalog | ||||
| !<md> [null, 0, null, null, -2147483648, -2147483648] | ||||
| @@ -0,0 +1,2 @@ | ||||
| #n:public | ||||
| !<md> [767, 0, null, null, -2147483648, -2147483648] | ||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										6
									
								
								.idea/jsLibraryMappings.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/jsLibraryMappings.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="JavaScriptLibraryMappings"> | ||||
|     <includedPredefinedLibrary name="Node.js Core" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectModuleManager"> | ||||
|     <modules> | ||||
|       <module fileurl="file://$PROJECT_DIR$/.idea/todo-baggins.iml" filepath="$PROJECT_DIR$/.idea/todo-baggins.iml" /> | ||||
|     </modules> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										11
									
								
								.idea/runConfigurations/dev.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.idea/runConfigurations/dev.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <component name="ProjectRunConfigurationManager"> | ||||
|   <configuration default="false" name="dev" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker"> | ||||
|     <deployment type="docker-compose.yml"> | ||||
|       <settings> | ||||
|         <option name="envFilePath" value="" /> | ||||
|         <option name="sourceFilePath" value="docker-compose-dev.yml" /> | ||||
|       </settings> | ||||
|     </deployment> | ||||
|     <method v="2" /> | ||||
|   </configuration> | ||||
| </component> | ||||
							
								
								
									
										8
									
								
								.idea/sqldialects.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/sqldialects.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="SqlDialectMappings"> | ||||
|     <file url="file://$PROJECT_DIR$/migrations/00000000000000_diesel_initial_setup/down.sql" dialect="GenericSQL" /> | ||||
|     <file url="file://$PROJECT_DIR$/migrations/00000000000000_diesel_initial_setup/up.sql" dialect="PostgreSQL" /> | ||||
|     <file url="PROJECT" dialect="PostgreSQL" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										11
									
								
								.idea/todo-baggins.iml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.idea/todo-baggins.iml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <module type="EMPTY_MODULE" version="4"> | ||||
|   <component name="NewModuleRootManager"> | ||||
|     <content url="file://$MODULE_DIR$"> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/target" /> | ||||
|     </content> | ||||
|     <orderEntry type="inheritedJdk" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										12
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="UTF-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" /> | ||||
|     </profile> | ||||
|   </component> | ||||
|   <component name="VcsDirectoryMappings"> | ||||
|     <mapping directory="" vcs="Git" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										3041
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										3041
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										23
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| [package] | ||||
| name = "todo-baggins" | ||||
| version = "0.1.0" | ||||
| authors = ["Matouš Volf <66163112+matous-volf@users.noreply.github.com>"] | ||||
| 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"] } | ||||
|  | ||||
| dioxus = { version = "0.5", features = ["fullstack", "router"] } | ||||
|  | ||||
| # Debug | ||||
| dioxus-logger = "0.5.1" | ||||
| dotenvy = "0.15.7" | ||||
| serde = "1.0.208" | ||||
| validator = { version = "0.18.1", features = ["derive"] } | ||||
|  | ||||
| [features] | ||||
| default = [] | ||||
| server = ["dioxus/axum"] | ||||
| web = ["dioxus/web"] | ||||
							
								
								
									
										43
									
								
								Dioxus.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								Dioxus.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| [application] | ||||
|  | ||||
| # App (Project) Name | ||||
| name = "todo-baggins" | ||||
|  | ||||
| # Dioxus App Default Platform | ||||
| # web, desktop, fullstack | ||||
| default_platform = "fullstack" | ||||
|  | ||||
| # `build` & `serve` dist path | ||||
| out_dir = "dist" | ||||
|  | ||||
| # resource (assets) file folder | ||||
| asset_dir = "assets" | ||||
|  | ||||
| [web.app] | ||||
|  | ||||
| # HTML title tag content | ||||
| title = "Todo Baggins" | ||||
|  | ||||
| [web.watcher] | ||||
|  | ||||
| # when watcher trigger, regenerate the `index.html` | ||||
| reload_html = true | ||||
|  | ||||
| # which files or dirs will be watcher monitoring | ||||
| watch_path = ["src", "assets"] | ||||
|  | ||||
| # include `assets` in web platform | ||||
| [web.resource] | ||||
|  | ||||
| # CSS style file | ||||
|  | ||||
| style = ["/styles/tailwind_output.css"] | ||||
|  | ||||
| # Javascript code file | ||||
| script = [] | ||||
|  | ||||
| [web.resource.dev] | ||||
|  | ||||
| # Javascript code file | ||||
| # serve: [dev-server] only | ||||
| script = [] | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 130 KiB | 
							
								
								
									
										1
									
								
								assets/styles/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assets/styles/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| /tailwind_output.css | ||||
							
								
								
									
										6
									
								
								diesel.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								diesel.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| # For documentation on how to configure this file, | ||||
| # see https://diesel.rs/guides/configuring-diesel-cli | ||||
|  | ||||
| [print_schema] | ||||
| file = "src/schema/mod.rs" | ||||
| custom_type_derives = ["diesel::query_builder::QueryId", "Clone"] | ||||
							
								
								
									
										31
									
								
								docker-compose-dev.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								docker-compose-dev.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| services: | ||||
|   app: | ||||
|     build: | ||||
|       dockerfile: docker/dev/app/Dockerfile | ||||
|     volumes: | ||||
|       - ./.env.dev:/srv/app/.env | ||||
|       - ./assets:/srv/app/assets | ||||
|       - ./src:/srv/app/src | ||||
|       - ./migrations:/srv/app/migrations | ||||
|       - ./Cargo.lock:/srv/app/Cargo.lock | ||||
|       - ./Cargo.toml:/srv/app/Cargo.toml | ||||
|       - ./diesel.toml:/srv/app/diesel.toml | ||||
|       - ./Dioxus.toml:/srv/app/Dioxus.toml | ||||
|       - ./package.json:/srv/app/package.json | ||||
|       - ./package-lock.json:/srv/app/package-lock.json | ||||
|     restart: always | ||||
|     ports: [ "8000:8000" ] | ||||
|     depends_on: [ "db" ] | ||||
|  | ||||
|   db: | ||||
|     image: postgres:16.4-bookworm | ||||
|     volumes: [ "db_data:/var/lib/postgresql/data" ] | ||||
|     ports: [ "5432:5432" ] | ||||
|     environment: | ||||
|       POSTGRES_DB: todo_baggins | ||||
|       POSTGRES_USER: app | ||||
|       POSTGRES_PASSWORD: app | ||||
|     restart: always | ||||
|  | ||||
| volumes: | ||||
|   db_data: | ||||
							
								
								
									
										0
									
								
								docker-compose-prod.yml
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										0
									
								
								docker-compose-prod.yml
									
									
									
									
									
										Executable file
									
								
							
							
								
								
									
										23
									
								
								docker/dev/app/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								docker/dev/app/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| FROM rust:1.80-bookworm | ||||
|  | ||||
| RUN rustup target add wasm32-unknown-unknown && \ | ||||
|     cargo install dioxus-cli diesel_cli && \ | ||||
|     apt-get update && apt-get install -y nodejs=18.19.0+dfsg-6~deb12u2 npm=9.2.0~ds1-1 supervisor=4.2.5-1 | ||||
|  | ||||
| COPY . /srv/app | ||||
| WORKDIR /srv/app | ||||
|  | ||||
| RUN npm install | ||||
|  | ||||
| COPY docker/dev/app/supervisord.conf /etc/supervisor/conf.d/supervisord.conf | ||||
|  | ||||
| RUN chown -R 1000:1000 /srv/app && \ | ||||
|     chown -R 1000:1000 /usr/local/cargo && \ | ||||
|     mkdir -p /.local/share/dioxus && \ | ||||
|     chown -R 1000:1000 /.local/share/dioxus | ||||
|  | ||||
| HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1 | ||||
|  | ||||
| USER 1000:1000 | ||||
|  | ||||
| CMD ["sh", "docker/dev/app/entrypoint.sh"] | ||||
							
								
								
									
										5
									
								
								docker/dev/app/entrypoint.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								docker/dev/app/entrypoint.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| diesel migration run | ||||
|  | ||||
| supervisord -c /etc/supervisor/conf.d/supervisord.conf | ||||
							
								
								
									
										23
									
								
								docker/dev/app/supervisord.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								docker/dev/app/supervisord.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| [supervisord] | ||||
| nodaemon=true | ||||
| logfile=/dev/null | ||||
| logfile_maxbytes=0 | ||||
| pidfile=/dev/null | ||||
|  | ||||
| [program:npm] | ||||
| command=npm run watch | ||||
| directory=/srv/app | ||||
| autostart=true | ||||
| autorestart=true | ||||
| stdout_logfile=/dev/fd/1 | ||||
| stdout_logfile_maxbytes=0 | ||||
| redirect_stderr=true | ||||
|  | ||||
| [program:dx] | ||||
| command=dx serve | ||||
| directory=/srv/app | ||||
| autostart=true | ||||
| autorestart=true | ||||
| stdout_logfile=/dev/fd/1 | ||||
| stdout_logfile_maxbytes=0 | ||||
| redirect_stderr=true | ||||
							
								
								
									
										6
									
								
								migrations/00000000000000_diesel_initial_setup/down.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								migrations/00000000000000_diesel_initial_setup/down.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| -- This file was automatically created by Diesel to setup helper functions | ||||
| -- and other internal bookkeeping. This file is safe to edit, any future | ||||
| -- changes will be added to existing projects as new migrations. | ||||
|  | ||||
| DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); | ||||
| DROP FUNCTION IF EXISTS diesel_set_updated_at(); | ||||
							
								
								
									
										36
									
								
								migrations/00000000000000_diesel_initial_setup/up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								migrations/00000000000000_diesel_initial_setup/up.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| -- This file was automatically created by Diesel to setup helper functions | ||||
| -- and other internal bookkeeping. This file is safe to edit, any future | ||||
| -- changes will be added to existing projects as new migrations. | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| -- Sets up a trigger for the given table to automatically set a column called | ||||
| -- `updated_at` whenever the row is modified (unless `updated_at` was included | ||||
| -- in the modified columns) | ||||
| -- | ||||
| -- # Example | ||||
| -- | ||||
| -- ```sql | ||||
| -- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); | ||||
| -- | ||||
| -- SELECT diesel_manage_updated_at('users'); | ||||
| -- ``` | ||||
| CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ | ||||
| BEGIN | ||||
|     EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s | ||||
|                     FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); | ||||
| END; | ||||
| $$ LANGUAGE plpgsql; | ||||
|  | ||||
| CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ | ||||
| BEGIN | ||||
|     IF ( | ||||
|         NEW IS DISTINCT FROM OLD AND | ||||
|         NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at | ||||
|     ) THEN | ||||
|         NEW.updated_at := current_timestamp; | ||||
|     END IF; | ||||
|     RETURN NEW; | ||||
| END; | ||||
| $$ LANGUAGE plpgsql; | ||||
							
								
								
									
										2
									
								
								migrations/2024-08-16-221326_create_projects/down.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								migrations/2024-08-16-221326_create_projects/down.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| -- This file should undo anything in `up.sql` | ||||
| DROP TABLE IF EXISTS "projects"; | ||||
							
								
								
									
										6
									
								
								migrations/2024-08-16-221326_create_projects/up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								migrations/2024-08-16-221326_create_projects/up.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| -- Your SQL goes here | ||||
| CREATE TABLE "projects"( | ||||
| 	"id" SERIAL NOT NULL PRIMARY KEY, | ||||
| 	"title" TEXT NOT NULL | ||||
| ); | ||||
|  | ||||
							
								
								
									
										1386
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1386
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										9
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| { | ||||
|   "dependencies": { | ||||
|     "tailwindcss": "^3.4.6" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "build": "tailwindcss -c src/styles/tailwind.config.js -i src/styles/tailwind.css -o assets/styles/tailwind_output.css", | ||||
|     "watch": "npm run build -- --watch" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										11
									
								
								src/components/app.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/components/app.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| use crate::route::Route; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn App() -> Element { | ||||
|     rsx! { | ||||
|         Router::<Route> {} | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								src/components/home.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/components/home.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| use crate::components::project_form::ProjectForm; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn Home() -> Element { | ||||
|     rsx! { | ||||
|         ProjectForm {} | ||||
|     } | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/components/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/components/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| pub(crate) mod app; | ||||
| pub(crate) mod home; | ||||
| pub(crate) mod project_form; | ||||
							
								
								
									
										30
									
								
								src/components/project_form.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/components/project_form.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| use crate::models::project::NewProject; | ||||
| use crate::server::projects::create_project; | ||||
| use dioxus::core_macro::{component, rsx}; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn ProjectForm() -> Element { | ||||
|     rsx! { | ||||
|         form { | ||||
|             onsubmit: move |event| { | ||||
|                 async move { | ||||
|                     let new_project = NewProject::new( | ||||
|                         event.values().get("title").unwrap().as_value() | ||||
|                     ); | ||||
|                     let _ = create_project(new_project).await; | ||||
|                 } | ||||
|             }, | ||||
|             input { | ||||
|                 r#type: "text", | ||||
|                 name: "title", | ||||
|                 placeholder: "title" | ||||
|             } | ||||
|             button { | ||||
|                 r#type: "submit", | ||||
|                 "create" | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/errors/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/errors/error.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::fmt::Display; | ||||
| use std::str::FromStr; | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Debug)] | ||||
| pub enum Error { | ||||
|     ServerInternal, | ||||
| } | ||||
|  | ||||
| // has to be implemented for Dioxus server functions | ||||
| impl Display for Error { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             Error::ServerInternal => write!(f, "internal server error"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // has to be implemented for Dioxus server functions | ||||
| impl FromStr for Error { | ||||
|     type Err = (); | ||||
|  | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         Ok(match s { | ||||
|             "internal server error" => Error::ServerInternal, | ||||
|             _ => return Err(()), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										43
									
								
								src/errors/error_vec.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/errors/error_vec.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| use std::fmt::Display; | ||||
| use std::str::FromStr; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct ErrorVec<T> { | ||||
|     errors: Vec<T>, | ||||
| } | ||||
|  | ||||
| impl<T> From<ErrorVec<T>> for Vec<T> { | ||||
|     fn from(e: ErrorVec<T>) -> Self { | ||||
|         e.errors | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> From<Vec<T>> for ErrorVec<T> { | ||||
|     fn from(e: Vec<T>) -> Self { | ||||
|         ErrorVec { errors: e } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // has to be implemented for Dioxus server functions | ||||
| impl<T: Display> Display for ErrorVec<T> { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         write!( | ||||
|             f, | ||||
|             "{}", | ||||
|             self.errors | ||||
|                 .iter() | ||||
|                 .map(|e| e.to_string()) | ||||
|                 .collect::<Vec<String>>() | ||||
|                 .join("\n") | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // has to be implemented for Dioxus server functions | ||||
| impl<T> FromStr for ErrorVec<T> { | ||||
|     type Err = (); | ||||
|  | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         Ok(ErrorVec { errors: Vec::new() }) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/errors/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/errors/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| pub(crate) mod error; | ||||
| pub(crate) mod error_vec; | ||||
| pub(crate) mod project_create_error; | ||||
							
								
								
									
										51
									
								
								src/errors/project_create_error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/errors/project_create_error.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| 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 ProjectCreateError { | ||||
|     TitleLengthInvalid, | ||||
|     Error(Error), | ||||
| } | ||||
|  | ||||
| impl From<ValidationErrors> for ErrorVec<ProjectCreateError> { | ||||
|     fn from(e: ValidationErrors) -> Self { | ||||
|         e.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" => ProjectCreateError::TitleLengthInvalid, | ||||
|                             _ => panic!("unexpected validation error code: {code}"), | ||||
|                         }) | ||||
|                         .collect::<Vec<ProjectCreateError>>(), | ||||
|                     _ => panic!("unexpected validation error kind"), | ||||
|                 }, | ||||
|                 _ => panic!("unexpected validation field name: {field}"), | ||||
|             }) | ||||
|             .collect::<Vec<ProjectCreateError>>() | ||||
|             .into() | ||||
|     } | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| impl FromStr for ProjectCreateError { | ||||
|     type Err = (); | ||||
|  | ||||
|     fn from_str(_: &str) -> Result<Self, Self::Err> { | ||||
|         Ok(ProjectCreateError::TitleLengthInvalid) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| mod components; | ||||
| mod errors; | ||||
| mod models; | ||||
| mod route; | ||||
| mod schema; | ||||
| mod server; | ||||
|  | ||||
| use components::app::App; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_logger::tracing::{info, Level}; | ||||
|  | ||||
| fn main() { | ||||
|     dioxus_logger::init(Level::INFO).expect("failed to initialize logger"); | ||||
|     info!("starting app"); | ||||
|  | ||||
|     let cfg = server_only!( | ||||
|         dioxus::fullstack::Config::new().addr(std::net::SocketAddr::from(([0, 0, 0, 0], 8000))) | ||||
|     ); | ||||
|  | ||||
|     LaunchBuilder::fullstack().with_cfg(cfg).launch(App); | ||||
| } | ||||
							
								
								
									
										1
									
								
								src/models/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/models/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| pub(crate) mod project; | ||||
							
								
								
									
										38
									
								
								src/models/project.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/models/project.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| use crate::schema::projects; | ||||
| use diesel::prelude::*; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use validator::Validate; | ||||
|  | ||||
| const TITLE_LENGTH_MIN: u64 = 1; | ||||
| const TITLE_LENGTH_MAX: u64 = 255; | ||||
|  | ||||
| #[derive(Queryable, Selectable, Serialize, Deserialize, Debug)] | ||||
| #[diesel(table_name = crate::schema::projects)] | ||||
| #[diesel(check_for_backend(diesel::pg::Pg))] | ||||
| pub struct Project { | ||||
|     id: i32, | ||||
|     title: String, | ||||
| } | ||||
|  | ||||
| impl Project { | ||||
|     pub fn id(&self) -> i32 { | ||||
|         self.id | ||||
|     } | ||||
|  | ||||
|     pub fn title(&self) -> &str { | ||||
|         &self.title | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Insertable, Serialize, Deserialize, Validate, Clone, Debug)] | ||||
| #[diesel(table_name = projects)] | ||||
| pub struct NewProject { | ||||
|     #[validate(length(min = "TITLE_LENGTH_MIN", max = "TITLE_LENGTH_MAX", code = "title_length"))] | ||||
|     pub title: String, | ||||
| } | ||||
|  | ||||
| impl NewProject { | ||||
|     pub fn new(title: String) -> Self { | ||||
|         Self { title } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										8
									
								
								src/route/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/route/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| use crate::components::home::Home; | ||||
| use dioxus::prelude::*; | ||||
|  | ||||
| #[derive(Clone, Routable, Debug, PartialEq)] | ||||
| pub(crate) enum Route { | ||||
|     #[route("/")] | ||||
|     Home {}, | ||||
| } | ||||
							
								
								
									
										8
									
								
								src/schema/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/schema/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| // @generated automatically by Diesel CLI. | ||||
|  | ||||
| diesel::table! { | ||||
|     projects (id) { | ||||
|         id -> Int4, | ||||
|         title -> Text, | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/server/database_connection.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/server/database_connection.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| use diesel::pg::PgConnection; | ||||
| use diesel::prelude::*; | ||||
| use dotenvy::dotenv; | ||||
| use std::env; | ||||
|  | ||||
| pub(crate) fn establish_database_connection() -> ConnectionResult<PgConnection> { | ||||
|     dotenv().ok(); | ||||
|  | ||||
|     let database_url = | ||||
|         env::var("DATABASE_URL").expect("The environment variable DATABASE_URL must be set."); | ||||
|     PgConnection::establish(&database_url) | ||||
| } | ||||
							
								
								
									
										2
									
								
								src/server/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/server/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| mod database_connection; | ||||
| pub(crate) mod projects; | ||||
							
								
								
									
										34
									
								
								src/server/projects.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/server/projects.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| use crate::errors::error::Error; | ||||
| 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 dioxus::prelude::*; | ||||
| use validator::Validate; | ||||
|  | ||||
| #[server] | ||||
| pub(crate) async fn create_project( | ||||
|     new_project: NewProject, | ||||
| ) -> Result<Project, ServerFnError<ErrorVec<ProjectCreateError>>> { | ||||
|     use crate::schema::projects; | ||||
|  | ||||
|     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() | ||||
|         )?; | ||||
|  | ||||
|     let new_project = diesel::insert_into(projects::table) | ||||
|         .values(&new_project) | ||||
|         .returning(Project::as_returning()) | ||||
|         .get_result(&mut connection) | ||||
|         .map_err::<ErrorVec<ProjectCreateError>, _>( | ||||
|             |_| vec![ProjectCreateError::Error(Error::ServerInternal), ].into() | ||||
|         )?; | ||||
|  | ||||
|     Ok(new_project) | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/styles/tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/styles/tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| /** @type {import('tailwindcss').Config} */ | ||||
| module.exports = { | ||||
|     mode: "all", | ||||
|     content: ["./src/**/*.{rs,html,css}", "./dist/**/*.html"], | ||||
|     theme: { | ||||
|         extend: {}, | ||||
|     }, | ||||
|     plugins: [], | ||||
| }; | ||||
							
								
								
									
										8
									
								
								src/styles/tailwind.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/styles/tailwind.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| /* stylelint-disable */ | ||||
| /* noinspection CssInvalidAtRule */ | ||||
| @tailwind base; | ||||
| /* noinspection CssInvalidAtRule */ | ||||
| @tailwind components; | ||||
| /* noinspection CssInvalidAtRule */ | ||||
| @tailwind utilities; | ||||
| /* stylelint-enable */ | ||||
		Reference in New Issue
	
	Block a user