web crate put add table
This commit is contained in:
@@ -101,6 +101,46 @@ impl TableDetailView {
|
||||
.filter(|column| column.renameable)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Expands a top-level removal choice to the generated columns the backend
|
||||
/// requires to travel with it. PHONE/IBAN companions name their source;
|
||||
/// linked projections use `link.source`.
|
||||
pub(crate) fn expanded_removal_ids(&self, selected: &[i64]) -> Result<Vec<i64>, ()> {
|
||||
let selected = selected.iter().copied().collect::<std::collections::HashSet<_>>();
|
||||
if selected
|
||||
.iter()
|
||||
.any(|id| !self.columns.iter().any(|column| column.column_id == *id))
|
||||
{
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let mut roots = selected.clone();
|
||||
for column in self.columns.iter().filter(|column| selected.contains(&column.column_id)) {
|
||||
if let Some(root_name) = column.generated_from.split('.').next()
|
||||
&& !root_name.is_empty()
|
||||
&& let Some(root) = self.columns.iter().find(|candidate| candidate.name == root_name)
|
||||
{
|
||||
roots.insert(root.column_id);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self
|
||||
.columns
|
||||
.iter()
|
||||
.filter(|column| {
|
||||
roots.contains(&column.column_id)
|
||||
|| self.columns.iter().any(|root| {
|
||||
roots.contains(&root.column_id)
|
||||
&& (column.generated_from == root.name
|
||||
|| column
|
||||
.generated_from
|
||||
.strip_prefix(&root.name)
|
||||
.is_some_and(|suffix| suffix.starts_with('.')))
|
||||
})
|
||||
})
|
||||
.map(|column| column.column_id)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -121,6 +161,12 @@ pub(crate) struct DetailColumn {
|
||||
}
|
||||
|
||||
impl DetailColumn {
|
||||
/// Generated/read-only rows are shown as part of their parent definition;
|
||||
/// choosing the parent expands to them in `expanded_removal_ids`.
|
||||
pub(crate) fn is_removal_choice(&self) -> bool {
|
||||
self.column_id > 0 && !self.generated && !self.read_only
|
||||
}
|
||||
|
||||
/// The badge list rendered under each column name.
|
||||
pub(crate) fn flags(&self, locale: &crate::i18n::Locale) -> Vec<String> {
|
||||
let mut flags = Vec::new();
|
||||
@@ -274,8 +320,10 @@ pub(crate) struct DeleteForm {
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(crate) struct PageInputs {
|
||||
pub selection: Selection,
|
||||
/// The columns staged for `AddTableColumns`.
|
||||
/// The new columns staged for the structural edit.
|
||||
pub columns: ColumnDraft,
|
||||
/// Existing column identities selected for removal.
|
||||
pub remove_column_ids: Vec<i64>,
|
||||
pub copy: CopyForm,
|
||||
pub invoice: InvoiceTemplateForm,
|
||||
pub status: Option<String>,
|
||||
@@ -316,6 +364,7 @@ pub(crate) struct TableDefinitionPageState {
|
||||
pub detail: Option<TableDetailView>,
|
||||
pub history: Vec<RenameEntry>,
|
||||
pub columns: ColumnDraft,
|
||||
pub remove_column_ids: Vec<i64>,
|
||||
pub copy: CopyForm,
|
||||
pub invoice: InvoiceTemplateForm,
|
||||
pub status: Option<String>,
|
||||
@@ -328,6 +377,10 @@ pub(crate) struct TableDefinitionPageState {
|
||||
}
|
||||
|
||||
impl TableDefinitionPageState {
|
||||
pub(crate) fn column_is_selected_for_removal(&self, column_id: &i64) -> bool {
|
||||
self.remove_column_ids.contains(column_id)
|
||||
}
|
||||
|
||||
/// Whether `name` is the page being rendered. Read by context.html.
|
||||
pub(crate) fn is(&self, name: &str) -> bool {
|
||||
self.active == name
|
||||
@@ -490,5 +543,11 @@ mod tests {
|
||||
detail.columns[2].flags(&crate::i18n::Locale::default()),
|
||||
vec!["EUR", "generated from accounting"]
|
||||
);
|
||||
|
||||
assert_eq!(detail.expanded_removal_ids(&[1]).unwrap(), [1, 2]);
|
||||
assert_eq!(detail.expanded_removal_ids(&[2]).unwrap(), [1, 2]);
|
||||
assert!(detail.expanded_removal_ids(&[99]).is_err());
|
||||
assert!(detail.columns[0].is_removal_choice());
|
||||
assert!(!detail.columns[1].is_removal_choice());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user