aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/GlobalKeyHandler.ts2
-rw-r--r--src/client/views/MainView.tsx8
-rw-r--r--src/client/views/PropertiesView.tsx51
-rw-r--r--src/client/views/StyleProvider.tsx46
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx5
-rw-r--r--src/client/views/collections/TreeView.scss41
-rw-r--r--src/client/views/collections/TreeView.tsx12
-rw-r--r--src/client/views/nodes/DocumentView.scss57
-rw-r--r--src/client/views/nodes/DocumentView.tsx23
-rw-r--r--src/client/views/nodes/FilterBox.scss163
-rw-r--r--src/client/views/nodes/FilterBox.tsx140
11 files changed, 484 insertions, 64 deletions
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 1c5277de0..6dc927877 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -27,6 +27,7 @@ import { SnappingManager } from "../util/SnappingManager";
import { SearchBox } from "./search/SearchBox";
import { random } from "lodash";
import { DocumentView } from "./nodes/DocumentView";
+import { SettingsManager } from "../util/SettingsManager";
import { AudioBox } from "./nodes/AudioBox";
const modifiers = ["control", "meta", "shift", "alt"];
@@ -132,6 +133,7 @@ export class KeyManager {
DictationManager.Controls.stop();
GoogleAuthenticationManager.Instance.cancel();
SharingManager.Instance.close();
+ if (!GroupManager.Instance.isOpen) SettingsManager.Instance.close();
GroupManager.Instance.close();
CollectionFreeFormViewChrome.Instance?.clearKeep();
window.getSelection()?.empty();
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index bd5db62ef..a0161b81e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -44,6 +44,7 @@ import { KeyManager } from './GlobalKeyHandler';
import { InkStrokeProperties } from './InkStrokeProperties';
import { LinkMenu } from './linking/LinkMenu';
import "./MainView.scss";
+import "./collections/TreeView.scss";
import { AudioBox } from './nodes/AudioBox';
import { DocumentLinksButton } from './nodes/DocumentLinksButton';
import { DocumentView, DocumentViewProps } from './nodes/DocumentView';
@@ -59,7 +60,7 @@ import { AnchorMenu } from './pdf/AnchorMenu';
import { PreviewCursor } from './PreviewCursor';
import { PropertiesView } from './PropertiesView';
import { SearchBox } from './search/SearchBox';
-import { DefaultStyleProvider, StyleProp } from './StyleProvider';
+import { DefaultStyleProvider, DashboardStyleProvider, StyleProp } from './StyleProvider';
const _global = (window /* browser */ || global /* node */) as any;
@observer
@@ -164,7 +165,8 @@ export class MainView extends React.Component {
fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo,
fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical,
fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, fa.faBorderAll,
- fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash, fa.faGripLines);
+ fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash, fa.faGripLines,
+ fa.faSave, fa.faBookmark);
this.initAuthenticationRouters();
}
@@ -343,7 +345,7 @@ export class MainView extends React.Component {
renderDepth={0}
scriptContext={CollectionDockingView.Instance.props.Document}
focus={emptyFunction}
- styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards ? this.DashboardStyleProvider : DefaultStyleProvider}
+ styleProvider={this._sidebarContent.title === "My Dashboards" ? this.DashboardStyleProvider : DefaultStyleProvider}
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 4aeb4e63a..1c6ad26e6 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -11,7 +11,7 @@ import { InkField } from "../../fields/InkField";
import { ComputedField } from "../../fields/ScriptField";
import { Cast, NumCast, StrCast } from "../../fields/Types";
import { denormalizeEmail, GetEffectiveAcl, SharingPermissions } from "../../fields/util";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse } from "../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../Utils";
import { DocumentType } from "../documents/DocumentTypes";
import { DocumentManager } from "../util/DocumentManager";
import { SelectionManager } from "../util/SelectionManager";
@@ -29,6 +29,7 @@ import { PropertiesButtons } from "./PropertiesButtons";
import { PropertiesDocContextSelector } from "./PropertiesDocContextSelector";
import "./PropertiesView.scss";
import { DefaultStyleProvider } from "./StyleProvider";
+import { FilterBox } from "./nodes/FilterBox";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -67,6 +68,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@observable openContexts: boolean = true;
@observable openAppearance: boolean = true;
@observable openTransform: boolean = true;
+ @observable openFilters: boolean = true;
+
// @observable selectedUser: string = "";
// @observable addButtonPressed: boolean = false;
@observable layoutDocAcls: boolean = false;
@@ -413,7 +416,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
const ownerSame = Doc.CurrentUserEmail !== target.author && docs.filter(doc => doc).every(doc => doc.author === docs[0].author);
// shifts the current user, owner, public to the top of the doc.
- tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-"));
+ // tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-"));
tableEntries.unshift(this.sharingItem("Public", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Public"] === docs[0]["acl-Public"]) ? (AclMap.get(target[AclSym]?.["acl-Public"]) || SharingPermissions.None) : "-multiple-"));
tableEntries.unshift(this.sharingItem("Me", showAdmin, docs.filter(doc => doc).every(doc => doc.author === Doc.CurrentUserEmail) ? "Owner" : effectiveAcls.every(acl => acl === effectiveAcls[0]) ? AclMap.get(effectiveAcls[0])! : "-multiple-", !ownerSame));
if (ownerSame) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, "Owner"));
@@ -510,8 +513,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
}
-
-
@computed
get controlPointsButton() {
const formatInstance = InkStrokeProperties.Instance;
@@ -897,16 +898,54 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
/>
<div className="propertiesView-acls-checkbox-text">Layout</div>
</div>) : (null)}
- <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
+ {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
<button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
<FontAwesomeIcon icon="redo-alt" color="white" size="1x" />
</button>
- </Tooltip>
+ </Tooltip> */}
</div>
{this.sharingTable}
</div>}
</div>
+ <div className="propertiesView-sharing">
+ <div className="propertiesView-sharing-title"
+ onPointerDown={action(() => this.openFilters = !this.openFilters)}
+ style={{ backgroundColor: this.openFilters ? "black" : "" }}>
+ Filters
+ <div className="propertiesView-sharing-title-icon">
+ <FontAwesomeIcon icon={this.openFilters ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {!this.openFilters ? (null) :
+ <div className="propertiesView-sharing-content">
+ <DocumentView
+ Document={Doc.UserDoc().currentFilter as any as Doc}
+ DataDoc={undefined}
+ addDocument={undefined}
+ addDocTab={returnFalse}
+ pinToPres={emptyFunction}
+ rootSelected={returnTrue}
+ removeDocument={returnFalse}
+ ScreenToLocalTransform={this.getTransform}
+ PanelWidth={this.docWidth}
+ PanelHeight={this.docHeight}
+ renderDepth={0}
+ scriptContext={CollectionDockingView.Instance.props.Document}
+ focus={emptyFunction}
+ styleProvider={DefaultStyleProvider}
+ parentActive={returnTrue}
+ whenActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ />
+ </div>}
+ </div>
+
{!this.isInk ? (null) :
<div className="propertiesView-appearance">
<div className="propertiesView-appearance-title"
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 1d822439a..101ecb9ad 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -15,6 +15,7 @@ import { MainView } from './MainView';
import { DocumentViewProps } from "./nodes/DocumentView";
import { FieldViewProps } from './nodes/FieldView';
import "./StyleProvider.scss";
+import "./collections/TreeView.scss";
import React = require("react");
import Color = require('color');
@@ -23,6 +24,7 @@ export enum StyleLayers {
}
export enum StyleProp {
+ TreeViewIcon = "treeViewIcon",
DocContents = "docContents", // when specified, the JSX returned will replace the normal rendering of the document view
Opacity = "opacity", // opacity of the document view
Hidden = "hidden", // whether the document view should not be isplayed
@@ -64,11 +66,14 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
const selected = property.includes(":selected");
const isCaption = property.includes(":caption");
const isAnchor = property.includes(":anchor");
+ const isFooter = property.includes(":footer");
+
const isBackground = () => StrListCast(doc?.layers).includes(StyleLayers.Background);
const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
switch (property.split(":")[0]) {
+ case StyleProp.TreeViewIcon: return doc ? Doc.toIcon(doc) : "question";
case StyleProp.DocContents: return undefined;
case StyleProp.WidgetColor: return darkScheme() ? "lightgrey" : "dimgrey";
case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
@@ -158,6 +163,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
if (doc?.type !== DocumentType.INK && layer === true) return "all";
return undefined;
case StyleProp.Decorations:
+ // if (isFooter)
+
if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) {
return doc && (isBackground() || selected) && (props?.renderDepth || 0) > 0 &&
((doc.type === DocumentType.COL && doc._viewType !== CollectionViewType.Pile) || [DocumentType.RTF, DocumentType.IMG, DocumentType.INK].includes(doc.type as DocumentType)) ?
@@ -169,6 +176,45 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
}
}
+
+function toggleHidden(e: React.MouseEvent, doc: Doc) {
+ UndoManager.RunInBatch(() => runInAction(() => {
+ e.stopPropagation();
+ doc.hidden = doc.hidden ? undefined : true;
+ }), "toggleHidden");
+}
+
+function toggleLock(e: React.MouseEvent, doc: Doc) {
+ UndoManager.RunInBatch(() => runInAction(() => {
+ e.stopPropagation();
+ doc.lockedPosition = doc.lockedPosition ? undefined : true;
+ }), "toggleHidden");
+}
+
+/**
+ * add lock and hide button decorations for the "Dashboards" flyout TreeView
+ */
+export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps | DocumentViewProps>, property: string) {
+ switch (property.split(":")[0]) {
+ case StyleProp.Decorations:
+ if (doc) {
+ const hidden = doc.hidden;
+ const locked = doc.lockedPosition;
+ return doc._viewType === CollectionViewType.Docking || (Doc.IsSystem(doc) && Doc.UserDoc().noviceMode) ? (null) :
+ <>
+ <div className={`styleProvider-treeView-hide${hidden ? "-active" : ""}`} onClick={(e) => toggleHidden(e, doc)}>
+ <FontAwesomeIcon icon={hidden ? "eye-slash" : "eye"} size="sm" />
+ </div>
+ <div className={`styleProvider-treeView-lock${locked ? "-active" : ""}`} onClick={(e) => toggleLock(e, doc)}>
+ <FontAwesomeIcon icon={locked ? "lock" : "unlock"} size="sm" />
+ </div>
+ </>;
+ }
+ default: return DefaultStyleProvider(doc, props, property);
+
+ }
+}
+
//
// a preliminary semantic-"layering/grouping" mechanism for determining interactive properties of documents
// currently, the provider tests whether the docuemnt's layer field matches the activeLayer field of the tab.
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 564939270..b9ad1680a 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -35,7 +35,8 @@ export type collectionTreeViewProps = {
};
@observer
-export class CollectionTreeView extends CollectionSubView<Document, Partial<collectionTreeViewProps>>(Document) {
+export class
+ CollectionTreeView extends CollectionSubView<Document, Partial<collectionTreeViewProps>>(Document) {
private treedropDisposer?: DragManager.DragDropDisposer;
private _isChildActive = false;
private _mainEle?: HTMLDivElement;
@@ -212,7 +213,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
render() {
TraceMobx();
if (!(this.doc instanceof Doc)) return (null);
- const background = this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
+ const background = this.props.treeViewHideTitle && this.props.treeViewHideHeaderFields ? "#9F9F9F" : this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
const paddingX = `${NumCast(this.doc._xPadding, 15)}px`;
const paddingTop = `${NumCast(this.doc._yPadding, 20)}px`;
const pointerEvents = !this.props.active() && !SnappingManager.GetIsDragging() && !this._isChildActive ? "none" : undefined;
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 067675038..2f74a49bb 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -8,6 +8,7 @@
width: 100%;
overflow: hidden;
}
+
.treeView-container,
.treeView-container-active {
.bullet-outline {
@@ -20,21 +21,26 @@
.treeView-bulletIcons {
width: 15px;
+
.treeView-expandIcon {
display: none;
left: -10px;
position: absolute;
}
+
.treeView-checkIcon {
- left: -10px;
+ left: 3.5px;
+ top: 2px;
position: absolute;
}
+
&:hover {
.treeView-expandIcon {
display: unset;
}
}
}
+
.bullet {
position: relative;
width: $TREE_BULLET_WIDTH;
@@ -45,9 +51,11 @@
border-radius: 4px;
}
}
+
.treeView-container-active {
z-index: 100;
position: relative;
+
.formattedTextbox-sidebar {
background-color: #ffff001f !important;
height: 500px !important;
@@ -70,7 +78,8 @@
display: flex;
overflow: hidden;
}
-.treeView-border{
+
+.treeView-border {
border-left: dashed 1px #00000042;
}
@@ -78,15 +87,20 @@
.treeView-header {
border: transparent 1px solid;
display: flex;
+
//align-items: center;
::-webkit-scrollbar {
- display: none;
+ display: none;
}
+
.formattedTextBox-cont {
- .formattedTextbox-sidebar, .formattedTextbox-sidebar-inking {
+
+ .formattedTextbox-sidebar,
+ .formattedTextbox-sidebar-inking {
overflow: visible !important;
border-left: unset;
}
+
overflow: visible !important;
}
@@ -104,12 +118,18 @@
margin-left: 0.25rem;
opacity: 0.75;
- >svg, .styleProvider-treeView-lock, .styleProvider-treeView-hide, .styleProvider-treeView-lock-active, .styleProvider-treeView-hide-active {
+ >svg,
+ .styleProvider-treeView-lock,
+ .styleProvider-treeView-hide,
+ .styleProvider-treeView-lock-active,
+ .styleProvider-treeView-hide-active {
margin-left: 0.25rem;
- margin-right: 0.25rem;
+ margin-right: 0.25rem;
}
-
- >svg, .styleProvider-treeView-lock, .styleProvider-treeView-hide {
+
+ >svg,
+ .styleProvider-treeView-lock,
+ .styleProvider-treeView-hide {
display: none;
}
}
@@ -134,7 +154,10 @@
}
.right-buttons-container {
- >svg, .styleProvider-treeView-lock, .styleProvider-treeView-hide {
+
+ >svg,
+ .styleProvider-treeView-lock,
+ .styleProvider-treeView-hide {
display: inherit;
}
}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index c4934cf45..816778c59 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -443,8 +443,17 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed get renderBullet() {
TraceMobx();
+
const iconType = Doc.toIcon(this.doc);
+
+ // console.log(this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon)); <- always undefined
+ //const iconType = this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon);
+
+
+ // const footerDecoration = this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decoration + ":footer");
+
const checked = this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
+
return <div className={`bullet${this.outlineMode ? "-outline" : ""}`} key={"bullet"}
title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
onClick={this.bulletClick}
@@ -468,7 +477,6 @@ export class TreeView extends React.Component<TreeViewProps> {
}
</div>;
}
-
@computed get showTitleEditorControl() { return ["*", this._uniqueId, this.props.treeView._uniqueId].includes(Doc.GetT(this.doc, "editTitle", "string", true) || ""); }
@computed get headerElements() {
return (Doc.IsSystem(this.doc) && Doc.UserDoc().noviceMode) || this.props.treeViewHideHeaderFields() ? (null) :
@@ -589,7 +597,7 @@ export class TreeView extends React.Component<TreeViewProps> {
{view}
</div >
<div className={"right-buttons-container"}>
- {this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations + (Doc.IsSystem(this.props.containingCollection) ? ":afterHeader" : ""))} {/* hide and lock buttons */}
+ {this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations)} {/* hide and lock buttons */}
{this.headerElements}
</div>
</>;
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 6f041e5ef..e01a21530 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -3,6 +3,7 @@
.documentView-effectsWrapper {
border-radius: inherit;
}
+
.documentView-node,
.documentView-node-topmost {
position: inherit;
@@ -37,14 +38,16 @@
overflow-y: scroll;
height: calc(100% - 20px);
}
+
.documentView-linkAnchorBoxAnchor {
- display:flex;
+ display: flex;
overflow: hidden;
.documentView-node {
- width:10px !important;
+ width: 10px !important;
}
}
+
.documentView-treeView {
max-height: 1.5em;
text-overflow: ellipsis;
@@ -52,7 +55,8 @@
white-space: pre;
width: 100%;
overflow: hidden;
- > .documentView-node {
+
+ >.documentView-node {
position: absolute;
}
}
@@ -61,14 +65,33 @@
border-radius: inherit;
width: 100%;
height: 100%;
+
+ .sharingIndicator {
+ height: 30px;
+ width: 30px;
+ border-radius: 50%;
+ position: absolute;
+ right: -15;
+ opacity: 0.9;
+ pointer-events: auto;
+ background-color: #9dca96;
+ letter-spacing: 2px;
+ font-size: 10px;
+ transition: transform 0.2s;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ }
}
.documentView-anchorCont {
position: absolute;
- top: 0;
- left: 0;
+ top: 0;
+ left: 0;
width: 100%;
- height: 100%;
+ height: 100%;
display: inline-block;
pointer-events: none;
}
@@ -81,6 +104,7 @@
top: 0;
left: 0;
}
+
.documentView-styleWrapper {
position: absolute;
display: inline-block;
@@ -94,7 +118,8 @@
position: absolute;
}
- .documentView-titleWrapper, .documentView-titleWrapper-hover {
+ .documentView-titleWrapper,
+ .documentView-titleWrapper-hover {
overflow: hidden;
color: white;
transform-origin: top left;
@@ -107,8 +132,9 @@
white-space: pre;
position: absolute;
}
+
.documentView-titleWrapper-hover {
- display:none;
+ display: none;
}
.documentView-searchHighlight {
@@ -131,18 +157,21 @@
}
-.documentView-node:hover, .documentView-node-topmost:hover {
- > .documentView-styleWrapper {
- > .documentView-titleWrapper-hover {
- display:inline-block;
+.documentView-node:hover,
+.documentView-node-topmost:hover {
+ >.documentView-styleWrapper {
+ >.documentView-titleWrapper-hover {
+ display: inline-block;
}
}
- > .documentView-styleWrapper {
- > .documentView-captionWrapper {
+
+ >.documentView-styleWrapper {
+ >.documentView-captionWrapper {
opacity: 1;
}
}
}
+
.contentFittingDocumentView {
position: relative;
display: flex;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 13e1f3d54..546eca427 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -7,7 +7,7 @@ import { InkTool } from '../../../fields/InkField';
import { listSpec } from "../../../fields/Schema";
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
-import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
+import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
import { MobileInterface } from '../../../mobile/MobileInterface';
import { emptyFunction, hasDescendantTarget, OmitKeys, returnFalse, returnVal, Utils } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
@@ -41,6 +41,9 @@ import { LinkAnchorBox } from './LinkAnchorBox';
import { PresBox } from './PresBox';
import { RadialMenu } from './RadialMenu';
import React = require("react");
+import { List } from '../../../fields/List';
+import { Tooltip } from '@material-ui/core';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export type DocAfterFocusFunc = (notFocused: boolean) => boolean;
export type DocFocusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, focused?: boolean) => void;
@@ -547,7 +550,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (this.props.Document === CurrentUserUtils.ActiveDashboard) {
alert((e.target as any)?.closest?.("*.lm_content") ?
"You can't perform this move most likely because you don't have permission to modify the destination." :
- "linking to document tabs not yet supported. Drop link on document content.");
+ "Linking to document tabs not yet supported. Drop link on document content.");
return;
}
if (de.complete.annoDragData) de.complete.annoDragData.annotationDocument = de.complete.annoDragData.annotationDocCreator();
@@ -722,9 +725,25 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
{this.layoutDoc.hideAllLinks ? (null) : this.allAnchors}
{this.hideLinkButton ? (null) :
<DocumentLinksButton View={this.props.DocumentView} links={this.allLinks} Offset={[this.topMost ? 0 : -15, undefined, undefined, this.topMost ? 10 : -20]} />}
+ {!this.props.Document.numUsersShared && !this.props.Document.numGroupsShared ? (null) :
+ <Tooltip title={<> <div className="dash-tooltip">Tap to open sharing menu</div></>}>
+ <div className="sharingIndicator"
+ onPointerDown={() => SharingManager.Instance.open(undefined, this.props.Document)}
+ style={{ backgroundColor: GetEffectiveAcl(this.props.Document[DataSym]) === AclAdmin ? "#9dca96" : "lightgrey" }}
+ >
+ <FontAwesomeIcon size="lg" icon={this.indicatorIcon} />
+ </div>
+ </Tooltip >
+ }
</div>;
}
+ get indicatorIcon() {
+ if (this.props.Document["acl-Public"] !== SharingPermissions.None) return "globe-americas";
+ else if (this.props.Document.numGroupsShared || NumCast(this.props.Document.numUsersShared, 0) > 1) return "users";
+ else return "user";
+ }
+
@undoBatch
hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true)
anchorPanelWidth = () => this.props.PanelWidth() || 1;
diff --git a/src/client/views/nodes/FilterBox.scss b/src/client/views/nodes/FilterBox.scss
index d32cc0d2b..144f161bc 100644
--- a/src/client/views/nodes/FilterBox.scss
+++ b/src/client/views/nodes/FilterBox.scss
@@ -1,17 +1,154 @@
-
-
.filterBox-flyout {
- width: 400px;
display: block;
text-align: left;
+ font-weight: 100;
+
.filterBox-flyout-facet {
- background-color: lightgray;
- text-align: left;
- display: inline-block;
- position: relative;
- width: 100%;
+ background-color: white;
+ text-align: left;
+ display: inline-block;
+ position: relative;
+ width: 100%;
+
+ .filterBox-flyout-facet-check {
+ margin-right: 6px;
+ }
+ }
+}
+
+
+.filter-bookmark {
+ //display: flex;
+
+ .filter-bookmark-icon {
+ float: right;
+ margin-right: 10px;
+ margin-top: 7px;
+ }
+}
+
+.filterBox-bottom {
+ // position: fixed;
+ // bottom: 0;
+ // width: 100%;
+}
+
+
+.filterBox-saveBookmark {
+ background-color: #e9e9e9;
+ border-radius: 11px;
+ padding-left: 8px;
+ padding-right: 8px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ margin: 8px;
+ display: flex;
+ font-size: 11px;
+
+ &:hover {
+ background-color: white;
}
+
+ .filterBox-saveBookmark-icon {
+ margin-right: 6px;
+ margin-top: 4px;
+ margin-left: 2px;
+ }
+
}
+
+.filterBox-title {
+
+ justify-content: center;
+ text-align: center;
+ padding-bottom: 13px;
+ font-size: 20px;
+ font-weight: bold;
+
+ .filterBox-span {
+ margin-right: 15px;
+ }
+
+}
+
+.filterBox-select-scope,
+.filterBox-select-bool,
+.filterBox-addWrapper,
+.filterBox-select-matched,
+.filterBox-saveWrapper {
+ font-size: 10px;
+ justify-content: center;
+ justify-items: center;
+ padding-bottom: 10px;
+ display: flex;
+}
+
+.filterBox-addWrapper {
+ font-size: 11px;
+ width: 100%;
+}
+
+.filterBox-saveWrapper {
+ width: 100%;
+}
+
+// .filterBox-top {
+// padding-bottom: 20px;
+// border-bottom: 2px solid black;
+// position: fixed;
+// top: 0;
+// width: 100%;
+// }
+
+.filterBox-select-scope {
+ padding-bottom: 20px;
+ border-bottom: 2px solid black;
+}
+
+
+.filterBox-select-bool {
+ margin-top: 6px;
+}
+
+.filterBox-select-text {
+ margin-right: 8px;
+ margin-left: 8px;
+ margin-top: 3px;
+}
+
+.filterBox-select-box {
+ margin-right: 2px;
+ font-size: 30px;
+ border: 0;
+ background: transparent;
+}
+
+.filterBox-selection {
+ border-radius: 6px;
+ border: none;
+ background-color: #e9e9e9;
+ padding: 2px;
+
+ &:hover {
+ background-color: white;
+ }
+}
+
+.filterBox-addFilter {
+ width: 120px;
+ background-color: #e9e9e9;
+ border-radius: 12px;
+ padding: 5px;
+ margin: 5px;
+ display: flex;
+ text-align: center;
+ justify-content: center;
+
+ &:hover {
+ background-color: white;
+ }
+}
+
.filterBox-treeView {
display: flex;
flex-direction: column;
@@ -20,24 +157,19 @@
position: absolute;
right: 0;
top: 0;
- border-left: solid 1px;
z-index: 1;
+ background-color: #9F9F9F;
.filterBox-addfacet {
display: inline-block;
width: 200px;
height: 30px;
- background: darkGray;
text-align: left;
.filterBox-addFacetButton {
display: flex;
margin: auto;
cursor: pointer;
-
- .filterBox-span {
- margin-right: 15px;
- }
}
>div,
@@ -50,6 +182,7 @@
.filterBox-tree {
display: inline-block;
width: 100%;
- height: calc(100% - 30px);
+ margin-bottom: 10px;
+ //height: calc(100% - 30px);
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index badacbc5c..2db610e43 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -1,6 +1,6 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { computed } from "mobx";
+import { action, computed } from "mobx";
import { observer } from "mobx-react";
import { DataSym, Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
@@ -20,9 +20,13 @@ import { FieldView, FieldViewProps } from './FieldView';
import './FilterBox.scss';
import { Scripting } from "../../util/Scripting";
import { values } from "lodash";
+import { tokenToString } from "typescript";
+import { SelectionManager } from "../../util/SelectionManager";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
+import Select from "react-select";
+import { UserOptions } from "../../util/GroupManager";
type FilterBoxDocument = makeInterface<[typeof documentSchema]>;
const FilterBoxDocument = makeInterface(documentSchema);
@@ -31,6 +35,11 @@ const FilterBoxDocument = makeInterface(documentSchema);
export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDocument>(FilterBoxDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FilterBox, fieldKey); }
+ public _filterBoolean = "AND";
+ public _filterScope = "Current Dashboard";
+ public _filterSelected = false;
+ public _filterMatch = "matched";
+
@computed get allDocs() {
const allDocs = new Set<Doc>();
if (CollectionDockingView.Instance) {
@@ -51,6 +60,13 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
return Array.from(keys.keys()).filter(key => key[0]).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_")) || noviceFields.includes(key) || !Doc.UserDoc().noviceMode).sort();
}
+ /**
+ * The current attributes selected to filter based on
+ */
+ @computed get activeAttributes() {
+ return DocListCast(this.dataDoc[this.props.fieldKey]);
+ }
+
gatherFieldValues(dashboard: Doc, facetKey: string) {
const childDocs = DocListCast((dashboard.data as any)[0].data);
const valueSet = new Set<string>();
@@ -88,7 +104,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
*/
facetClick = (facetHeader: string) => {
const targetDoc = CollectionDockingView.Instance.props.Document;
- const found = DocListCast(this.dataDoc[this.props.fieldKey]).findIndex(doc => doc.title === facetHeader);
+ const found = this.activeAttributes.findIndex(doc => doc.title === facetHeader);
if (found !== -1) {
(this.dataDoc[this.props.fieldKey] as List<Doc>).splice(found, 1);
const docFilter = Cast(targetDoc._docFilters, listSpec("string"));
@@ -159,25 +175,86 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
return script ? () => script : undefined;
}
+ @action
+ changeBool = (e: any) => {
+ this._filterBoolean = e.currentTarget.value;
+ console.log(this._filterBoolean);
+ }
+
+ @action
+ changeScope = (e: any) => {
+ this._filterScope = e.currentTarget.value;
+ console.log(this._filterScope);
+ }
+
+ @action
+ changeMatch = (e: any) => {
+ this._filterMatch = e.currentTarget.value;
+ console.log(this._filterMatch);
+ }
+
+
+ @action
+ changeSelected = (e: any) => {
+ if (this._filterSelected) {
+ this._filterSelected = false;
+ SelectionManager.DeselectAll();
+ } else {
+ this._filterSelected = true;
+ // helper method to select specified docs
+ }
+ console.log(this._filterSelected);
+ }
+
render() {
const facetCollection = this.props.Document;
- const flyout = <div className="filterBox-flyout" style={{ width: `100%`, height: this.props.PanelHeight() - 30 }} onWheel={e => e.stopPropagation()}>
+ const flyout = <div className="filterBox-flyout" style={{ width: `100%` }} onWheel={e => e.stopPropagation()}>
{this._allFacets.map(facet => <label className="filterBox-flyout-facet" key={`${facet}`} onClick={e => this.facetClick(facet)}>
- <input type="checkbox" onChange={e => { }} checked={DocListCast(this.props.Document[this.props.fieldKey]).some(d => d.title === facet)} />
+ <input className="filterBox-flyout-facet-check" type="checkbox" onChange={e => { }} checked={DocListCast(this.props.Document[this.props.fieldKey]).some(d => d.title === facet)} />
<span className="checkmark" />
{facet}
</label>)}
</div>;
+ const attributes = this.activeAttributes;
+
+ // const options = this._allFacets.filter(facet => !attributes.some(attribute => attribute.title === facet)).map(facet => ({ value: facet, label: facet }));
+ const options = this._allFacets.map(facet => ({ value: facet, label: facet }));
+
return this.props.dontRegisterView ? (null) : <div className="filterBox-treeView" style={{ width: "100%" }}>
- <div className="filterBox-addFacet" style={{ width: "100%" }} onPointerDown={e => e.stopPropagation()}>
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
- <div className="filterBox-addFacetButton">
- <FontAwesomeIcon icon={"edit"} size={"lg"} />
- <span className="filterBox-span">Choose Facets</span>
- </div>
- </Flyout>
+
+ {/* <div className="filterBox-top"> */}
+ {/* <div className="filter-bookmark">
+ <FontAwesomeIcon className="filter-bookmark-icon" icon={"bookmark"} size={"lg"} />
+ </div>
+
+ <div className="filterBox-title">
+ <span className="filterBox-span">Choose Filters</span>
+ </div> */}
+
+ <div className="filterBox-select-bool">
+ <select className="filterBox-selection" onChange={e => this.changeBool(e)}>
+ <option value="AND" key="AND">AND</option>
+ <option value="OR" key="OR">OR</option>
+ </select>
+ <div className="filterBox-select-text">filters in </div>
+ <select className="filterBox-selection" onChange={e => this.changeScope(e)}>
+ <option value="Current Dashboard" key="Current Dashboard">Current Dashboard</option>
+ <option value="Current Tab" key="Current Tab">Current Tab</option>
+ <option value="Current Collection" key="Current Collection">Current Collection</option>
+ </select>
</div>
+
+ {/* <div className="filterBox-select-scope">
+ <div className="filterBox-select-text">Scope: </div>
+ <select className="filterBox-selection" onChange={e => this.changeScope(e)}>
+ <option value="Current Dashboard" key="Current Dashboard">Current Dashboard</option>
+ <option value="Current Tab" key="Current Tab">Current Tab</option>
+ <option value="Current Collection" key="Current Collection">Current Collection</option>
+ </select>
+ </div> */}
+ {/* </div> */}
+
<div className="filterBox-tree" key="tree">
<CollectionTreeView
Document={facetCollection}
@@ -215,6 +292,47 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
removeDocument={returnFalse}
addDocument={returnFalse} />
</div>
+ {/* <Flyout className="filterBox-flyout" anchorPoint={anchorPoints.RIGHT_TOP} content={flyout}>
+ <div className="filterBox-addWrapper">
+ <div className="filterBox-addFilter"> + add a filter</div>
+ </div>
+ </Flyout> */}
+ <Select
+ placeholder="Add a filter..."
+ options={options}
+ isMulti={false}
+ onChange={val => this.facetClick((val as UserOptions).value)}
+ value={null}
+ closeMenuOnSelect={false}
+ />
+
+ <div className="filterBox-bottom">
+ <div className="filterBox-select-matched">
+ <input className="filterBox-select-box" type="checkbox"
+ onChange={e => this.changeSelected(e)} />
+ <div className="filterBox-select-text">select</div>
+ <select className="filterBox-selection" onChange={e => this.changeMatch(e)}>
+ <option value="matched" key="matched">matched</option>
+ <option value="unmatched" key="unmatched">unmatched</option>
+ </select>
+ <div className="filterBox-select-text">documents</div>
+ </div>
+
+ <div style={{ display: "flex" }}>
+ <div className="filterBox-saveWrapper">
+ <div className="filterBox-saveBookmark">
+ <FontAwesomeIcon className="filterBox-saveBookmark-icon" icon={"save"} size={"sm"} />
+ <div>SAVE</div>
+ </div>
+ </div>
+ <div className="filterBox-saveWrapper">
+ <div className="filterBox-saveBookmark">
+ <FontAwesomeIcon className="filterBox-saveBookmark-icon" icon={"bookmark"} size={"sm"} />
+ <div>MY FILTERS</div>
+ </div>
+ </div>
+ </div>
+ </div>
</div>;
}
}