diff --git a/Cargo.lock b/Cargo.lock index aa08b5c..302cb77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3414,6 +3414,7 @@ dependencies = [ "saleor-app-sdk", "semver", "serde", + "strum 0.26.2", "surrealdb", "thiserror", "tokio", @@ -3923,6 +3924,9 @@ name = "strum" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros 0.26.2", +] [[package]] name = "strum_macros" diff --git a/Cargo.toml b/Cargo.toml index 3ed93ed..bf6b035 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ serde = { version = "1.0.202", features = ["derive"] } semver = { version = "1.0.23", features = ["serde"] } saleor-app-sdk = { version = "0.2.3", default-features = false } chrono = { version = "0.4.38", features = ["serde"] } +strum = { version = "0.26.2", features = ["derive"] } [features] hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"] diff --git a/db/000073.log b/db/000073.log new file mode 100644 index 0000000..5743ec3 Binary files /dev/null and b/db/000073.log differ diff --git a/db/000077.sst b/db/000077.sst new file mode 100644 index 0000000..86dc836 Binary files /dev/null and b/db/000077.sst differ diff --git a/db/CURRENT b/db/CURRENT new file mode 100644 index 0000000..f8d57cc --- /dev/null +++ b/db/CURRENT @@ -0,0 +1 @@ +MANIFEST-000074 diff --git a/db/IDENTITY b/db/IDENTITY new file mode 100644 index 0000000..35f14cb --- /dev/null +++ b/db/IDENTITY @@ -0,0 +1 @@ +b5f7ce4a-316f-4c07-b7bc-cd8d68a9439c \ No newline at end of file diff --git a/db/LOCK b/db/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG b/db/LOG new file mode 100644 index 0000000..ccc994d --- /dev/null +++ b/db/LOG @@ -0,0 +1 @@ +2024/06/03-19:37:28.956980 624181 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717436248 acquiring thread 624180: db/LOCK: No locks available diff --git a/db/LOG.old.1717435701378412 b/db/LOG.old.1717435701378412 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717435706407552 b/db/LOG.old.1717435706407552 new file mode 100644 index 0000000..8f96461 --- /dev/null +++ b/db/LOG.old.1717435706407552 @@ -0,0 +1 @@ +2024/06/03-19:28:21.378715 614548 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717435701 acquiring thread 614547: db/LOCK: No locks available diff --git a/db/LOG.old.1717435706433232 b/db/LOG.old.1717435706433232 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717435724748969 b/db/LOG.old.1717435724748969 new file mode 100644 index 0000000..ddd0fc6 --- /dev/null +++ b/db/LOG.old.1717435724748969 @@ -0,0 +1 @@ +2024/06/03-19:28:26.433575 614548 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717435706 acquiring thread 614547: db/LOCK: No locks available diff --git a/db/LOG.old.1717435729131921 b/db/LOG.old.1717435729131921 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717435729162210 b/db/LOG.old.1717435729162210 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717435750726033 b/db/LOG.old.1717435750726033 new file mode 100644 index 0000000..247f669 --- /dev/null +++ b/db/LOG.old.1717435750726033 @@ -0,0 +1 @@ +2024/06/03-19:28:49.162709 615596 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717435729 acquiring thread 615595: db/LOCK: No locks available diff --git a/db/LOG.old.1717435750753549 b/db/LOG.old.1717435750753549 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717435798384726 b/db/LOG.old.1717435798384726 new file mode 100644 index 0000000..6c4fbd6 --- /dev/null +++ b/db/LOG.old.1717435798384726 @@ -0,0 +1 @@ +2024/06/03-19:29:10.753898 616639 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717435750 acquiring thread 616638: db/LOCK: No locks available diff --git a/db/LOG.old.1717435798416760 b/db/LOG.old.1717435798416760 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717435802312556 b/db/LOG.old.1717435802312556 new file mode 100644 index 0000000..66f5ef1 --- /dev/null +++ b/db/LOG.old.1717435802312556 @@ -0,0 +1 @@ +2024/06/03-19:29:58.417187 617450 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717435798 acquiring thread 617449: db/LOCK: No locks available diff --git a/db/LOG.old.1717435946446866 b/db/LOG.old.1717435946446866 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717435946481362 b/db/LOG.old.1717435946481362 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717435984147165 b/db/LOG.old.1717435984147165 new file mode 100644 index 0000000..5d61e58 --- /dev/null +++ b/db/LOG.old.1717435984147165 @@ -0,0 +1 @@ +2024/06/03-19:32:26.481702 619379 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717435946 acquiring thread 619378: db/LOCK: No locks available diff --git a/db/LOG.old.1717435984174324 b/db/LOG.old.1717435984174324 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717436222135051 b/db/LOG.old.1717436222135051 new file mode 100644 index 0000000..8cd5df4 --- /dev/null +++ b/db/LOG.old.1717436222135051 @@ -0,0 +1 @@ +2024/06/03-19:33:04.174695 620857 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717435984 acquiring thread 620856: db/LOCK: No locks available diff --git a/db/LOG.old.1717436222174269 b/db/LOG.old.1717436222174269 new file mode 100644 index 0000000..e69de29 diff --git a/db/LOG.old.1717436248932389 b/db/LOG.old.1717436248932389 new file mode 100644 index 0000000..8898568 --- /dev/null +++ b/db/LOG.old.1717436248932389 @@ -0,0 +1 @@ +2024/06/03-19:37:02.174732 623193 [WARN] [db/db_impl/db_impl_open.cc:2074] DB::Open() failed: IO error: lock hold by current process, acquire time 1717436222 acquiring thread 623192: db/LOCK: No locks available diff --git a/db/LOG.old.1717436248956615 b/db/LOG.old.1717436248956615 new file mode 100644 index 0000000..e69de29 diff --git a/db/MANIFEST-000074 b/db/MANIFEST-000074 new file mode 100644 index 0000000..11ca6f4 Binary files /dev/null and b/db/MANIFEST-000074 differ diff --git a/db/OPTIONS-000071 b/db/OPTIONS-000071 new file mode 100644 index 0000000..8f0fb8c --- /dev/null +++ b/db/OPTIONS-000071 @@ -0,0 +1,199 @@ +# This is a RocksDB option file. +# +# For detailed file format spec, please refer to the example file +# in examples/rocksdb_option_file_example.ini +# + +[Version] + rocksdb_version=8.1.1 + options_file_version=1.1 + +[DBOptions] + compaction_readahead_size=0 + strict_bytes_per_sync=false + bytes_per_sync=0 + max_background_jobs=16 + avoid_flush_during_shutdown=false + max_background_flushes=-1 + delayed_write_rate=16777216 + max_open_files=-1 + max_subcompactions=1 + writable_file_max_buffer_size=1048576 + wal_bytes_per_sync=0 + max_background_compactions=-1 + max_total_wal_size=0 + delete_obsolete_files_period_micros=21600000000 + stats_dump_period_sec=600 + stats_history_buffer_size=1048576 + stats_persist_period_sec=600 + enforce_single_del_contracts=true + lowest_used_cache_tier=kNonVolatileBlockTier + bgerror_resume_retry_interval=1000000 + best_efforts_recovery=false + log_readahead_size=0 + write_dbid_to_manifest=false + wal_compression=kNoCompression + manual_wal_flush=false + db_host_id=__hostname__ + two_write_queues=false + random_access_max_buffer_size=1048576 + avoid_unnecessary_blocking_io=false + skip_checking_sst_file_sizes_on_db_open=false + flush_verify_memtable_count=true + fail_if_options_file_error=false + atomic_flush=false + verify_sst_unique_id_in_manifest=true + skip_stats_update_on_db_open=false + track_and_verify_wals_in_manifest=false + paranoid_checks=true + create_if_missing=true + max_write_batch_group_size_bytes=1048576 + avoid_flush_during_recovery=false + file_checksum_gen_factory=nullptr + enable_thread_tracking=false + allow_fallocate=true + allow_data_in_errors=false + error_if_exists=false + use_direct_io_for_flush_and_compaction=false + create_missing_column_families=true + WAL_size_limit_MB=0 + use_direct_reads=false + persist_stats_to_disk=false + allow_mmap_reads=false + allow_mmap_writes=false + use_adaptive_mutex=false + allow_2pc=false + is_fd_close_on_exec=true + max_log_file_size=0 + access_hint_on_compaction_start=NORMAL + max_file_opening_threads=16 + wal_filter=nullptr + use_fsync=false + table_cache_numshardbits=6 + dump_malloc_stats=false + db_write_buffer_size=0 + allow_ingest_behind=false + keep_log_file_num=20 + max_bgerror_resume_count=2147483647 + allow_concurrent_memtable_write=true + recycle_log_file_num=0 + log_file_time_to_roll=0 + manifest_preallocation_size=4194304 + enable_write_thread_adaptive_yield=true + WAL_ttl_seconds=0 + max_manifest_file_size=1073741824 + wal_recovery_mode=kPointInTimeRecovery + enable_pipelined_write=true + write_thread_slow_yield_usec=3 + unordered_write=false + write_thread_max_yield_usec=100 + advise_random_on_open=true + info_log_level=WARN_LEVEL + + +[CFOptions "default"] + compression_opts={max_dict_buffer_bytes=0;enabled=false;max_dict_bytes=0;parallel_threads=1;zstd_max_train_bytes=0;level=32767;use_zstd_dict_trainer=true;strategy=0;window_bits=-14;} + memtable_protection_bytes_per_key=0 + target_file_size_multiplier=1 + report_bg_io_stats=false + write_buffer_size=268435456 + memtable_huge_page_size=0 + max_successive_merges=0 + max_write_buffer_number=32 + prefix_extractor=nullptr + bottommost_compression_opts={max_dict_buffer_bytes=0;enabled=false;max_dict_bytes=0;parallel_threads=1;zstd_max_train_bytes=0;level=32767;use_zstd_dict_trainer=true;strategy=0;window_bits=-14;} + paranoid_file_checks=false + blob_garbage_collection_force_threshold=1.000000 + enable_blob_files=true + blob_file_starting_level=0 + memtable_prefix_bloom_size_ratio=0.000000 + inplace_update_num_locks=10000 + blob_compaction_readahead_size=0 + ignore_max_compaction_bytes_for_input=true + arena_block_size=1048576 + level0_stop_writes_trigger=36 + blob_compression_type=kNoCompression + level0_slowdown_writes_trigger=20 + hard_pending_compaction_bytes_limit=274877906944 + soft_pending_compaction_bytes_limit=68719476736 + target_file_size_base=536870912 + level0_file_num_compaction_trigger=4 + max_compaction_bytes=13421772800 + disable_auto_compactions=false + check_flush_compaction_key_order=true + min_blob_size=4096 + memtable_whole_key_filtering=false + max_bytes_for_level_base=268435456 + last_level_temperature=kUnknown + compaction_options_fifo={allow_compaction=false;age_for_warm=0;max_table_files_size=1073741824;} + max_bytes_for_level_multiplier=10.000000 + compression_per_level=kNoCompression:kNoCompression:kLZ4HCCompression:kLZ4HCCompression:kLZ4HCCompression + max_bytes_for_level_multiplier_additional=1:1:1:1:1:1:1 + max_sequential_skip_in_iterations=8 + prepopulate_blob_cache=kDisable + compression=kSnappyCompression + compaction_options_universal={incremental=false;compression_size_percent=-1;allow_trivial_move=false;max_size_amplification_percent=200;max_merge_width=4294967295;stop_style=kCompactionStopStyleTotalSize;min_merge_width=2;size_ratio=1;} + blob_garbage_collection_age_cutoff=0.250000 + ttl=2592000 + periodic_compaction_seconds=0 + sample_for_compression=0 + blob_file_size=268435456 + enable_blob_garbage_collection=false + experimental_mempurge_threshold=0.000000 + bottommost_compression=kDisableCompressionOption + min_write_buffer_number_to_merge=4 + preserve_internal_time_seconds=0 + preclude_last_level_data_seconds=0 + sst_partitioner_factory=nullptr + num_levels=7 + force_consistency_checks=true + memtable_insert_with_hint_prefix_extractor=nullptr + memtable_factory=SkipListFactory + level_compaction_dynamic_file_size=true + max_write_buffer_number_to_maintain=0 + optimize_filters_for_hits=false + level_compaction_dynamic_level_bytes=false + compaction_style=kCompactionStyleLevel + compaction_filter=nullptr + inplace_update_support=false + merge_operator=nullptr + table_factory=BlockBasedTable + bloom_locality=0 + comparator=leveldb.BytewiseComparator + compaction_filter_factory=nullptr + max_write_buffer_size_to_maintain=8589934592 + compaction_pri=kMinOverlappingRatio + +[TableOptions/BlockBasedTable "default"] + initial_auto_readahead_size=8192 + pin_top_level_index_and_filter=true + block_align=false + block_size_deviation=10 + checksum=kXXH3 + index_shortening=kShortenSeparators + num_file_reads_for_auto_readahead=2 + whole_key_filtering=true + data_block_index_type=kDataBlockBinarySearch + index_type=kBinarySearch + no_block_cache=false + index_block_restart_interval=1 + data_block_hash_table_util_ratio=0.750000 + prepopulate_block_cache=kDisable + pin_l0_filter_and_index_blocks_in_cache=false + filter_policy=nullptr + cache_index_and_filter_blocks_with_high_priority=true + verify_compression=false + block_restart_interval=16 + max_auto_readahead_size=262144 + flush_block_policy_factory=FlushBlockBySizePolicyFactory + partition_filters=false + cache_index_and_filter_blocks=false + block_size=4096 + metadata_block_size=4096 + optimize_filters_for_memory=false + detect_filter_construct_corruption=false + format_version=5 + metadata_cache_options={unpartitioned_pinning=kFallback;partition_pinning=kFallback;top_level_index_pinning=kFallback;} + read_amp_bytes_per_bit=0 + enable_index_compression=true + diff --git a/db/OPTIONS-000076 b/db/OPTIONS-000076 new file mode 100644 index 0000000..8f0fb8c --- /dev/null +++ b/db/OPTIONS-000076 @@ -0,0 +1,199 @@ +# This is a RocksDB option file. +# +# For detailed file format spec, please refer to the example file +# in examples/rocksdb_option_file_example.ini +# + +[Version] + rocksdb_version=8.1.1 + options_file_version=1.1 + +[DBOptions] + compaction_readahead_size=0 + strict_bytes_per_sync=false + bytes_per_sync=0 + max_background_jobs=16 + avoid_flush_during_shutdown=false + max_background_flushes=-1 + delayed_write_rate=16777216 + max_open_files=-1 + max_subcompactions=1 + writable_file_max_buffer_size=1048576 + wal_bytes_per_sync=0 + max_background_compactions=-1 + max_total_wal_size=0 + delete_obsolete_files_period_micros=21600000000 + stats_dump_period_sec=600 + stats_history_buffer_size=1048576 + stats_persist_period_sec=600 + enforce_single_del_contracts=true + lowest_used_cache_tier=kNonVolatileBlockTier + bgerror_resume_retry_interval=1000000 + best_efforts_recovery=false + log_readahead_size=0 + write_dbid_to_manifest=false + wal_compression=kNoCompression + manual_wal_flush=false + db_host_id=__hostname__ + two_write_queues=false + random_access_max_buffer_size=1048576 + avoid_unnecessary_blocking_io=false + skip_checking_sst_file_sizes_on_db_open=false + flush_verify_memtable_count=true + fail_if_options_file_error=false + atomic_flush=false + verify_sst_unique_id_in_manifest=true + skip_stats_update_on_db_open=false + track_and_verify_wals_in_manifest=false + paranoid_checks=true + create_if_missing=true + max_write_batch_group_size_bytes=1048576 + avoid_flush_during_recovery=false + file_checksum_gen_factory=nullptr + enable_thread_tracking=false + allow_fallocate=true + allow_data_in_errors=false + error_if_exists=false + use_direct_io_for_flush_and_compaction=false + create_missing_column_families=true + WAL_size_limit_MB=0 + use_direct_reads=false + persist_stats_to_disk=false + allow_mmap_reads=false + allow_mmap_writes=false + use_adaptive_mutex=false + allow_2pc=false + is_fd_close_on_exec=true + max_log_file_size=0 + access_hint_on_compaction_start=NORMAL + max_file_opening_threads=16 + wal_filter=nullptr + use_fsync=false + table_cache_numshardbits=6 + dump_malloc_stats=false + db_write_buffer_size=0 + allow_ingest_behind=false + keep_log_file_num=20 + max_bgerror_resume_count=2147483647 + allow_concurrent_memtable_write=true + recycle_log_file_num=0 + log_file_time_to_roll=0 + manifest_preallocation_size=4194304 + enable_write_thread_adaptive_yield=true + WAL_ttl_seconds=0 + max_manifest_file_size=1073741824 + wal_recovery_mode=kPointInTimeRecovery + enable_pipelined_write=true + write_thread_slow_yield_usec=3 + unordered_write=false + write_thread_max_yield_usec=100 + advise_random_on_open=true + info_log_level=WARN_LEVEL + + +[CFOptions "default"] + compression_opts={max_dict_buffer_bytes=0;enabled=false;max_dict_bytes=0;parallel_threads=1;zstd_max_train_bytes=0;level=32767;use_zstd_dict_trainer=true;strategy=0;window_bits=-14;} + memtable_protection_bytes_per_key=0 + target_file_size_multiplier=1 + report_bg_io_stats=false + write_buffer_size=268435456 + memtable_huge_page_size=0 + max_successive_merges=0 + max_write_buffer_number=32 + prefix_extractor=nullptr + bottommost_compression_opts={max_dict_buffer_bytes=0;enabled=false;max_dict_bytes=0;parallel_threads=1;zstd_max_train_bytes=0;level=32767;use_zstd_dict_trainer=true;strategy=0;window_bits=-14;} + paranoid_file_checks=false + blob_garbage_collection_force_threshold=1.000000 + enable_blob_files=true + blob_file_starting_level=0 + memtable_prefix_bloom_size_ratio=0.000000 + inplace_update_num_locks=10000 + blob_compaction_readahead_size=0 + ignore_max_compaction_bytes_for_input=true + arena_block_size=1048576 + level0_stop_writes_trigger=36 + blob_compression_type=kNoCompression + level0_slowdown_writes_trigger=20 + hard_pending_compaction_bytes_limit=274877906944 + soft_pending_compaction_bytes_limit=68719476736 + target_file_size_base=536870912 + level0_file_num_compaction_trigger=4 + max_compaction_bytes=13421772800 + disable_auto_compactions=false + check_flush_compaction_key_order=true + min_blob_size=4096 + memtable_whole_key_filtering=false + max_bytes_for_level_base=268435456 + last_level_temperature=kUnknown + compaction_options_fifo={allow_compaction=false;age_for_warm=0;max_table_files_size=1073741824;} + max_bytes_for_level_multiplier=10.000000 + compression_per_level=kNoCompression:kNoCompression:kLZ4HCCompression:kLZ4HCCompression:kLZ4HCCompression + max_bytes_for_level_multiplier_additional=1:1:1:1:1:1:1 + max_sequential_skip_in_iterations=8 + prepopulate_blob_cache=kDisable + compression=kSnappyCompression + compaction_options_universal={incremental=false;compression_size_percent=-1;allow_trivial_move=false;max_size_amplification_percent=200;max_merge_width=4294967295;stop_style=kCompactionStopStyleTotalSize;min_merge_width=2;size_ratio=1;} + blob_garbage_collection_age_cutoff=0.250000 + ttl=2592000 + periodic_compaction_seconds=0 + sample_for_compression=0 + blob_file_size=268435456 + enable_blob_garbage_collection=false + experimental_mempurge_threshold=0.000000 + bottommost_compression=kDisableCompressionOption + min_write_buffer_number_to_merge=4 + preserve_internal_time_seconds=0 + preclude_last_level_data_seconds=0 + sst_partitioner_factory=nullptr + num_levels=7 + force_consistency_checks=true + memtable_insert_with_hint_prefix_extractor=nullptr + memtable_factory=SkipListFactory + level_compaction_dynamic_file_size=true + max_write_buffer_number_to_maintain=0 + optimize_filters_for_hits=false + level_compaction_dynamic_level_bytes=false + compaction_style=kCompactionStyleLevel + compaction_filter=nullptr + inplace_update_support=false + merge_operator=nullptr + table_factory=BlockBasedTable + bloom_locality=0 + comparator=leveldb.BytewiseComparator + compaction_filter_factory=nullptr + max_write_buffer_size_to_maintain=8589934592 + compaction_pri=kMinOverlappingRatio + +[TableOptions/BlockBasedTable "default"] + initial_auto_readahead_size=8192 + pin_top_level_index_and_filter=true + block_align=false + block_size_deviation=10 + checksum=kXXH3 + index_shortening=kShortenSeparators + num_file_reads_for_auto_readahead=2 + whole_key_filtering=true + data_block_index_type=kDataBlockBinarySearch + index_type=kBinarySearch + no_block_cache=false + index_block_restart_interval=1 + data_block_hash_table_util_ratio=0.750000 + prepopulate_block_cache=kDisable + pin_l0_filter_and_index_blocks_in_cache=false + filter_policy=nullptr + cache_index_and_filter_blocks_with_high_priority=true + verify_compression=false + block_restart_interval=16 + max_auto_readahead_size=262144 + flush_block_policy_factory=FlushBlockBySizePolicyFactory + partition_filters=false + cache_index_and_filter_blocks=false + block_size=4096 + metadata_block_size=4096 + optimize_filters_for_memory=false + detect_filter_construct_corruption=false + format_version=5 + metadata_cache_options={unpartitioned_pinning=kFallback;partition_pinning=kFallback;top_level_index_pinning=kFallback;} + read_amp_bytes_per_bit=0 + enable_index_compression=true + diff --git a/src/app.rs b/src/app.rs index 9724dd0..1fd67b2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,10 +1,17 @@ +use crate::components::header::Header; use crate::error_template::{AppError, ErrorTemplate}; -use crate::server::types::SaleorApp; - +use crate::routes::apps::Apps; +use crate::routes::guides::Guides; +use crate::routes::home::Home; use leptos::*; use leptos_meta::*; use leptos_router::*; +#[derive(Params, PartialEq)] +pub struct UrlAppParams { + slug: String, +} + #[component] pub fn App() -> impl IntoView { // Provides context that manages stylesheets, titles, meta tags, etc. @@ -14,43 +21,25 @@ pub fn App() -> impl IntoView { // sets the document title - + <Title text="Saleors Harbour"/> + <Header/> // content for this welcome page <Router fallback=|| { let mut outside_errors = Errors::default(); outside_errors.insert_with_default_key(AppError::NotFound); view! { <ErrorTemplate outside_errors/> }.into_view() }> - <main> + <main class="p-4 md:p-8 md:px-16"> <Routes> - <Route path="" view=HomePage/> + <Route path="" view=Home/> + <Route path="/apps" view=Apps/> + <Route path="/apps/" view=Apps/> + <Route path="/apps/create" view=Apps/> + <Route path="/apps/update/:slug" view=Apps/> + <Route path="/guides" view=Guides/> </Routes> </main> </Router> } } - -#[server] -pub async fn get_all_apps() -> Result<Vec<SaleorApp>, ServerFnError>{ - let conn = crate::server::db::connect()?; - let res = conn.query("SELECT * FROM saleor_app WHERE saleor_app.name ='Sitemap generator' "); - dbg!(&res); - _ = res.await; - Err(ServerFnError::new("rip")) -} - -/// Renders the home page of your application. -#[component] -fn HomePage() -> impl IntoView { - let apps = create_resource(|| (), |_| async move {get_all_apps().await}); - view! { - <h1>"Welcome to Leptos!"</h1> - {move || match apps.get() { - Some(_d) => view! { <p>"loaded smt"</p> }.into_view(), - None => view! { <p>"loading..."</p> }.into_view(), - }} - - <div></div> - } -} diff --git a/src/components/app_list.rs b/src/components/app_list.rs new file mode 100644 index 0000000..c4b97ca --- /dev/null +++ b/src/components/app_list.rs @@ -0,0 +1,40 @@ +use leptos::*; + +use crate::server::functions::get_all_apps; + + +#[component] +pub fn app_list() -> impl IntoView { + let apps = create_resource(|| (), |_| async move {get_all_apps().await}); + view! { + <h1>"Welcome to Leptos!"</h1> + <Suspense fallback=move || { + view! { <p>"Loading..."</p> } + }> + {move || { + apps.get() + .map(|apps| { + match apps { + Ok(apps) => { + view! { + <ul> + + {apps + .into_iter() + .map(|app| view! { <li>{app.name}</li> }) + .collect_view()} + </ul> + } + .into_view() + } + Err(e) => { + view! { <p>"Failed fetching apps, " {e.to_string()}</p> } + .into_view() + } + } + }) + }} + + </Suspense> + } +} diff --git a/src/components/header.rs b/src/components/header.rs new file mode 100644 index 0000000..923b83b --- /dev/null +++ b/src/components/header.rs @@ -0,0 +1,42 @@ +use crate::components::search::Search; +use leptos::*; + +#[component] +pub fn Header() -> impl IntoView { + view! { + <header> + <div class="z-10 w-full px-4 lg:px-8 h-12 md:h-18 items-center align-center + bg-brand-sea-500 font-sans grid grid-cols-3"> + <ul class="flex flex-row gap-4 text-brand-white"> + <li> + <a href="/">home</a> + </li> + + <li> + <a href="/apps">apps</a> + </li> + + <li> + <a href="/guides">guides</a> + </li> + </ul> + <span class="text-xl font-bold text-brand-sea-100 w-fit mx-auto"> + <a href="/">"Saleors Harbour"</a> + </span> + + <Search/> + <div> + <script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script> + <script> + kofiWidgetOverlay.draw("djkato", { + "type": "floating-chat", + "floating-chat.donateButton.text": "Support me", + "floating-chat.donateButton.background-color": "#094074", + "floating-chat.donateButton.text-color": "#FEF9EF" + }); + </script> + </div> + </div> + </header> + } +} diff --git a/src/components/mod.rs b/src/components/mod.rs new file mode 100644 index 0000000..1ad4a86 --- /dev/null +++ b/src/components/mod.rs @@ -0,0 +1,4 @@ +pub mod app_list; +pub mod header; +pub mod search; +pub mod universal; diff --git a/src/components/search.rs b/src/components/search.rs new file mode 100644 index 0000000..fb375b1 --- /dev/null +++ b/src/components/search.rs @@ -0,0 +1,33 @@ +use crate::components::universal::text_line::TextLine; +use leptos::*; + +#[component] +pub fn Search() -> impl IntoView { + let (search_text, search_text_setter) = create_signal("".to_string()); + view! { + <div class="transition-all focus-within:fixed focus-within:z-50 top-12 left-0 right-0 + focus-within:p-4 focus-within:pt-8 focus-within:h-screen focus-within:bg-brand-monochrome-100 + md:focus-within:static md:focus-within:h-auto md:focus-within:bg-transparent md:focus-within:p-0"> + <div class="relative"> + // <TextLine {theme_inverse} error_atom={_error} value={_search_text} type={"text"} title="Čo hľadáte?" name="productSearch" /> + <TextLine title="Čo hľadáte?" required=false value_setter=search_text_setter/> + </div> + // {#if products} + // <div + // class="hidden group-focus-within/search:block pt-8 md:pt-0 md:absolute md:w-[24rem] rounded-base md:gentle-shadow + // bg-brand-monochrome-100 overflow-scroll h-screen md:h-[80vh]"> + // <div class="grid grid-cols-1 gap-4 h-fit w-full md:fit p-4"> + // {#each products as product} + // <ProductCardCompact product={product.node} /> + // {/each} + // {#if products.length == 0} + // <div class="w-full min-h-[8rem] relative flex items-center justify-center text-brand-cyan-600"> + // <span class="text-lg">Nič sa nenašlo...</span> + // </div> + // {/if} + // </div> + // </div> + // {/if} + </div> + } +} diff --git a/src/components/universal/app_editor.rs b/src/components/universal/app_editor.rs new file mode 100644 index 0000000..b4bf0a7 --- /dev/null +++ b/src/components/universal/app_editor.rs @@ -0,0 +1,91 @@ +use leptos::*; +use strum::IntoEnumIterator; + +use crate::server::types::{AppCategory, DeploymentType}; + +#[component] +pub fn app_editor() -> impl IntoView { + let name = create_node_ref(); + let slug = create_node_ref(); + let authors = create_node_ref(); + let built_for_url = create_node_ref(); + let description = create_node_ref(); + let version = create_node_ref(); + let images = create_node_ref(); + let logo = create_node_ref(); + let manifest = create_node_ref(); + let supported_deployments = create_node_ref(); + let category = create_node_ref(); + let docker_compose = create_node_ref(); + + view! { + <form> + <label> + <input node_ref=name type="text" placeholder="Name"/> + </label> + <label> + <input node_ref=slug type="text" placeholder="Slug"/> + </label> + <label> + <input node_ref=authors type="text" placeholder="<Author, authors@email.tld>"/> + </label> + <label> + <input + node_ref=built_for_url + id="built_for_url" + placeholder="https://superfaktura.sk/" + /> + </label> + + <label> + <textarea + node_ref=description + id="description" + placeholder="Description" + ></textarea> + </label> + <label> + <input node_ref=version id="version" type="text" placeholder="Version"/> + </label> + <label> + <input node_ref=images id="images" type="file" placeholder="Example images"/> + </label> + <label> + <input node_ref=logo id="logo" type="file" placeholder="Logo"/> + </label> + <label> + <textarea node_ref=manifest id="manifest" placeholder="JSON"></textarea> + </label> + <label> + <select multiple node_ref=supported_deployments id="supported_deployments"> + {move || { + DeploymentType::iter() + .map(|d| { + let s: &'static str = d.into(); + view! { <option value=s>{s}</option> }.into_view() + }) + .collect_view() + }} + + </select> + </label> + <label> + <select node_ref=category id="category"> + {move || { + AppCategory::iter() + .map(|d| { + let s: &'static str = d.into(); + view! { <option value=s>{s}</option> } + }) + .collect_view() + }} + + </select> + </label> + <label> + <textarea node_ref=docker_compose id="docker_compose"></textarea> + </label> + + </form> + } +} diff --git a/src/components/universal/mod.rs b/src/components/universal/mod.rs new file mode 100644 index 0000000..59a55b6 --- /dev/null +++ b/src/components/universal/mod.rs @@ -0,0 +1,2 @@ +pub mod app_editor; +pub mod text_line; diff --git a/src/components/universal/text_line.rs b/src/components/universal/text_line.rs new file mode 100644 index 0000000..a52abf6 --- /dev/null +++ b/src/components/universal/text_line.rs @@ -0,0 +1,32 @@ +use leptos::*; + +#[component] +pub fn TextLine( + title: &'static str, + required: bool, + value_setter: WriteSignal<String>, +) -> impl IntoView { + view! { + <div class="![&_*]:text-brand-white"> + <label class="relative h-base rounded-sm border-[3px] overflow-hidden + flex flex-row flex-nowrap items-center px-4 pr-6 pt-4 pb-0.5"> + <input + required=required + on:input=move |ev| value_setter.update(|t| *t = event_target_value(&ev)) + placeholder=" " + class="font-serif appearance-none peer text-base w-full bg-inherit" + /> + <span class="absolute font-sans text-sm -top-0.5 transition-all duration-75 + peer-placeholder-shown:top-1.5 peer-focus:-top-0.5 peer-focus:text-sm"> + {title} + {match required { + true => "*", + false => "", + }} + + </span> + </label> + + </div> + } +} diff --git a/src/lib.rs b/src/lib.rs index dbcbb70..32befb0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,8 @@ pub mod error_template; #[cfg(feature = "ssr")] pub mod fileserv; +pub mod components; +pub mod routes; pub mod server; #[cfg(feature = "hydrate")] diff --git a/src/main.rs b/src/main.rs index 43ea6e6..7d84e3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,6 @@ pub mod server; +pub mod components; +pub mod routes; #[cfg(feature = "ssr")] #[tokio::main] diff --git a/src/routes/apps/create.rs b/src/routes/apps/create.rs new file mode 100644 index 0000000..a777b7f --- /dev/null +++ b/src/routes/apps/create.rs @@ -0,0 +1,6 @@ +use leptos::*; + +#[component] +pub fn Create() -> impl IntoView { + view! {} +} diff --git a/src/routes/apps/mod.rs b/src/routes/apps/mod.rs new file mode 100644 index 0000000..30eb5c3 --- /dev/null +++ b/src/routes/apps/mod.rs @@ -0,0 +1,7 @@ +pub mod create; +pub mod update; + +use leptos::*; + +#[component] +pub fn Apps() -> impl IntoView {} diff --git a/src/routes/apps/update.rs b/src/routes/apps/update.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/guides.rs b/src/routes/guides.rs new file mode 100644 index 0000000..4bd5392 --- /dev/null +++ b/src/routes/guides.rs @@ -0,0 +1,4 @@ +use leptos::*; + +#[component] +pub fn Guides() -> impl IntoView {} diff --git a/src/routes/home.rs b/src/routes/home.rs new file mode 100644 index 0000000..b8f23f4 --- /dev/null +++ b/src/routes/home.rs @@ -0,0 +1,11 @@ +use leptos::*; + +#[component] +pub fn Home() -> impl IntoView { + view! { + <h1>Saleor community Harbour</h1> + <p class="italic text-lg"> + Crafted fer ye to muster yer wits an all the booty an wisdom ye may be needin fer yer next voyage. + </p> + } +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs new file mode 100644 index 0000000..016b0dc --- /dev/null +++ b/src/routes/mod.rs @@ -0,0 +1,3 @@ +pub mod apps; +pub mod guides; +pub mod home; diff --git a/src/server/db.rs b/src/server/db.rs index 7f1bd0a..cf4d975 100644 --- a/src/server/db.rs +++ b/src/server/db.rs @@ -1,56 +1,51 @@ -use std::path::PathBuf; - -use saleor_app_sdk::manifest::AppManifest; use serde::Deserialize; use surrealdb::engine::local::Db; use surrealdb::engine::local::RocksDb; use surrealdb::sql::Thing; use surrealdb::Surreal; -use super::types::SaleorApp; - #[derive(Debug, Deserialize)] struct Record { #[allow(dead_code)] id: Thing, } -#[tokio::main] pub async fn connect() -> surrealdb::Result<Surreal<Db>> { // Create database connection - let db = Surreal::new::<RocksDb>("/db").await?; + let db = Surreal::new::<RocksDb>("./db").await?; // Select a specific namespace / database db.use_ns("marketplace").use_db("apps").await?; - let demo_data: Vec<Record> = db.create("saleor_app").content(SaleorApp{ - name: "Sitemap generator".to_owned(), - logo: PathBuf::new(), - images: vec![PathBuf::new()], - authors: vec![], - versions: vec![semver::Version::parse( "2.1.1").unwrap()], - description: "Sitemap stuff".to_owned(), - is_verified: true, - last_updated: chrono::Local::now().into(), - built_for_url: None, - supported_apls: vec![], - supported_deployments: vec![], - minimal_docker_compose: "".to_owned(), - manifest: AppManifest{ - name: "Sitemap generator".to_owned(), - id: "hihihaha".to_owned(), - about: None, - brand: None, - author: None, - version: "2.1.1".to_owned(), - app_url: "localhost:3000".to_owned(), - token_target_url: "localhost:3000".to_owned(), - ..Default::default() - } - }).await?; + // let demo_data: Vec<Record> = db.create("saleor_app").content(SaleorApp{ + // name: "Sitemap generator".to_owned(), + // logo: PathBuf::new(), + // images: vec![PathBuf::new()], + // authors: vec![], + // versions: vec![semver::Version::parse( "2.1.1").unwrap()], + // description: "Sitemap stuff".to_owned(), + // is_verified: true, + // last_updated: chrono::Local::now().into(), + // built_for_url: None, + // supported_apls: vec![], + // supported_deployments: vec![], + // minimal_docker_compose: "".to_owned(), + // manifest: AppManifest{ + // name: "Sitemap generator".to_owned(), + // id: "hihihaha".to_owned(), + // about: None, + // brand: None, + // author: None, + // version: "2.1.1".to_owned(), + // app_url: "localhost:3000".to_owned(), + // token_target_url: "localhost:3000".to_owned(), + // ..Default::default() + // } + // }).await?; + + // dbg!(demo_data); - dbg!(demo_data); // // Create a new person with a random id // let created: Vec<Record> = db // .create("person") diff --git a/src/server/functions.rs b/src/server/functions.rs new file mode 100644 index 0000000..b345320 --- /dev/null +++ b/src/server/functions.rs @@ -0,0 +1,16 @@ +use leptos::*; + +use super::types::SaleorApp; + +#[server] +pub async fn get_all_apps() -> Result<Vec<SaleorApp>, ServerFnError>{ + let conn = crate::server::db::connect().await?; + let mut res = conn.query("SELECT * FROM saleor_app").await?; + + let apps :Vec<SaleorApp> = res.take(0)?; + // dbg!(&apps); + Ok(apps) +} + + + diff --git a/src/server/mod.rs b/src/server/mod.rs index 02e9f16..4425323 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,4 +1,5 @@ #[cfg(feature = "ssr")] pub mod db; +pub mod functions; pub mod types; diff --git a/src/server/types.rs b/src/server/types.rs index 07a24e4..f52e7fb 100644 --- a/src/server/types.rs +++ b/src/server/types.rs @@ -8,9 +8,11 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct SaleorApp { pub name: String, + pub slug: String, pub authors: Vec<AppAuthor>, pub description: String, pub versions: Vec<Version>, + pub curr_version: Version, /** All files will target ./public/app_data/<app-id>/ */ @@ -33,9 +35,12 @@ pub struct SaleorApp { pub minimal_docker_compose: String, pub supported_apls: Vec<CustomAplType>, pub last_updated: chrono::DateTime<FixedOffset>, + pub categories: Vec<AppCategory>, } -#[derive(Debug, Serialize, PartialEq, Deserialize, Clone)] +#[derive( + Debug, Serialize, PartialEq, Deserialize, Clone, strum::EnumIter, strum::IntoStaticStr, +)] pub enum DeploymentType { Docker, Podman, @@ -54,3 +59,20 @@ pub struct AppAuthor { #[derive(Debug, Serialize, PartialEq, Deserialize, Clone)] pub struct CustomAplType(String); + +#[derive( + Debug, Serialize, PartialEq, Deserialize, Clone, strum::EnumIter, strum::IntoStaticStr, +)] +pub enum AppCategory { + CMS, + Messaging, + Taxes, + Payments, + CRM, + Monitoring, + Marketplaces, + Search, + SEO, + DashboardUtilities, + Other, +} diff --git a/style/base.css b/style/base.css index a0b3509..175f94e 100644 --- a/style/base.css +++ b/style/base.css @@ -1,5 +1,78 @@ -@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital@0;1&display=swap'); +@import url("https://fonts.googleapis.com/css2?family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Space+Grotesk:wght@300..700&display=swap"); + @tailwind base; @tailwind components; @tailwind utilities; + +@layer base { + body { + @apply bg-brand-white; + } + + html { + @apply text-brand-black; + } + + ::selection { + @apply bg-brand-sunset-400; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + @apply font-sans my-4 text-brand-sea-300 text-2xl; + } + + h2 { + @apply text-brand-sea-300 text-xl; + } + + h3, + h4, + h5, + h6 { + @apply text-brand-sea-500 text-base; + } + + p { + @apply font-serif my-2 text-base; + } + + input:disabled, + button:disabled { + @apply brightness-50 cursor-not-allowed; + } + + details, + summary { + @apply list-none; + } + + input:focus, + input:active, + option:focus, + option:active { + @apply !outline-none !appearance-none !select-none shadow-none !border-none; + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } +} + +@layer components { + .header-gradient { + background: theme("colors.brand-sea.400"); + background: linear-gradient(25deg, + theme("colors.brand-sunset.500") 0%, + theme("colors.brand-sea.300") 45%, + theme("colors.brand-sea.300") 55%, + theme("colors.brand-sunset.500") 100%); + } +} diff --git a/tailwind.config.js b/tailwind.config.js index 9d923f1..bad3a9a 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -3,6 +3,55 @@ module.exports = { content: { files: ["*.html", "./src/**/*.rs"], }, - theme: {}, + theme: { + fontFamily: { + sans: ["Space Grotesk", "sans-serif"], + serif: ["PT Serif", "serif"], + }, + fontSize: { + xs: "0.75rem", + sm: "0.875rem", + base: "0.875rem", + "base-sans": "1rem", + lg: "1.125rem", + xl: "1.5rem", + "2xl": "2rem", + }, + borderRadius: { + base: "0.5rem", + sm: "0.25rem", + xs: "0.156rem", + lg: "1rem", + xl: "2rem", + max: "999999px", + }, + extend: { + colors: { + "brand-sea": { + 100: "#C5ECE0", + 200: "#17C3B2", + 300: "#1DA0A8", + 400: "#227C9D", + 500: "#094074", + }, + "brand-sunset": { + 100: "#FEF9EF", + 200: "#FFEED1", + 300: "#FFE2B3", + 400: "#FFD795", + 500: "#FFCB77", + }, + "brand-red": { + 100: "#FED6D0", + 200: "#FEB3B1", + 300: "#FE9092", + 400: "#FE7F83", + 500: "#FE6D73", + }, + "brand-black": "#161a1e", + "brand-white": "#fbfbfb", + }, + }, + }, plugins: [], -} +};