web: more fixes

This commit is contained in:
Abdullah Atta
2023-12-22 08:21:46 +05:00
parent 7b3f671159
commit 36150fb55b
15 changed files with 96 additions and 81 deletions

View File

@@ -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({

View File

@@ -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

View File

@@ -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

View File

@@ -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
});

View File

@@ -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} />}

View File

@@ -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>
);
}

View File

@@ -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()
);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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");

View File

@@ -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
});
}

View File

@@ -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);
}

View File

@@ -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