pub extern crate bson;
pub extern crate crossbeam_channel;
pub extern crate mkutil;
#[cfg(feature = "gui")]
pub extern crate egui_extras;
#[cfg(feature = "gui")]
pub extern crate mktree;
#[cfg(any(feature = "shotgrid", feature = "shotgrid_async_test"))]
pub extern crate shotgrid_rs;
#[cfg(any(feature = "egui_demo", feature = "easy_mark"))]
pub extern crate egui_demo_lib;
#[cfg(feature = "collab")]
pub extern crate futures_util;
#[cfg(feature = "collab")]
pub extern crate tokio_tungstenite;
#[cfg(feature = "collab")]
pub extern crate quick_protobuf;
mod asset;
pub mod media;
pub mod prelude;
pub mod production;
pub mod user;
#[cfg(feature = "collab")]
pub mod collab;
#[cfg(feature = "review_item")]
pub mod review_item;
#[cfg(feature = "stage_graph")]
pub mod stage;
#[cfg(feature = "alert")]
pub mod alert;
#[cfg(feature = "query_message")]
pub mod query_msg;
#[cfg(feature = "ticket")]
pub mod ticket;
#[cfg(any(feature = "shotgrid", feature = "shotgrid_async_test"))]
pub mod shotgrid;
pub use asset::*;
use prelude::*;
pub use production::Project;
pub use user::*;
#[cfg(feature = "image_processing")]
use hconf::once_cell::sync::OnceCell;
#[allow(unused_imports)]
use hconf::{
colored::Colorize,
log::{debug, error, info, warn},
ClientCfgCel,
};
#[cfg(feature = "gui")]
pub use mktree::egui;
pub use mkutil::{aquamarine, glob};
use anyhow::{anyhow, Context, Result as AnyResult};
use async_trait::async_trait;
use bson::oid::ObjectId;
use chrono::{
prelude::{DateTime, Local, Utc},
Duration,
};
use dyn_clone::DynClone;
#[allow(unused_imports)]
#[cfg(feature = "gui")]
use egui::{Align, Color32, Layout, RichText, TextStyle};
#[cfg(all(feature = "image_processing", feature = "gui"))]
use egui::{ImageButton, Widget};
#[cfg(feature = "image_processing")]
use egui_extras::RetainedImage;
#[cfg(any(feature = "query_message", feature = "review_item"))]
use egui_extras::DatePickerButton;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::{
cmp::Ordering,
collections::{BTreeSet, HashMap, HashSet},
fmt,
path::{Path, PathBuf},
};
use strum::IntoEnumIterator;
pub const DAY_MONTH_YEAR_FORMAT: &str = "%d %b %Y %H:%M";
pub const MONTH_DAY_YEAR_FORMAT: &str = "%b %d %Y %H:%M";
pub const YEAR_MONTH_DAY_FORMAT: &str = "%Y-%m-%d %H:%M";
pub trait BsonId {
fn bson_id_as_ref(&self) -> Option<&ObjectId>;
fn bson_id(&self) -> AnyResult<&ObjectId>;
}
#[derive(Debug, Clone)]
pub struct DbSource {
pub label: String,
pub dbi: Option<Box<dyn DbConnect>>,
pub default_pp_umbrella: Option<String>,
pub pp_members: Result<Vec<Project>, DatabaseError>,
}
impl Default for DbSource {
fn default() -> Self {
Self {
label: String::new(),
dbi: None,
default_pp_umbrella: None,
pp_members: Err(DatabaseError::Uninitialized),
}
}
}
impl DbSource {
pub fn empty(label: &str) -> Self {
Self {
label: label.to_owned(),
..Default::default()
}
}
#[cfg(feature = "gui")]
pub fn pp_umbrella_debug_ui(&mut self, ui: &mut egui::Ui) {
match &self.default_pp_umbrella {
Some(umbrella) => {
ui.label(format!(
"☂ {} default Pan-project Umbrella: {}",
self.label, &umbrella
));
}
None => {
ui.colored_label(
Color32::RED,
format!("🚫 {}: UNDEFINED default umbrella", self.label),
);
}
};
}
#[cfg(feature = "gui")]
pub fn pp_member_error(&mut self, ui: &mut egui::Ui) {
if let Err(e) = &self.pp_members {
ui.colored_label(Color32::RED, format!("🚫 {} members: {}", self.label, e));
};
}
}
#[async_trait]
pub trait DbConnect: DynClone + fmt::Debug + Send + Sync {
async fn try_connect(&mut self) -> Result<(), DatabaseError>;
async fn list_all_productions(&self) -> Result<Vec<Project>, DatabaseError>;
async fn list_panproject_members(
&self,
pp_umbrella: Option<String>,
) -> Result<Vec<Project>, DatabaseError>;
}
dyn_clone::clone_trait_object!(DbConnect);
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum MediaMode {
#[default]
Read,
WriteSuggest,
WriteCompose,
WriteEdit,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, strum::AsRefStr, strum::EnumIter)]
pub enum Genesis {
#[default]
Create,
Update,
Delete,
}
#[cfg(feature = "gui")]
pub fn genesis_stage_options_ui(ui: &mut egui::Ui, mode: &mut Genesis) {
ui.horizontal(|ui| {
for m in Genesis::iter() {
ui.selectable_value(
mode,
m.clone(),
RichText::new(m.as_ref()).text_style(TextStyle::Heading),
);
}
});
}
#[derive(Debug, Clone, Default, PartialEq, Eq, strum::AsRefStr, strum::EnumIter)]
pub enum GenesisSimple {
Create,
#[default]
Edit,
}
#[cfg(feature = "gui")]
pub fn genesis_simple_options_ui(ui: &mut egui::Ui, mode: &mut GenesisSimple) {
ui.horizontal(|ui| {
for m in GenesisSimple::iter() {
ui.selectable_value(
mode,
m.clone(),
RichText::new(m.as_ref()).text_style(TextStyle::Heading),
);
}
});
}
pub trait ReadWriteSuggest {
fn write_suggest() -> Self;
fn with_mode(self, mode: MediaMode) -> Self;
fn mode(&self) -> &MediaMode;
#[allow(unused_variables)]
fn mode_mut(&mut self, mode: MediaMode) {}
#[cfg(feature = "gui")]
fn read_mode_ui(&mut self, _ui: &mut egui::Ui) {}
#[cfg(feature = "gui")]
fn write_suggest_ui(&mut self, _ui: &mut egui::Ui) {}
#[cfg(feature = "gui")]
fn write_compose_ui(&mut self, _ui: &mut egui::Ui) {}
#[cfg(feature = "gui")]
fn write_edit_ui(&mut self, _ui: &mut egui::Ui) {}
}
#[derive(Debug, Clone)]
pub enum ReadState {
Read,
Unread,
}
#[derive(Debug, Clone)]
pub enum InstantiationState {
Instantiated,
Uninstantiated,
}
#[derive(Debug, Clone, Default, PartialEq, strum::AsRefStr, strum::EnumIter)]
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
pub enum ChronoFormat {
#[default]
#[strum(serialize = "Day-M-Y")]
DayMonthYear,
#[strum(serialize = "Month-D-Y")]
MonthDayYear,
#[strum(serialize = "Year-M-D")]
YearMonthDay,
}
impl ChronoFormat {
pub fn to_format_str(&self) -> &str {
match self {
ChronoFormat::DayMonthYear => DAY_MONTH_YEAR_FORMAT,
ChronoFormat::MonthDayYear => MONTH_DAY_YEAR_FORMAT,
ChronoFormat::YearMonthDay => YEAR_MONTH_DAY_FORMAT,
}
}
}
#[derive(Debug, Clone, Default)]
pub enum CreatedAtOrdering {
#[default]
NewestFirst,
OldestFirst,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, strum::AsRefStr, strum::EnumIter)]
pub enum FilterOp {
#[strum(serialize = "All (AND)")]
All,
#[default]
#[strum(serialize = "Any (OR)")]
Any,
}
impl FilterOp {
pub fn hint(&self) -> &str {
match &self {
FilterOp::All => "Intersection",
FilterOp::Any => "Union",
}
}
#[cfg(feature = "gui")]
fn hover_text(&self) -> &str {
match &self {
FilterOp::All => "\"Intersection\" behaviour",
FilterOp::Any => "\"Union\" behaviour",
}
}
}
#[cfg(feature = "gui")]
pub fn filter_operation_options_ui(op: &mut FilterOp, ui: &mut egui::Ui) {
for p in FilterOp::iter() {
ui.selectable_value(op, p.clone(), p.as_ref())
.on_hover_text(p.hover_text());
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub enum DetailLevel {
#[default]
Stub,
Full,
}
#[derive(Debug, Clone, PartialEq)]
pub enum VcsLiteVersion {
V(u16),
Last,
}
impl VcsLiteVersion {
pub fn as_str(&self) -> String {
format!("{}", self)
}
}
impl fmt::Display for VcsLiteVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let version = match self {
VcsLiteVersion::V(num) => format!("{:>3}", num),
VcsLiteVersion::Last => "last".to_string(),
};
write!(f, "{}", version)
}
}
#[derive(Debug, Clone, PartialEq, Eq, strum::AsRefStr)]
pub enum VcsLiteSession {
#[strum(serialize = "WIP")]
Wip,
Review,
Draft,
Full,
Ingest,
Store,
Publish,
Render,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "mongo", derive(Serialize, Deserialize))]
pub struct HtmlLink {
text: String,
href: String,
}
pub trait CacheClear {
fn clear_cache(&mut self) {}
}