mirror of
https://github.com/zadam/trilium.git
synced 2025-12-17 12:54:24 +01:00
feat(layout/search_definition): integrate view options directly in search parameters
This commit is contained in:
parent
6b9b9a96c3
commit
a7ca839afb
@ -889,7 +889,8 @@
|
||||
"search_parameters": "Search Parameters",
|
||||
"unknown_search_option": "Unknown search option {{searchOptionName}}",
|
||||
"search_note_saved": "Search note has been saved into {{- notePathTitle}}",
|
||||
"actions_executed": "Actions have been executed."
|
||||
"actions_executed": "Actions have been executed.",
|
||||
"view_options": "View options:"
|
||||
},
|
||||
"similar_notes": {
|
||||
"title": "Similar Notes",
|
||||
|
||||
@ -4,29 +4,8 @@ body.experimental-feature-new-layout {
|
||||
}
|
||||
|
||||
.title-actions {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
gap: 0.25em;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
padding-inline-start: 15px;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 0.2em;
|
||||
font-size: 0.8em;
|
||||
|
||||
.collapsible-title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
input.form-control {
|
||||
padding: 2px 8px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
apps/client/src/widgets/note_bars/CollectionProperties.css
Normal file
20
apps/client/src/widgets/note_bars/CollectionProperties.css
Normal file
@ -0,0 +1,20 @@
|
||||
.collection-properties {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
gap: 0.25em;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
font-size: 0.8em;
|
||||
|
||||
.dropdown-menu {
|
||||
input.form-control {
|
||||
padding: 2px 8px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,14 @@
|
||||
import "./CollectionProperties.css";
|
||||
|
||||
import { t } from "i18next";
|
||||
import { useContext } from "preact/hooks";
|
||||
import { Fragment } from "preact/jsx-runtime";
|
||||
|
||||
import FNote from "../../entities/fnote";
|
||||
import { getHelpUrlForNote } from "../../services/in_app_help";
|
||||
import { openInAppHelpFromUrl } from "../../services/utils";
|
||||
import { ViewTypeOptions } from "../collections/interface";
|
||||
import ActionButton from "../react/ActionButton";
|
||||
import Dropdown from "../react/Dropdown";
|
||||
import { FormDropdownDivider, FormDropdownSubmenu, FormListItem, FormListToggleableItem } from "../react/FormList";
|
||||
import FormTextBox from "../react/FormTextBox";
|
||||
@ -12,9 +17,6 @@ import Icon from "../react/Icon";
|
||||
import { ParentComponent } from "../react/react_utils";
|
||||
import { bookPropertiesConfig, BookProperty, ButtonProperty, CheckBoxProperty, ComboBoxItem, ComboBoxProperty, NumberProperty, SplitButtonProperty } from "../ribbon/collection-properties-config";
|
||||
import { useViewType, VIEW_TYPE_MAPPINGS } from "../ribbon/CollectionPropertiesTab";
|
||||
import ActionButton from "../react/ActionButton";
|
||||
import { getHelpUrlForNote } from "../../services/in_app_help";
|
||||
import { openInAppHelpFromUrl } from "../../services/utils";
|
||||
|
||||
const ICON_MAPPINGS: Record<ViewTypeOptions, string> = {
|
||||
grid: "bx bxs-grid",
|
||||
@ -30,12 +32,12 @@ export default function CollectionProperties({ note }: { note: FNote }) {
|
||||
const [ viewType, setViewType ] = useViewType(note);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="collection-properties">
|
||||
<ViewTypeSwitcher viewType={viewType} setViewType={setViewType} />
|
||||
<ViewOptions note={note} viewType={viewType} />
|
||||
<div className="spacer" />
|
||||
<HelpButton note={note} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -187,9 +189,9 @@ function ComboBoxPropertyView({ note, property }: { note: FNote, property: Combo
|
||||
{index < property.options.length - 1 && <FormDropdownDivider />}
|
||||
</Fragment>
|
||||
);
|
||||
} else {
|
||||
return renderItem(option);
|
||||
}
|
||||
return renderItem(option);
|
||||
|
||||
})}
|
||||
</FormDropdownSubmenu>
|
||||
);
|
||||
|
||||
@ -60,7 +60,7 @@ export const RIBBON_TAB_DEFINITIONS: TabConfiguration[] = [
|
||||
title: t("book_properties.book_properties"),
|
||||
icon: "bx bx-book",
|
||||
content: CollectionPropertiesTab,
|
||||
show: ({ note }) => !isNewLayout && note?.type === "book" || note?.type === "search",
|
||||
show: ({ note }) => !isNewLayout && (note?.type === "book" || note?.type === "search"),
|
||||
toggleCommand: "toggleRibbonTabBookProperties"
|
||||
},
|
||||
{
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
import FormTextArea from "../react/FormTextArea";
|
||||
import NoteAutocomplete from "../react/NoteAutocomplete";
|
||||
import FormSelect from "../react/FormSelect";
|
||||
import Icon from "../react/Icon";
|
||||
import FormTextBox from "../react/FormTextBox";
|
||||
import { AttributeType } from "@triliumnext/commons";
|
||||
import { ComponentChildren, VNode } from "preact";
|
||||
import { useEffect, useMemo, useRef } from "preact/hooks";
|
||||
|
||||
import appContext from "../../components/app_context";
|
||||
import FNote from "../../entities/fnote";
|
||||
import { removeOwnedAttributesByNameOrType } from "../../services/attributes";
|
||||
import { AttributeType } from "@triliumnext/commons";
|
||||
import { useNoteLabel, useNoteRelation, useSpacedUpdate, useTooltip } from "../react/hooks";
|
||||
import { t } from "../../services/i18n";
|
||||
import { useEffect, useMemo, useRef } from "preact/hooks";
|
||||
import appContext from "../../components/app_context";
|
||||
import server from "../../services/server";
|
||||
import FormSelect from "../react/FormSelect";
|
||||
import FormTextArea from "../react/FormTextArea";
|
||||
import FormTextBox from "../react/FormTextBox";
|
||||
import HelpRemoveButtons from "../react/HelpRemoveButtons";
|
||||
import { useNoteLabel, useNoteRelation, useSpacedUpdate, useTooltip } from "../react/hooks";
|
||||
import Icon from "../react/Icon";
|
||||
import NoteAutocomplete from "../react/NoteAutocomplete";
|
||||
|
||||
export interface SearchOption {
|
||||
attributeName: string;
|
||||
@ -134,7 +135,7 @@ function SearchOption({ note, title, titleIcon, children, help, attributeName, a
|
||||
}}
|
||||
/>
|
||||
</tr>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function SearchStringOption({ note, refreshResults, error, ...restProps }: SearchOptionProps) {
|
||||
@ -210,7 +211,7 @@ function SearchStringOption({ note, refreshResults, error, ...restProps }: Searc
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</SearchOption>
|
||||
</SearchOption>;
|
||||
}
|
||||
|
||||
function SearchScriptOption({ note, ...restProps }: SearchOptionProps) {
|
||||
@ -232,7 +233,7 @@ function SearchScriptOption({ note, ...restProps }: SearchOptionProps) {
|
||||
noteIdChanged={noteId => setSearchScript(noteId ?? "root")}
|
||||
placeholder={t("search_script.placeholder")}
|
||||
/>
|
||||
</SearchOption>
|
||||
</SearchOption>;
|
||||
}
|
||||
|
||||
function AncestorOption({ note, ...restProps}: SearchOptionProps) {
|
||||
@ -245,9 +246,9 @@ function AncestorOption({ note, ...restProps}: SearchOptionProps) {
|
||||
{ value: "eq1", label: `${t("ancestor.depth_eq", { count: 1 })} (${t("ancestor.direct_children")})` }
|
||||
];
|
||||
|
||||
for (let i=2; i<=9; i++) options.push({ value: "eq" + i, label: t("ancestor.depth_eq", { count: i }) });
|
||||
for (let i=0; i<=9; i++) options.push({ value: "gt" + i, label: t("ancestor.depth_gt", { count: i }) });
|
||||
for (let i=2; i<=9; i++) options.push({ value: "lt" + i, label: t("ancestor.depth_lt", { count: i }) });
|
||||
for (let i=2; i<=9; i++) options.push({ value: `eq${ i}`, label: t("ancestor.depth_eq", { count: i }) });
|
||||
for (let i=0; i<=9; i++) options.push({ value: `gt${ i}`, label: t("ancestor.depth_gt", { count: i }) });
|
||||
for (let i=2; i<=9; i++) options.push({ value: `lt${ i}`, label: t("ancestor.depth_lt", { count: i }) });
|
||||
|
||||
return options;
|
||||
}, []);
|
||||
@ -279,7 +280,7 @@ function FastSearchOption({ ...restProps }: SearchOptionProps) {
|
||||
titleIcon="bx bx-run" title={t("fast_search.fast_search")}
|
||||
help={t("fast_search.description")}
|
||||
{...restProps}
|
||||
/>
|
||||
/>;
|
||||
}
|
||||
|
||||
function DebugOption({ ...restProps }: SearchOptionProps) {
|
||||
@ -290,14 +291,14 @@ function DebugOption({ ...restProps }: SearchOptionProps) {
|
||||
{t("debug.access_info")}
|
||||
</>}
|
||||
{...restProps}
|
||||
/>
|
||||
/>;
|
||||
}
|
||||
|
||||
function IncludeArchivedNotesOption({ ...restProps }: SearchOptionProps) {
|
||||
return <SearchOption
|
||||
titleIcon="bx bx-archive" title={t("include_archived_notes.include_archived_notes")}
|
||||
{...restProps}
|
||||
/>
|
||||
/>;
|
||||
}
|
||||
|
||||
function OrderByOption({ note, ...restProps }: SearchOptionProps) {
|
||||
@ -340,7 +341,7 @@ function OrderByOption({ note, ...restProps }: SearchOptionProps) {
|
||||
{ value: "desc", title: t("order_by.desc") }
|
||||
]}
|
||||
/>
|
||||
</SearchOption>
|
||||
</SearchOption>;
|
||||
}
|
||||
|
||||
function LimitOption({ note, defaultValue, ...restProps }: SearchOptionProps) {
|
||||
@ -356,5 +357,5 @@ function LimitOption({ note, defaultValue, ...restProps }: SearchOptionProps) {
|
||||
type="number" min="1" step="1"
|
||||
currentValue={limit ?? defaultValue} onChange={setLimit}
|
||||
/>
|
||||
</SearchOption>
|
||||
</SearchOption>;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import appContext from "../../components/app_context";
|
||||
import FNote from "../../entities/fnote";
|
||||
import attributes from "../../services/attributes";
|
||||
import bulk_action, { ACTION_GROUPS } from "../../services/bulk_action";
|
||||
import { isExperimentalFeatureEnabled } from "../../services/experimental_features";
|
||||
import froca from "../../services/froca";
|
||||
import { t } from "../../services/i18n";
|
||||
import server from "../../services/server";
|
||||
@ -15,6 +16,7 @@ import tree from "../../services/tree";
|
||||
import { getErrorMessage } from "../../services/utils";
|
||||
import ws from "../../services/ws";
|
||||
import RenameNoteBulkAction from "../bulk_actions/note/rename_note";
|
||||
import CollectionProperties from "../note_bars/CollectionProperties";
|
||||
import Button from "../react/Button";
|
||||
import Dropdown from "../react/Dropdown";
|
||||
import { FormListHeader, FormListItem } from "../react/FormList";
|
||||
@ -24,6 +26,8 @@ import { ParentComponent } from "../react/react_utils";
|
||||
import { TabContext } from "./ribbon-interface";
|
||||
import { SEARCH_OPTIONS, SearchOption } from "./SearchDefinitionOptions";
|
||||
|
||||
const isNewLayout = isExperimentalFeatureEnabled("new-layout");
|
||||
|
||||
export default function SearchDefinitionTab({ note, ntxId, hidden }: Pick<TabContext, "note" | "ntxId" | "hidden">) {
|
||||
const parentComponent = useContext(ParentComponent);
|
||||
const [ searchOptions, setSearchOptions ] = useState<{ availableOptions: SearchOption[], activeOptions: SearchOption[] }>();
|
||||
@ -78,7 +82,7 @@ export default function SearchDefinitionTab({ note, ntxId, hidden }: Pick<TabCon
|
||||
return (
|
||||
<div className="search-definition-widget">
|
||||
<div className="search-settings">
|
||||
{note && !hidden &&
|
||||
{note && !hidden && (
|
||||
<table className="search-setting-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
@ -111,6 +115,11 @@ export default function SearchDefinitionTab({ note, ntxId, hidden }: Pick<TabCon
|
||||
defaultValue={defaultValue}
|
||||
/>;
|
||||
})}
|
||||
|
||||
{isNewLayout && <tr className="view-options">
|
||||
<td className="title-column">{t("search_definition.view_options")}</td>
|
||||
<td><CollectionProperties note={note} /></td>
|
||||
</tr>}
|
||||
</tbody>
|
||||
<BulkActionsList note={note} />
|
||||
<tbody className="search-actions">
|
||||
@ -156,7 +165,7 @@ export default function SearchDefinitionTab({ note, ntxId, hidden }: Pick<TabCon
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user