diff options
52 files changed, 207 insertions, 207 deletions
diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index 4b86a8341..15fd6313a 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -311,7 +311,7 @@ export namespace GooglePhotos { sources .filter(source => ImageCast(Doc.GetProto(source).data)) .forEach(async source => { - const data = ImageCast(Doc.GetProto(source).data); + const data = ImageCast(Doc.GetProto(source).data)!; const url = data.url.href; const target = Doc.MakeEmbedding(source); const description = parseDescription(target, descriptionKey); diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx index 4e321a893..b50e39c02 100644 --- a/src/client/util/CalendarManager.tsx +++ b/src/client/util/CalendarManager.tsx @@ -162,7 +162,7 @@ export class CalendarManager extends ObservableReactComponent<object> { console.log('my calendars: ', Doc.MyCalendars); if (this.creationType === 'new-calendar') { - Doc.AddDocToList(Doc.MyCalendars, 'data', calendar); // add to new calendar to dashboard calendars + Doc.MyCalendars && Doc.AddDocToList(Doc.MyCalendars, 'data', calendar); // add to new calendar to dashboard calendars } } }; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index ad57c2a62..3bae2881e 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -173,10 +173,10 @@ export class DocumentManager { while ( containerDocContext.length && DocCast(containerDocContext[0]?.embedContainer) && - DocCast(containerDocContext[0].embedContainer)?._type_collection !== CollectionViewType.Docking && + DocCast(containerDocContext[0].embedContainer)!._type_collection !== CollectionViewType.Docking && (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0])) ) { - containerDocContext = [Cast(containerDocContext[0].embedContainer, Doc, null), ...containerDocContext]; + containerDocContext = [DocCast(containerDocContext[0].embedContainer)!, ...containerDocContext]; } return containerDocContext; } @@ -248,7 +248,7 @@ export class DocumentManager { finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done. ) => { const options = optionsIn; - Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc); + Doc.MyRecentlyClosed && Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc); const docContextPath = DocumentManager.GetContextPath(targetDoc, true); if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false; let activatedTab = false; @@ -272,7 +272,7 @@ export class DocumentManager { })); if (options.openLocation?.includes(OpenWhere.lightbox)) { // even if we found the document view, if the target is a lightbox, we try to open it in the lightbox to preserve lightbox semantics (eg, there's only one active doc in the lightbox) - const target = DocCast(targetDoc.annotationOn, targetDoc); + const target = DocCast(targetDoc.annotationOn, targetDoc)!; const compView = this.getDocumentView(DocCast(target.embedContainer))?.ComponentView; if ((compView?.addDocTab ?? compView?._props.addDocTab)?.(target, options.openLocation)) { await new Promise<void>(waitres => { diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 344e2e4c0..d8e0c4cbe 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -217,7 +217,8 @@ export class LinkManager { } // finds the opposite anchor of a given anchor in a link - public static getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined { + public static getOppositeAnchor(linkDoc: Doc | undefined, anchor: Doc | undefined): Doc | undefined { + if (!linkDoc || !anchor) return undefined; const id = LinkManager.anchorIndex(linkDoc, anchor); const a1 = DocCast(linkDoc.link_anchor_1); const a2 = DocCast(linkDoc.link_anchor_2); diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts index 62a09a8bc..4f0423342 100644 --- a/src/client/util/ReplayMovements.ts +++ b/src/client/util/ReplayMovements.ts @@ -108,9 +108,11 @@ export class ReplayMovements { movements.forEach((movement, i) => { if (typeof movement.doc === 'string') { - movements[i].doc = IdToDoc(movement.doc); - if (!movements[i].doc) { + const doc = IdToDoc(movement.doc); + if (!doc) { console.log('ERROR: tracked doc not found'); + } else { + movements[i].doc = doc; } } }); diff --git a/src/client/util/ScriptManager.ts b/src/client/util/ScriptManager.ts index 9158f6c0b..8c7f88bf6 100644 --- a/src/client/util/ScriptManager.ts +++ b/src/client/util/ScriptManager.ts @@ -1,7 +1,6 @@ -import { Doc, DocListCast } from '../../fields/Doc'; +import { Doc, DocListCast, StrListCast } from '../../fields/Doc'; import { List } from '../../fields/List'; -import { listSpec } from '../../fields/Schema'; -import { Cast, StrCast } from '../../fields/Types'; +import { StrCast } from '../../fields/Types'; import { Docs } from '../documents/Documents'; import { ScriptingGlobals } from './ScriptingGlobals'; @@ -10,7 +9,6 @@ export class ScriptManager { // eslint-disable-next-line no-use-before-define private static _instance: ScriptManager; public static get Instance(): ScriptManager { - // eslint-disable-next-line no-return-assign return this._instance || (this._instance = new this()); } private constructor() { @@ -58,7 +56,7 @@ export class ScriptManager { public static addScriptToGlobals(scriptDoc: Doc): void { ScriptingGlobals.removeGlobal(StrCast(scriptDoc.name)); - const params = Cast(scriptDoc['data-params'], listSpec('string'), []); + const params = StrListCast(scriptDoc['data-params']); const paramNames = params.reduce((o: string, p: string) => { let out = o; if (params.indexOf(p) === params.length - 1) { @@ -69,7 +67,6 @@ export class ScriptManager { return out; }, '' as string); - // eslint-disable-next-line no-new-func const f = new Function(paramNames, StrCast(scriptDoc.script)); Object.defineProperty(f, 'name', { value: StrCast(scriptDoc.name), writable: false }); diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index e4adcaa7e..fc3bb99ab 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -13,7 +13,7 @@ export namespace SearchUtil { const blockedKeys = matchKeyNames ? [] : Object.entries(DocOptions) - .filter(([, info]: [string, FInfo]) => !info?.searchable()) + .filter(([, info]: [string, FieldType | FInfo | undefined]) => (info instanceof FInfo ? !info.searchable() : true)) .map(([key]) => key); const exact = queryIn.startsWith('='); @@ -22,8 +22,7 @@ export namespace SearchUtil { const results = new ObservableMap<Doc, string[]>(); if (collectionDoc) { const docs = DocListCast(collectionDoc[Doc.LayoutDataKey(collectionDoc)]); - // eslint-disable-next-line @typescript-eslint/ban-types - const docIDs: String[] = []; + const docIDs: string[] = []; SearchUtil.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => { const dtype = StrCast(doc.type) as DocumentType; if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) { diff --git a/src/client/util/reportManager/ReportManagerComponents.tsx b/src/client/util/reportManager/ReportManagerComponents.tsx index 92f877859..80653779e 100644 --- a/src/client/util/reportManager/ReportManagerComponents.tsx +++ b/src/client/util/reportManager/ReportManagerComponents.tsx @@ -1,5 +1,3 @@ -/* eslint-disable react/require-default-props */ -/* eslint-disable prefer-destructuring */ /* eslint-disable no-use-before-define */ import * as React from 'react'; import ReactMarkdown from 'react-markdown'; @@ -299,7 +297,7 @@ export function IssueView({ issue }: IssueViewProps) { </div> </div> )} - <ReactMarkdown className="issue-content" remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}> + <ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}> {issueBody} </ReactMarkdown> </div> diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index f61f6db18..3ceb23ffd 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -113,12 +113,12 @@ export class DashboardView extends ObservableReactComponent<object> { getDashboards = (whichGroup: DashboardGroup) => { if (whichGroup === DashboardGroup.MyDashboards) { - return DocListCast(Doc.MyDashboards.data).filter(dashboard => dashboard.$author === ClientUtils.CurrentUserEmail()); + return DocListCast(Doc.MyDashboards?.data).filter(dashboard => dashboard.$author === ClientUtils.CurrentUserEmail()); } - return DocListCast(Doc.MySharedDocs.data_dashboards).filter(doc => doc.dockingConfig); + return DocListCast(Doc.MySharedDocs?.data_dashboards).filter(doc => doc.dockingConfig); }; - isUnviewedSharedDashboard = (dashboard: Doc) => !DocListCast(Doc.MySharedDocs.viewed).includes(dashboard); + isUnviewedSharedDashboard = (dashboard: Doc) => !DocListCast(Doc.MySharedDocs?.viewed).includes(dashboard); @undoBatch createNewDashboard = (name: string, background?: string) => { @@ -155,7 +155,7 @@ export class DashboardView extends ObservableReactComponent<object> { @action openNewDashboardModal = () => { this.openModal = true; - this.setNewDashboardName(`Dashboard ${DocListCast(Doc.MyDashboards.data).length + 1}`); + this.setNewDashboardName(`Dashboard ${DocListCast(Doc.MyDashboards?.data).length + 1}`); }; _downX: number = 0; @@ -191,7 +191,7 @@ export class DashboardView extends ObservableReactComponent<object> { <Button text={'Shared Dashboards (' + this.getDashboards(DashboardGroup.SharedDashboards).length + ')'} active={this.selectedDashboardGroup === DashboardGroup.SharedDashboards} - color={this.getDashboards(DashboardGroup.SharedDashboards).some(dash => !DocListCast(Doc.MySharedDocs.viewed).includes(dash)) ? 'green' : color} + color={this.getDashboards(DashboardGroup.SharedDashboards).some(dash => !DocListCast(Doc.MySharedDocs?.viewed).includes(dash)) ? 'green' : color} align="flex-start" onClick={() => this.selectDashboardGroup(DashboardGroup.SharedDashboards)} fillWidth @@ -275,7 +275,7 @@ export class DashboardView extends ObservableReactComponent<object> { } public static openSharedDashboard = (dashboard: Doc) => { - Doc.AddDocToList(Doc.MySharedDocs, 'viewed', dashboard); + Doc.MySharedDocs && Doc.AddDocToList(Doc.MySharedDocs, 'viewed', dashboard); DashboardView.openDashboard(Doc.BestEmbedding(dashboard)); }; @@ -283,8 +283,8 @@ export class DashboardView extends ObservableReactComponent<object> { /// this also sets the readonly state of the dashboard based on the current mode of dash (from its url) public static openDashboard = (doc: Doc | undefined, fromHistory = false) => { if (!doc) return false; - Doc.AddDocToList(Doc.MyDashboards, 'data', doc); - Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', doc); + Doc.MyDashboards && Doc.AddDocToList(Doc.MyDashboards, 'data', doc); + Doc.MyRecentlyClosed && Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', doc); // this has the side-effect of setting the main container since we're assigning the active/guest dashboard Doc.UserDoc() ? (Doc.ActiveDashboard = doc) : (Doc.GuestDashboard = doc); @@ -316,11 +316,11 @@ export class DashboardView extends ObservableReactComponent<object> { }; public static removeDashboard = (dashboard: Doc) => { - const dashboards = DocListCast(Doc.MyDashboards.data).filter(dash => dash !== dashboard); + const dashboards = DocListCast(Doc.MyDashboards?.data).filter(dash => dash !== dashboard); undoable(() => { if (dashboard === Doc.ActiveDashboard) DashboardView.openDashboard(dashboards.lastElement()); - Doc.RemoveDocFromList(Doc.MyDashboards, 'data', dashboard); - Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', dashboard, undefined, true, true); + Doc.MyDashboards && Doc.RemoveDocFromList(Doc.MyDashboards, 'data', dashboard); + Doc.MyRecentlyClosed && Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', dashboard, undefined, true, true); if (!dashboards.length) Doc.ActivePage = 'home'; }, 'remove dashboard')(); }; @@ -409,7 +409,7 @@ export class DashboardView extends ObservableReactComponent<object> { }; public static createNewDashboard = (id?: string, name?: string, background?: string) => { - const dashboardCount = DocListCast(Doc.MyDashboards.data).length + 1; + const dashboardCount = DocListCast(Doc.MyDashboards?.data).length + 1; const freeformOptions: DocumentOptions = { x: 0, y: 400, @@ -425,8 +425,8 @@ export class DashboardView extends ObservableReactComponent<object> { const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = DashboardView.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); - Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true); - Doc.AddDocToList(Doc.MyDashboards, 'data', dashboardDoc); + Doc.MyHeaderBar && Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true); + Doc.MyDashboards && Doc.AddDocToList(Doc.MyDashboards, 'data', dashboardDoc); freeformDoc._embedContainer = dashboardDoc; dashboardDoc.$myPaneCount = 1; dashboardDoc.$myOverlayDocs = new List<Doc>(); diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 425f5b6bb..41f38c008 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -99,7 +99,7 @@ export class InkStrokeProperties { controls.splice(i, 4, ...splicepts.map(p => ({ X: p.x, Y: p.y }))); // Updating the indices of the control points whose handle tangency has been broken. - doc.brokenInkIndices = new List(Cast(doc.brokenInkIndices, listSpec('number'), []).map(control => (control > i ? control + 4 : control))); + doc.brokenInkIndices = new List(NumListCast(doc.brokenInkIndices).map(control => (control > i ? control + 4 : control))); runInAction(() => { this._currentPoint = -1; }); @@ -252,7 +252,7 @@ export class InkStrokeProperties { this.applyFunction(inkView, (view: DocumentView, ink: InkData) => { const order = controlIndex % 4; const closed = InkingStroke.IsClosed(ink); - const brokenIndices = Cast(inkView.Document.brokenInkIndices, listSpec('number'), []); + const brokenIndices = NumListCast(inkView.Document.brokenInkIndices); if (origInk && this._currentPoint > 0 && this._currentPoint < ink.length - 1 && brokenIndices.findIndex(value => value === controlIndex) === -1) { const cptBefore = ink[controlIndex]; const cpt = { X: cptBefore.X + deltaX, Y: cptBefore.Y + deltaY }; @@ -405,9 +405,9 @@ export class InkStrokeProperties { this.applyFunction(inkView, (view: DocumentView, ink: InkData) => { const doc = view.Document; const brokenIndices = Cast(doc.brokenInkIndices, listSpec('number'), []); - const ind = brokenIndices.findIndex(value => value === controlIndex); + const ind = brokenIndices?.findIndex(value => value === controlIndex) ?? -1; if (ind !== -1) { - brokenIndices.splice(ind, 1); + brokenIndices!.splice(ind, 1); const [controlPoint, handleA, handleB] = [ink[controlIndex], ink[handleIndexA], ink[handleIndexB]]; const oppositeHandleA = this.rotatePoint(handleA, controlPoint, Math.PI); const angleDifference = InkStrokeProperties.angleChange(handleB, oppositeHandleA, controlPoint); diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 0a49ea28e..0136f6abe 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -26,8 +26,8 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { DashColor, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { Doc } from '../../fields/Doc'; -import { InkData, InkField } from '../../fields/InkField'; -import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; +import { InkData } from '../../fields/InkField'; +import { BoolCast, InkCast, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; import { Gestures } from '../../pen-gestures/GestureTypes'; import { Docs } from '../documents/Documents'; @@ -35,6 +35,7 @@ import { DocumentType } from '../documents/DocumentTypes'; import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; import { UndoManager } from '../util/UndoManager'; +import { CollectionFreeFormView } from './collections/collectionFreeForm'; import { ContextMenu } from './ContextMenu'; import { ViewBoxAnnotatableComponent } from './DocComponent'; import { Colors } from './global/globalEnums'; @@ -42,14 +43,13 @@ import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; import './InkStroke.scss'; import { InkStrokeProperties } from './InkStrokeProperties'; import { InkTangentHandles } from './InkTangentHandles'; +import { InkTranscription } from './InkTranscription'; +import { DocumentView } from './nodes/DocumentView'; import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox, FormattedTextBoxProps } from './nodes/formattedText/FormattedTextBox'; import { PinDocView, PinProps } from './PinFuncs'; import { StyleProp } from './StyleProp'; import { ViewBoxInterface } from './ViewBoxInterface'; -import { InkTranscription } from './InkTranscription'; -import { CollectionFreeFormView } from './collections/collectionFreeForm'; -import { DocumentView } from './nodes/DocumentView'; // eslint-disable-next-line @typescript-eslint/no-require-imports const { INK_MASK_SIZE } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @@ -245,7 +245,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() * factor for converting between ink and screen space. */ inkScaledData = () => { - const inkData = Cast(this.dataDoc[this.fieldKey], InkField, Cast(this.layoutDoc[this.fieldKey], InkField, null) ?? null)?.inkData ?? []; + const inkData = InkCast(this.dataDoc[this.fieldKey], InkCast(this.layoutDoc[this.fieldKey]) ?? null)?.inkData ?? []; const inkStrokeWidth = NumCast(this.layoutDoc.stroke_width, 1); const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2; const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2; diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 66936c64c..28566ba1d 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -385,18 +385,19 @@ export class PropertiesButtons extends React.Component { const followLoc = this.selectedDoc._followLinkLocation; const linkedToLightboxView = () => Doc.Links(this.selectedDoc).some(link => Doc.getOppositeAnchor(link, this.selectedDoc)?._isLightbox); - let active = false; - // prettier-ignore - switch (value[0]) { - case 'linkInPlace': active = linkButton && followLoc === OpenWhere.lightbox && !linkedToLightboxView(); break; - case 'linkOnRight': active = linkButton && followLoc === OpenWhere.addRight; break; - case 'enterPortal': active = linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView(); break; - case 'toggleDetail':active = ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail'); break; - case 'nothing': active = !linkButton && this.selectedDoc.onClick === undefined;break; - default: - } + const active = () => { + // prettier-ignore + switch (value[0]) { + case 'linkInPlace': return linkButton && followLoc === OpenWhere.lightbox && !linkedToLightboxView(); break; + case 'linkOnRight': return linkButton && followLoc === OpenWhere.addRight; break; + case 'enterPortal': return linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView(); break; + case 'toggleDetail':return ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail'); break; + case 'nothing': return !linkButton && this.selectedDoc.onClick === undefined;break; + default: return false; + } + }; return ( - <div className="list-item" key={`${value}`} style={{ backgroundColor: active ? Colors.LIGHT_BLUE : undefined }} onClick={click}> + <div className="list-item" key={`${value}`} style={{ backgroundColor: active() ? Colors.LIGHT_BLUE : undefined }} onClick={click}> {value[1]} </div> ); diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index e30d14eae..5a00e6a89 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -1,18 +1,16 @@ -/* eslint-disable react/require-default-props */ -/* eslint-disable react/no-unused-prop-types */ import { action } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../fields/Doc'; -import { Cast } from '../../fields/Types'; +import { DocCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; import { LinkManager } from '../util/LinkManager'; import { SettingsManager } from '../util/SettingsManager'; import './PropertiesDocBacklinksSelector.scss'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { LinkMenu } from './linking/LinkMenu'; -import { OpenWhere } from './nodes/OpenWhere'; import { DocumentView } from './nodes/DocumentView'; +import { OpenWhere } from './nodes/OpenWhere'; type PropertiesDocBacklinksSelectorProps = { Document: Doc; @@ -26,7 +24,7 @@ export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDo getOnClick = action((link: Doc) => { const linkAnchor = this.props.Document; const other = Doc.getOppositeAnchor(link, linkAnchor); - const otherdoc = !other ? undefined : other.annotationOn && other.type !== DocumentType.RTF ? Cast(other.annotationOn, Doc, null) : other; + const otherdoc = !other ? undefined : other.annotationOn && other.type !== DocumentType.RTF ? DocCast(other.annotationOn) : other; LinkManager.Instance.currentLink = link; if (otherdoc) { otherdoc.hidden = false; diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index ee6486a9c..1aa956e16 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; -import { Cast, StrCast } from '../../fields/Types'; +import { DocCast, StrCast } from '../../fields/Types'; import { ObservableReactComponent } from './ObservableReactComponent'; import './PropertiesDocContextSelector.scss'; import { CollectionDockingView } from './collections/CollectionDockingView'; @@ -29,7 +29,7 @@ export class PropertiesDocContextSelector extends ObservableReactComponent<Prope const target = this._props.DocView.Document; const targetContext = this._props.DocView.containerViewPath?.().lastElement()?.Document; const embeddings = Doc.GetEmbeddings(target); - const containerProtos = embeddings.filter(embedding => embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set<Doc>()); + const containerProtos = embeddings.filter(embedding => DocCast(embedding.embedContainer)).reduce((set, embedding) => set.add(DocCast(embedding.embedContainer)!), new Set<Doc>()); const containerSets = Array.from(containerProtos.keys()).map(container => (Doc.GetEmbeddings(container).length ? Doc.GetEmbeddings(container) : [container])); const containers = containerSets.reduce((p, set) => { set.map(s => p.add(s)); diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx index 32b97b31a..067020a62 100644 --- a/src/client/views/UndoStack.tsx +++ b/src/client/views/UndoStack.tsx @@ -7,9 +7,8 @@ import { SettingsManager } from '../util/SettingsManager'; import { UndoManager } from '../util/UndoManager'; import './UndoStack.scss'; -interface UndoStackProps {} @observer -export class UndoStack extends React.Component<UndoStackProps> { +export class UndoStack extends React.Component<object> { render() { const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userVariantColor; const color = UndoManager.batchCounter.get() ? 'black' : SettingsManager.userColor; @@ -34,7 +33,6 @@ export class UndoStack extends React.Component<UndoStackProps> { {Array.from(UndoManager.undoStackNames).map((name, i) => ( <div className="undoStack-resultContainer" - // eslint-disable-next-line react/no-array-index-key key={i} onClick={() => { const size = UndoManager.undoStackNames.length; @@ -48,7 +46,6 @@ export class UndoStack extends React.Component<UndoStackProps> { .map((name, i) => ( <div className="undoStack-resultContainer" - // eslint-disable-next-line react/no-array-index-key key={i} onClick={() => { for (let n = 0; n <= i; n++) UndoManager.Redo(); diff --git a/src/client/views/animationtimeline/Region.tsx b/src/client/views/animationtimeline/Region.tsx index 99163f6c6..40fcb2bf6 100644 --- a/src/client/views/animationtimeline/Region.tsx +++ b/src/client/views/animationtimeline/Region.tsx @@ -12,6 +12,18 @@ import './Region.scss'; import './Timeline.scss'; import { TimelineMenu } from './TimelineMenu'; +export const RegionDataSchema = createSchema({ + position: defaultSpec('number', 0), + duration: defaultSpec('number', 0), + keyframes: listSpec(Doc), + fadeIn: defaultSpec('number', 0), + fadeOut: defaultSpec('number', 0), + functions: listSpec(Doc), + hasData: defaultSpec('boolean', false), +}); +export type RegionData = makeInterface<[typeof RegionDataSchema]>; +export const RegionData = makeInterface(RegionDataSchema); + /** * Useful static functions that you can use. Mostly for logic, but you can also add UI logic here also */ @@ -108,18 +120,6 @@ export namespace RegionHelpers { }; } -export const RegionDataSchema = createSchema({ - position: defaultSpec('number', 0), - duration: defaultSpec('number', 0), - keyframes: listSpec(Doc), - fadeIn: defaultSpec('number', 0), - fadeOut: defaultSpec('number', 0), - functions: listSpec(Doc), - hasData: defaultSpec('boolean', false), -}); -export type RegionData = makeInterface<[typeof RegionDataSchema]>; -export const RegionData = makeInterface(RegionDataSchema); - interface IProps { animatedDoc: Doc; RegionData: Doc; @@ -184,7 +184,7 @@ export class Region extends ObservableReactComponent<IProps> { return RegionHelpers.convertPixelTime(this.regiondata.fadeOut, 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement); } - constructor(props: any) { + constructor(props: IProps) { super(props); makeObservable(this); } @@ -220,9 +220,7 @@ export class Region extends ObservableReactComponent<IProps> { }, 200); this._doubleClickEnabled = true; document.addEventListener('pointermove', this.onBarPointerMove); - document.addEventListener('pointerup', (e: PointerEvent) => { - document.removeEventListener('pointermove', this.onBarPointerMove); - }); + document.addEventListener('pointerup', () => document.removeEventListener('pointermove', this.onBarPointerMove)); } }; @@ -426,6 +424,7 @@ export class Region extends ObservableReactComponent<IProps> { .map(region => ({ pos: NumCast(region.position), dur: NumCast(region.duration) })) .forEach(({ pos, dur }) => { if (pos !== this.regiondata.position) { + // eslint-disable-next-line no-param-reassign val += this.regiondata.position; if (val < 0 || (val > pos && val < pos + dur)) { cannotMove = true; @@ -483,7 +482,6 @@ export class Region extends ObservableReactComponent<IProps> { * this probably needs biggest change, since everyone expected all keyframes to have a circle (and draggable) */ drawKeyframes = () => { - const keyframeDivs: JSX.Element[] = []; return DocListCast(this.regiondata.keyframes).map(kf => { return ( <> diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 1e4ed74be..dea7b6aae 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,4 +1,4 @@ -import { action, computed, intercept, makeObservable, observable, reaction, runInAction } from 'mobx'; +import { action, computed, intercept, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, DocListCastAsync, Opt } from '../../../fields/Doc'; @@ -6,7 +6,7 @@ import { Copy } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { listSpec } from '../../../fields/Schema'; -import { Cast, NumCast } from '../../../fields/Types'; +import { Cast, DocCast, NumCast } from '../../../fields/Types'; import { Transform } from '../../util/Transform'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { Region, RegionData, RegionHelpers } from './Region'; @@ -29,16 +29,16 @@ interface IProps { @observer export class Track extends ObservableReactComponent<IProps> { @observable private _inner = React.createRef<HTMLDivElement>(); - @observable private _currentBarXReaction: any = undefined; - @observable private _timelineVisibleReaction: any = undefined; - @observable private _autoKfReaction: any = undefined; + @observable private _currentBarXReaction: IReactionDisposer | undefined = undefined; + @observable private _timelineVisibleReaction: IReactionDisposer | undefined = undefined; + @observable private _autoKfReaction: IReactionDisposer | undefined = undefined; @observable private _newKeyframe: boolean = false; private readonly MAX_TITLE_HEIGHT = 75; @observable private _trackHeight = 0; private primitiveWhitelist = ['x', 'y', '_freeform_panX', '_freeform_panY', '_width', '_height', '_rotation', 'opacity', '_layout_scrollTop']; private objectWhitelist = ['data']; - constructor(props: any) { + constructor(props: IProps) { super(props); makeObservable(this); } @@ -101,11 +101,11 @@ export class Track extends ObservableReactComponent<IProps> { } const keyframes = Cast(this.saveStateRegion.keyframes, listSpec(Doc)) as List<Doc>; const kfIndex = keyframes.indexOf(this.saveStateKf); - const kf = keyframes[kfIndex] as Doc; //index in the keyframe + const kf = DocCast(keyframes[kfIndex]); //index in the keyframe if (this._newKeyframe) { - DocListCast(this.saveStateRegion.keyframes).forEach((kf, index) => { - this.copyDocDataToKeyFrame(kf); - kf.opacity = index === 0 || index === 3 ? 0.1 : 1; + DocListCast(this.saveStateRegion.keyframes).forEach((keyF, index) => { + this.copyDocDataToKeyFrame(keyF); + keyF.opacity = index === 0 || index === 3 ? 0.1 : 1; }); this._newKeyframe = false; } @@ -144,7 +144,7 @@ export class Track extends ObservableReactComponent<IProps> { () => { return [...this.primitiveWhitelist.map(key => this._props.animatedDoc[key]), ...objects]; }, - (changed, reaction) => { + (/* changed, reaction */) => { //check for region const region = this.findRegion(this.time); if (region !== undefined) { @@ -374,7 +374,7 @@ export class Track extends ObservableReactComponent<IProps> { @action copyDocDataToKeyFrame = (doc: Doc) => { - var somethingChanged = false; + let somethingChanged = false; this.primitiveWhitelist.map(key => { const originalVal = this._props.animatedDoc[key]; somethingChanged = somethingChanged || originalVal !== doc[key]; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 1576a8e4a..7f835938b 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -46,7 +46,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { makeObservable(this); CollectionMenu.Instance = this; this._canFade = false; // don't let the inking menu fade away - this.Pinned = Cast(Doc.UserDoc().menuCollections_pinned, 'boolean', true); + this.Pinned = BoolCast(Doc.UserDoc().menuCollections_pinned, true); this.jumpTo(300, 300); } @@ -269,7 +269,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu initialize: (button: Doc) => { const activeDash = Doc.ActiveDashboard; if (activeDash) { - button.target_childFilters = (Doc.MySearcher._childFilters || activeDash._childFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._childFilters || activeDash._childFilters) as ObjectField) : undefined; + button.target_childFilters = (Doc.MySearcher?._childFilters || activeDash._childFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher?._childFilters || activeDash._childFilters) as ObjectField) : undefined; button.target_searchFilterDocs = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs) : undefined; } }, diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index f283b0abe..461689a70 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -155,7 +155,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV // all docs are added to the column directly to the left. @undoBatch deleteColumn = () => { - const colHdrData = Array.from(Cast(this._props.Doc[this._props.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null)); + const colHdrData = Array.from(Cast(this._props.Doc[this._props.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), [])!); if (this._props.headingObject) { // this._props.docList.forEach(d => (d['$'+this._props.pivotField] = undefined)); colHdrData.splice(colHdrData.indexOf(this._props.headingObject), 1); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index eea128803..5a85c8ee3 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -67,7 +67,6 @@ export class CollectionPileView extends CollectionSubView() { return ( <div className="collectionPileView-innards" style={{ pointerEvents: this.contentEvents }}> <CollectionFreeFormView - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} // layoutEngine={this.layoutEngine} addDocument={this.addPileDoc} diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index fd4bdf364..4e7e19548 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -435,7 +435,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack anchor['$' + endTag] = anchorEndTime; if (addAsAnnotation) { if (Cast(dataDoc[fieldKey], listSpec(Doc), null)) { - Cast(dataDoc[fieldKey], listSpec(Doc), []).push(anchor); + Cast(dataDoc[fieldKey], listSpec(Doc), [])!.push(anchor); } else { dataDoc[fieldKey] = new List<Doc>([anchor]); } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 3497a62cb..bee5d016d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -137,7 +137,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree if (res && de.complete.docDragData) { if (this.Document !== Doc.MyRecentlyClosed) de.complete.docDragData.droppedDocuments.forEach(doc => { - if (this.Document !== Doc.MyRecentlyClosed) Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, doc); + if (this.Document !== Doc.MyRecentlyClosed) Doc.MyRecentlyClosed && Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, doc); }); } return res; @@ -193,7 +193,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree res && doclist.forEach(doc => { Doc.SetContainer(doc, this.Document); - if (this.Document !== Doc.MyRecentlyClosed) Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, doc); + if (this.Document !== Doc.MyRecentlyClosed) Doc.MyRecentlyClosed && Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, doc); }); return res; }; @@ -273,8 +273,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree ); } childContextMenuItems = () => { - const customScripts = Cast(this.Document.childContextMenuScripts, listSpec(ScriptField), []); - const customFilters = Cast(this.Document.childContextMenuFilters, listSpec(ScriptField), []); + const customScripts = Cast(this.Document.childContextMenuScripts, listSpec(ScriptField), [])!; + const customFilters = Cast(this.Document.childContextMenuFilters, listSpec(ScriptField), [])!; const icons = StrListCast(this.Document.childContextMenuIcons); return StrListCast(this.Document.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); }; diff --git a/src/client/views/collections/FlashcardPracticeUI.tsx b/src/client/views/collections/FlashcardPracticeUI.tsx index f24a8acb7..2f46c00bd 100644 --- a/src/client/views/collections/FlashcardPracticeUI.tsx +++ b/src/client/views/collections/FlashcardPracticeUI.tsx @@ -60,7 +60,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp get practiceField() { return this._props.fieldKey + "_practice"; } // prettier-ignore - @computed get filterDoc() { return DocListCast(Doc.MyContextMenuBtns.data).find(doc => doc.title === 'Filter'); } // prettier-ignore + @computed get filterDoc() { return DocListCast(Doc.MyContextMenuBtns?.data).find(doc => doc.title === 'Filter'); } // prettier-ignore @computed get practiceMode() { return this._props.allChildDocs().some(doc => doc._layout_flashcardType) ? StrCast(this._props.layoutDoc.practiceMode) : ''; } // prettier-ignore btnHeight = () => NumCast(this.filterDoc?.height); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 4beb75074..fb2d0955f 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -70,7 +70,7 @@ export interface TreeViewProps { treeViewHideHeaderFields: () => boolean; renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle onCheckedClick?: () => ScriptField; - onChildClick?: () => ScriptField; + onChildClick?: () => ScriptField | undefined; skipFields?: string[]; firstLevel: boolean; // TODO: [AL] add these @@ -1268,7 +1268,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { treeViewHideHeaderFields: () => boolean, renderedIds: string[], onCheckedClick: undefined | (() => ScriptField), - onChildClick: undefined | (() => ScriptField), + onChildClick: undefined | (() => ScriptField | undefined), skipFields: string[] | undefined, firstLevel: boolean, whenChildContentsActiveChanged: (isActive: boolean) => void, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 158bac7ba..4d17dedfb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -108,7 +108,7 @@ export function computePassLayout(poolData: Map<string, PoolData>, pivotDoc: Doc } function toNumber(val: FieldResult<FieldType>) { - return val === undefined ? undefined : DateCast(val) ? DateCast(val).date.getTime() : NumCast(val, Number(StrCast(val))); + return val === undefined ? undefined : DateCast(val) ? DateCast(val)!.date.getTime() : NumCast(val, Number(StrCast(val))); } export function computeStarburstLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] /* , engineProps: any */) { diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 72485aa86..ad05a798b 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -106,7 +106,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() { // assign the face in the image that's closest to the face collection's face if (faceAnno) { - faceAnno.face && FaceRecognitionHandler.UniqueFaceRemoveFaceImage(faceAnno, DocCast(faceAnno.face)); + DocCast(faceAnno.face) && FaceRecognitionHandler.UniqueFaceRemoveFaceImage(faceAnno, DocCast(faceAnno.face)!); FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, this.Document); faceAnno.$face = this.Document[DocData]; } @@ -116,7 +116,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() { ?.filter(doc => DocCast(doc.face)?.type === DocumentType.UFACE) .forEach(faceAnno => { const imgDoc = faceAnno; - faceAnno.face && FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, DocCast(faceAnno.face)); + DocCast(faceAnno.face) && FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, DocCast(faceAnno.face)!); FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, this.Document); faceAnno.$face = this.Document[DocData]; }); @@ -187,7 +187,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() { ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); })}> {FaceRecognitionHandler.UniqueFaceImages(this.Document).map((doc, i) => { - const [name, type] = ImageCastToNameType(doc[Doc.LayoutDataKey(doc)]) ?? ['-missing-', '.png']; + const [name, type] = ImageCastToNameType(doc?.[Doc.LayoutDataKey(doc)]) ?? ['-missing-', '.png']; return ( <div className="image-wrapper" @@ -197,7 +197,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() { this, e, () => { - const dragDoc = DocListCast(doc.data_annotations).find(a => a.face === this.Document[DocData]) ?? this.Document; + const dragDoc = DocListCast(doc?.data_annotations).find(a => a.face === this.Document[DocData]) ?? this.Document; DragManager.StartDocumentDrag([e.target as HTMLElement], new DragManager.DocumentDragData([dragDoc], dropActionType.embed), e.clientX, e.clientY); return true; }, @@ -205,7 +205,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() { emptyFunction ) }> - <img onClick={() => DocumentView.showDocument(doc, { willZoomCentered: true })} style={{ maxWidth: '60px', margin: '10px' }} src={`${name}_o.${type}`} /> + <img onClick={() => doc && DocumentView.showDocument(doc, { willZoomCentered: true })} style={{ maxWidth: '60px', margin: '10px' }} src={`${name}_o.${type}`} /> <div className="remove-item"> <IconButton tooltip={'Remove Doc From Face Collection'} onPointerDown={() => this.removeFaceImageFromUniqueFace(doc)} icon={'x'} style={{ width: '4px' }} size={Size.XSMALL} /> </div> @@ -239,11 +239,12 @@ export class FaceCollectionBox extends ViewBoxBaseComponent<FieldViewProps>() { } moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => !!(this._props.removeDocument?.(doc) && addDocument?.(doc)); + // eslint-disable-next-line @typescript-eslint/no-unused-vars addDocument = (doc: Doc | Doc[], annotationKey?: string) => { const uniqueFaceDoc = doc instanceof Doc ? doc : doc[0]; const added = uniqueFaceDoc.type === DocumentType.UFACE; if (added) { - Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); + Doc.MyFaceCollection && Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'myUniqueFaces', uniqueFaceDoc); } return added; diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 81a2d8e64..16d33eb93 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -107,7 +107,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea focus: emptyFunction, addDocTab: SchemaTableCell.addFieldDoc, pinToPres: returnZero, - Document: DocCast(Document.rootDocument, Document), + Document: DocCast(Document.rootDocument, Document)!, fieldKey: fieldKey, PanelWidth: columnWidth, PanelHeight: props.rowHeight, diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 8e1edc1ee..8b34b4139 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -106,7 +106,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro const { Doc: Document, fieldKey, /* getFinfo,*/ columnWidth, isRowActive } = props; let protoCount = 0; const layoutDoc = fieldKey.startsWith('_') ? Document[DocLayout] : Document; - let doc = Document; + let doc: Doc | undefined = Document; while (doc) { if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) break; protoCount++; @@ -168,9 +168,11 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro while ((matches = idPattern.exec(field)) !== null) { results.push([matches[0], matches[1].replace(/"/g, '')]); } - results.forEach(idFuncPair => { - modField = modField.replace(idFuncPair[0], 'd' + DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1])).toString()); - }); + results + .filter(idFuncPair => IdToDoc(idFuncPair[1])) + .forEach(idFuncPair => { + modField = modField.replace(idFuncPair[0], 'd' + DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1])!).toString()); + }); if (modField.endsWith(';')) modField = modField.substring(0, modField.length - 1); @@ -328,7 +330,7 @@ export class SchemaImageCell extends ObservableReactComponent<SchemaTableCellPro const altpaths = alts .map(doc => Cast(doc[Doc.LayoutDataKey(doc)], ImageField, null)?.url) .filter(url => url) - .map(url => this.choosePath(url)); // access the primary layout data of the alternate documents + .map(url => this.choosePath(url!)); // access the primary layout data of the alternate documents const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; // If there is a path, follow it; otherwise, follow a link to a default image icon const url = paths.length ? paths : [ClientUtils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')]; @@ -379,7 +381,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp } @observable _pickingDate: boolean = false; - @computed get date(): DateField { + @computed get date(): DateField | undefined { // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined. return DateCast(this._props.Doc[this._props.fieldKey]); } @@ -399,7 +401,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp return ( <> <div style={{ pointerEvents: 'none' }} tabIndex={1}> - <DatePicker dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={emptyFunction} /> + <DatePicker dateFormat="Pp" selected={this.date?.date ?? new Date()} onChange={emptyFunction} /> </div> {pointerEvents === 'none' || !selectedCell(this._props) ? null : ( <Popup @@ -410,7 +412,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp background={SnappingManager.userBackgroundColor} popup={ <div style={{ width: 'fit-content', height: '200px' }}> - <DatePicker open dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={this.handleChange} /> + <DatePicker open dateFormat="Pp" selected={this.date?.date ?? new Date()} onChange={this.handleChange} /> </div> } /> diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index c15508669..9eaf0e491 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -1,10 +1,9 @@ -/* eslint-disable react/require-default-props */ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, StrListCast } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; -import { Cast, DocCast } from '../../../fields/Types'; +import { DocCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentView } from '../nodes/DocumentView'; import './LinkMenu.scss'; @@ -56,7 +55,7 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> { ? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(linkDoc.link_anchor_2) : DocCast(linkDoc.link_anchor_1) - : Doc.getOppositeAnchor(linkDoc, sourceDoc) || Doc.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null)?.annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null)); + : Doc.getOppositeAnchor(linkDoc, sourceDoc) || Doc.getOppositeAnchor(linkDoc, DocCast(linkDoc.link_anchor_2)?.annotationOn === sourceDoc ? DocCast(linkDoc.link_anchor_2) : DocCast(linkDoc.link_anchor_1)); return !destDoc || !sourceDoc ? null : ( <LinkMenuItem key={linkDoc[Id]} diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 1c92c3b0d..c984a7053 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -68,8 +68,8 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> { @computed get sourceAnchor() { const ldoc = this._props.linkDoc; if (this._props.sourceDoc !== ldoc.link_anchor_1 && this._props.sourceDoc !== ldoc.link_anchor_2) { - if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_1).annotationOn), this._props.sourceDoc)) return DocCast(ldoc.link_anchor_1); - if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_2).annotationOn), this._props.sourceDoc)) return DocCast(ldoc.link_anchor_2); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_1)?.annotationOn), this._props.sourceDoc)) return DocCast(ldoc.link_anchor_1); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_2)?.annotationOn), this._props.sourceDoc)) return DocCast(ldoc.link_anchor_2); } return this._props.sourceDoc; } diff --git a/src/client/views/newlightbox/ExploreView/ExploreView.tsx b/src/client/views/newlightbox/ExploreView/ExploreView.tsx index f8c07cc43..7f9a13549 100644 --- a/src/client/views/newlightbox/ExploreView/ExploreView.tsx +++ b/src/client/views/newlightbox/ExploreView/ExploreView.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import * as React from 'react'; import { StrCast } from '../../../../fields/Types'; import { NewLightboxView } from '../NewLightboxView'; @@ -19,7 +17,7 @@ export function ExploreView(props: IExploreView) { const x = (rec.embedding.x / xBound) * 50; const y = (rec.embedding.y / yBound) * 50; return ( - <div className="exploreView-doc" onClick={() => {}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}> + <div key={'' + x + ' ' + y} className="exploreView-doc" onClick={() => {}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}> {rec.title} </div> ); diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index 87cef01d2..7ec45d0dd 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -5,7 +5,7 @@ import { returnEmptyFilter, returnTrue } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; import { CreateLinkToActiveAudio, Doc, DocListCast, Opt, returnEmptyDoclist } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; -import { Cast, NumCast, StrCast, toList } from '../../../fields/Types'; +import { Cast, DocCast, NumCast, StrCast, toList } from '../../../fields/Types'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { GestureOverlay } from '../GestureOverlay'; @@ -100,7 +100,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> { SnappingManager.SetExploreMode(false); } else { const l = CreateLinkToActiveAudio(() => doc).lastElement(); - l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen'); + DocCast(l?.link_anchor_2) && (DocCast(l!.link_anchor_2)!.backgroundColor = 'lightgreen'); DocumentView.CurrentlyPlaying?.forEach(dv => dv.ComponentView?.Pause?.()); // DocumentView.PinDoc(doc, { hidePresBox: true }); this._history ? this._history.push({ doc, target }) : (this._history = [{ doc, target }]); @@ -142,7 +142,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> { const targetDocView = target && DocumentView.getLightboxDocumentView(target); if (targetDocView && target) { const l = CreateLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement(); - l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen'); + DocCast(l?.link_anchor_2) && (DocCast(l!.link_anchor_2)!.backgroundColor = 'lightgreen'); DocumentView.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 }); if (NewLightboxView._history?.lastElement().target !== target) NewLightboxView._history?.push({ doc, target }); } else if (!target && NewLightboxView.path.length) { @@ -326,7 +326,6 @@ export class NewLightboxView extends React.Component<LightboxViewProps> { } interface NewLightboxTourBtnProps { navBtn: (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: string, display: () => string, click: (e: React.MouseEvent) => void, color?: string) => JSX.Element; - // eslint-disable-next-line react/no-unused-prop-types future: () => Opt<Doc[]>; stepInto: () => void; } diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index c80e8ebc1..9369ff98a 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -108,7 +108,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // all CSV records in the dataset (that aren't an empty row) @computed.struct get records() { try { - const records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); + const records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey])?.url.href ?? ''); this._urlError = false; return records?.filter(record => Object.keys(record).some(key => record[key])) ?? []; } catch { @@ -344,7 +344,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { componentDidMount() { this._props.setContentViewBox?.(this); if (!this._urlError) { - if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData(); + if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey])?.url.href ?? '')) this.fetchData(); } this._disposers.datavis = reaction( () => { @@ -386,8 +386,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { this.layoutDoc._dataViz_schemaOG = loading; } const ogDoc = this.layoutDoc._dataViz_schemaOG as Doc; - const ogHref = CsvCast(ogDoc[this.fieldKey]) ? CsvCast(ogDoc[this.fieldKey]).url.href : undefined; - const { href } = CsvCast(this.Document[this.fieldKey]).url; + const ogHref = CsvCast(ogDoc[this.fieldKey]) ? CsvCast(ogDoc[this.fieldKey])!.url.href : undefined; + const { href } = CsvCast(this.Document[this.fieldKey])?.url ?? { href: '' }; if (ogHref && !DataVizBox.datasetSchemaOG.has(href)) { // sets original dataset to the var const lastRow = current.pop(); @@ -399,7 +399,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }, current => { if (current) { - const { href } = CsvCast(this.Document[this.fieldKey]).url; + const { href } = CsvCast(this.Document[this.fieldKey])?.url ?? { href: '' }; if (this.layoutDoc.dataViz_schemaLive) DataVizBox.dataset.set(href, current); else DataVizBox.dataset.set(href, DataVizBox.datasetSchemaOG.get(href)!); } @@ -414,9 +414,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { fetchData = () => { if (!this.Document.dataViz_asSchema) { - DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests + DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey])?.url.href ?? '', []); // assign temporary dataset as a lock to prevent duplicate server requests fetch('/csvData?uri=' + (this.dataUrl?.url.href ?? '')) // - .then(res => res.json().then(action(jsonRes => !jsonRes.errno && DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, jsonRes)))); + .then(res => res.json().then(action(jsonRes => !jsonRes.errno && DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey])?.url.href ?? '', jsonRes)))); } }; @@ -523,7 +523,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { GPTPopup.Instance.createFilteredDoc = this.createFilteredDoc; GPTPopup.Instance.setDataJson(''); GPTPopup.Instance.setMode(GPTPopupMode.DATA); - const csvdata = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); + const csvdata = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey])?.url.href ?? ''); GPTPopup.Instance.setDataJson(JSON.stringify(csvdata)); GPTPopup.Instance.generateDataAnalysis(); }); diff --git a/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx b/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx index 8ae29a88c..1e2a95d31 100644 --- a/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx +++ b/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx @@ -11,10 +11,8 @@ import { DragManager } from '../../../util/DragManager'; import { DocumentView } from '../DocumentView'; import './SchemaCSVPopUp.scss'; -interface SchemaCSVPopUpProps {} - @observer -export class SchemaCSVPopUp extends React.Component<SchemaCSVPopUpProps> { +export class SchemaCSVPopUp extends React.Component<object> { // eslint-disable-next-line no-use-before-define static Instance: SchemaCSVPopUp; @@ -23,7 +21,7 @@ export class SchemaCSVPopUp extends React.Component<SchemaCSVPopUpProps> { @observable public target: Doc | undefined = undefined; @observable public visible: boolean = false; - constructor(props: SchemaCSVPopUpProps) { + constructor(props: object) { super(props); makeObservable(this); SchemaCSVPopUp.Instance = this; diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 5450d03b1..a7c4a00b0 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -5,10 +5,9 @@ import { IReactionDisposer, action, computed, makeObservable, observable, reacti import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; -import { Doc, NumListCast } from '../../../../../fields/Doc'; +import { Doc, NumListCast, StrListCast } from '../../../../../fields/Doc'; import { List } from '../../../../../fields/List'; -import { listSpec } from '../../../../../fields/Schema'; -import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; +import { DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; import { ObservableReactComponent } from '../../../ObservableReactComponent'; @@ -108,13 +107,13 @@ export class Histogram extends ObservableReactComponent<HistogramProps> { } @computed get defaultBarColor() { - return Cast(this.layoutDoc.dataViz_histogram_defaultColor, 'string', '#69b3a2'); + return StrCast(this.layoutDoc.dataViz_histogram_defaultColor, '#69b3a2')!; } @computed get barColors() { - return Cast(this.layoutDoc.dataViz_histogram_barColors, listSpec('string'), null); + return StrListCast(this.layoutDoc.dataViz_histogram_barColors); } @computed get selectedBins() { - return Cast(this.layoutDoc.dataViz_histogram_selectedBins, listSpec('number'), null); + return NumListCast(this.layoutDoc.dataViz_histogram_selectedBins); } @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } { @@ -129,7 +128,7 @@ export class Histogram extends ObservableReactComponent<HistogramProps> { // restore selected bars this._histogramSvg?.selectAll('rect').attr('class', dIn => { const d = dIn as HistogramData; - if (this.selectedBins.some(selBin => d[0] === selBin)) { + if (this.selectedBins?.some(selBin => d[0] === selBin)) { this._selectedBars.push(d); return 'histogram-bar hover'; } @@ -199,10 +198,10 @@ export class Histogram extends ObservableReactComponent<HistogramProps> { const alreadySelected = this._selectedBars.findIndex(eachData => !Object.keys(d).some(key => d[key] !== eachData[key])); if (alreadySelected !== -1) { this._selectedBars.splice(alreadySelected, 1); - this.selectedBins.splice(alreadySelected, 1); + this.selectedBins?.splice(alreadySelected, 1); } else { this._selectedBars.push(d); - this.selectedBins.push(d[0] as number); + this.selectedBins?.push(d[0] as number); } const showSelectedLabel = (dataset: HistogramData[]) => { const datum = dataset.lastElement(); diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 6b047546c..80fadf178 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -26,7 +26,7 @@ export interface LineChartProps { layoutDoc: Doc; axes: string[]; titleCol: string; - records: { [key: string]: any }[]; + records: { [key: string]: string }[]; width: number; height: number; dataDoc: Doc; @@ -47,7 +47,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> { @observable _currSelected: DataPoint | undefined = undefined; // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates - constructor(props: any) { + constructor(props: LineChartProps) { super(props); makeObservable(this); } @@ -79,7 +79,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> { @computed get incomingHighlited() { // return selected x and y axes // otherwise, use the selection of whatever is linked to us - const incomingVizBox = DocumentView.getFirstDocumentView(this.parentViz)?.ComponentView as DataVizBox; + const incomingVizBox = this.parentViz && (DocumentView.getFirstDocumentView(this.parentViz)?.ComponentView as DataVizBox); const highlitedRowIds = NumListCast(incomingVizBox?.layoutDoc?.dataViz_highlitedRows); return this._tableData.filter((record, i) => highlitedRowIds.includes(this._tableDataIds[i])); // get all the datapoints they have selected field set by incoming anchor } @@ -170,8 +170,8 @@ export class LineChart extends ObservableReactComponent<LineChartProps> { } }); if (!ptWasSelected) { - selectedDatapoints.push(d.x + ',' + d.y); - this._currSelected = selectedDatapoints.length > 1 ? undefined : d; + selectedDatapoints?.push(d.x + ',' + d.y); + this._currSelected = (selectedDatapoints?.length ?? 0 > 1) ? undefined : d; } // for filtering child dataviz docs @@ -190,7 +190,14 @@ export class LineChart extends ObservableReactComponent<LineChartProps> { } } - drawDataPoints(data: DataPoint[], idx: number, xScale: d3.ScaleLinear<number, number, never>, yScale: d3.ScaleLinear<number, number, never>, higlightFocusPt: any, tooltip: any) { + drawDataPoints( + data: DataPoint[], // + idx: number, + xScale: d3.ScaleLinear<number, number, never>, + yScale: d3.ScaleLinear<number, number, never>, + higlightFocusPt: d3.Selection<SVGGElement, unknown, null, undefined>, + tooltip: d3.Selection<HTMLDivElement, unknown, null, undefined> + ) { if (this._lineChartSvg) { const circleClass = '.circle-' + idx; this._lineChartSvg @@ -211,7 +218,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> { .on('mouseleave', () => { tooltip?.transition().duration(300).style('opacity', 0); }) - .on('click', (e: any) => { + .on('click', e => { const d0 = { x: Number(e.target.getAttribute('data-x')), y: Number(e.target.getAttribute('data-y')) }; // find .circle-d1 with data-x = d0.x and data-y = d0.y this.setCurrSelected(d0); @@ -220,7 +227,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> { } } - drawChart = (dataSet: any[][], rangeVals: { xMin?: number; xMax?: number; yMin?: number; yMax?: number }, width: number, height: number) => { + drawChart = (dataSet: { x: number; y: number }[][], rangeVals: { xMin?: number; xMax?: number; yMin?: number; yMax?: number }, width: number, height: number) => { // clearing tooltip and the current chart d3.select(this._lineChartRef).select('svg').remove(); d3.select(this._lineChartRef).select('.tooltip').remove(); @@ -277,7 +284,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> { svg.append('path').attr('stroke', 'red'); // legend - const color: any = d3.scaleOrdinal().range(['black', 'blue']).domain([this._props.axes[1], this._props.axes[2]]); + const color = d3.scaleOrdinal().range(['black', 'blue']).domain([this._props.axes[1], this._props.axes[2]]); svg.selectAll('mydots') .data([this._props.axes[1], this._props.axes[2]]) .enter() diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index b73123691..ad2731109 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -128,7 +128,7 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> { selected.splice(selected.indexOf(rowId), 1); } else selected?.push(rowId); e.stopPropagation(); - this.hasRowsToFilter = selected.length > 0; + this.hasRowsToFilter = (selected?.length ?? 0) > 0; }; columnPointerDown = (e: React.PointerEvent, col: string) => { diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index dcc6e27ed..3cacb6692 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -1,7 +1,6 @@ import { action, computed, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc } from '../../../fields/Doc'; import { NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { DocUtils } from '../../documents/DocUtils'; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 34e3a5d76..a6872f8dc 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -6,16 +6,17 @@ import { DateField } from '../../../fields/DateField'; import { Doc, Field, FieldType, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ScriptField } from '../../../fields/ScriptField'; +import { WebField } from '../../../fields/URLField'; +import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; import { Transform } from '../../util/Transform'; +import { ContextMenuProps } from '../ContextMenuItem'; import { PinProps } from '../PinFuncs'; import { ViewBoxInterface } from '../ViewBoxInterface'; import { DocumentView } from './DocumentView'; import { FocusViewOptions } from './FocusViewOptions'; -import { OpenWhere } from './OpenWhere'; -import { WebField } from '../../../fields/URLField'; -import { ContextMenuProps } from '../ContextMenuItem'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; +import { OpenWhere } from './OpenWhere'; export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt<number>; export type StyleProviderFuncType = ( diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 91c351895..8e4b64851 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -2,10 +2,11 @@ import functionPlot, { Chart } from 'function-plot'; import { action, computed, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { returnFalse, setupMoveUpEvents } from '../../../ClientUtils'; +import { emptyFunction } from '../../../Utils'; +import { Doc, DocListCast, NumListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; -import { listSpec } from '../../../fields/Schema'; -import { Cast, StrCast } from '../../../fields/Types'; +import { StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { DocUtils } from '../../documents/DocUtils'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -15,8 +16,6 @@ import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { PinDocView, PinProps } from '../PinFuncs'; import { FieldView, FieldViewProps } from './FieldView'; -import { returnFalse, setupMoveUpEvents } from '../../../ClientUtils'; -import { emptyFunction } from '../../../Utils'; @observer export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { @@ -76,7 +75,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps> this._plotEle = ele || this._plotEle; const width = this._props.PanelWidth(); const height = this._props.PanelHeight(); - const xrange = Cast(this.layoutDoc.xRange, listSpec('number'), [-10, 10]); + const xrange = NumListCast(this.layoutDoc.xRange, [-10, 10])!; try { this._plotEle?.children.length && this._plotEle.removeChild(this._plotEle.children[0]); this._plot = functionPlot({ diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 9c6b8e99c..999d7089b 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -212,7 +212,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { drop = undoable( action((e: Event, de: DragManager.DropEvent) => { - if (de.complete.docDragData && this._props.rejectDrop?.(de.complete.docDragData?.draggedDocuments, this.DocumentView?.())) { + if (de.complete.docDragData && this._props.rejectDrop?.(de, this.DocumentView?.())) { let added: boolean | undefined; const hitDropTarget = (ele: HTMLElement, dropTarget: HTMLDivElement | null): boolean => { if (!ele) return false; diff --git a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx index 8784a709a..8bb7ddd9f 100644 --- a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx @@ -43,7 +43,7 @@ export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> { return this._left > 0; } - constructor(props: Readonly<{}>) { + constructor(props: AntimodeMenuProps) { super(props); DirectionsAnchorMenu.Instance = this; diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx index 6f1f58a4c..fa863e123 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.tsx +++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx @@ -105,9 +105,10 @@ export class CalendarBox extends CollectionSubView() { // TODO: Return a different color based on the event type eventToColor = (event: Doc): string => { - return 'red'; + return 'red' + event; }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars internalDocDrop = (e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData) => { if (!super.onInternalDrop(e, de)) return false; de.complete.docDragData?.droppedDocuments.forEach(doc => { diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx index 528bcd05a..6c3da8977 100644 --- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx +++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx @@ -196,7 +196,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // Add CSV details to linked files this._linked_csv_files.push({ - filename: CsvCast(newLinkedDoc.data).url.pathname, + filename: CsvCast(newLinkedDoc.data)?.url.pathname ?? '', id: csvId, text: csvData, }); @@ -634,6 +634,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }; getDirectMatchingSegmentStart = (doc: Doc, citationText: string, indexesOfSegments: string[]): number => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const originalSegments = JSON.parse(StrCast(doc.original_segments!)).map((segment: any, index: number) => ({ index: index.toString(), text: segment.text, @@ -877,7 +878,8 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { return LinkManager.Instance.getAllRelatedLinks(this.Document) .map(d => DocCast(LinkManager.getOppositeAnchor(d, this.Document))) .map(d => DocCast(d?.annotationOn, d)) - .filter(d => d); + .filter(d => d) + .map(d => d!); } /** @@ -889,6 +891,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { .map(d => DocCast(LinkManager.getOppositeAnchor(d, this.Document))) .map(d => DocCast(d?.annotationOn, d)) .filter(d => d) + .map(d => d!) .filter(d => { console.log(d.ai_doc_id); return d.ai_doc_id; @@ -905,15 +908,14 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { LinkManager.Instance.getAllRelatedLinks(this.Document) .map(d => DocCast(LinkManager.getOppositeAnchor(d, this.Document))) .map(d => DocCast(d?.annotationOn, d)) - .filter(d => d) - .filter(d => d.summary) + .filter(d => d?.summary) .map((doc, index) => { - if (PDFCast(doc.data)) { - return `<summary file_name="${PDFCast(doc.data).url.pathname}" applicable_tools=["rag"]>${doc.summary}</summary>`; - } else if (CsvCast(doc.data)) { - return `<summary file_name="${CsvCast(doc.data).url.pathname}" applicable_tools=["dataAnalysis"]>${doc.summary}</summary>`; + if (PDFCast(doc?.data)) { + return `<summary file_name="${PDFCast(doc!.data)!.url.pathname}" applicable_tools=["rag"]>${doc!.summary}</summary>`; + } else if (CsvCast(doc?.data)) { + return `<summary file_name="${CsvCast(doc!.data)!.url.pathname}" applicable_tools=["dataAnalysis"]>${doc!.summary}</summary>`; } else { - return `${index + 1}) ${doc.summary}`; + return `${index + 1}) ${doc?.summary}`; } }) .join('\n') + '\n' diff --git a/src/client/views/nodes/chatbot/tools/GetDocsTool.ts b/src/client/views/nodes/chatbot/tools/GetDocsTool.ts index 05482a66e..42a7747d3 100644 --- a/src/client/views/nodes/chatbot/tools/GetDocsTool.ts +++ b/src/client/views/nodes/chatbot/tools/GetDocsTool.ts @@ -40,7 +40,10 @@ export class GetDocsTool extends BaseTool<GetDocsToolParamsType> { } async execute(args: ParametersType<GetDocsToolParamsType>): Promise<Observation[]> { - const docs = args.document_ids.map(doc_id => DocCast(DocServer.GetCachedRefField(doc_id))); + const docs = args.document_ids + .map(doc_id => DocCast(DocServer.GetCachedRefField(doc_id))) + .filter(d => d) + .map(d => d!); const collection = Docs.Create.FreeformDocument(docs, { title: args.title }); this._docView._props.addDocTab(collection, OpenWhere.addRight); return [{ type: 'text', text: `Collection created in Dash called ${args.title}` }]; diff --git a/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts b/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts index c1915a398..6d524e40f 100644 --- a/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts +++ b/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts @@ -15,7 +15,6 @@ import { Networking } from '../../../../Network'; import { AI_Document, CHUNK_TYPE, RAGChunk } from '../types/types'; import OpenAI from 'openai'; import { Embedding } from 'openai/resources'; -import { PineconeEnvironmentVarsNotSupportedError } from '@pinecone-database/pinecone/dist/errors'; dotenv.config(); @@ -101,7 +100,7 @@ export class Vectorstore { } else { // Start processing the document. doc.ai_document_status = 'PROGRESS'; - const local_file_path: string = CsvCast(doc.data)?.url?.pathname ?? PDFCast(doc.data)?.url?.pathname ?? VideoCast(doc.data)?.url?.pathname ?? AudioCast(doc.data)?.url?.pathname; + const local_file_path = CsvCast(doc.data)?.url?.pathname ?? PDFCast(doc.data)?.url?.pathname ?? VideoCast(doc.data)?.url?.pathname ?? AudioCast(doc.data)?.url?.pathname; if (!local_file_path) { console.log('Invalid file path.'); @@ -112,13 +111,13 @@ export class Vectorstore { let result: AI_Document & { doc_id: string }; if (isAudioOrVideo) { console.log('Processing media file...'); - const response = await Networking.PostToServer('/processMediaFile', { fileName: path.basename(local_file_path) }); + const response = (await Networking.PostToServer('/processMediaFile', { fileName: path.basename(local_file_path) })) as { [key: string]: unknown }; const segmentedTranscript = response.condensed; console.log(segmentedTranscript); - const summary = response.summary; + const summary = response.summary as string; doc.summary = summary; // Generate embeddings for each chunk - const texts = segmentedTranscript.map((chunk: any) => chunk.text); + const texts = (segmentedTranscript as { text: string }[])?.map(chunk => chunk.text); try { const embeddingsResponse = await this.openai.embeddings.create({ @@ -138,7 +137,7 @@ export class Vectorstore { file_name: local_file_path, num_pages: 0, summary: '', - chunks: segmentedTranscript.map((chunk: any, index: number) => ({ + chunks: (segmentedTranscript as { text: string; start: number; end: number; indexes: string[] }[]).map((chunk, index) => ({ id: uuidv4(), values: (embeddingsResponse.data as Embedding[])[index].embedding, // Assign embedding metadata: { @@ -173,7 +172,7 @@ export class Vectorstore { } else { // Existing document processing logic remains unchanged console.log('Processing regular document...'); - const { jobId } = await Networking.PostToServer('/createDocument', { file_path: local_file_path }); + const { jobId } = (await Networking.PostToServer('/createDocument', { file_path: local_file_path })) as { jobId: string }; while (true) { await new Promise(resolve => setTimeout(resolve, 2000)); @@ -297,7 +296,7 @@ export class Vectorstore { encoding_format: 'float', }); - let queryEmbedding = queryEmbeddingResponse.data[0].embedding; + const queryEmbedding = queryEmbeddingResponse.data[0].embedding; // Extract the embedding from the response. diff --git a/src/client/views/nodes/formattedText/DailyJournal.tsx b/src/client/views/nodes/formattedText/DailyJournal.tsx index 797a9b812..871c556e6 100644 --- a/src/client/views/nodes/formattedText/DailyJournal.tsx +++ b/src/client/views/nodes/formattedText/DailyJournal.tsx @@ -161,7 +161,7 @@ export class DailyJournal extends ViewBoxAnnotatableComponent<FieldViewProps>() // Check if doc or selection changed if (!prevState.doc.eq(state.doc) || !prevState.selection.eq(state.selection)) { - let found = false; + const found = false; const textToRemove = this.predictiveText; state.doc.descendants((node, pos) => { diff --git a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx index b241b27d7..6cfe9a62c 100644 --- a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx +++ b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx @@ -1,6 +1,6 @@ import { action, makeObservable, observable } from 'mobx'; import * as React from 'react'; -import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc'; +import { Doc, DocListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { emptyFunction } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 1891cfd4c..e8a5235c9 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -50,7 +50,7 @@ interface IAnnotationProps extends FieldViewProps { } @observer export class Annotation extends ObservableReactComponent<IAnnotationProps> { - constructor(props: any) { + constructor(props: IAnnotationProps) { super(props); makeObservable(this); } @@ -58,7 +58,7 @@ export class Annotation extends ObservableReactComponent<IAnnotationProps> { @computed get linkHighlighted() { const found = LinkManager.Instance.getAllDirectLinks(this._props.annoDoc).find(link => { const a1 = Doc.getOppositeAnchor(link, this._props.annoDoc); - return a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, a1)); + return a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, a1)!); }); return found; } @@ -112,6 +112,7 @@ export class Annotation extends ObservableReactComponent<IAnnotationProps> { outline = () => (this.linkHighlighted ? 'solid 1px lightBlue' : undefined); background = () => (this._props.annoDoc[Highlight] ? 'orange' : StrCast(this._props.annoDoc.backgroundColor)); render() { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const forceRenderHack = [this.background(), this.outline(), this.opacity()]; // forces a re-render when these change -- because RegionAnnotation doesn't do this internally.. return ( <div style={{ display: this._props.annoDoc.textCopied && !Doc.GetBrushHighlightStatus(this._props.annoDoc) ? 'none' : undefined }}> @@ -121,7 +122,7 @@ export class Annotation extends ObservableReactComponent<IAnnotationProps> { .map(([x, y, width, height]) => ( <div key={'' + x + y + width + height} - style={{ pointerEvents: this._props.pointerEvents?.() as any }} + style={{ pointerEvents: this._props.pointerEvents?.() as Property.PointerEvents }} onPointerDown={this.onPointerDown} onContextMenu={this.onContextMenu} onPointerEnter={() => { diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index f60eb486e..cb837e3ab 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -162,7 +162,7 @@ export class FaceRecognitionHandler { }); uniqueFaceDoc.$face = `Face${faceDocNum}`; uniqueFaceDoc.$face_annos = new List<Doc>(); - Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); + Doc.MyFaceCollection && Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'myUniqueFaces', uniqueFaceDoc); return uniqueFaceDoc; @@ -208,9 +208,9 @@ export class FaceRecognitionHandler { setTimeout(() => this.classifyFacesInImage(imgDoc), 1000); } else { const imgUrl = ImageCast(imgDoc[Doc.LayoutDataKey(imgDoc)]); - if (imgUrl && !DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc[DocData])) { + if (imgUrl && !DocListCast(Doc.MyFaceCollection?.examinedFaceDocs).includes(imgDoc[DocData])) { // only examine Docs that have an image and that haven't already been examined. - Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc[DocData]); + Doc.MyFaceCollection && Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc[DocData]); FaceRecognitionHandler.loadImage(imgUrl).then( // load image and analyze faces img => faceapi diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 1c17dd369..ba94f0504 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -231,7 +231,7 @@ export class Doc extends RefField { public static AddLink: (link: Doc, checkExists?: boolean) => void; public static DeleteLink: (link: Doc) => void; public static Links: (link: Doc | undefined) => Doc[]; - public static getOppositeAnchor: (linkDoc: Doc, anchor: Doc) => Doc | undefined; + public static getOppositeAnchor: (linkDoc: Doc | undefined, anchor: Doc | undefined) => Doc | undefined; // KeyValueBox SetField (defined there) public static SetField: (doc: Doc, key: string, value: string, forceOnDelegate?: boolean, setResult?: (value: FieldResult) => void) => boolean; // UserDoc "API" diff --git a/src/fields/Types.ts b/src/fields/Types.ts index e6755f828..ba2e9bb6f 100644 --- a/src/fields/Types.ts +++ b/src/fields/Types.ts @@ -1,5 +1,6 @@ import { DateField } from './DateField'; import { Doc, FieldType, FieldResult, Opt } from './Doc'; +import { InkField } from './InkField'; import { List } from './List'; import { ProxyField } from './Proxy'; import { RefField } from './RefField'; @@ -99,6 +100,7 @@ export function VideoCast (field: FieldResult, defaultVal: VideoField | null = n export function AudioCast (field: FieldResult, defaultVal: AudioField | null = null) { return Cast(field, AudioField, defaultVal); } // prettier-ignore export function PDFCast (field: FieldResult, defaultVal: PdfField | null = null) { return Cast(field, PdfField, defaultVal); } // prettier-ignore export function ImageCast (field: FieldResult, defaultVal: ImageField | null = null) { return Cast(field, ImageField, defaultVal); } // prettier-ignore +export function InkCast (field: FieldResult, defaultVal: InkField | null = null) { return Cast(field, InkField, defaultVal); } // prettier-ignore export function ImageCastToNameType(field: FieldResult, defaultVal: ImageField | null = null) { const href = ImageCast(field, defaultVal)?.url.href; |