From ed68b76a42a067b54cfbad5c3ffbd6069343a56b Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 10:58:51 +0100 Subject: [PATCH 01/15] Add sorting preset table definitions Signed-off-by: trivernis --- ...220205092929_add-sorting-preset-tables.sql | 20 +++++++++ .../mediarepo-database/src/entities/mod.rs | 3 ++ .../src/entities/sort_key.rs | 26 +++++++++++ .../src/entities/sorting_preset.rs | 27 ++++++++++++ .../src/entities/sorting_preset_key.rs | 44 +++++++++++++++++++ 5 files changed, 120 insertions(+) create mode 100644 mediarepo-daemon/mediarepo-database/migrations/20220205092929_add-sorting-preset-tables.sql create mode 100644 mediarepo-daemon/mediarepo-database/src/entities/sort_key.rs create mode 100644 mediarepo-daemon/mediarepo-database/src/entities/sorting_preset.rs create mode 100644 mediarepo-daemon/mediarepo-database/src/entities/sorting_preset_key.rs diff --git a/mediarepo-daemon/mediarepo-database/migrations/20220205092929_add-sorting-preset-tables.sql b/mediarepo-daemon/mediarepo-database/migrations/20220205092929_add-sorting-preset-tables.sql new file mode 100644 index 0000000..0f0faa4 --- /dev/null +++ b/mediarepo-daemon/mediarepo-database/migrations/20220205092929_add-sorting-preset-tables.sql @@ -0,0 +1,20 @@ +-- Add migration script here +CREATE TABLE sorting_presets ( + id INTEGER PRIMARY KEY AUTOINCREMENT +); + +CREATE TABLE sort_keys ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + key_type INTEGER NOT NULL DEFAULT 0, + ascending INTEGER NOT NULL CHECK (ascending IN (0, 1)), + value VARCHAR(128) +); + +CREATE TABLE sorting_preset_keys ( + preset_id INTEGER REFERENCES sorting_presets (id) ON DELETE CASCADE, + key_id INTEGER REFERENCES sort_keys (id), + key_index INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (preset_id, key_id) +); + +CREATE INDEX sorting_preset_index ON sorting_preset_keys (preset_id); \ No newline at end of file diff --git a/mediarepo-daemon/mediarepo-database/src/entities/mod.rs b/mediarepo-daemon/mediarepo-database/src/entities/mod.rs index 4b8acde..3eee5ae 100644 --- a/mediarepo-daemon/mediarepo-database/src/entities/mod.rs +++ b/mediarepo-daemon/mediarepo-database/src/entities/mod.rs @@ -4,5 +4,8 @@ pub mod content_descriptor_tag; pub mod file; pub mod file_metadata; pub mod namespace; +pub mod sort_key; +pub mod sorting_preset; +pub mod sorting_preset_key; pub mod source; pub mod tag; diff --git a/mediarepo-daemon/mediarepo-database/src/entities/sort_key.rs b/mediarepo-daemon/mediarepo-database/src/entities/sort_key.rs new file mode 100644 index 0000000..4ebdd1f --- /dev/null +++ b/mediarepo-daemon/mediarepo-database/src/entities/sort_key.rs @@ -0,0 +1,26 @@ +use sea_orm::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "sort_keys")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub key_type: i32, + pub ascending: bool, + pub value: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl Related for Entity { + fn to() -> RelationDef { + super::sorting_preset_key::Relation::SortingPreset.def() + } + + fn via() -> Option { + Some(super::sorting_preset_key::Relation::SortingKey.def().rev()) + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset.rs b/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset.rs new file mode 100644 index 0000000..5bae84b --- /dev/null +++ b/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset.rs @@ -0,0 +1,27 @@ +use sea_orm::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "sorting_presets")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl Related for Entity { + fn to() -> RelationDef { + super::sorting_preset_key::Relation::SortingKey.def() + } + + fn via() -> Option { + Some( + super::sorting_preset_key::Relation::SortingPreset + .def() + .rev(), + ) + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset_key.rs b/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset_key.rs new file mode 100644 index 0000000..4381031 --- /dev/null +++ b/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset_key.rs @@ -0,0 +1,44 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "sorting_preset_keys")] +pub struct Model { + #[sea_orm(primary_key)] + preset_id: i32, + + #[sea_orm(primary_key)] + key_id: i32, + + key_index: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::sorting_preset::Entity" + from = "Column::PresetId", + to = "super::sorting_preset::Column::Id" + )] + SortingPreset, + + #[sea_orm( + belongs_to = "super::sort_key::Entity", + from = "Column::KeyId", + to = "super::sort_key::Column::Id" + )] + SortingKey, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::SortingPreset.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::SortingKey.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} From 3e768d7c7c4fb8b8f7190bf4bf6c0ced494baace Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 11:24:54 +0100 Subject: [PATCH 02/15] Add sorting preset dto and function to retrieve all presets Signed-off-by: trivernis --- .../mediarepo-logic/src/dao/file/mod.rs | 16 +----- .../mediarepo-logic/src/dao/job/mod.rs | 20 ++------ .../mediarepo-logic/src/dao/mod.rs | 29 +++++++++++ .../src/dao/sorting_preset/mod.rs | 34 +++++++++++++ .../mediarepo-logic/src/dao/tag/mod.rs | 16 +----- .../mediarepo-logic/src/dto/mod.rs | 5 +- .../mediarepo-logic/src/dto/sorting_preset.rs | 49 +++++++++++++++++++ 7 files changed, 122 insertions(+), 47 deletions(-) create mode 100644 mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs create mode 100644 mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/file/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/file/mod.rs index 210cf50..93f012c 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/file/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/file/mod.rs @@ -1,10 +1,10 @@ use sea_orm::prelude::*; use tokio::io::AsyncReadExt; +use crate::dao_provider; use mediarepo_core::error::RepoResult; use mediarepo_database::entities::{content_descriptor, file, file_metadata}; -use crate::dao::{DaoContext, DaoProvider}; use crate::dto::{FileDto, FileMetadataDto, ThumbnailDto}; pub mod add; @@ -12,21 +12,9 @@ pub mod delete; pub mod find; pub mod update; -pub struct FileDao { - ctx: DaoContext, -} - -impl DaoProvider for FileDao { - fn dao_ctx(&self) -> DaoContext { - self.ctx.clone() - } -} +dao_provider!(FileDao); impl FileDao { - pub fn new(ctx: DaoContext) -> Self { - Self { ctx } - } - #[tracing::instrument(level = "debug", skip(self))] pub async fn all(&self) -> RepoResult> { let files = file::Entity::find() diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/job/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/job/mod.rs index c47b28a..16bace3 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/job/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/job/mod.rs @@ -1,20 +1,6 @@ +use crate::dao_provider; + pub mod migrate_content_descriptors; pub mod sqlite_operations; -use crate::dao::{DaoContext, DaoProvider}; - -pub struct JobDao { - ctx: DaoContext, -} - -impl DaoProvider for JobDao { - fn dao_ctx(&self) -> DaoContext { - self.ctx.clone() - } -} - -impl JobDao { - pub fn new(ctx: DaoContext) -> JobDao { - Self { ctx } - } -} +dao_provider!(JobDao); diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/mod.rs index f3cf620..84c5964 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/mod.rs @@ -5,13 +5,38 @@ use mediarepo_core::fs::thumbnail_store::ThumbnailStore; use crate::dao::file::FileDao; use crate::dao::job::JobDao; +use crate::dao::sorting_preset::SortingPresetDao; use crate::dao::tag::TagDao; pub mod file; pub mod job; pub mod repo; +pub mod sorting_preset; pub mod tag; +#[macro_export] +macro_rules! dao_provider { + ($name:ident) => { + use crate::dao::{DaoContext, DaoProvider}; + + pub struct $name { + ctx: DaoContext, + } + + impl DaoProvider for $name { + fn dao_ctx(&self) -> DaoContext { + self.ctx.clone() + } + } + + impl $name { + pub fn new(ctx: DaoContext) -> Self { + Self { ctx } + } + } + }; +} + #[derive(Clone)] pub struct DaoContext { pub db: DatabaseConnection, @@ -33,6 +58,10 @@ pub trait DaoProvider { fn job(&self) -> JobDao { JobDao::new(self.dao_ctx()) } + + fn sorting_preset(&self) -> SortingPresetDao { + SortingPresetDao::new(self.dao_ctx()) + } } fn opt_to_active_val>(opt: Option) -> ActiveValue { diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs new file mode 100644 index 0000000..eb8f241 --- /dev/null +++ b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs @@ -0,0 +1,34 @@ +use crate::dao_provider; +use crate::dto::{SortKeyDto, SortingPresetDto}; +use mediarepo_core::error::RepoResult; +use mediarepo_database::entities::{sort_key, sorting_preset, sorting_preset_key}; +use sea_orm::prelude::*; +use sea_orm::{JoinType, QueryOrder, QuerySelect}; + +dao_provider!(SortingPresetDao); + +impl SortingPresetDao { + #[tracing::instrument(level = "debug", skip(self))] + pub async fn all(&self) -> RepoResult> { + let presets = sorting_preset::Entity::find() + .find_with_related(sort_key::Entity) + .join( + JoinType::InnerJoin, + sorting_preset_key::Relation::SortingKey.def(), + ) + .order_by_asc(sorting_preset_key::Column::KeyIndex) + .all(&self.ctx.db) + .await? + .into_iter() + .map(map_sorting_preset_dto) + .collect(); + + Ok(presets) + } +} + +fn map_sorting_preset_dto( + entry: (sorting_preset::Model, Vec), +) -> SortingPresetDto { + SortingPresetDto::new(entry.0, entry.1.into_iter().map(SortKeyDto::new).collect()) +} diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/tag/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/tag/mod.rs index 7f38e23..c931f10 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/tag/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/tag/mod.rs @@ -10,7 +10,7 @@ use mediarepo_core::utils::parse_namespace_and_tag; use mediarepo_database::entities::{content_descriptor, content_descriptor_tag, namespace, tag}; use crate::dao::tag::by_name::TagByNameQuery; -use crate::dao::{DaoContext, DaoProvider}; +use crate::dao_provider; use crate::dto::{NamespaceDto, TagDto}; pub mod add; @@ -19,21 +19,9 @@ pub mod by_name; pub mod cdids_with_namespaced_tags; pub mod mappings; -pub struct TagDao { - ctx: DaoContext, -} - -impl DaoProvider for TagDao { - fn dao_ctx(&self) -> DaoContext { - self.ctx.clone() - } -} +dao_provider!(TagDao); impl TagDao { - pub fn new(ctx: DaoContext) -> Self { - Self { ctx } - } - #[tracing::instrument(level = "debug", skip(self))] pub async fn all(&self) -> RepoResult> { let tags = tag::Entity::find() diff --git a/mediarepo-daemon/mediarepo-logic/src/dto/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dto/mod.rs index 0d7a962..2444214 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dto/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dto/mod.rs @@ -1,12 +1,13 @@ pub use file::*; pub use file_metadata::*; pub use namespace::*; +pub use sorting_preset::*; pub use tag::*; pub use thumbnail::*; mod file; mod file_metadata; -mod tag; mod namespace; +mod sorting_preset; +mod tag; mod thumbnail; - diff --git a/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs b/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs new file mode 100644 index 0000000..462d904 --- /dev/null +++ b/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs @@ -0,0 +1,49 @@ +use mediarepo_database::entities::sort_key; +use mediarepo_database::entities::sorting_preset; + +#[derive(Clone, Debug)] +pub struct SortingPresetDto { + model: sorting_preset::Model, + keys: Vec, +} + +impl SortingPresetDto { + pub fn new(model: sorting_preset::Model, keys: Vec) -> Self { + Self { model, keys } + } + + pub fn id(&self) -> i32 { + self.model.id + } + + pub fn keys(&self) -> &Vec { + &self.keys + } +} + +#[derive(Clone, Debug)] +pub struct SortKeyDto { + model: sort_key::Model, +} + +impl SortKeyDto { + pub fn new(model: sort_key::Model) -> Self { + Self { model } + } + + pub fn id(&self) -> i32 { + self.model.id + } + + pub fn key_type(&self) -> i32 { + self.model.key_type + } + + pub fn ascending(&self) -> bool { + self.model.ascending + } + + pub fn value(&self) -> Option<&String> { + self.model.value.as_ref() + } +} From c34d9d564970370a6494d93a18ff02e4d67e3b69 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 12:32:08 +0100 Subject: [PATCH 03/15] Add function to add sorting presets Signed-off-by: trivernis --- .../src/dao/sorting_preset/add.rs | 146 ++++++++++++++++++ .../src/dao/sorting_preset/mod.rs | 2 + .../mediarepo-logic/src/dto/sorting_preset.rs | 52 ++++++- 3 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs new file mode 100644 index 0000000..f8e51f6 --- /dev/null +++ b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs @@ -0,0 +1,146 @@ +use crate::dao::sorting_preset::SortingPresetDao; +use crate::dto::{AddSortKeyDto, AddSortingPresetDto, SortKeyDto, SortingPresetDto}; +use mediarepo_core::error::RepoResult; +use mediarepo_database::entities::{sort_key, sorting_preset, sorting_preset_key}; +use sea_orm::prelude::*; +use sea_orm::ActiveValue::Set; +use sea_orm::{Condition, ConnectionTrait, DatabaseTransaction, JoinType, QuerySelect}; + +impl SortingPresetDao { + #[tracing::instrument(level = "debug", skip(self))] + pub async fn add(&self, preset: AddSortingPresetDto) -> RepoResult { + let trx = self.ctx.db.begin().await?; + let keys = add_keys(&trx, preset.keys).await?; + let key_ids = keys + .iter() + .enumerate() + .map(|(idx, key)| (idx, key.id())) + .collect::>(); + let condition = key_ids + .iter() + .cloned() + .map(create_mapping_condition) + .fold(Condition::any(), |acc, cond| acc.add(cond)); + let existing_preset: Option = sorting_preset::Entity::find() + .join( + JoinType::InnerJoin, + sorting_preset_key::Relation::SortingPreset.def().rev(), + ) + .filter(condition) + .one(&trx) + .await?; + if let Some(model) = existing_preset { + trx.commit().await?; + return Ok(SortingPresetDto::new(model, keys)); + } + let preset_model = sorting_preset::ActiveModel { + ..Default::default() + }; + let preset_model = preset_model.insert(&trx).await?; + let mapping_models = key_ids + .into_iter() + .map(|(idx, key)| sorting_preset_key::ActiveModel { + preset_id: Set(preset_model.id), + key_id: Set(key), + key_index: Set(idx as i32), + }) + .collect::>(); + sorting_preset_key::Entity::insert_many(mapping_models) + .exec(&trx) + .await?; + trx.commit().await?; + + Ok(SortingPresetDto::new(preset_model, keys)) + } +} + +async fn add_keys( + trx: &DatabaseTransaction, + mut keys: Vec, +) -> RepoResult> { + let mut key_dtos = find_sort_keys(trx, &keys).await?; + key_dtos.iter().for_each(|key| { + keys.retain(|k| { + k.ascending != key.ascending() + && Some(k.key_type) != key.key_type() + && key.value() != key.value() + }) + }); + + if !keys.is_empty() { + let active_models: Vec = keys + .iter() + .cloned() + .map(|key| sort_key::ActiveModel { + key_type: Set(key.key_type.to_number()), + ascending: Set(key.ascending), + value: Set(key.value), + ..Default::default() + }) + .collect(); + sort_key::Entity::insert_many(active_models) + .exec(trx) + .await?; + let mut new_keys = find_sort_keys(trx, &keys).await?; + key_dtos.append(&mut new_keys); + } + + let keys_original_order = keys + .into_iter() + .filter_map(|k| { + key_dtos + .iter() + .find(|key| { + k.ascending != key.ascending() + && Some(k.key_type) != key.key_type() + && key.value() != key.value() + }) + .cloned() + }) + .collect::>(); + + Ok(keys_original_order) +} + +async fn find_sort_keys( + trx: &DatabaseTransaction, + keys: &Vec, +) -> RepoResult> { + if keys.is_empty() { + return Ok(vec![]); + } + let condition = keys + .iter() + .cloned() + .map(create_sort_key_condition) + .fold(Condition::any(), |acc, cond| acc.add(cond)); + let keys = sort_key::Entity::find() + .filter(condition) + .all(trx) + .await? + .into_iter() + .map(SortKeyDto::new) + .collect(); + + Ok(keys) +} + +fn create_sort_key_condition(key: AddSortKeyDto) -> Condition { + let mut condition = Condition::all() + .add(sort_key::Column::KeyType.eq(key.key_type.to_number())) + .add(sort_key::Column::Ascending.eq(key.ascending)); + + if let Some(value) = key.value { + condition = condition.add(sort_key::Column::Value.eq(value)) + } else { + condition = condition.add(sort_key::Column::Value.is_null()) + } + + condition +} + +fn create_mapping_condition(entry: (usize, i32)) -> Condition { + Condition::all() + .add(sorting_preset_key::Column::KeyId.eq(entry.1)) + .add(sorting_preset_key::Column::KeyIndex.eq(entry.0 as i32)) +} diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs index eb8f241..9cfe7af 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs @@ -1,3 +1,5 @@ +pub mod add; + use crate::dao_provider; use crate::dto::{SortKeyDto, SortingPresetDto}; use mediarepo_core::error::RepoResult; diff --git a/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs b/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs index 462d904..df413d7 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs @@ -1,3 +1,7 @@ +use crate::dto::KeyType::{ + FileChangeTime, FileCreatedTime, FileImportedTime, FileName, FileSize, FileType, Namespace, + NumTags, +}; use mediarepo_database::entities::sort_key; use mediarepo_database::entities::sorting_preset; @@ -35,8 +39,8 @@ impl SortKeyDto { self.model.id } - pub fn key_type(&self) -> i32 { - self.model.key_type + pub fn key_type(&self) -> Option { + KeyType::from_number(self.model.key_type) } pub fn ascending(&self) -> bool { @@ -47,3 +51,47 @@ impl SortKeyDto { self.model.value.as_ref() } } + +#[derive(Clone, Copy, Debug, PartialOrd, PartialEq)] +pub enum KeyType { + Namespace = 0, + FileName = 1, + FileSize = 2, + FileImportedTime = 3, + FileCreatedTime = 4, + FileChangeTime = 5, + FileType = 6, + NumTags = 7, +} + +impl KeyType { + pub fn from_number(number: i32) -> Option { + match number { + 0 => Some(Namespace), + 1 => Some(FileName), + 2 => Some(FileSize), + 3 => Some(FileImportedTime), + 4 => Some(FileCreatedTime), + 5 => Some(FileChangeTime), + 6 => Some(FileType), + 7 => Some(NumTags), + _ => None, + } + } + + pub fn to_number(&self) -> i32 { + self.clone() as i32 + } +} + +#[derive(Clone, Debug)] +pub struct AddSortingPresetDto { + pub keys: Vec, +} + +#[derive(Clone, Debug)] +pub struct AddSortKeyDto { + pub key_type: KeyType, + pub ascending: bool, + pub value: Option, +} From 78a5780ff1aec2eb51a5ac5d16f6ba0f75081772 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 12:39:39 +0100 Subject: [PATCH 04/15] Add function to delete sorting presets Signed-off-by: trivernis --- .../mediarepo-logic/src/dao/sorting_preset/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs index 9cfe7af..a265aa5 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs @@ -27,6 +27,16 @@ impl SortingPresetDao { Ok(presets) } + + #[tracing::instrument(level = "debug", skip(self))] + pub async fn delete(&self, id: i32) -> RepoResult<()> { + sorting_preset::Entity::delete_many() + .filter(sorting_preset::Column::Id.eq(id)) + .exec(&self.ctx.db) + .await?; + + Ok(()) + } } fn map_sorting_preset_dto( From d22c7499f782aff57880f18fd77daae4ab7ca26f Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 14:17:11 +0100 Subject: [PATCH 05/15] Add api to manage sorting presets Signed-off-by: trivernis --- mediarepo-api/Cargo.toml | 38 ++++++------- mediarepo-api/src/client_api/mod.rs | 5 ++ mediarepo-api/src/client_api/preset.rs | 54 +++++++++++++++++++ .../src/tauri_plugin/commands/mod.rs | 2 + .../src/tauri_plugin/commands/preset.rs | 27 ++++++++++ mediarepo-api/src/tauri_plugin/mod.rs | 5 +- mediarepo-api/src/types/filtering.rs | 6 +++ 7 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 mediarepo-api/src/client_api/preset.rs create mode 100644 mediarepo-api/src/tauri_plugin/commands/preset.rs diff --git a/mediarepo-api/Cargo.toml b/mediarepo-api/Cargo.toml index 5a8a80e..522a42f 100644 --- a/mediarepo-api/Cargo.toml +++ b/mediarepo-api/Cargo.toml @@ -1,52 +1,52 @@ [package] name = "mediarepo-api" -version = "0.28.0" +version = "0.28.1" edition = "2018" license = "gpl-3" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tracing = "^0.1.29" -thiserror = "^1.0.30" -async-trait = {version = "^0.1.52", optional=true} -parking_lot = {version="^0.11.2", optional=true} -serde_json = {version="^1.0.73", optional=true} -directories = {version="^4.0.1", optional=true} -mime_guess = {version = "^2.0.3", optional=true} -serde_piecewise_default = "^0.2.0" -futures = {version = "^0.3.19", optional=true} -url = {version = "^2.2.2", optional=true } -pathsearch = {version="^0.2.0", optional=true} +tracing = "0.1.30" +thiserror = "1.0.30" +async-trait = { version = "0.1.52", optional = true } +parking_lot = { version = "0.12.0", optional = true } +serde_json = { version = "1.0.78", optional = true } +directories = { version = "4.0.1", optional = true } +mime_guess = { version = "2.0.3", optional = true } +serde_piecewise_default = "0.2.0" +futures = { version = "0.3.19", optional = true } +url = { version = "2.2.2", optional = true } +pathsearch = { version = "0.2.0", optional = true } [dependencies.bromine] -version = "^0.17.1" +version = "0.17.1" optional = true features = ["serialize_bincode"] [dependencies.serde] -version = "^1.0.132" +version = "1.0.136" features = ["serde_derive"] [dependencies.chrono] -version = "^0.4.19" +version = "0.4.19" features = ["serde"] [dependencies.tauri] -version = "^1.0.0-beta.8" +version = "1.0.0-beta.8" optional=true default-features = false features = [] [dependencies.tokio] -version = "^1.15.0" +version = "1.16.1" optional = true features = ["sync", "fs", "net", "io-util", "io-std", "time", "rt", "process"] [dependencies.toml] -version = "^0.5.8" +version = "0.5.8" optional = true [features] tauri-plugin = ["client-api","tauri", "parking_lot", "serde_json", "tokio", "toml", "directories", "mime_guess", "futures", "url"] -client-api = ["bromine", "async-trait", "tokio", "pathsearch"] \ No newline at end of file +client-api = ["bromine", "async-trait", "tokio", "pathsearch"] diff --git a/mediarepo-api/src/client_api/mod.rs b/mediarepo-api/src/client_api/mod.rs index c3fbf2f..3dfbcab 100644 --- a/mediarepo-api/src/client_api/mod.rs +++ b/mediarepo-api/src/client_api/mod.rs @@ -4,6 +4,7 @@ pub mod job; pub mod protocol; pub mod repo; pub mod tag; +pub mod preset; use crate::client_api::error::{ApiError, ApiResult}; use crate::client_api::file::FileApi; @@ -15,6 +16,7 @@ use async_trait::async_trait; use bromine::ipc::stream_emitter::EmitMetadata; use bromine::prelude::*; use tokio::time::Duration; +use crate::client_api::preset::PresetApi; #[async_trait] pub trait IPCApi { @@ -48,6 +50,7 @@ pub struct ApiClient { pub tag: TagApi, pub repo: RepoApi, pub job: JobApi, + pub preset: PresetApi, } impl Clone for ApiClient { @@ -58,6 +61,7 @@ impl Clone for ApiClient { tag: self.tag.clone(), repo: self.repo.clone(), job: self.job.clone(), + preset: self.preset.clone(), } } } @@ -70,6 +74,7 @@ impl ApiClient { tag: TagApi::new(ctx.clone()), repo: RepoApi::new(ctx.clone()), job: JobApi::new(ctx.clone()), + preset: PresetApi::new(ctx.clone()), ctx, } } diff --git a/mediarepo-api/src/client_api/preset.rs b/mediarepo-api/src/client_api/preset.rs new file mode 100644 index 0000000..f62e0fc --- /dev/null +++ b/mediarepo-api/src/client_api/preset.rs @@ -0,0 +1,54 @@ +use std::time::Duration; +use bromine::prelude::*; +use crate::client_api::error::ApiResult; +use crate::types::filtering::{SortingPreset, SortKey}; +use super::IPCApi; + +#[derive(Clone)] +pub struct PresetApi { + ctx: PooledContext, +} + +impl IPCApi for PresetApi { + fn namespace() -> &'static str { + "presets" + } + + fn ctx(&self) -> PoolGuard { + self.ctx.acquire() + } +} + +impl PresetApi { + pub fn new(ctx: PooledContext) -> Self { + Self { ctx } + } + + /// Returns all sorting presets of the repository + #[tracing::instrument(level = "debug", skip(self))] + pub async fn all_sorting_presets(&self) -> ApiResult> { + self.emit_and_get( + "sorting_presets", + (), + Some(Duration::from_secs(1)) + ) + .await + } + + /// Adds a new sorting preset with the given keys + #[tracing::instrument(level = "debug", skip(self))] + pub async fn add_sorting_preset(&self, keys: Vec) -> ApiResult { + self.emit_and_get( + "add_sorting_preset", + keys, + Some(Duration::from_secs(1)) + ) + .await + } + + /// Deletes a given sorting preset by id + #[tracing::instrument(level = "debug", skip(self))] + pub async fn delete_sorting_preset(&self, id: i32) -> ApiResult<()> { + self.emit_and_get("delete_sorting_preset", id, Some(Duration::from_secs(1))).await + } +} diff --git a/mediarepo-api/src/tauri_plugin/commands/mod.rs b/mediarepo-api/src/tauri_plugin/commands/mod.rs index bd6a259..c06b7c8 100644 --- a/mediarepo-api/src/tauri_plugin/commands/mod.rs +++ b/mediarepo-api/src/tauri_plugin/commands/mod.rs @@ -5,6 +5,7 @@ pub use file::*; pub use job::*; pub use repo::*; pub use tag::*; +pub use preset::*; use crate::tauri_plugin::state::{ApiState, AppState, BufferState}; @@ -13,6 +14,7 @@ pub mod file; pub mod job; pub mod repo; pub mod tag; +pub mod preset; pub type ApiAccess<'a> = State<'a, ApiState>; pub type AppAccess<'a> = State<'a, AppState>; diff --git a/mediarepo-api/src/tauri_plugin/commands/preset.rs b/mediarepo-api/src/tauri_plugin/commands/preset.rs new file mode 100644 index 0000000..8bdb206 --- /dev/null +++ b/mediarepo-api/src/tauri_plugin/commands/preset.rs @@ -0,0 +1,27 @@ +use crate::tauri_plugin::commands::ApiAccess; +use crate::tauri_plugin::error::PluginResult; +use crate::types::filtering::{SortingPreset, SortKey}; + +#[tauri::command] +pub async fn all_sorting_presets(api_state: ApiAccess<'_>) -> PluginResult> { + let api = api_state.api().await?; + let presets = api.preset.all_sorting_presets().await?; + + Ok(presets) +} + +#[tauri::command] +pub async fn add_sorting_preset(api_state: ApiAccess<'_>, sort_keys: Vec) -> PluginResult { + let api = api_state.api().await?; + let preset = api.preset.add_sorting_preset(sort_keys).await?; + + Ok(preset) +} + +#[tauri::command] +pub async fn delete_sorting_preset(api_state: ApiAccess<'_>, id: i32) -> PluginResult<()> { + let api = api_state.api().await?; + api.preset.delete_sorting_preset(id).await?; + + Ok(()) +} \ No newline at end of file diff --git a/mediarepo-api/src/tauri_plugin/mod.rs b/mediarepo-api/src/tauri_plugin/mod.rs index 37e11c6..7a570a7 100644 --- a/mediarepo-api/src/tauri_plugin/mod.rs +++ b/mediarepo-api/src/tauri_plugin/mod.rs @@ -70,7 +70,10 @@ impl MediarepoPlugin { run_job, update_file_status, delete_file, - get_file_tag_map + get_file_tag_map, + all_sorting_presets, + add_sorting_preset, + delete_sorting_preset ]), } } diff --git a/mediarepo-api/src/types/filtering.rs b/mediarepo-api/src/types/filtering.rs index 916db73..3ffca1e 100644 --- a/mediarepo-api/src/types/filtering.rs +++ b/mediarepo-api/src/types/filtering.rs @@ -71,3 +71,9 @@ pub enum SortDirection { } impl Eq for SortDirection {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct SortingPreset { + pub id: i32, + pub keys: Vec, +} \ No newline at end of file From 5aadd9c24569230f2991b04a10de0804808bbe64 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 14:50:37 +0100 Subject: [PATCH 06/15] Add api implementation for sorting presets Signed-off-by: trivernis --- mediarepo-daemon/Cargo.lock | 157 ++++++++++++------ mediarepo-daemon/Cargo.toml | 26 +-- mediarepo-daemon/mediarepo-core/Cargo.toml | 38 ++--- .../mediarepo-database/Cargo.toml | 10 +- mediarepo-daemon/mediarepo-logic/Cargo.toml | 20 +-- .../mediarepo-logic/src/dto/sorting_preset.rs | 4 + mediarepo-daemon/mediarepo-socket/Cargo.toml | 18 +- .../mediarepo-socket/src/from_model.rs | 45 ++++- .../mediarepo-socket/src/namespaces/mod.rs | 2 + .../src/namespaces/presets.rs | 116 +++++++++++++ 10 files changed, 324 insertions(+), 112 deletions(-) create mode 100644 mediarepo-daemon/mediarepo-socket/src/namespaces/presets.rs diff --git a/mediarepo-daemon/Cargo.lock b/mediarepo-daemon/Cargo.lock index c095862..b4dee04 100644 --- a/mediarepo-daemon/Cargo.lock +++ b/mediarepo-daemon/Cargo.lock @@ -216,23 +216,23 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake2b_simd" -version = "0.5.11" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" dependencies = [ "arrayref", - "arrayvec 0.5.2", + "arrayvec 0.7.2", "constant_time_eq", ] [[package]] name = "blake2s_simd" -version = "0.5.11" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" dependencies = [ "arrayref", - "arrayvec 0.5.2", + "arrayvec 0.7.2", "constant_time_eq", ] @@ -255,15 +255,17 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", "generic-array", ] [[package]] -name = "block-padding" -version = "0.2.1" +name = "block-buffer" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +checksum = "03588e54c62ae6d763e2a80090d50353b785795361b4ff5b3bf0a5097fc31c0b" +dependencies = [ + "generic-array", +] [[package]] name = "bromine" @@ -407,9 +409,9 @@ dependencies = [ [[package]] name = "console-api" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f67643a7d716307ad10b3e3aef02826382acbe349a3e7605ac57556148bc87" +checksum = "cc347c19eb5b940f396ac155822caee6662f850d97306890ac3773ed76c90c5a" dependencies = [ "prost", "prost-types", @@ -462,6 +464,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.1" @@ -502,7 +513,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", ] [[package]] @@ -513,17 +524,17 @@ checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", ] [[package]] name = "crossbeam-epoch" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" +checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", "lazy_static", "memoffset", "scopeguard", @@ -531,12 +542,12 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b979d76c9fcb84dffc80a73f7290da0f83e4c95773494674cb44b76d13a7a110" +checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", ] [[package]] @@ -552,14 +563,23 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" +checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" dependencies = [ "cfg-if 1.0.0", "lazy_static", ] +[[package]] +name = "crypto-common" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +dependencies = [ + "generic-array", +] + [[package]] name = "data-encoding" version = "2.3.2" @@ -613,6 +633,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" +dependencies = [ + "block-buffer 0.10.1", + "crypto-common", + "generic-array", +] + [[package]] name = "dotenv" version = "0.15.0" @@ -1329,7 +1360,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mediarepo-api" -version = "0.28.0" +version = "0.28.1" dependencies = [ "bromine", "chrono", @@ -1513,26 +1544,26 @@ dependencies = [ [[package]] name = "multihash" -version = "0.15.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e540106213dc639fe2b632a7d9e3525169ef081378a7c2da4457b84fec44c0" +checksum = "7392bffd88bc0c4f8297e36a777ab9f80b7127409c4a1acb8fee99c9f27addcd" dependencies = [ "blake2b_simd", "blake2s_simd", "blake3", - "digest", - "generic-array", + "core2", + "digest 0.10.1", "multihash-derive", - "sha2", + "sha2 0.10.1", "sha3", "unsigned-varint", ] [[package]] name = "multihash-derive" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" +checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -2048,7 +2079,7 @@ checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel", "crossbeam-deque", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", "lazy_static", "num_cpus", ] @@ -2251,9 +2282,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fed7948b6c68acbb6e20c334f55ad635dc0f75506963de4464289fbd3b051ac" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" dependencies = [ "bitflags", "core-foundation", @@ -2264,9 +2295,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57321bf8bc2362081b2599912d2961fe899c0efadf1b4b2f8d48b3e253bb96c" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ "core-foundation-sys", "libc", @@ -2350,23 +2381,32 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.1", +] + [[package]] name = "sha3" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" dependencies = [ - "block-buffer", - "digest", + "digest 0.10.1", "keccak", - "opaque-debug", ] [[package]] @@ -2460,7 +2500,7 @@ dependencies = [ "crc", "crossbeam-channel", "crossbeam-queue", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", "either", "flume", "futures-channel", @@ -2483,7 +2523,7 @@ dependencies = [ "rust_decimal", "serde 1.0.136", "serde_json", - "sha2", + "sha2 0.9.9", "smallvec", "sqlformat", "sqlx-rt", @@ -2507,7 +2547,7 @@ dependencies = [ "proc-macro2 1.0.36", "quote 1.0.15", "serde_json", - "sha2", + "sha2 0.9.9", "sqlx-core", "sqlx-rt", "syn 1.0.86", @@ -2921,9 +2961,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" dependencies = [ "cfg-if 1.0.0", "log", @@ -2945,9 +2985,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" dependencies = [ "proc-macro2 1.0.36", "quote 1.0.15", @@ -2956,11 +2996,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" dependencies = [ "lazy_static", + "valuable", ] [[package]] @@ -2998,9 +3039,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" dependencies = [ "serde 1.0.136", "tracing-core", @@ -3008,9 +3049,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5312f325fe3588e277415f5a6cca1f4ccad0f248c4cd5a4bd33032d7286abc22" +checksum = "74786ce43333fcf51efe947aed9718fbe46d5c7328ec3f1029e818083966d9aa" dependencies = [ "ansi_term", "lazy_static", @@ -3127,6 +3168,12 @@ dependencies = [ "serde 1.0.136", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/mediarepo-daemon/Cargo.toml b/mediarepo-daemon/Cargo.toml index f97dc99..b4fce69 100644 --- a/mediarepo-daemon/Cargo.toml +++ b/mediarepo-daemon/Cargo.toml @@ -16,17 +16,17 @@ name = "mediarepo-daemon" path = "src/main.rs" [dependencies] -tracing = "^0.1.29" -toml = "^0.5.8" -structopt ="^0.3.26" -glob = "^0.3.0" -tracing-flame = "^0.2.0" -tracing-appender = "^0.2.0" -tracing-log = "^0.1.2" -rolling-file = "^0.1.0" -num-integer = "^0.1.44" -console-subscriber = "^0.1.1" -log = "^0.4.14" +tracing = "0.1.30" +toml = "0.5.8" +structopt = "0.3.26" +glob = "0.3.0" +tracing-flame = "0.2.0" +tracing-appender = "0.2.0" +tracing-log = "0.1.2" +rolling-file = "0.1.0" +num-integer = "0.1.44" +console-subscriber = "0.1.1" +log = "0.4.14" [dependencies.mediarepo-core] path = "./mediarepo-core" @@ -42,9 +42,9 @@ version = "1.16.1" features = ["macros", "rt-multi-thread", "io-std", "io-util"] [dependencies.tracing-subscriber] -version="0.3.7" +version= "0.3.8" features = ["env-filter", "ansi", "json"] [features] default = ["ffmpeg"] -ffmpeg = ["mediarepo-core/ffmpeg", "mediarepo-logic/ffmpeg"] \ No newline at end of file +ffmpeg = ["mediarepo-core/ffmpeg", "mediarepo-logic/ffmpeg"] diff --git a/mediarepo-daemon/mediarepo-core/Cargo.toml b/mediarepo-daemon/mediarepo-core/Cargo.toml index 8960310..75034c6 100644 --- a/mediarepo-daemon/mediarepo-core/Cargo.toml +++ b/mediarepo-daemon/mediarepo-core/Cargo.toml @@ -7,39 +7,39 @@ workspace = ".." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -thiserror = "^1.0.30" -multihash = "^0.15.0" -multibase = "^0.9.1" -base64 = "^0.13.0" -toml = "^0.5.8" -serde = "^1.0.136" -typemap_rev = "^0.1.5" -futures = "^0.3.19" -itertools = "^0.10.3" -glob = "^0.3.0" -tracing = "^0.1.29" -data-encoding = "^2.3.2" -tokio-graceful-shutdown = "^0.4.3" +thiserror = "1.0.30" +multihash = "0.16.1" +multibase = "0.9.1" +base64 = "0.13.0" +toml = "0.5.8" +serde = "1.0.136" +typemap_rev = "0.1.5" +futures = "0.3.19" +itertools = "0.10.3" +glob = "0.3.0" +tracing = "0.1.30" +data-encoding = "2.3.2" +tokio-graceful-shutdown = "0.4.3" [dependencies.thumbnailer] -version = "^0.3" +version = "0.3.0" default-features = false [dependencies.sea-orm] -version = "^0.5.0" +version = "0.5.0" default-features = false [dependencies.sqlx] -version = "^0.5.10" +version = "0.5.10" default-features = false features = ["migrate"] [dependencies.tokio] -version = "^1.16.1" +version = "1.16.1" features = ["fs", "io-util", "io-std"] [dependencies.config] -version = "^0.11.0" +version = "0.11.0" features = ["toml"] [dependencies.mediarepo-api] @@ -48,4 +48,4 @@ features = ["bromine"] [features] default = [] -ffmpeg = ["thumbnailer/ffmpeg"] \ No newline at end of file +ffmpeg = ["thumbnailer/ffmpeg"] diff --git a/mediarepo-daemon/mediarepo-database/Cargo.toml b/mediarepo-daemon/mediarepo-database/Cargo.toml index 4a2e670..1e79ee4 100644 --- a/mediarepo-daemon/mediarepo-database/Cargo.toml +++ b/mediarepo-daemon/mediarepo-database/Cargo.toml @@ -7,17 +7,17 @@ workspace = ".." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chrono = "^0.4.19" -tracing = "^0.1.29" +chrono = "0.4.19" +tracing = "0.1.30" [dependencies.mediarepo-core] path = "../mediarepo-core" [dependencies.sqlx] -version = "^0.5.10" +version = "0.5.10" features = ["migrate"] [dependencies.sea-orm] -version = "^0.5.0" +version = "0.5.0" features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros", "debug-print"] -default-features = false \ No newline at end of file +default-features = false diff --git a/mediarepo-daemon/mediarepo-logic/Cargo.toml b/mediarepo-daemon/mediarepo-logic/Cargo.toml index ca50233..08a02e6 100644 --- a/mediarepo-daemon/mediarepo-logic/Cargo.toml +++ b/mediarepo-daemon/mediarepo-logic/Cargo.toml @@ -7,13 +7,13 @@ workspace = ".." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chrono = "^0.4.19" -typemap_rev = "^0.1.5" -serde = "^1.0.136" -mime_guess = "^2.0.3" -mime = "^0.3.16" -tracing = "^0.1.29" -async-trait = "^0.1.52" +chrono = "0.4.19" +typemap_rev = "0.1.5" +serde = "1.0.136" +mime_guess = "2.0.3" +mime = "0.3.16" +tracing = "0.1.30" +async-trait = "0.1.52" [dependencies.mediarepo-core] path = "../mediarepo-core" @@ -22,14 +22,14 @@ path = "../mediarepo-core" path = "../mediarepo-database" [dependencies.sea-orm] -version = "^0.5.0-rc.1" +version = "0.5.0" features = ["runtime-tokio-native-tls", "macros"] default-features = false [dependencies.tokio] -version = "^1.15.0" +version = "1.16.1" features = ["fs", "io-std", "io-util"] [features] -ffmpeg = ["mediarepo-core/ffmpeg"] \ No newline at end of file +ffmpeg = ["mediarepo-core/ffmpeg"] diff --git a/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs b/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs index df413d7..f83eef4 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs @@ -23,6 +23,10 @@ impl SortingPresetDto { pub fn keys(&self) -> &Vec { &self.keys } + + pub fn into_keys(self) -> Vec { + self.keys + } } #[derive(Clone, Debug)] diff --git a/mediarepo-daemon/mediarepo-socket/Cargo.toml b/mediarepo-daemon/mediarepo-socket/Cargo.toml index 2c56382..9f38030 100644 --- a/mediarepo-daemon/mediarepo-socket/Cargo.toml +++ b/mediarepo-daemon/mediarepo-socket/Cargo.toml @@ -7,11 +7,11 @@ workspace = ".." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "^1.0.136" -tracing = "^0.1.29" -compare = "^0.1.0" -port_check = "^0.1.5" -rayon = "^1.5.1" +serde = "1.0.136" +tracing = "0.1.30" +compare = "0.1.0" +port_check = "0.1.5" +rayon = "1.5.1" [dependencies.mediarepo-core] path = "../mediarepo-core" @@ -23,13 +23,13 @@ path = "../mediarepo-database" path = "../mediarepo-logic" [dependencies.tokio] -version = "^1.16.1" +version = "1.16.1" features = ["net"] [dependencies.chrono] -version = "^0.4.19" +version = "0.4.19" features = ["serde"] [dependencies.tracing-futures] -version = "^0.2.5" -features = ["tokio-executor"] \ No newline at end of file +version = "0.2.5" +features = ["tokio-executor"] diff --git a/mediarepo-daemon/mediarepo-socket/src/from_model.rs b/mediarepo-daemon/mediarepo-socket/src/from_model.rs index eeffd64..bf101e9 100644 --- a/mediarepo-daemon/mediarepo-socket/src/from_model.rs +++ b/mediarepo-daemon/mediarepo-socket/src/from_model.rs @@ -1,9 +1,13 @@ use mediarepo_core::mediarepo_api::types::files::{ FileBasicDataResponse, FileMetadataResponse, FileStatus, ThumbnailMetadataResponse, }; +use mediarepo_core::mediarepo_api::types::filtering::{ + SortDirection, SortKey, SortNamespace, SortingPreset, +}; use mediarepo_core::mediarepo_api::types::tags::{NamespaceResponse, TagResponse}; use mediarepo_logic::dto::{ - FileDto, FileMetadataDto, FileStatus as FileStatusModel, NamespaceDto, TagDto, ThumbnailDto, + FileDto, FileMetadataDto, FileStatus as FileStatusModel, KeyType, NamespaceDto, SortKeyDto, + SortingPresetDto, TagDto, ThumbnailDto, }; pub trait FromModel { @@ -73,3 +77,42 @@ impl FromModel for NamespaceResponse { } } } + +impl FromModel for SortingPreset { + fn from_model(model: SortingPresetDto) -> Self { + SortingPreset { + id: model.id(), + keys: model + .into_keys() + .into_iter() + .filter_map(map_sort_dto_to_key) + .collect(), + } + } +} + +fn map_sort_dto_to_key(dto: SortKeyDto) -> Option { + let direction = map_direction(dto.ascending()); + + match dto.key_type()? { + KeyType::Namespace => Some(SortKey::Namespace(SortNamespace { + name: dto.value()?.to_owned(), + direction, + })), + KeyType::FileName => Some(SortKey::FileName(direction)), + KeyType::FileSize => Some(SortKey::FileSize(direction)), + KeyType::FileImportedTime => Some(SortKey::FileImportedTime(direction)), + KeyType::FileCreatedTime => Some(SortKey::FileCreatedTime(direction)), + KeyType::FileChangeTime => Some(SortKey::FileChangeTime(direction)), + KeyType::FileType => Some(SortKey::FileType(direction)), + KeyType::NumTags => Some(SortKey::NumTags(direction)), + } +} + +fn map_direction(ascending: bool) -> SortDirection { + if ascending { + SortDirection::Ascending + } else { + SortDirection::Descending + } +} diff --git a/mediarepo-daemon/mediarepo-socket/src/namespaces/mod.rs b/mediarepo-daemon/mediarepo-socket/src/namespaces/mod.rs index 3817972..164ad5f 100644 --- a/mediarepo-daemon/mediarepo-socket/src/namespaces/mod.rs +++ b/mediarepo-daemon/mediarepo-socket/src/namespaces/mod.rs @@ -3,6 +3,7 @@ use mediarepo_core::bromine::{namespace, namespace::Namespace, IPCBuilder}; pub mod files; pub mod jobs; +pub mod presets; pub mod repo; pub mod tags; @@ -12,4 +13,5 @@ pub fn build_namespaces(builder: IPCBuilder) .add_namespace(namespace!(tags::TagsNamespace)) .add_namespace(namespace!(repo::RepoNamespace)) .add_namespace(namespace!(jobs::JobsNamespace)) + .add_namespace(namespace!(presets::PresetsNamespace)) } diff --git a/mediarepo-daemon/mediarepo-socket/src/namespaces/presets.rs b/mediarepo-daemon/mediarepo-socket/src/namespaces/presets.rs new file mode 100644 index 0000000..1e2ad3c --- /dev/null +++ b/mediarepo-daemon/mediarepo-socket/src/namespaces/presets.rs @@ -0,0 +1,116 @@ +use crate::from_model::FromModel; +use crate::utils::get_repo_from_context; +use mediarepo_core::bromine::prelude::*; +use mediarepo_core::mediarepo_api::types::filtering::{SortDirection, SortKey, SortingPreset}; +use mediarepo_logic::dao::DaoProvider; +use mediarepo_logic::dto::{AddSortKeyDto, AddSortingPresetDto, KeyType}; + +pub struct PresetsNamespace; + +impl NamespaceProvider for PresetsNamespace { + fn name() -> &'static str { + "presets" + } + + fn register(handler: &mut EventHandler) { + events!(handler, + "all_sorting_presets" => Self::all_sorting_presets, + "add_sorting_preset" => Self::add_sorting_preset, + "delete_sorting_preset" => Self::delete_sorting_preset + ); + } +} + +impl PresetsNamespace { + #[tracing::instrument(skip_all)] + pub async fn all_sorting_presets(ctx: &Context, _: Event) -> IPCResult<()> { + let repo = get_repo_from_context(ctx).await; + let sorting_presets: Vec = repo + .sorting_preset() + .all() + .await? + .into_iter() + .map(SortingPreset::from_model) + .collect(); + ctx.emit_to(Self::name(), "all_sorting_presets", sorting_presets) + .await?; + + Ok(()) + } + + #[tracing::instrument(skip_all)] + pub async fn add_sorting_preset(ctx: &Context, event: Event) -> IPCResult<()> { + let keys = event + .payload::>()? + .into_iter() + .map(sort_key_to_add_dto) + .collect(); + let repo = get_repo_from_context(ctx).await; + let preset = repo + .sorting_preset() + .add(AddSortingPresetDto { keys }) + .await?; + ctx.emit_to( + Self::name(), + "add_sorting_preset", + SortingPreset::from_model(preset), + ) + .await?; + + Ok(()) + } + + #[tracing::instrument(skip_all)] + pub async fn delete_sorting_preset(ctx: &Context, event: Event) -> IPCResult<()> { + let id = event.payload::()?; + let repo = get_repo_from_context(ctx).await; + repo.sorting_preset().delete(id).await?; + + Ok(()) + } +} + +fn sort_key_to_add_dto(key: SortKey) -> AddSortKeyDto { + match key { + SortKey::Namespace(namespace) => AddSortKeyDto { + ascending: namespace.direction == SortDirection::Ascending, + key_type: KeyType::Namespace, + value: Some(namespace.name), + }, + SortKey::FileName(dir) => AddSortKeyDto { + ascending: dir == SortDirection::Ascending, + key_type: KeyType::FileName, + value: None, + }, + SortKey::FileSize(dir) => AddSortKeyDto { + ascending: dir == SortDirection::Ascending, + key_type: KeyType::FileSize, + value: None, + }, + SortKey::FileImportedTime(dir) => AddSortKeyDto { + ascending: dir == SortDirection::Ascending, + key_type: KeyType::FileImportedTime, + value: None, + }, + SortKey::FileCreatedTime(dir) => AddSortKeyDto { + ascending: dir == SortDirection::Ascending, + key_type: KeyType::FileCreatedTime, + value: None, + }, + SortKey::FileChangeTime(dir) => AddSortKeyDto { + ascending: dir == SortDirection::Ascending, + key_type: KeyType::FileChangeTime, + value: None, + }, + SortKey::FileType(dir) => AddSortKeyDto { + ascending: dir == SortDirection::Ascending, + key_type: KeyType::FileType, + value: None, + }, + SortKey::NumTags(dir) => AddSortKeyDto { + ascending: dir == SortDirection::Ascending, + key_type: KeyType::NumTags, + value: None, + }, + } +} From c0dca663b0c5c4a8df3a7353d0bc05b9109018fd Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 15:37:17 +0100 Subject: [PATCH 07/15] Refactor SortKey to store backend representation internally Signed-off-by: trivernis --- mediarepo-ui/src-tauri/Cargo.lock | 141 +++++++++++++----- mediarepo-ui/src-tauri/Cargo.toml | 14 +- mediarepo-ui/src/api/Api.ts | 15 ++ mediarepo-ui/src/api/api-types/files.ts | 2 +- mediarepo-ui/src/api/api-types/functions.ts | 4 + mediarepo-ui/src/api/api-types/presets.ts | 6 + mediarepo-ui/src/api/api-types/requests.ts | 14 +- mediarepo-ui/src/api/models/SortKey.ts | 106 +++++++++++++ mediarepo-ui/src/api/models/SortingPreset.ts | 20 +++ .../file-search/file-search.component.ts | 8 +- .../sort-dialog/sort-dialog.component.ts | 5 +- mediarepo-ui/src/app/models/SortKey.ts | 35 ----- mediarepo-ui/src/app/models/TabState.ts | 16 +- .../src/app/services/file/file.service.ts | 4 +- .../services/preset/preset.service.spec.ts | 16 ++ .../src/app/services/preset/preset.service.ts | 17 +++ 16 files changed, 323 insertions(+), 100 deletions(-) create mode 100644 mediarepo-ui/src/api/api-types/presets.ts create mode 100644 mediarepo-ui/src/api/models/SortKey.ts create mode 100644 mediarepo-ui/src/api/models/SortingPreset.ts delete mode 100644 mediarepo-ui/src/app/models/SortKey.ts create mode 100644 mediarepo-ui/src/app/services/preset/preset.service.spec.ts create mode 100644 mediarepo-ui/src/app/services/preset/preset.service.ts diff --git a/mediarepo-ui/src-tauri/Cargo.lock b/mediarepo-ui/src-tauri/Cargo.lock index 9b93484..b5081b6 100644 --- a/mediarepo-ui/src-tauri/Cargo.lock +++ b/mediarepo-ui/src-tauri/Cargo.lock @@ -161,9 +161,9 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block-buffer" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +checksum = "03588e54c62ae6d763e2a80090d50353b785795361b4ff5b3bf0a5097fc31c0b" dependencies = [ "generic-array", ] @@ -506,9 +506,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" +checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -519,9 +519,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" +checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" dependencies = [ "cfg-if 1.0.0", "lazy_static", @@ -799,9 +799,9 @@ dependencies = [ [[package]] name = "futf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" dependencies = [ "mac", "new_debug_unreachable", @@ -1416,9 +1416,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.116" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74" +checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" [[package]] name = "lock_api" @@ -1499,7 +1499,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mediarepo-api" -version = "0.28.0" +version = "0.28.1" dependencies = [ "async-trait", "bromine", @@ -1507,7 +1507,7 @@ dependencies = [ "directories", "futures", "mime_guess", - "parking_lot", + "parking_lot 0.12.0", "pathsearch", "serde", "serde_json", @@ -1865,7 +1865,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.0", ] [[package]] @@ -1882,6 +1892,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2f4f894f3865f6c0e02810fc597300f34dc2510f66400da262d8ae10e75767d" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "pathdiff" version = "0.2.1" @@ -2377,7 +2400,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.4", + "semver 1.0.5", ] [[package]] @@ -2425,9 +2448,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "security-framework" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fed7948b6c68acbb6e20c334f55ad635dc0f75506963de4464289fbd3b051ac" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" dependencies = [ "bitflags", "core-foundation 0.9.2", @@ -2438,9 +2461,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57321bf8bc2362081b2599912d2961fe899c0efadf1b4b2f8d48b3e253bb96c" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ "core-foundation-sys 0.8.3", "libc", @@ -2477,9 +2500,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7" [[package]] name = "semver-parser" @@ -2654,14 +2677,14 @@ dependencies = [ [[package]] name = "string_cache" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923f0f39b6267d37d23ce71ae7235602134b250ace715dd2c90421998ddac0c6" +checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26" dependencies = [ "lazy_static", "new_debug_unreachable", - "parking_lot", - "phf_shared 0.8.0", + "parking_lot 0.11.2", + "phf_shared 0.10.0", "precomputed-hash", "serde", ] @@ -2811,7 +2834,7 @@ dependencies = [ "ndk-glue", "ndk-sys", "objc", - "parking_lot", + "parking_lot 0.11.2", "raw-window-handle 0.3.4", "scopeguard", "serde", @@ -2857,7 +2880,7 @@ dependencies = [ "rand 0.8.4", "raw-window-handle 0.3.4", "rfd", - "semver 1.0.4", + "semver 1.0.5", "serde", "serde_json", "serde_repr", @@ -3088,9 +3111,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -3100,9 +3123,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" dependencies = [ "proc-macro2 1.0.36", "quote 1.0.15", @@ -3111,11 +3134,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" dependencies = [ "lazy_static", + "valuable", ] [[package]] @@ -3131,9 +3155,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5312f325fe3588e277415f5a6cca1f4ccad0f248c4cd5a4bd33032d7286abc22" +checksum = "74786ce43333fcf51efe947aed9718fbe46d5c7328ec3f1029e818083966d9aa" dependencies = [ "ansi_term", "lazy_static", @@ -3235,6 +3259,12 @@ dependencies = [ "getrandom 0.2.4", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -3476,6 +3506,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceb069ac8b2117d36924190469735767f0990833935ab430155e71a44bafe148" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" + +[[package]] +name = "windows_i686_gnu" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" + +[[package]] +name = "windows_i686_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" + [[package]] name = "winres" version = "0.1.12" diff --git a/mediarepo-ui/src-tauri/Cargo.toml b/mediarepo-ui/src-tauri/Cargo.toml index 28ad054..ee837a0 100644 --- a/mediarepo-ui/src-tauri/Cargo.toml +++ b/mediarepo-ui/src-tauri/Cargo.toml @@ -10,20 +10,20 @@ edition = "2018" build = "src/build.rs" [build-dependencies] -tauri-build = { version = "^1.0.0-beta.4" } +tauri-build = "1.0.0-beta.4" [dependencies] -serde_json = "^1.0" -serde = { version = "^1.0", features = ["derive"] } -thiserror = "^1.0.30" -typemap_rev = "^0.1.5" +serde_json = "1.0.78" +serde = { version = "1.0.136", features = ["derive"] } +thiserror = "1.0.30" +typemap_rev = "0.1.5" [dependencies.tauri] -version = "^1.0.0-beta.8" +version = "1.0.0-beta.8" features = ["dialog-all", "path-all", "shell-all"] [dependencies.tracing-subscriber] -version = "^0.3.0" +version = "0.3.8" features = ["env-filter"] [dependencies.mediarepo-api] diff --git a/mediarepo-ui/src/api/Api.ts b/mediarepo-ui/src/api/Api.ts index 292cd8f..27e1d58 100644 --- a/mediarepo-ui/src/api/Api.ts +++ b/mediarepo-ui/src/api/Api.ts @@ -4,12 +4,14 @@ import {ApiFunction} from "./api-types/functions"; import { AddLocalFileREquest, AddRepositoryRequest, + AddSortingPresetRequest, ChangeFileTagsRequest, CheckDaemonRunningRequest, CheckLocalRepositoryExistsRequest, CreateTagsRequest, DeleteFileRequest, DeleteRepositoryRequest, + DeleteSortingPresetRequest, DeleteThumbnailsRequest, FindFilesRequest, GetFileMetadataRequest, @@ -31,6 +33,7 @@ import { import {RepositoryData, RepositoryMetadata, SizeMetadata} from "./api-types/repo"; import {CdTagMappings, NamespaceData, TagData} from "./api-types/tags"; import {ShortCache} from "./ShortCache"; +import {SortingPresetData} from "./api-types/presets"; export class MediarepoApi { @@ -184,6 +187,18 @@ export class MediarepoApi { return this.invokePlugin(ApiFunction.RunJob, request); } + public static async getAllSortingPresets(): Promise { + return ShortCache.cached("sorting-presets", () => this.invokePlugin(ApiFunction.GetAllSortingPresets), 1000); + } + + public static async addSortingPreset(request: AddSortingPresetRequest): Promise { + return this.invokePlugin(ApiFunction.AddSortingPreset, request); + } + + public static async deleteSortingPreset(request: DeleteSortingPresetRequest): Promise { + return this.invokePlugin(ApiFunction.DeleteSortingPreset, request); + } + private static async invokePlugin(fn: ApiFunction, args?: any): Promise { return invoke(`plugin:mediarepo|${fn}`, args); } diff --git a/mediarepo-ui/src/api/api-types/files.ts b/mediarepo-ui/src/api/api-types/files.ts index 004917e..cf6387d 100644 --- a/mediarepo-ui/src/api/api-types/files.ts +++ b/mediarepo-ui/src/api/api-types/files.ts @@ -41,7 +41,7 @@ export type ValueComparator = | { Greater: T } | { Between: T[] } -export type SortKey = { Namespace: SortNamespace } +export type SortKeyData = { Namespace: SortNamespace } | { FileName: SortDirection } | { FileSize: SortDirection } | { FileImportedTime: SortDirection } diff --git a/mediarepo-ui/src/api/api-types/functions.ts b/mediarepo-ui/src/api/api-types/functions.ts index 5f61ed0..44f8041 100644 --- a/mediarepo-ui/src/api/api-types/functions.ts +++ b/mediarepo-ui/src/api/api-types/functions.ts @@ -40,4 +40,8 @@ export enum ApiFunction { SetFrontendState = "set_frontend_state", // jobs RunJob = "run_job", + // presets + GetAllSortingPresets = "all_sorting_presets", + AddSortingPreset = "add_sorting_preset", + DeleteSortingPreset = "delete_sorting_preset", } diff --git a/mediarepo-ui/src/api/api-types/presets.ts b/mediarepo-ui/src/api/api-types/presets.ts new file mode 100644 index 0000000..01eb00f --- /dev/null +++ b/mediarepo-ui/src/api/api-types/presets.ts @@ -0,0 +1,6 @@ +import {SortKeyData} from "./files"; + +export type SortingPresetData = { + id: number, + keys: SortKeyData[], +} diff --git a/mediarepo-ui/src/api/api-types/requests.ts b/mediarepo-ui/src/api/api-types/requests.ts index c6c0d24..e58e50c 100644 --- a/mediarepo-ui/src/api/api-types/requests.ts +++ b/mediarepo-ui/src/api/api-types/requests.ts @@ -1,4 +1,4 @@ -import {FileOsMetadata, FileStatus, FilterExpression, SortKey} from "./files"; +import {FileOsMetadata, FileStatus, FilterExpression, SortKeyData} from "./files"; import {RepositoryData, SizeType} from "./repo"; import {JobType} from "./job"; @@ -40,7 +40,7 @@ export type GetSizeRequest = { export type FindFilesRequest = { filters: FilterExpression[], - sortBy: SortKey[] + sortBy: SortKeyData[] }; export type UpdateFileNameRequest = { @@ -107,4 +107,12 @@ export type SetFrontendStateRequest = { export type RunJobRequest = { jobType: JobType, -} +}; + +export type AddSortingPresetRequest = { + sort_keys: SortKeyData[] +}; + +export type DeleteSortingPresetRequest = { + id: number +}; diff --git a/mediarepo-ui/src/api/models/SortKey.ts b/mediarepo-ui/src/api/models/SortKey.ts new file mode 100644 index 0000000..674237e --- /dev/null +++ b/mediarepo-ui/src/api/models/SortKey.ts @@ -0,0 +1,106 @@ +import {SortDirection, SortKeyData} from "../api-types/files"; + +export type SortType = + "Namespace" + | "FileName" + | "FileSize" + | "FileImportedTime" + | "FileCreatedTime" + | "FileChangeTime" + | "FileType" + | "NumTags"; + +export class SortKey { + + constructor(private data: SortKeyData) { + this.data = data; + } + + public get sortType(): SortType { + return Reflect.ownKeys(this.data)[0] as SortType; + } + + public set sortType(value: SortType) { + if (value == "Namespace") { + this.data = { + Namespace: { + direction: this.sortDirection, + name: "" + } + }; + } else { + this.data = { + [value]: { + direction: this.sortDirection + } + } as SortKeyData; + } + } + + public get sortDirection(): SortDirection { + if ("Namespace" in this.data) { + return this.data.Namespace.direction; + } else { + // @ts-ignore + return this.data[this.sortType]; + } + } + + public set sortDirection(value: SortDirection) { + const sortType = this.sortType; + if ("Namespace" in this.data) { + this.data.Namespace.direction = value; + } else { + // @ts-ignore + this.data[this.sortType] = value; + } + } + + public get namespaceName(): string | undefined { + if ("Namespace" in this.data) { + return this.data.Namespace.name; + } + return undefined; + } + + public set namespaceName(value: string | undefined) { + if (value && "Namespace" in this.data) { + this.data.Namespace.name = value; + } + } + + public static fromValues( + sortType: SortType, + sortDirection: SortDirection, + namespaceName: string | undefined + ) { + let data; + + if (sortType === "Namespace") { + data = { + Namespace: { + name: namespaceName!, + direction: sortDirection + } + }; + } else { + data = { + [sortType]: sortDirection + } as SortKeyData; + } + + return new SortKey(data); + } + + public toString(): string { + if (this.sortType == "Namespace") { + return `${this.sortType} '${this.namespaceName}' ${this.sortDirection}`; + } else { + return `${this.sortType} ${this.sortDirection}`; + } + } + + public rawData(): SortKeyData { + return this.data; + } +} diff --git a/mediarepo-ui/src/api/models/SortingPreset.ts b/mediarepo-ui/src/api/models/SortingPreset.ts new file mode 100644 index 0000000..9eb258a --- /dev/null +++ b/mediarepo-ui/src/api/models/SortingPreset.ts @@ -0,0 +1,20 @@ +import {SortKey} from "./SortKey"; +import {SortingPresetData} from "../api-types/presets"; + +export class SortingPreset { + private readonly _id: number; + private keys: SortKey[]; + + constructor(presetData: SortingPresetData) { + this._id = presetData.id; + this.keys = presetData.keys.map(SortKey.fromRawData); + } + + public get id(): number { + return this._id; + } + + public get sortKeys(): SortKey[] { + return this.sortKeys; + } +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts index 065c974..9737c2d 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts @@ -9,7 +9,7 @@ import { Output, ViewChild } from "@angular/core"; -import {SortKey} from "../../../../models/SortKey"; +import {SortKey} from "../../../../../api/models/SortKey"; import {MatDialog} from "@angular/material/dialog"; import {SortDialogComponent} from "./sort-dialog/sort-dialog.component"; import {LoggingService} from "../../../../services/logging/logging.service"; @@ -128,10 +128,8 @@ export class FileSearchComponent implements AfterViewChecked, OnInit { public openSortDialog() { const sortEntries = this.sortExpression.map( - key => JSON.parse(JSON.stringify(key))).map( - key => new SortKey(key.sortType, key.sortDirection, - key.namespaceName - )); + key => JSON.parse(JSON.stringify(key.rawData()))).map( + data => new SortKey(data)); const openedDialog = this.dialog.open(SortDialogComponent, { minWidth: "40vw", data: { diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts index 13b6c44..4bd7271 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts @@ -1,6 +1,6 @@ import {ChangeDetectionStrategy, Component, Inject} from "@angular/core"; import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; -import {SortKey} from "../../../../../models/SortKey"; +import {SortKey} from "../../../../../../api/models/SortKey"; import {CdkDragDrop, moveItemInArray} from "@angular/cdk/drag-drop"; import {Namespace} from "../../../../../../api/models/Namespace"; import {TagService} from "../../../../../services/tag/tag.service"; @@ -22,12 +22,13 @@ export class SortDialogComponent { constructor(public tagService: TagService, public dialogRef: MatDialogRef, @Inject( MAT_DIALOG_DATA) data: any) { this.sortEntries = data.sortEntries; + console.debug(this.sortEntries); tagService.namespaces.subscribe( namespaces => this.namespaces = namespaces); } addNewSortKey() { - const sortKey = new SortKey("FileName", "Ascending", undefined); + const sortKey = SortKey.fromValues("FileName", "Ascending", undefined); this.sortEntries.push(sortKey); } diff --git a/mediarepo-ui/src/app/models/SortKey.ts b/mediarepo-ui/src/app/models/SortKey.ts deleted file mode 100644 index 7738b30..0000000 --- a/mediarepo-ui/src/app/models/SortKey.ts +++ /dev/null @@ -1,35 +0,0 @@ -export class SortKey { - - - constructor( - public sortType: "Namespace" | "FileName" | "FileSize" | "FileImportedTime" | "FileCreatedTime" | "FileChangeTime" | "FileType" | "NumTags", - public sortDirection: "Ascending" | "Descending", - public namespaceName: string | undefined - ) { - } - - public toString(): string { - if (this.sortType == "Namespace") { - return `${this.sortType} '${this.namespaceName}' ${this.sortDirection}`; - } else { - return `${this.sortType} ${this.sortDirection}`; - } - } - - public toBackendType(): any { - - if (this.sortType == "Namespace") { - return { - "Namespace": { - direction: this.sortDirection, - name: this.namespaceName - } - }; - } else { - let returnObj: any = {}; - returnObj[this.sortType] = this.sortDirection; - - return returnObj; - } - } -} diff --git a/mediarepo-ui/src/app/models/TabState.ts b/mediarepo-ui/src/app/models/TabState.ts index df9c6a3..2798640 100644 --- a/mediarepo-ui/src/app/models/TabState.ts +++ b/mediarepo-ui/src/app/models/TabState.ts @@ -2,10 +2,11 @@ import {BehaviorSubject} from "rxjs"; import {TabCategory} from "./TabCategory"; import {FileService} from "../services/file/file.service"; import {File} from "../../api/models/File"; -import {SortKey} from "./SortKey"; +import {SortKey} from "../../api/models/SortKey"; import {debounceTime} from "rxjs/operators"; import {mapNew} from "../../api/models/adaptors"; import {SearchFilters} from "../../api/models/SearchFilters"; +import {SortKeyData} from "../../api/api-types/files"; export class TabState { public uuid: number; @@ -17,7 +18,7 @@ export class TabState { public files = new BehaviorSubject([]); public filters = new BehaviorSubject(new SearchFilters([])); public sortKeys = new BehaviorSubject( - [new SortKey( + [SortKey.fromValues( "FileImportedTime", "Ascending", undefined @@ -50,14 +51,7 @@ export class TabState { dto.category, fileService ); - const sortKeys = dto.sortKeys.map( - (s: { sortType: any, sortDirection: any, namespaceName: any }) => - new SortKey( - s.sortType, - s.sortDirection, - s.namespaceName - ) - ); + const sortKeys = dto.sortKeys.map((data: SortKeyData) => new SortKey(data)); state.filters.next(new SearchFilters(dto.filters ?? [])); state.sortKeys.next(sortKeys); state.mode.next(dto.mode ?? "grid"); @@ -90,7 +84,7 @@ export class TabState { uuid: this.uuid, category: this.category, filters: this.filters.value.getFilters(), - sortKeys: this.sortKeys.value, + sortKeys: this.sortKeys.value.map(key => key.rawData()), mode: this.mode.value, selectedFileHash: this.selectedCD.value, files: this.category === TabCategory.Import ? this.files.value.map( diff --git a/mediarepo-ui/src/app/services/file/file.service.ts b/mediarepo-ui/src/app/services/file/file.service.ts index 6d49a8d..4f2e549 100644 --- a/mediarepo-ui/src/app/services/file/file.service.ts +++ b/mediarepo-ui/src/app/services/file/file.service.ts @@ -1,7 +1,7 @@ import {Inject, Injectable} from "@angular/core"; import {File} from "../../../api/models/File"; import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser"; -import {SortKey} from "../../models/SortKey"; +import {SortKey} from "../../../api/models/SortKey"; import {MediarepoApi} from "../../../api/Api"; import {mapMany, mapNew} from "../../../api/models/adaptors"; import {FileMetadata, FileStatus} from "../../../api/api-types/files"; @@ -26,7 +26,7 @@ export class FileService { return MediarepoApi.findFiles( { filters: filters.getFilters(), - sortBy: sortBy.map(k => k.toBackendType()) + sortBy: sortBy.map(k => k.rawData()) }) .then(mapMany(mapNew(File))); } diff --git a/mediarepo-ui/src/app/services/preset/preset.service.spec.ts b/mediarepo-ui/src/app/services/preset/preset.service.spec.ts new file mode 100644 index 0000000..0e4a6b3 --- /dev/null +++ b/mediarepo-ui/src/app/services/preset/preset.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { PresetService } from './preset.service'; + +describe('PresetService', () => { + let service: PresetService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(PresetService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/services/preset/preset.service.ts b/mediarepo-ui/src/app/services/preset/preset.service.ts new file mode 100644 index 0000000..32fb28b --- /dev/null +++ b/mediarepo-ui/src/app/services/preset/preset.service.ts @@ -0,0 +1,17 @@ +import {Injectable} from "@angular/core"; +import {SortingPreset} from "../../../api/models/SortingPreset"; +import {MediarepoApi} from "../../../api/Api"; +import {mapMany, mapNew} from "../../../api/models/adaptors"; + +@Injectable({ + providedIn: "root" +}) +export class PresetService { + + constructor() { + } + + public async getAllSortingPresets(): Promise { + return MediarepoApi.getAllSortingPresets().then(mapMany(mapNew(SortingPreset))); + } +} From ece096fb866c18984301c7fef6420e34bf9eb6d8 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 16:03:04 +0100 Subject: [PATCH 08/15] Replace sortingExpression with sortingPreset in all files Signed-off-by: trivernis --- mediarepo-ui/src/api/models/SortKey.ts | 10 +++---- mediarepo-ui/src/api/models/SortingPreset.ts | 25 +++++++++++++++-- .../file-search/file-search.component.html | 3 +- .../file-search/file-search.component.ts | 20 ++++++------- .../sort-dialog/sort-dialog.component.html | 20 +++++++------ .../sort-dialog/sort-dialog.component.ts | 28 +++++++++++++------ mediarepo-ui/src/app/models/TabState.ts | 22 ++++++++------- .../src/app/services/file/file.service.ts | 2 +- .../src/app/services/state/state.service.ts | 22 +++++++-------- 9 files changed, 94 insertions(+), 58 deletions(-) diff --git a/mediarepo-ui/src/api/models/SortKey.ts b/mediarepo-ui/src/api/models/SortKey.ts index 674237e..6ed1d57 100644 --- a/mediarepo-ui/src/api/models/SortKey.ts +++ b/mediarepo-ui/src/api/models/SortKey.ts @@ -69,13 +69,17 @@ export class SortKey { } } + public get rawData(): SortKeyData { + return this.data; + } + public static fromValues( sortType: SortType, sortDirection: SortDirection, namespaceName: string | undefined ) { let data; - + if (sortType === "Namespace") { data = { Namespace: { @@ -99,8 +103,4 @@ export class SortKey { return `${this.sortType} ${this.sortDirection}`; } } - - public rawData(): SortKeyData { - return this.data; - } } diff --git a/mediarepo-ui/src/api/models/SortingPreset.ts b/mediarepo-ui/src/api/models/SortingPreset.ts index 9eb258a..43bc7f3 100644 --- a/mediarepo-ui/src/api/models/SortingPreset.ts +++ b/mediarepo-ui/src/api/models/SortingPreset.ts @@ -1,20 +1,39 @@ import {SortKey} from "./SortKey"; import {SortingPresetData} from "../api-types/presets"; +import {mapNew} from "./adaptors"; export class SortingPreset { - private readonly _id: number; private keys: SortKey[]; constructor(presetData: SortingPresetData) { this._id = presetData.id; - this.keys = presetData.keys.map(SortKey.fromRawData); + this.keys = presetData.keys.map(mapNew(SortKey)); } + private _id: number; + public get id(): number { return this._id; } + public set id(value: number) { + this._id = value; + } + public get sortKeys(): SortKey[] { - return this.sortKeys; + return this.keys; + } + + public get rawData(): SortingPresetData { + return { + id: this._id, + keys: this.keys.map(k => k.rawData), + }; + } + + public static fromValues(id: number, keys: SortKey[]) { + let preset = new SortingPreset({ id, keys: [] }); + preset.keys = keys; + return preset; } } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html index e4de89f..f9e7f61 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html @@ -35,7 +35,8 @@ - + diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts index 9737c2d..7c6f149 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts @@ -9,7 +9,6 @@ import { Output, ViewChild } from "@angular/core"; -import {SortKey} from "../../../../../api/models/SortKey"; import {MatDialog} from "@angular/material/dialog"; import {SortDialogComponent} from "./sort-dialog/sort-dialog.component"; import {LoggingService} from "../../../../services/logging/logging.service"; @@ -23,6 +22,7 @@ import {FileStatus, FilterExpression,} from "../../../../../api/api-types/files" import {filterExpressionToString} from "../../../../utils/filter-utils"; import {MatCheckboxChange} from "@angular/material/checkbox"; import * as deepEqual from "fast-deep-equal"; +import {SortingPreset} from "../../../../../api/models/SortingPreset"; @Component({ @@ -32,7 +32,7 @@ import * as deepEqual from "fast-deep-equal"; changeDetection: ChangeDetectionStrategy.OnPush }) export class FileSearchComponent implements AfterViewChecked, OnInit { - public sortExpression: SortKey[] = []; + public sortingPreset: SortingPreset = new SortingPreset({ id: -1, keys: [] }); public filters: SearchFilters = new SearchFilters([]); @Input() availableTags: Tag[] = []; @@ -68,7 +68,7 @@ export class FileSearchComponent implements AfterViewChecked, OnInit { this.filters = f; this.assignDisplayedFilters(); }); - this.state.sortKeys.subscribe(s => this.sortExpression = s); + this.state.sortingPreset.subscribe(s => this.sortingPreset = s); this.applyStatusFromFilters(); this.needsScroll = true; this.assignDisplayedFilters(); @@ -127,20 +127,18 @@ export class FileSearchComponent implements AfterViewChecked, OnInit { } public openSortDialog() { - const sortEntries = this.sortExpression.map( - key => JSON.parse(JSON.stringify(key.rawData()))).map( - data => new SortKey(data)); + const sortingPreset = new SortingPreset(JSON.parse(JSON.stringify(this.sortingPreset.rawData))); const openedDialog = this.dialog.open(SortDialogComponent, { minWidth: "40vw", data: { - sortEntries, + sortingPreset, }, disableClose: true, }); - openedDialog.afterClosed().subscribe(async (sortExpression) => { - if (sortExpression) { - this.sortExpression = sortExpression; - this.state.setSortKeys(this.sortExpression); + openedDialog.afterClosed().subscribe(async (sortingPreset) => { + if (sortingPreset) { + this.sortingPreset = sortingPreset; + this.state.setSortingPreset(this.sortingPreset); } }); } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html index c6fc105..a350274 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html @@ -1,7 +1,7 @@

Sort Entries

-
+
@@ -21,14 +21,16 @@ Namespace Name - - + {{namespace.name}} @@ -37,16 +39,18 @@
Direction - + Ascending Descending - - diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts index 4bd7271..76b65d7 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts @@ -5,6 +5,7 @@ import {CdkDragDrop, moveItemInArray} from "@angular/cdk/drag-drop"; import {Namespace} from "../../../../../../api/models/Namespace"; import {TagService} from "../../../../../services/tag/tag.service"; import {compareSearchResults} from "../../../../../utils/compare-utils"; +import {SortingPreset} from "../../../../../../api/models/SortingPreset"; @Component({ selector: "app-sort-dialog", @@ -14,31 +15,34 @@ import {compareSearchResults} from "../../../../../utils/compare-utils"; }) export class SortDialogComponent { - public sortEntries: SortKey[] = []; + public sortingPreset: SortingPreset = SortingPreset.fromValues(-1, []); public suggestedNamespaces: Namespace[] = []; + private previousId: number = -1; private namespaces: Namespace[] = []; constructor(public tagService: TagService, public dialogRef: MatDialogRef, @Inject( MAT_DIALOG_DATA) data: any) { - this.sortEntries = data.sortEntries; - console.debug(this.sortEntries); + this.sortingPreset = data.sortingPreset; + console.debug(this.sortingPreset); tagService.namespaces.subscribe( namespaces => this.namespaces = namespaces); } addNewSortKey() { const sortKey = SortKey.fromValues("FileName", "Ascending", undefined); - this.sortEntries.push(sortKey); + this.handlePresetChange(); + this.sortingPreset.sortKeys.push(sortKey); } public removeSortKey(sortKey: SortKey): void { - const index = this.sortEntries.indexOf(sortKey); - this.sortEntries.splice(index, 1); + const index = this.sortingPreset.sortKeys.indexOf(sortKey); + this.handlePresetChange(); + this.sortingPreset.sortKeys.splice(index, 1); } public confirmSort(): void { - this.dialogRef.close(this.sortEntries); + this.dialogRef.close(this.sortingPreset); } public cancelSort(): void { @@ -46,7 +50,8 @@ export class SortDialogComponent { } public onSortEntryDrop(event: CdkDragDrop): void { - moveItemInArray(this.sortEntries, event.previousIndex, + this.handlePresetChange(); + moveItemInArray(this.sortingPreset.sortKeys, event.previousIndex, event.currentIndex ); } @@ -56,4 +61,11 @@ export class SortDialogComponent { (a, b) => compareSearchResults(value, a.name, b.name)) .slice(0, 50); } + + public handlePresetChange() { + if (this.sortingPreset.id >= 0) { + this.previousId = this.sortingPreset.id; + this.sortingPreset.id = -1; + } + } } diff --git a/mediarepo-ui/src/app/models/TabState.ts b/mediarepo-ui/src/app/models/TabState.ts index 2798640..fc75b1b 100644 --- a/mediarepo-ui/src/app/models/TabState.ts +++ b/mediarepo-ui/src/app/models/TabState.ts @@ -6,7 +6,7 @@ import {SortKey} from "../../api/models/SortKey"; import {debounceTime} from "rxjs/operators"; import {mapNew} from "../../api/models/adaptors"; import {SearchFilters} from "../../api/models/SearchFilters"; -import {SortKeyData} from "../../api/api-types/files"; +import {SortingPreset} from "../../api/models/SortingPreset"; export class TabState { public uuid: number; @@ -17,12 +17,14 @@ export class TabState { public files = new BehaviorSubject([]); public filters = new BehaviorSubject(new SearchFilters([])); - public sortKeys = new BehaviorSubject( + public sortingPreset = new BehaviorSubject(SortingPreset.fromValues( + -1, [SortKey.fromValues( "FileImportedTime", "Ascending", undefined - )]); + )] + )); private fileService: FileService; @@ -37,7 +39,7 @@ export class TabState { if (this.category === TabCategory.Files) { this.filters.pipe(debounceTime(500)) .subscribe(async () => await this.findFiles()); - this.sortKeys.pipe(debounceTime(100)) + this.sortingPreset.pipe(debounceTime(100)) .subscribe(async () => await this.findFiles()); } } @@ -51,9 +53,9 @@ export class TabState { dto.category, fileService ); - const sortKeys = dto.sortKeys.map((data: SortKeyData) => new SortKey(data)); + state.filters.next(new SearchFilters(dto.filters ?? [])); - state.sortKeys.next(sortKeys); + state.sortingPreset.next(new SortingPreset(dto.sortingPreset)); state.mode.next(dto.mode ?? "grid"); state.selectedCD.next(dto.selectedFileHash); state.files.next((dto.files ?? []).map(mapNew(File))); @@ -65,7 +67,7 @@ export class TabState { this.loading.next(true); const files = await this.fileService.findFiles( this.filters.value, - this.sortKeys.value + this.sortingPreset.value.sortKeys ); this.files.next(files); this.loading.next(false); @@ -75,8 +77,8 @@ export class TabState { this.filters.next(filters); } - public setSortKeys(keys: SortKey[]) { - this.sortKeys.next(keys); + public setSortingPreset(preset: SortingPreset) { + this.sortingPreset.next(preset); } public getDTO(): any { @@ -84,7 +86,7 @@ export class TabState { uuid: this.uuid, category: this.category, filters: this.filters.value.getFilters(), - sortKeys: this.sortKeys.value.map(key => key.rawData()), + sortingPreset: this.sortingPreset.value.rawData, mode: this.mode.value, selectedFileHash: this.selectedCD.value, files: this.category === TabCategory.Import ? this.files.value.map( diff --git a/mediarepo-ui/src/app/services/file/file.service.ts b/mediarepo-ui/src/app/services/file/file.service.ts index 4f2e549..ab783a9 100644 --- a/mediarepo-ui/src/app/services/file/file.service.ts +++ b/mediarepo-ui/src/app/services/file/file.service.ts @@ -26,7 +26,7 @@ export class FileService { return MediarepoApi.findFiles( { filters: filters.getFilters(), - sortBy: sortBy.map(k => k.rawData()) + sortBy: sortBy.map(k => k.rawData) }) .then(mapMany(mapNew(File))); } diff --git a/mediarepo-ui/src/app/services/state/state.service.ts b/mediarepo-ui/src/app/services/state/state.service.ts index 00a4738..3d2a0f7 100644 --- a/mediarepo-ui/src/app/services/state/state.service.ts +++ b/mediarepo-ui/src/app/services/state/state.service.ts @@ -59,6 +59,16 @@ export class StateService { this.state.next(state); } + /** + * Sets the state of the frontend + * @returns {Promise} + */ + public async saveState(): Promise { + if (this.repoService.selectedRepository.value) { + await MediarepoApi.setFrontendState({ state: this.state.value.serializeJson() }); + } + } + private subscribeToState(state: AppState) { state.tabs.subscribe(async tabs => { this.tabSubscriptions.forEach(s => s.unsubscribe()); @@ -70,7 +80,7 @@ export class StateService { private subscribeToTab(tab: TabState) { this.tabSubscriptions.push(tab.filters .subscribe(() => this.stateChange.next())); - this.tabSubscriptions.push(tab.sortKeys + this.tabSubscriptions.push(tab.sortingPreset .subscribe(() => this.stateChange.next())); this.tabSubscriptions.push( tab.selectedCD.subscribe(() => this.stateChange.next())); @@ -78,14 +88,4 @@ export class StateService { tab.mode.subscribe(() => this.stateChange.next())); this.tabSubscriptions.push(tab.files.subscribe(() => this.stateChange.next())); } - - /** - * Sets the state of the frontend - * @returns {Promise} - */ - public async saveState(): Promise { - if (this.repoService.selectedRepository.value) { - await MediarepoApi.setFrontendState({state: this.state.value.serializeJson()}); - } - } } From e431450a436721c2d43100245d52b31163450f78 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 16:33:30 +0100 Subject: [PATCH 09/15] Improve sort preset display Signed-off-by: trivernis --- mediarepo-ui/src/api/models/SortingPreset.ts | 4 +++ .../file-search/file-search.component.html | 5 ++-- .../sort-button/sort-button.component.html | 14 ++++++++++ .../sort-button/sort-button.component.scss | 27 +++++++++++++++++++ .../sort-button/sort-button.component.spec.ts | 25 +++++++++++++++++ .../sort-button/sort-button.component.ts | 17 ++++++++++++ .../shared/sidebar/sidebar.module.ts | 12 +++++++-- mediarepo-ui/src/colors.scss | 3 +++ 8 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html create mode 100644 mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss create mode 100644 mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.spec.ts create mode 100644 mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.ts diff --git a/mediarepo-ui/src/api/models/SortingPreset.ts b/mediarepo-ui/src/api/models/SortingPreset.ts index 43bc7f3..5fe3d28 100644 --- a/mediarepo-ui/src/api/models/SortingPreset.ts +++ b/mediarepo-ui/src/api/models/SortingPreset.ts @@ -36,4 +36,8 @@ export class SortingPreset { preset.keys = keys; return preset; } + + public toString(): string { + return this.sortKeys.join(", "); + } } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html index f9e7f61..4161489 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html @@ -35,8 +35,9 @@ - +
diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html new file mode 100644 index 0000000..5bfa0a4 --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html @@ -0,0 +1,14 @@ + diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss new file mode 100644 index 0000000..1fad7f8 --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss @@ -0,0 +1,27 @@ +@import "src/colors"; + +.sort-button { + width: 100%; + align-items: center; + background-color: $background-lighter-10; + text-overflow: ellipsis; + overflow: hidden; +} + +.sort-key-direction { + font-size: 1.5em; + vertical-align: bottom; + margin-bottom: 0.6em; +} + +.sort-key-type { + color: $primary-lighter-50 +} + +.sort-key-namespace { + color: $accent-lighter-10; +} + +.sort-key:last-child .key-divider { + display: none; +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.spec.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.spec.ts new file mode 100644 index 0000000..04601bd --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SortButtonComponent } from './sort-button.component'; + +describe('SortButtonComponent', () => { + let component: SortButtonComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SortButtonComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SortButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.ts new file mode 100644 index 0000000..c76e985 --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.ts @@ -0,0 +1,17 @@ +import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from "@angular/core"; +import {SortingPreset} from "../../../../../../api/models/SortingPreset"; + +@Component({ + selector: "app-sort-button", + templateUrl: "./sort-button.component.html", + styleUrls: ["./sort-button.component.scss"], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SortButtonComponent { + + @Input() selectedPreset!: SortingPreset; + @Output() appClick = new EventEmitter(); + + constructor() { + } +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts b/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts index a3671f1..57b8de1 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts @@ -7,9 +7,11 @@ import { MatAddCircle, MatChangeCircle, MatDeleteSweep, + MatExpandLess, + MatExpandMore, MatFilterAlt, MatRemove, - MatRemoveCircle + MatRemoveCircle, } from "@ng-icons/material-icons"; import {MatRippleModule} from "@angular/material/core"; import {MatButtonModule} from "@angular/material/button"; @@ -48,6 +50,8 @@ import { } from "./file-search/filter-dialog/filter-expression-list-item/filter-expression-list-item.component"; import {GetTagQueryPipe} from "./file-search/filter-pipes/get-tag-query.pipe"; import {GetPropertyQueryPipe} from "./file-search/filter-pipes/get-property-query.pipe"; +import {SortButtonComponent} from "./file-search/sort-button/sort-button.component"; +import {MatTooltipModule} from "@angular/material/tooltip"; @NgModule({ @@ -66,6 +70,7 @@ import {GetPropertyQueryPipe} from "./file-search/filter-pipes/get-property-quer FilterExpressionListItemComponent, GetTagQueryPipe, GetPropertyQueryPipe, + SortButtonComponent, ], exports: [ TagEditComponent, @@ -81,7 +86,9 @@ import {GetPropertyQueryPipe} from "./file-search/filter-pipes/get-property-quer MatAddCircle, MatRemoveCircle, MatDeleteSweep, - MatFilterAlt + MatFilterAlt, + MatExpandMore, + MatExpandLess, }), MatRippleModule, MatButtonModule, @@ -102,6 +109,7 @@ import {GetPropertyQueryPipe} from "./file-search/filter-pipes/get-property-quer MatMenuModule, ReactiveFormsModule, MatAutocompleteModule, + MatTooltipModule, ] }) export class SidebarModule { diff --git a/mediarepo-ui/src/colors.scss b/mediarepo-ui/src/colors.scss index 08316df..e8403cc 100644 --- a/mediarepo-ui/src/colors.scss +++ b/mediarepo-ui/src/colors.scss @@ -6,6 +6,7 @@ $primary-lighter-10: lighten($primary, 10%); $primary-lighter-20: lighten($primary, 20%); $primary-lighter-30: lighten($primary, 30%); $primary-lighter-40: lighten($primary, 40%); +$primary-lighter-50: lighten($primary, 50%); $primary-darker-10: darken($primary, 10%); $primary-darker-20: darken($primary, 20%); $primary-darker-30: darken($primary, 30%); @@ -21,6 +22,8 @@ $text: #FFF; $text-darker-10: darken($text, 10%); $background: #424242; +$background-lighter-05: lighten($background, 4%); +$background-lighter-10: lighten($background, 10%); // specifics $tag-namespace: $accent-lighter-10; From 12d85b50cc0cce5dbe33bc3a88fffb229516ca6b Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 18:28:55 +0100 Subject: [PATCH 10/15] Fix preset creation Signed-off-by: trivernis --- ..._fix-uniqueness-of-sorting-preset-keys.sql | 17 +++++ .../src/entities/sorting_preset_key.rs | 1 + .../src/dao/sorting_preset/add.rs | 62 +++++++++++++------ .../src/dao/sorting_preset/mod.rs | 6 +- .../src/namespaces/files/mod.rs | 6 +- .../src/namespaces/presets.rs | 2 + 6 files changed, 67 insertions(+), 27 deletions(-) create mode 100644 mediarepo-daemon/mediarepo-database/migrations/20220205165133_fix-uniqueness-of-sorting-preset-keys.sql diff --git a/mediarepo-daemon/mediarepo-database/migrations/20220205165133_fix-uniqueness-of-sorting-preset-keys.sql b/mediarepo-daemon/mediarepo-database/migrations/20220205165133_fix-uniqueness-of-sorting-preset-keys.sql new file mode 100644 index 0000000..e2b3c71 --- /dev/null +++ b/mediarepo-daemon/mediarepo-database/migrations/20220205165133_fix-uniqueness-of-sorting-preset-keys.sql @@ -0,0 +1,17 @@ +PRAGMA foreign_keys= off; +ALTER TABLE sorting_preset_keys + RENAME TO _sorting_preset_keys_old; + +CREATE TABLE sorting_preset_keys +( + preset_id INTEGER REFERENCES sorting_presets (id) ON DELETE CASCADE, + key_id INTEGER REFERENCES sort_keys (id), + key_index INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (preset_id, key_id, key_index) +); + +INSERT INTO sorting_preset_keys SELECT * FROM _sorting_preset_keys_old; + +DROP TABLE _sorting_preset_keys_old; + +PRAGMA foreign_keys= on; diff --git a/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset_key.rs b/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset_key.rs index 4381031..6d882db 100644 --- a/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset_key.rs +++ b/mediarepo-daemon/mediarepo-database/src/entities/sorting_preset_key.rs @@ -9,6 +9,7 @@ pub struct Model { #[sea_orm(primary_key)] key_id: i32, + #[sea_orm(primary_key)] key_index: i32, } diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs index f8e51f6..81c8aeb 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs @@ -4,7 +4,13 @@ use mediarepo_core::error::RepoResult; use mediarepo_database::entities::{sort_key, sorting_preset, sorting_preset_key}; use sea_orm::prelude::*; use sea_orm::ActiveValue::Set; -use sea_orm::{Condition, ConnectionTrait, DatabaseTransaction, JoinType, QuerySelect}; +use sea_orm::{ + Condition, ConnectionTrait, DatabaseTransaction, DbBackend, FromQueryResult, JoinType, + QuerySelect, Statement, +}; + +#[allow(unused_imports)] +use sea_orm::TryGetableMany; // otherwise intellijrust hates on me impl SortingPresetDao { #[tracing::instrument(level = "debug", skip(self))] @@ -33,10 +39,17 @@ impl SortingPresetDao { trx.commit().await?; return Ok(SortingPresetDto::new(model, keys)); } - let preset_model = sorting_preset::ActiveModel { - ..Default::default() - }; - let preset_model = preset_model.insert(&trx).await?; + + // sea_orm currently doesn't support all-default-value inserts. + // TODOD: Replace after the change for default inserts has been merged + let preset_model = sorting_preset::Model::find_by_statement(Statement::from_string( + DbBackend::Sqlite, + "INSERT INTO sorting_presets DEFAULT VALUES RETURNING *;".to_string(), + )) + .one(&trx) + .await? + .expect("failed to insert new sorting preset"); + let mapping_models = key_ids .into_iter() .map(|(idx, key)| sorting_preset_key::ActiveModel { @@ -45,9 +58,12 @@ impl SortingPresetDao { key_index: Set(idx as i32), }) .collect::>(); - sorting_preset_key::Entity::insert_many(mapping_models) - .exec(&trx) - .await?; + + if !mapping_models.is_empty() { + sorting_preset_key::Entity::insert_many(mapping_models) + .exec(&trx) + .await?; + } trx.commit().await?; Ok(SortingPresetDto::new(preset_model, keys)) @@ -56,19 +72,21 @@ impl SortingPresetDao { async fn add_keys( trx: &DatabaseTransaction, - mut keys: Vec, + keys: Vec, ) -> RepoResult> { let mut key_dtos = find_sort_keys(trx, &keys).await?; + let mut insert_keys = keys.clone(); + key_dtos.iter().for_each(|key| { - keys.retain(|k| { + insert_keys.retain(|k| { k.ascending != key.ascending() - && Some(k.key_type) != key.key_type() - && key.value() != key.value() + || k.key_type != key.key_type().unwrap() + || !compare_opts_eq(key.value(), k.value.as_ref()) }) }); - if !keys.is_empty() { - let active_models: Vec = keys + if !insert_keys.is_empty() { + let active_models: Vec = insert_keys .iter() .cloned() .map(|key| sort_key::ActiveModel { @@ -81,7 +99,7 @@ async fn add_keys( sort_key::Entity::insert_many(active_models) .exec(trx) .await?; - let mut new_keys = find_sort_keys(trx, &keys).await?; + let mut new_keys = find_sort_keys(trx, &insert_keys).await?; key_dtos.append(&mut new_keys); } @@ -91,9 +109,9 @@ async fn add_keys( key_dtos .iter() .find(|key| { - k.ascending != key.ascending() - && Some(k.key_type) != key.key_type() - && key.value() != key.value() + k.ascending == key.ascending() + && k.key_type == key.key_type().unwrap() + && compare_opts_eq(key.value(), k.value.as_ref()) }) .cloned() }) @@ -144,3 +162,11 @@ fn create_mapping_condition(entry: (usize, i32)) -> Condition { .add(sorting_preset_key::Column::KeyId.eq(entry.1)) .add(sorting_preset_key::Column::KeyIndex.eq(entry.0 as i32)) } + +fn compare_opts_eq(opt1: Option, opt2: Option) -> bool { + if let (Some(opt1), Some(opt2)) = (&opt1, &opt2) { + opt1 == opt2 + } else { + opt1.is_none() && opt2.is_none() + } +} diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs index a265aa5..06fbf1c 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs @@ -5,7 +5,7 @@ use crate::dto::{SortKeyDto, SortingPresetDto}; use mediarepo_core::error::RepoResult; use mediarepo_database::entities::{sort_key, sorting_preset, sorting_preset_key}; use sea_orm::prelude::*; -use sea_orm::{JoinType, QueryOrder, QuerySelect}; +use sea_orm::QueryOrder; dao_provider!(SortingPresetDao); @@ -14,10 +14,6 @@ impl SortingPresetDao { pub async fn all(&self) -> RepoResult> { let presets = sorting_preset::Entity::find() .find_with_related(sort_key::Entity) - .join( - JoinType::InnerJoin, - sorting_preset_key::Relation::SortingKey.def(), - ) .order_by_asc(sorting_preset_key::Column::KeyIndex) .all(&self.ctx.db) .await? diff --git a/mediarepo-daemon/mediarepo-socket/src/namespaces/files/mod.rs b/mediarepo-daemon/mediarepo-socket/src/namespaces/files/mod.rs index 644a6f0..339b6bd 100644 --- a/mediarepo-daemon/mediarepo-socket/src/namespaces/files/mod.rs +++ b/mediarepo-daemon/mediarepo-socket/src/namespaces/files/mod.rs @@ -291,10 +291,8 @@ impl FilesNamespace { let found_thumbnail = thumbnails.into_iter().find(|thumb| { let Dimensions { height, width } = thumb.size(); - *height >= min_size.0 - && *height <= max_size.0 - && *width >= min_size.1 - && *width <= max_size.1 + (*height <= max_size.0 && *width <= max_size.1) + && (*width >= min_size.1 || *height >= min_size.0) }); let thumbnail = if let Some(thumbnail) = found_thumbnail { diff --git a/mediarepo-daemon/mediarepo-socket/src/namespaces/presets.rs b/mediarepo-daemon/mediarepo-socket/src/namespaces/presets.rs index 1e2ad3c..fbcd50c 100644 --- a/mediarepo-daemon/mediarepo-socket/src/namespaces/presets.rs +++ b/mediarepo-daemon/mediarepo-socket/src/namespaces/presets.rs @@ -65,6 +65,8 @@ impl PresetsNamespace { let id = event.payload::()?; let repo = get_repo_from_context(ctx).await; repo.sorting_preset().delete(id).await?; + ctx.emit_to(Self::name(), "delete_sorting_preset", ()) + .await?; Ok(()) } From 91531bc94070061e860f54b3b28ccc85046b8306 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 18:29:13 +0100 Subject: [PATCH 11/15] Add sorting preset selection in sort dialog Signed-off-by: trivernis --- mediarepo-ui/src/api/api-types/requests.ts | 2 +- mediarepo-ui/src/api/models/SortKey.ts | 8 ++- mediarepo-ui/src/api/models/SortingPreset.ts | 5 ++ .../sort-button/sort-button.component.html | 8 +-- .../sort-button/sort-button.component.scss | 18 ----- .../sort-dialog/sort-dialog.component.html | 34 +++++++++- .../sort-dialog/sort-dialog.component.scss | 15 ++++- .../sort-dialog/sort-dialog.component.ts | 65 +++++++++++++++++-- .../sort-preset-item.component.html | 7 ++ .../sort-preset-item.component.scss | 20 ++++++ .../sort-preset-item.component.spec.ts | 25 +++++++ .../sort-preset-item.component.ts | 16 +++++ .../shared/sidebar/sidebar.module.ts | 2 + .../src/app/services/preset/preset.service.ts | 9 +++ 14 files changed, 197 insertions(+), 37 deletions(-) create mode 100644 mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.html create mode 100644 mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.scss create mode 100644 mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.spec.ts create mode 100644 mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.ts diff --git a/mediarepo-ui/src/api/api-types/requests.ts b/mediarepo-ui/src/api/api-types/requests.ts index e58e50c..f0bec62 100644 --- a/mediarepo-ui/src/api/api-types/requests.ts +++ b/mediarepo-ui/src/api/api-types/requests.ts @@ -110,7 +110,7 @@ export type RunJobRequest = { }; export type AddSortingPresetRequest = { - sort_keys: SortKeyData[] + sortKeys: SortKeyData[] }; export type DeleteSortingPresetRequest = { diff --git a/mediarepo-ui/src/api/models/SortKey.ts b/mediarepo-ui/src/api/models/SortKey.ts index 6ed1d57..bf85cb4 100644 --- a/mediarepo-ui/src/api/models/SortKey.ts +++ b/mediarepo-ui/src/api/models/SortKey.ts @@ -98,9 +98,13 @@ export class SortKey { public toString(): string { if (this.sortType == "Namespace") { - return `${this.sortType} '${this.namespaceName}' ${this.sortDirection}`; + return `${this.sortType} '${this.namespaceName}' ${this.getDirectionString()}`; } else { - return `${this.sortType} ${this.sortDirection}`; + return `${this.sortType} ${this.getDirectionString()}`; } } + + private getDirectionString(): string { + return this.sortDirection === "Ascending" ? "â–²" : "â–¼"; + } } diff --git a/mediarepo-ui/src/api/models/SortingPreset.ts b/mediarepo-ui/src/api/models/SortingPreset.ts index 5fe3d28..1b0dc9b 100644 --- a/mediarepo-ui/src/api/models/SortingPreset.ts +++ b/mediarepo-ui/src/api/models/SortingPreset.ts @@ -37,6 +37,11 @@ export class SortingPreset { return preset; } + public setData(data: SortingPresetData) { + this._id = data.id; + this.keys = data.keys.map(mapNew(SortKey)); + } + public toString(): string { return this.sortKeys.join(", "); } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html index 5bfa0a4..74c859c 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html @@ -4,11 +4,5 @@ class="sort-button" mat-flat-button> Sort: - - {{key.sortType}} - {{key.namespaceName}} - - - | - + diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss index 1fad7f8..4448aea 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss @@ -7,21 +7,3 @@ text-overflow: ellipsis; overflow: hidden; } - -.sort-key-direction { - font-size: 1.5em; - vertical-align: bottom; - margin-bottom: 0.6em; -} - -.sort-key-type { - color: $primary-lighter-50 -} - -.sort-key-namespace { - color: $accent-lighter-10; -} - -.sort-key:last-child .key-divider { - display: none; -} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html index a350274..9d0c74b 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html @@ -1,5 +1,19 @@ -

Sort Entries

+

+ Sort Entries +

+ + Preset + + + + {{preset.toString()}} + + +
@@ -58,6 +72,22 @@
- + + + + +
diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.scss b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.scss index 03a3540..81d185d 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.scss +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.scss @@ -18,12 +18,17 @@ mat-form-field, .filler, .drag-handle { } .dialog-actions { - display: flex; - flex-direction: row-reverse; width: 100%; + display: block; button { margin-left: 1em; + float: right; + } + + button.button-left { + float: left; + margin-right: 1em; } } @@ -57,3 +62,9 @@ mat-form-field, .filler, .drag-handle { background-color: darken(dimgrey, 20); border-radius: 1em; } + +.preset-selection { + width: calc(100% - 2em); + display: block; + font-size: 1em; +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts index 76b65d7..fb9fdfc 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts @@ -1,4 +1,4 @@ -import {ChangeDetectionStrategy, Component, Inject} from "@angular/core"; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit} from "@angular/core"; import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; import {SortKey} from "../../../../../../api/models/SortKey"; import {CdkDragDrop, moveItemInArray} from "@angular/cdk/drag-drop"; @@ -6,6 +6,8 @@ import {Namespace} from "../../../../../../api/models/Namespace"; import {TagService} from "../../../../../services/tag/tag.service"; import {compareSearchResults} from "../../../../../utils/compare-utils"; import {SortingPreset} from "../../../../../../api/models/SortingPreset"; +import {PresetService} from "../../../../../services/preset/preset.service"; +import {LoggingService} from "../../../../../services/logging/logging.service"; @Component({ selector: "app-sort-dialog", @@ -13,22 +15,36 @@ import {SortingPreset} from "../../../../../../api/models/SortingPreset"; styleUrls: ["./sort-dialog.component.scss"], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class SortDialogComponent { +export class SortDialogComponent implements OnInit { public sortingPreset: SortingPreset = SortingPreset.fromValues(-1, []); + public availablePresets: SortingPreset[] = []; public suggestedNamespaces: Namespace[] = []; + public emptyPreset = SortingPreset.fromValues(-1, []); - private previousId: number = -1; + public previousId: number = -1; private namespaces: Namespace[] = []; - constructor(public tagService: TagService, public dialogRef: MatDialogRef, @Inject( - MAT_DIALOG_DATA) data: any) { + constructor( + public logger: LoggingService, + public tagService: TagService, + public presetService: PresetService, + public changeDetector: ChangeDetectorRef, + public dialogRef: MatDialogRef, + @Inject( + MAT_DIALOG_DATA) data: any + ) { this.sortingPreset = data.sortingPreset; + this.previousId = this.sortingPreset.id; console.debug(this.sortingPreset); tagService.namespaces.subscribe( namespaces => this.namespaces = namespaces); } + public async ngOnInit() { + this.availablePresets = await this.presetService.getAllSortingPresets(); + } + addNewSortKey() { const sortKey = SortKey.fromValues("FileName", "Ascending", undefined); this.handlePresetChange(); @@ -68,4 +84,43 @@ export class SortDialogComponent { this.sortingPreset.id = -1; } } + + public async savePreset() { + await this.deletePreset(); + await this.saveNewPreset(); + } + + public async saveNewPreset() { + let newPreset = await this.logger.try(() => this.presetService.addSortingPreset(this.sortingPreset.sortKeys)); + if (newPreset) { + this.sortingPreset.setData(newPreset.rawData); + this.previousId = this.sortingPreset.id; + this.availablePresets.push(new SortingPreset(JSON.parse(JSON.stringify(newPreset.rawData)))); + this.changeDetector.detectChanges(); + } + } + + public async deletePreset() { + if (this.previousId >= 0) { + const index = this.availablePresets.findIndex(p => p.id == this.previousId); + if (index >= 0) { + this.availablePresets.splice(index, 1); + this.changeDetector.detectChanges(); + } + try { + await this.presetService.deleteSortingPreset(this.previousId); + } catch (err: any) { + this.logger.warn(`Could not delete previous preset: ${err.message}`); + } + } + } + + public selectPreset(presetId: number): void { + const preset = this.availablePresets.find(p => p.id == presetId); + + if (preset) { + this.sortingPreset.setData(JSON.parse(JSON.stringify(preset.rawData))); + this.previousId = preset.id; + } + } } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.html new file mode 100644 index 0000000..7300b4e --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.html @@ -0,0 +1,7 @@ + + {{key.sortType}} + {{key.namespaceName}} + + + | + diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.scss b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.scss new file mode 100644 index 0000000..667f8ea --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.scss @@ -0,0 +1,20 @@ +@import "src/colors"; + + +.sort-key-direction { + font-size: 1.5em; + vertical-align: bottom; + margin-bottom: 0.6em; +} + +.sort-key-type { + color: $primary-lighter-50 +} + +.sort-key-namespace { + color: $accent-lighter-10; +} + +.sort-key:last-child .key-divider { + display: none; +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.spec.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.spec.ts new file mode 100644 index 0000000..1756cd3 --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SortPresetItemComponent } from './sort-preset-item.component'; + +describe('SortPresetItemComponent', () => { + let component: SortPresetItemComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SortPresetItemComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SortPresetItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.ts new file mode 100644 index 0000000..7e18532 --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.ts @@ -0,0 +1,16 @@ +import {ChangeDetectionStrategy, Component, Input} from "@angular/core"; +import {SortingPreset} from "../../../../../../api/models/SortingPreset"; + +@Component({ + selector: "app-sort-preset-item", + templateUrl: "./sort-preset-item.component.html", + styleUrls: ["./sort-preset-item.component.scss"], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SortPresetItemComponent { + + @Input() preset!: SortingPreset; + + constructor() { + } +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts b/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts index 57b8de1..211fb91 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts @@ -52,6 +52,7 @@ import {GetTagQueryPipe} from "./file-search/filter-pipes/get-tag-query.pipe"; import {GetPropertyQueryPipe} from "./file-search/filter-pipes/get-property-query.pipe"; import {SortButtonComponent} from "./file-search/sort-button/sort-button.component"; import {MatTooltipModule} from "@angular/material/tooltip"; +import { SortPresetItemComponent } from './file-search/sort-preset-item/sort-preset-item.component'; @NgModule({ @@ -71,6 +72,7 @@ import {MatTooltipModule} from "@angular/material/tooltip"; GetTagQueryPipe, GetPropertyQueryPipe, SortButtonComponent, + SortPresetItemComponent, ], exports: [ TagEditComponent, diff --git a/mediarepo-ui/src/app/services/preset/preset.service.ts b/mediarepo-ui/src/app/services/preset/preset.service.ts index 32fb28b..1b41688 100644 --- a/mediarepo-ui/src/app/services/preset/preset.service.ts +++ b/mediarepo-ui/src/app/services/preset/preset.service.ts @@ -2,6 +2,7 @@ import {Injectable} from "@angular/core"; import {SortingPreset} from "../../../api/models/SortingPreset"; import {MediarepoApi} from "../../../api/Api"; import {mapMany, mapNew} from "../../../api/models/adaptors"; +import {SortKey} from "../../../api/models/SortKey"; @Injectable({ providedIn: "root" @@ -14,4 +15,12 @@ export class PresetService { public async getAllSortingPresets(): Promise { return MediarepoApi.getAllSortingPresets().then(mapMany(mapNew(SortingPreset))); } + + public async addSortingPreset(keys: SortKey[]): Promise { + return MediarepoApi.addSortingPreset({ sortKeys: keys.map(k => k.rawData) }).then(mapNew(SortingPreset)); + } + + public async deleteSortingPreset(id: number): Promise { + return MediarepoApi.deleteSortingPreset({ id }); + } } From a5a0134c56f2863882c275dc35561e11638bf649 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 19:16:32 +0100 Subject: [PATCH 12/15] Fix api call name Signed-off-by: trivernis --- mediarepo-api/src/client_api/preset.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediarepo-api/src/client_api/preset.rs b/mediarepo-api/src/client_api/preset.rs index f62e0fc..31beaa6 100644 --- a/mediarepo-api/src/client_api/preset.rs +++ b/mediarepo-api/src/client_api/preset.rs @@ -28,7 +28,7 @@ impl PresetApi { #[tracing::instrument(level = "debug", skip(self))] pub async fn all_sorting_presets(&self) -> ApiResult> { self.emit_and_get( - "sorting_presets", + "all_sorting_presets", (), Some(Duration::from_secs(1)) ) From 341c1a35d610dc195b8f2dd7b95b91ef0942231f Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 19:21:02 +0100 Subject: [PATCH 13/15] Fix handling of the empty preset option Signed-off-by: trivernis --- .../file-search/sort-dialog/sort-dialog.component.html | 2 +- .../sidebar/file-search/sort-dialog/sort-dialog.component.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html index 9d0c74b..1a53b2f 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html @@ -5,7 +5,7 @@ Preset - + p.id == presetId); - + const preset = this.availablePresets.find(p => p.id == presetId) ?? this.emptyPreset; + if (preset) { this.sortingPreset.setData(JSON.parse(JSON.stringify(preset.rawData))); this.previousId = preset.id; From 6d6a17bac5937ea07a14e7a6ca81adcdbfee1103 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 20:44:46 +0100 Subject: [PATCH 14/15] Add default value to empty sort preset Signed-off-by: trivernis --- mediarepo-ui/src/api/models/SortKey.ts | 4 +--- .../sidebar/file-search/sort-dialog/sort-dialog.component.ts | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mediarepo-ui/src/api/models/SortKey.ts b/mediarepo-ui/src/api/models/SortKey.ts index bf85cb4..4bd651c 100644 --- a/mediarepo-ui/src/api/models/SortKey.ts +++ b/mediarepo-ui/src/api/models/SortKey.ts @@ -30,9 +30,7 @@ export class SortKey { }; } else { this.data = { - [value]: { - direction: this.sortDirection - } + [value]: this.sortDirection } as SortKeyData; } } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts index 128cc38..d9ed433 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts @@ -20,7 +20,9 @@ export class SortDialogComponent implements OnInit { public sortingPreset: SortingPreset = SortingPreset.fromValues(-1, []); public availablePresets: SortingPreset[] = []; public suggestedNamespaces: Namespace[] = []; - public emptyPreset = SortingPreset.fromValues(-1, []); + public emptyPreset = SortingPreset.fromValues(-1, [ + SortKey.fromValues("FileImportedTime", "Ascending", undefined) + ]); public previousId: number = -1; private namespaces: Namespace[] = []; From 6507809bcccc8fe0bdd8478365270a14465bd66b Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 21:02:47 +0100 Subject: [PATCH 15/15] Fix style issues Signed-off-by: trivernis --- mediarepo-ui/src/api/models/File.ts | 8 +- mediarepo-ui/src/api/models/Repository.ts | 2 +- .../app/components/core/core.component.scss | 1 + .../src/app/components/core/core.module.ts | 22 +-- .../files-tab-sidebar.component.html | 7 +- .../files-tab-sidebar.component.ts | 23 +-- .../core/files-tab/files-tab.component.html | 3 +- .../import-tab-sidebar.component.html | 7 +- .../core/import-tab/import-tab.component.html | 13 +- .../core/import-tab/import-tab.component.ts | 2 +- .../download-daemon-dialog.component.html | 3 +- .../download-daemon-dialog.component.spec.ts | 6 +- .../download-daemon-dialog.component.ts | 8 +- .../repositories-tab.component.html | 7 +- .../repository-card.component.ts | 68 ++++----- .../repository-details-view.component.html | 22 +-- .../repository-details-view.component.spec.ts | 6 +- .../repository-details-view.component.ts | 20 +-- .../input-receiver.directive.ts | 15 +- .../metadata-entry.component.spec.ts | 2 +- .../image-viewer/image-viewer.component.ts | 12 +- .../native-file-select.component.ts | 10 +- .../add-repository-dialog.component.html | 20 ++- .../edit-repository-dialog.component.html | 7 +- .../edit-repository-dialog.component.spec.ts | 6 +- .../repository-form.component.spec.ts | 2 +- .../repository-form.component.ts | 18 +-- .../repository/repository.module.ts | 14 +- .../file-import/file-import.component.spec.ts | 2 +- .../editable-metadata-entry.component.html | 6 +- .../editable-metadata-entry.component.spec.ts | 6 +- .../editable-metadata-entry.component.ts | 10 +- .../file-metadata.component.scss | 3 + .../file-metadata.component.spec.ts | 2 +- .../sort-button/sort-button.component.spec.ts | 38 ++--- .../sort-preset-item.component.spec.ts | 38 ++--- .../shared/sidebar/sidebar.module.ts | 2 +- .../src/app/services/file/file.helper.ts | 2 +- .../src/app/services/import/import.service.ts | 4 +- .../src/app/services/job/job.service.ts | 2 +- .../services/preset/preset.service.spec.ts | 22 +-- mediarepo-ui/src/assets/icon.svg | 134 +++++++++--------- mediarepo-ui/src/index.html | 10 +- mediarepo-ui/src/test.ts | 15 +- 44 files changed, 279 insertions(+), 351 deletions(-) diff --git a/mediarepo-ui/src/api/models/File.ts b/mediarepo-ui/src/api/models/File.ts index 84c5a8f..67f3bd8 100644 --- a/mediarepo-ui/src/api/models/File.ts +++ b/mediarepo-ui/src/api/models/File.ts @@ -22,11 +22,11 @@ export class File { return this.basicData.status; } - public get mimeType(): string { - return this.basicData.mime_type; - } - public set status(value: FileStatus) { this.basicData.status = value; } + + public get mimeType(): string { + return this.basicData.mime_type; + } } diff --git a/mediarepo-ui/src/api/models/Repository.ts b/mediarepo-ui/src/api/models/Repository.ts index 9eb5ed6..cbc8efa 100644 --- a/mediarepo-ui/src/api/models/Repository.ts +++ b/mediarepo-ui/src/api/models/Repository.ts @@ -22,7 +22,7 @@ export class Repository { return this.repoData.local; } - public update(data: {name?: string, address?: string, path?: string, local?: boolean}) { + public update(data: { name?: string, address?: string, path?: string, local?: boolean }) { this.repoData = Object.assign(this.repoData, data); } } diff --git a/mediarepo-ui/src/app/components/core/core.component.scss b/mediarepo-ui/src/app/components/core/core.component.scss index e4f50ca..a805f59 100644 --- a/mediarepo-ui/src/app/components/core/core.component.scss +++ b/mediarepo-ui/src/app/components/core/core.component.scss @@ -36,6 +36,7 @@ mat-tab-group { right: 0; top: 0; height: 100%; + ng-icon { font-size: 1.5em; margin-top: calc(-50%); diff --git a/mediarepo-ui/src/app/components/core/core.module.ts b/mediarepo-ui/src/app/components/core/core.module.ts index d3ffbc9..dbd097f 100644 --- a/mediarepo-ui/src/app/components/core/core.module.ts +++ b/mediarepo-ui/src/app/components/core/core.module.ts @@ -1,17 +1,11 @@ import {NgModule} from "@angular/core"; import {CommonModule} from "@angular/common"; import {CoreComponent} from "./core.component"; -import { - RepositoriesTabComponent -} from "./repositories-tab/repositories-tab.component"; +import {RepositoriesTabComponent} from "./repositories-tab/repositories-tab.component"; import {FilesTabComponent} from "./files-tab/files-tab.component"; -import { - FilesTabSidebarComponent -} from "./files-tab/files-tab-sidebar/files-tab-sidebar.component"; +import {FilesTabSidebarComponent} from "./files-tab/files-tab-sidebar/files-tab-sidebar.component"; import {ImportTabComponent} from "./import-tab/import-tab.component"; -import { - ImportTabSidebarComponent -} from "./import-tab/import-tab-sidebar/import-tab-sidebar.component"; +import {ImportTabSidebarComponent} from "./import-tab/import-tab-sidebar/import-tab-sidebar.component"; import {MatButtonModule} from "@angular/material/button"; import {MatSidenavModule} from "@angular/material/sidenav"; import {MatProgressBarModule} from "@angular/material/progress-bar"; @@ -30,9 +24,7 @@ import {SidebarModule} from "../shared/sidebar/sidebar.module"; import {FileModule} from "../shared/file/file.module"; import {AppCommonModule} from "../shared/app-common/app-common.module"; import {ReactiveFormsModule} from "@angular/forms"; -import { - RepositoryCardComponent -} from "./repositories-tab/repository-card/repository-card.component"; +import {RepositoryCardComponent} from "./repositories-tab/repository-card/repository-card.component"; import {MatCardModule} from "@angular/material/card"; import {MatListModule} from "@angular/material/list"; import {MatDialogModule} from "@angular/material/dialog"; @@ -42,9 +34,7 @@ import {TagModule} from "../shared/tag/tag.module"; import { DownloadDaemonDialogComponent } from "./repositories-tab/download-daemon-dialog/download-daemon-dialog.component"; -import { - RepositoryModule -} from "../shared/repository/repository/repository.module"; +import {RepositoryModule} from "../shared/repository/repository/repository.module"; import {MatToolbarModule} from "@angular/material/toolbar"; import { RepositoryDetailsViewComponent @@ -76,7 +66,7 @@ import { MatProgressBarModule, MatCheckboxModule, ScrollingModule, - NgIconsModule.withIcons({...materialIcons}), + NgIconsModule.withIcons({ ...materialIcons }), FlexModule, MatButtonModule, MatMenuModule, diff --git a/mediarepo-ui/src/app/components/core/files-tab/files-tab-sidebar/files-tab-sidebar.component.html b/mediarepo-ui/src/app/components/core/files-tab/files-tab-sidebar/files-tab-sidebar.component.html index 6c677c9..9a29759 100644 --- a/mediarepo-ui/src/app/components/core/files-tab/files-tab-sidebar/files-tab-sidebar.component.html +++ b/mediarepo-ui/src/app/components/core/files-tab/files-tab-sidebar/files-tab-sidebar.component.html @@ -1,9 +1,12 @@