mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
web: more fixes
This commit is contained in:
@@ -87,7 +87,7 @@ async function deleteAttachments(ids: string[]) {
|
||||
action: async (report) => {
|
||||
for (let i = 0; i < ids.length; ++i) {
|
||||
const id = ids[i];
|
||||
const attachment = await attachmentStore.get().attachments?.item(id);
|
||||
const attachment = await db.attachments.attachment(id);
|
||||
if (!attachment) continue;
|
||||
|
||||
report({
|
||||
|
||||
@@ -24,6 +24,7 @@ import useRoutes from "../../hooks/use-routes";
|
||||
import RouteContainer from "../route-container";
|
||||
import routes from "../../navigation/routes";
|
||||
import { Flex } from "@theme-ui/components";
|
||||
import { isRouteResult } from "../../navigation/types";
|
||||
|
||||
function CachedRouter() {
|
||||
const [RouteResult, location] = useRoutes(routes, {
|
||||
@@ -39,9 +40,10 @@ function CachedRouter() {
|
||||
NavigationEvents.publish("onNavigate", RouteResult, location);
|
||||
}, [RouteResult, location]);
|
||||
|
||||
if (!RouteResult) return null;
|
||||
if (!RouteResult || !isRouteResult(RouteResult)) return null;
|
||||
if (RouteResult.key === "general" || !cachedRoutes.current[RouteResult.key])
|
||||
cachedRoutes.current[RouteResult.key] = RouteResult.component;
|
||||
cachedRoutes.current[RouteResult.key] =
|
||||
RouteResult.component as React.FunctionComponent;
|
||||
|
||||
return (
|
||||
<RouteContainer
|
||||
|
||||
@@ -275,7 +275,7 @@ function Notebooks({ noteId }: { noteId: string }) {
|
||||
estimatedSize={50}
|
||||
getItemKey={(index) => result.value.key(index)}
|
||||
items={result.value.ids}
|
||||
renderItem={({ item: index }) => (
|
||||
renderItem={({ index }) => (
|
||||
<ResolvedItem index={index} items={result.value} type="notebook">
|
||||
{({ item, data }) => (
|
||||
<ListItemWrapper item={item} data={data} simplified />
|
||||
@@ -302,7 +302,7 @@ function Reminders({ noteId }: { noteId: string }) {
|
||||
estimatedSize={54}
|
||||
getItemKey={(index) => result.value.key(index)}
|
||||
items={result.value.ids}
|
||||
renderItem={({ item: index }) => (
|
||||
renderItem={({ index }) => (
|
||||
<ResolvedItem index={index} items={result.value} type="reminder">
|
||||
{({ item, data }) => (
|
||||
<ListItemWrapper item={item} data={data} simplified />
|
||||
@@ -329,7 +329,7 @@ function Attachments({ noteId }: { noteId: string }) {
|
||||
getItemKey={(index) => result.value.key(index)}
|
||||
items={result.value.ids}
|
||||
header={<></>}
|
||||
renderRow={({ item: index }) => (
|
||||
renderRow={({ index }) => (
|
||||
<ResolvedItem index={index} type="attachment" items={result.value}>
|
||||
{({ item }) => <ListItemWrapper item={item} compact />}
|
||||
</ResolvedItem>
|
||||
@@ -367,7 +367,7 @@ function SessionHistory({
|
||||
estimatedSize={28}
|
||||
getItemKey={(index) => result.value.key(index)}
|
||||
items={result.value.ids}
|
||||
renderItem={({ item: index }) => (
|
||||
renderItem={({ index }) => (
|
||||
<ResolvedItem type="session" index={index} items={result.value}>
|
||||
{({ item }) => (
|
||||
<SessionItem
|
||||
|
||||
@@ -64,7 +64,6 @@ export function SessionItem(props: SessionItemProps) {
|
||||
onClick={async () => {
|
||||
const content = await db.noteHistory.content(session.id);
|
||||
if (!content) return;
|
||||
// toggleProperties(false);
|
||||
if (session.locked) {
|
||||
await Vault.askPassword(async (password) => {
|
||||
try {
|
||||
@@ -85,7 +84,10 @@ export function SessionItem(props: SessionItemProps) {
|
||||
});
|
||||
} else {
|
||||
onOpenPreviewSession({
|
||||
content,
|
||||
content: {
|
||||
data: content.data as string,
|
||||
type: content.type
|
||||
},
|
||||
dateCreated: session.dateCreated,
|
||||
dateEdited: session.dateModified
|
||||
});
|
||||
|
||||
@@ -126,7 +126,7 @@ function AddTagsDialog(props: AddTagsDialogProps) {
|
||||
const { selected, setSelected } = useSelectionStore.getState();
|
||||
setSelected([...selected, { id: tagId, new: true, op: "add" }]);
|
||||
}}
|
||||
renderItem={({ item: index }) => {
|
||||
renderItem={({ index }) => {
|
||||
return (
|
||||
<ResolvedItem key={index} type="tag" items={tags} index={index}>
|
||||
{({ item }) => <TagItem tag={item} />}
|
||||
|
||||
@@ -160,7 +160,14 @@ function AttachmentsDialog({ onClose }: AttachmentsDialogProps) {
|
||||
}}
|
||||
>
|
||||
<Sidebar
|
||||
onDownloadAll={() => download(allAttachments?.ungrouped || [])}
|
||||
onDownloadAll={async () =>
|
||||
download(
|
||||
await db.attachments.all.ids({
|
||||
sortBy: "dateCreated",
|
||||
sortDirection: "desc"
|
||||
})
|
||||
)
|
||||
}
|
||||
filter={async (query) => {
|
||||
setAttachments(await db.lookup.attachments(query).sorted());
|
||||
}}
|
||||
@@ -248,10 +255,12 @@ function AttachmentsDialog({ onClose }: AttachmentsDialogProps) {
|
||||
<Label>
|
||||
<Checkbox
|
||||
sx={{ width: 18, height: 18 }}
|
||||
onChange={(e) => {
|
||||
onChange={async (e) => {
|
||||
setSelected(
|
||||
e.currentTarget.checked
|
||||
? attachments.ungrouped
|
||||
? await filterAttachments(
|
||||
currentRoute.current
|
||||
).ids()
|
||||
: []
|
||||
);
|
||||
}}
|
||||
@@ -310,8 +319,8 @@ function AttachmentsDialog({ onClose }: AttachmentsDialogProps) {
|
||||
}
|
||||
mode="fixed"
|
||||
estimatedSize={30}
|
||||
getItemKey={(index) => attachments.getKey(index)}
|
||||
items={attachments.ungrouped}
|
||||
getItemKey={(index) => attachments.key(index)}
|
||||
items={attachments.ids}
|
||||
context={{
|
||||
isSelected: (id: string) => selected.indexOf(id) > -1,
|
||||
select: (id: string) => {
|
||||
@@ -339,7 +348,7 @@ export default AttachmentsDialog;
|
||||
|
||||
function AttachmentRow(
|
||||
props: VirtualizedTableRowProps<
|
||||
string,
|
||||
boolean,
|
||||
{
|
||||
isSelected: (id: string) => boolean;
|
||||
select: (id: string) => void;
|
||||
@@ -349,18 +358,20 @@ function AttachmentRow(
|
||||
) {
|
||||
if (!props.context) return null;
|
||||
return (
|
||||
<ResolvedItem id={props.item} items={props.context.attachments}>
|
||||
{({ item }) =>
|
||||
item.type === "attachment" ? (
|
||||
<Attachment
|
||||
rowRef={props.rowRef}
|
||||
style={props.style}
|
||||
item={item}
|
||||
isSelected={props.context?.isSelected(props.item)}
|
||||
onSelected={() => props.context?.select(props.item)}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
<ResolvedItem
|
||||
index={props.index}
|
||||
items={props.context.attachments}
|
||||
type="attachment"
|
||||
>
|
||||
{({ item }) => (
|
||||
<Attachment
|
||||
rowRef={props.rowRef}
|
||||
style={props.style}
|
||||
item={item}
|
||||
isSelected={props.context?.isSelected(item.id)}
|
||||
onSelected={() => props.context?.select(item.id)}
|
||||
/>
|
||||
)}
|
||||
</ResolvedItem>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ export const BackupExportSettings: SettingsGroup[] = [
|
||||
if (await verifyAccount())
|
||||
await exportNotes(
|
||||
value as "txt" | "md" | "html" | "md-frontmatter",
|
||||
db.notes.all.map((n) => n.id)
|
||||
await db.notes.all.ids()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,7 @@ import useHashLocation from "./use-hash-location";
|
||||
import { Params, Routes } from "../navigation/types";
|
||||
|
||||
let lastRoute: unknown | null = null;
|
||||
export default function useHashRoutes<T extends string, TRouteResult>(
|
||||
routes: Routes<T, TRouteResult>
|
||||
) {
|
||||
export default function useHashRoutes<T extends string>(routes: Routes<T>) {
|
||||
const [{ location, update }] = useHashLocation();
|
||||
if (!update) return lastRoute;
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ import makeMatcher from "wouter/matcher";
|
||||
import { navigate, getHomeRoute } from "../navigation";
|
||||
import { Params, Routes } from "../navigation/types";
|
||||
|
||||
export default function useRoutes<T extends string, TRouteResult>(
|
||||
routes: Routes<T, TRouteResult>,
|
||||
export default function useRoutes<T extends string>(
|
||||
routes: Routes<T>,
|
||||
options?: {
|
||||
hooks?: { beforeNavigate: (location: string) => void };
|
||||
fallbackRoute?: string;
|
||||
|
||||
@@ -27,20 +27,9 @@ import { navigate } from ".";
|
||||
import Trash from "../views/trash";
|
||||
import { store as notestore } from "../stores/note-store";
|
||||
import Reminders from "../views/reminders";
|
||||
import { defineRoutes } from "./types";
|
||||
import React from "react";
|
||||
import { RouteContainerButtons } from "../components/route-container";
|
||||
import { RouteResult, defineRoutes } from "./types";
|
||||
import { CREATE_BUTTON_MAP } from "../common";
|
||||
|
||||
type RouteResult = {
|
||||
key: string;
|
||||
type: "notes" | "notebooks" | "reminders" | "trash" | "tags";
|
||||
title?: string | (() => Promise<string | undefined>);
|
||||
component: React.FunctionComponent;
|
||||
props?: any;
|
||||
buttons?: RouteContainerButtons;
|
||||
};
|
||||
|
||||
function defineRoute(route: RouteResult): RouteResult {
|
||||
return route;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,30 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RouteContainerButtons } from "../components/route-container";
|
||||
|
||||
export type RouteResult = {
|
||||
key: string;
|
||||
type: "notes" | "notebooks" | "reminders" | "trash" | "tags";
|
||||
title?: string | (() => Promise<string | undefined>);
|
||||
component:
|
||||
| ((props?: any) => JSX.Element | null)
|
||||
| React.ReactNode
|
||||
| React.MemoExoticComponent<React.FunctionComponent>;
|
||||
props?: any;
|
||||
buttons?: RouteContainerButtons;
|
||||
};
|
||||
|
||||
export function isRouteResult(obj: any): obj is RouteResult {
|
||||
return (
|
||||
!!obj &&
|
||||
typeof obj === "object" &&
|
||||
"key" in obj &&
|
||||
"type" in obj &&
|
||||
"component" in obj
|
||||
);
|
||||
}
|
||||
|
||||
type IsParameter<Part> = Part extends `:${infer Parameter}?`
|
||||
? Parameter
|
||||
: Part extends `:${infer Parameter}`
|
||||
@@ -38,12 +62,12 @@ export type Params<Path> = {
|
||||
[Key in FilteredParts<Path>]: string;
|
||||
};
|
||||
|
||||
export type Routes<T extends string, TRouteResult> = {
|
||||
[Path in T]: (params: Params<Path>) => TRouteResult | void;
|
||||
export type Routes<T extends string> = {
|
||||
[Path in T]: (
|
||||
params: Params<Path>
|
||||
) => boolean | React.ReactNode | RouteResult | void;
|
||||
};
|
||||
|
||||
export function defineRoutes<T extends string, TRouteResult>(
|
||||
routes: Routes<T, TRouteResult>
|
||||
): Routes<T, TRouteResult> {
|
||||
export function defineRoutes<T extends string>(routes: Routes<T>): Routes<T> {
|
||||
return routes;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class AttachmentStore extends BaseStore<AttachmentStore> {
|
||||
abortController = new AbortController();
|
||||
const attachmentStream = new AttachmentStream(
|
||||
ids,
|
||||
(id) => this.attachments?.item(id),
|
||||
(id) => db.attachments.attachment(id),
|
||||
abortController.signal,
|
||||
(current) => {
|
||||
this.set({ status: { current, total: ids.length } });
|
||||
@@ -87,7 +87,7 @@ class AttachmentStore extends BaseStore<AttachmentStore> {
|
||||
|
||||
recheck = async (ids: string[]) => {
|
||||
for (const id of ids) {
|
||||
const attachment = await this.attachments?.item(id);
|
||||
const attachment = await db.attachments.attachment(id);
|
||||
if (!attachment) continue;
|
||||
try {
|
||||
this._changeWorkingStatus(attachment.hash, "recheck");
|
||||
|
||||
@@ -122,9 +122,9 @@ async function processNote(entry: ZipEntry, attachments: Record<string, any>) {
|
||||
if (!noteId) return;
|
||||
|
||||
for (const nb of notebooks) {
|
||||
const notebook = await importNotebook(nb).catch(() => ({ id: undefined }));
|
||||
if (!notebook.id) continue;
|
||||
await db.notes.addToNotebook(notebook.id, noteId);
|
||||
const notebookId = await importNotebook(nb).catch(() => undefined);
|
||||
if (!notebookId) continue;
|
||||
await db.notes.addToNotebook(notebookId, noteId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,18 +135,12 @@ async function fileToJson<T>(file: ZipEntry) {
|
||||
|
||||
async function importNotebook(
|
||||
notebook: Notebook | undefined
|
||||
): Promise<{ id?: string; topic?: string }> {
|
||||
if (!notebook) return {};
|
||||
|
||||
let nb = db.notebooks.all.find((nb) => nb.title === notebook.notebook);
|
||||
if (!nb) {
|
||||
const nbId = await db.notebooks.add({
|
||||
title: notebook.notebook
|
||||
});
|
||||
nb = db.notebooks?.notebook(nbId)?.data;
|
||||
if (!nb) return {};
|
||||
}
|
||||
|
||||
const topic = nb.topics.find((t: any) => t.title === notebook.topic);
|
||||
return { id: nb ? nb.id : undefined, topic: topic ? topic.id : undefined };
|
||||
): Promise<string | undefined> {
|
||||
if (!notebook) return;
|
||||
const nb = await db.notebooks.find(notebook.notebook);
|
||||
return nb
|
||||
? nb.id
|
||||
: await db.notebooks.add({
|
||||
title: notebook.notebook
|
||||
});
|
||||
}
|
||||
|
||||
@@ -226,6 +226,10 @@ export class Notebooks implements ICollection {
|
||||
return notebook;
|
||||
}
|
||||
|
||||
find(title: string) {
|
||||
return this.all.find((eb) => eb("notebooks.title", "==", title));
|
||||
}
|
||||
|
||||
exists(id: string) {
|
||||
return this.collection.exists(id);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,7 @@ type Batch<T> = {
|
||||
export class VirtualizedGrouping<T> {
|
||||
private cache: Map<number, Batch<T>> = new Map();
|
||||
private pending: Map<number, Promise<Batch<T>>> = new Map();
|
||||
public ids: number[];
|
||||
private loadBatchTimeout?: number;
|
||||
public ids: boolean[];
|
||||
|
||||
constructor(
|
||||
count: number,
|
||||
@@ -43,7 +42,7 @@ export class VirtualizedGrouping<T> {
|
||||
) => Map<number, { index: number; hidden?: boolean; group: GroupHeader }>,
|
||||
readonly groups?: () => Promise<{ index: number; group: GroupHeader }[]>
|
||||
) {
|
||||
this.ids = new Array(count).fill(0);
|
||||
this.ids = new Array(count).fill(false);
|
||||
}
|
||||
|
||||
key(index: number) {
|
||||
@@ -95,14 +94,6 @@ export class VirtualizedGrouping<T> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the cache
|
||||
*/
|
||||
refresh(ids: number[]) {
|
||||
this.ids = ids;
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
|
||||
Reference in New Issue
Block a user