feat: sync pdf and note
This commit is contained in:
parent
f10d617689
commit
6e1ea32255
@ -22,7 +22,6 @@ import { ObjPageDto } from '../../../model/obj/obj-page.dto';
|
|||||||
import { ObjPageNoteDto } from '../../../model/obj/obj-note.dto';
|
import { ObjPageNoteDto } from '../../../model/obj/obj-note.dto';
|
||||||
import { ObjPdfDto } from '../../../model/obj/obj-pdf.dto';
|
import { ObjPdfDto } from '../../../model/obj/obj-pdf.dto';
|
||||||
import { ObjPinDto } from '../../../model/obj/obj-pin.dto';
|
import { ObjPinDto } from '../../../model/obj/obj-pin.dto';
|
||||||
import { ObjTaskDto } from '../../../model/obj/obj-task.dto';
|
|
||||||
import { fnConsoleLog } from '../../../fn/fn-console';
|
import { fnConsoleLog } from '../../../fn/fn-console';
|
||||||
|
|
||||||
export class ObjGetOriginCommand implements ICommand<Promise<ObjDto<ObjPageDataDto>[]>> {
|
export class ObjGetOriginCommand implements ICommand<Promise<ObjDto<ObjPageDataDto>[]>> {
|
||||||
@ -45,10 +44,8 @@ export class ObjGetOriginCommand implements ICommand<Promise<ObjDto<ObjPageDataD
|
|||||||
if ((obj.data as ObjPinDto).data.url.href === this.data.href) continue;
|
if ((obj.data as ObjPinDto).data.url.href === this.data.href) continue;
|
||||||
} else if (obj.type === ObjTypeDto.PageNote) {
|
} else if (obj.type === ObjTypeDto.PageNote) {
|
||||||
if ((obj.data as ObjPageNoteDto).url.href === this.data.href) continue;
|
if ((obj.data as ObjPageNoteDto).url.href === this.data.href) continue;
|
||||||
} else if (obj.type === ObjTypeDto.PageTask) {
|
|
||||||
if ((obj.data as ObjTaskDto).url?.href === this.data.href) continue;
|
|
||||||
} else if (obj.type === ObjTypeDto.Pdf) {
|
} else if (obj.type === ObjTypeDto.Pdf) {
|
||||||
if ((obj.data as ObjPdfDto).rawUrl === this.data.href) continue;
|
if ((obj.data as ObjPdfDto).data.rawUrl === this.data.href) continue;
|
||||||
}
|
}
|
||||||
out.push(obj);
|
out.push(obj);
|
||||||
// TODO pagination - now show last 10
|
// TODO pagination - now show last 10
|
||||||
|
@ -45,7 +45,7 @@ export class PageNoteAddCommand implements ICommand<Promise<void>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
await SwTaskStore.addTask(SwTaskType.WORDS_ADD_INDEX, {
|
await SwTaskStore.addTask(SwTaskType.WORDS_ADD_INDEX, {
|
||||||
words: this.note.words,
|
words: this.note.data.words,
|
||||||
objectId: id
|
objectId: id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ export class PageNoteRemoveCommand implements ICommand<void> {
|
|||||||
await LinkHrefStore.noteDel(data.url, this.obj.id);
|
await LinkHrefStore.noteDel(data.url, this.obj.id);
|
||||||
|
|
||||||
await SwTaskStore.addTask(SwTaskType.WORDS_REMOVE_INDEX, {
|
await SwTaskStore.addTask(SwTaskType.WORDS_REMOVE_INDEX, {
|
||||||
words: data.words,
|
words: data.data.words,
|
||||||
objectId: this.obj.id
|
objectId: this.obj.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -17,14 +17,14 @@
|
|||||||
import { BrowserStorage } from '@pinmenote/browser-api';
|
import { BrowserStorage } from '@pinmenote/browser-api';
|
||||||
import { ICommand } from '../../model/shared/common.dto';
|
import { ICommand } from '../../model/shared/common.dto';
|
||||||
import { ObjDto } from '../../model/obj/obj.dto';
|
import { ObjDto } from '../../model/obj/obj.dto';
|
||||||
import { ObjPageNoteDto } from '../../model/obj/obj-note.dto';
|
import { ObjNoteDataDto, ObjPageNoteDto } from '../../model/obj/obj-note.dto';
|
||||||
import { ObjUpdateIndexAddCommand } from '../obj/index/obj-update-index-add.command';
|
import { ObjUpdateIndexAddCommand } from '../obj/index/obj-update-index-add.command';
|
||||||
import { ObjectStoreKeys } from '../../keys/object.store.keys';
|
import { ObjectStoreKeys } from '../../keys/object.store.keys';
|
||||||
import { SwTaskStore } from '../../store/sw-task.store';
|
import { SwTaskStore } from '../../store/sw-task.store';
|
||||||
import { SwTaskType } from '../../model/sw-task.model';
|
import { SwTaskType } from '../../model/sw-task.model';
|
||||||
import { WordFactory } from '../../text/word.factory';
|
import { WordFactory } from '../../text/word.factory';
|
||||||
import { fnConsoleLog } from '../../fn/fn-console';
|
import { fnConsoleLog } from '../../fn/fn-console';
|
||||||
import { fnSha256 } from '../../fn/fn-hash';
|
import { fnSha256Object } from '../../fn/fn-hash';
|
||||||
|
|
||||||
export class PageNoteUpdateCommand implements ICommand<void> {
|
export class PageNoteUpdateCommand implements ICommand<void> {
|
||||||
constructor(private obj: ObjDto<ObjPageNoteDto>, private title: string, private description: string) {}
|
constructor(private obj: ObjDto<ObjPageNoteDto>, private title: string, private description: string) {}
|
||||||
@ -37,24 +37,28 @@ export class PageNoteUpdateCommand implements ICommand<void> {
|
|||||||
await BrowserStorage.set<ObjPageNoteDto>(`${ObjectStoreKeys.NOTE_HASH}:${this.obj.data.hash}`, this.obj.data);
|
await BrowserStorage.set<ObjPageNoteDto>(`${ObjectStoreKeys.NOTE_HASH}:${this.obj.data.hash}`, this.obj.data);
|
||||||
|
|
||||||
this.obj.data.prev = this.obj.data.hash;
|
this.obj.data.prev = this.obj.data.hash;
|
||||||
this.obj.data.hash = fnSha256(this.title + this.description + (this.obj.data.url?.href || '') + dt.toString());
|
|
||||||
|
|
||||||
this.obj.data.title = this.title;
|
const words = new Set<string>([...WordFactory.toWordList(this.title), ...WordFactory.toWordList(this.description)]);
|
||||||
this.obj.data.description = this.description;
|
|
||||||
|
const newData: ObjNoteDataDto = {
|
||||||
|
title: this.title,
|
||||||
|
description: this.description,
|
||||||
|
words: Array.from(words),
|
||||||
|
hashtags: this.obj.data.data.hashtags
|
||||||
|
};
|
||||||
|
this.obj.data.hash = fnSha256Object({ ...newData, url: this.obj.data.url, dt });
|
||||||
|
|
||||||
|
this.obj.data.data = newData;
|
||||||
this.obj.updatedAt = dt;
|
this.obj.updatedAt = dt;
|
||||||
|
|
||||||
// Remove words from index
|
// Remove words from index
|
||||||
await SwTaskStore.addTask(SwTaskType.WORDS_REMOVE_INDEX, {
|
await SwTaskStore.addTask(SwTaskType.WORDS_REMOVE_INDEX, {
|
||||||
words: this.obj.data.words,
|
words: this.obj.data.data.words,
|
||||||
objectId: this.obj.id
|
objectId: this.obj.id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update words
|
|
||||||
const words = new Set<string>([...WordFactory.toWordList(this.title), ...WordFactory.toWordList(this.description)]);
|
|
||||||
this.obj.data.words = Array.from(words);
|
|
||||||
|
|
||||||
await SwTaskStore.addTask(SwTaskType.WORDS_ADD_INDEX, {
|
await SwTaskStore.addTask(SwTaskType.WORDS_ADD_INDEX, {
|
||||||
words: this.obj.data.words,
|
words: Array.from(words),
|
||||||
objectId: this.obj.id
|
objectId: this.obj.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -22,11 +22,11 @@ import { ICommand } from '../../model/shared/common.dto';
|
|||||||
import { LinkHrefStore } from '../../store/link-href.store';
|
import { LinkHrefStore } from '../../store/link-href.store';
|
||||||
import { ObjAddIdCommand } from '../obj/id/obj-add-id.command';
|
import { ObjAddIdCommand } from '../obj/id/obj-add-id.command';
|
||||||
import { ObjNextIdCommand } from '../obj/id/obj-next-id.command';
|
import { ObjNextIdCommand } from '../obj/id/obj-next-id.command';
|
||||||
import { ObjPdfDto } from '../../model/obj/obj-pdf.dto';
|
import { ObjPdfDataDto, ObjPdfDto } from '../../model/obj/obj-pdf.dto';
|
||||||
import { ObjectStoreKeys } from '../../keys/object.store.keys';
|
import { ObjectStoreKeys } from '../../keys/object.store.keys';
|
||||||
import { ScreenshotFactory } from '../../factory/screenshot.factory';
|
import { ScreenshotFactory } from '../../factory/screenshot.factory';
|
||||||
import { UrlFactory } from '../../factory/url.factory';
|
import { UrlFactory } from '../../factory/url.factory';
|
||||||
import { fnSha256 } from '../../fn/fn-hash';
|
import { fnSha256, fnSha256Object } from '../../fn/fn-hash';
|
||||||
import { ImageResizeFactory } from '../../factory/image-resize.factory';
|
import { ImageResizeFactory } from '../../factory/image-resize.factory';
|
||||||
|
|
||||||
export class PdfAddCommand implements ICommand<Promise<void>> {
|
export class PdfAddCommand implements ICommand<Promise<void>> {
|
||||||
@ -46,13 +46,17 @@ export class PdfAddCommand implements ICommand<Promise<void>> {
|
|||||||
|
|
||||||
const url = UrlFactory.newUrl();
|
const url = UrlFactory.newUrl();
|
||||||
|
|
||||||
const data: ObjPdfDto = {
|
const pdfData: Omit<ObjPdfDataDto, 'hash'> = {
|
||||||
hash,
|
|
||||||
screenshot,
|
screenshot,
|
||||||
rawUrl: this.value.url,
|
rawUrl: this.value.url,
|
||||||
url,
|
url,
|
||||||
hashtags: []
|
hashtags: []
|
||||||
};
|
};
|
||||||
|
const pdfDataHash = fnSha256Object(pdfData);
|
||||||
|
const data: ObjPdfDto = {
|
||||||
|
hash,
|
||||||
|
data: { ...pdfData, hash: pdfDataHash }
|
||||||
|
};
|
||||||
|
|
||||||
const dto: ObjDto<ObjPdfDto> = {
|
const dto: ObjDto<ObjPdfDto> = {
|
||||||
id,
|
id,
|
||||||
|
@ -27,7 +27,7 @@ export class PdfRemoveCommand implements ICommand<Promise<void>> {
|
|||||||
await BrowserStorage.remove(`${ObjectStoreKeys.PDF_DATA}:${this.dto.hash}`);
|
await BrowserStorage.remove(`${ObjectStoreKeys.PDF_DATA}:${this.dto.hash}`);
|
||||||
await BrowserStorage.remove(`${ObjectStoreKeys.OBJECT_ID}:${this.id}`);
|
await BrowserStorage.remove(`${ObjectStoreKeys.OBJECT_ID}:${this.id}`);
|
||||||
|
|
||||||
await LinkHrefStore.del(this.dto.url, this.id);
|
await LinkHrefStore.del(this.dto.data.url, this.id);
|
||||||
|
|
||||||
await new ObjRemoveIdCommand(this.id, ObjectStoreKeys.OBJECT_LIST).execute();
|
await new ObjRemoveIdCommand(this.id, ObjectStoreKeys.OBJECT_LIST).execute();
|
||||||
}
|
}
|
||||||
|
@ -77,15 +77,13 @@ export class DownloadImageButton {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private downloadScreenshot = async (screenshot: string): Promise<void> => {
|
private downloadScreenshot = async (screenshot: string): Promise<void> => {
|
||||||
let url = '';
|
const url = window.URL.createObjectURL(fnB64toBlob(screenshot));
|
||||||
let filename = '';
|
let filename = '';
|
||||||
switch (this.model.doc.settings.screenshotFormat) {
|
switch (this.model.doc.settings.screenshotFormat) {
|
||||||
case 'jpeg':
|
case 'jpeg':
|
||||||
url = window.URL.createObjectURL(fnB64toBlob(screenshot, 'image/jpeg'));
|
|
||||||
filename = `${fnUid()}.jpg`;
|
filename = `${fnUid()}.jpg`;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
url = window.URL.createObjectURL(fnB64toBlob(screenshot, 'image/png'));
|
|
||||||
filename = `${fnUid()}.png`;
|
filename = `${fnUid()}.png`;
|
||||||
}
|
}
|
||||||
const data = { url, filename };
|
const data = { url, filename };
|
||||||
|
@ -14,8 +14,13 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
export const fnB64toBlob = (b64Data: string, contentType = '', sliceSize = 512): Blob => {
|
export const fnB64toBlob = (b64Data: string, sliceSize = 512): Blob => {
|
||||||
const byteCharacters = window.atob(b64Data.split(',')[1]);
|
const a = b64Data.split(',');
|
||||||
|
const contentType = a[0].substring(5).split(';')[0];
|
||||||
|
let data = a[1];
|
||||||
|
if (data.endsWith('%3D')) data = data.replaceAll('%3D', '=');
|
||||||
|
// console.log('fnB64toBlob', 'contentType', contentType, 'data', data);
|
||||||
|
const byteCharacters = atob(data);
|
||||||
const byteArrays = [];
|
const byteArrays = [];
|
||||||
|
|
||||||
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
||||||
|
@ -22,6 +22,10 @@ export interface ObjPageNoteDto extends ObjNoteDto {
|
|||||||
export interface ObjNoteDto {
|
export interface ObjNoteDto {
|
||||||
hash: string;
|
hash: string;
|
||||||
prev?: string;
|
prev?: string;
|
||||||
|
data: ObjNoteDataDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ObjNoteDataDto {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
words: string[];
|
words: string[];
|
||||||
|
@ -18,8 +18,13 @@ import { ObjUrlDto } from './obj.dto';
|
|||||||
|
|
||||||
export interface ObjPdfDto {
|
export interface ObjPdfDto {
|
||||||
hash: string;
|
hash: string;
|
||||||
|
data: ObjPdfDataDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ObjPdfDataDto {
|
||||||
screenshot: string;
|
screenshot: string;
|
||||||
rawUrl: string;
|
rawUrl: string;
|
||||||
url: ObjUrlDto;
|
url: ObjUrlDto;
|
||||||
hashtags: string[];
|
hashtags: string[];
|
||||||
|
hash: string;
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the pinmenote-extension distribution (https://github.com/pinmenote/pinmenote-extension).
|
|
||||||
* Copyright (c) 2023 Michal Szczepanski.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* 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 { ObjUrlDto } from './obj.dto';
|
|
||||||
|
|
||||||
export interface ObjTaskDto {
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
url?: ObjUrlDto;
|
|
||||||
words: string[];
|
|
||||||
hashtags: string[];
|
|
||||||
}
|
|
@ -28,7 +28,6 @@ import { ObjDto } from '../../../common/model/obj/obj.dto';
|
|||||||
import { ObjPageNoteDto } from '../../../common/model/obj/obj-note.dto';
|
import { ObjPageNoteDto } from '../../../common/model/obj/obj-note.dto';
|
||||||
import { ObjViewComponent } from '../obj/obj-view.component';
|
import { ObjViewComponent } from '../obj/obj-view.component';
|
||||||
import { PopupFunctionsComponent } from '../popup-functions/popup-functions.component';
|
import { PopupFunctionsComponent } from '../popup-functions/popup-functions.component';
|
||||||
import { TaskComponent } from '../task/task.component';
|
|
||||||
|
|
||||||
export const MainViewComponent: FunctionComponent = () => {
|
export const MainViewComponent: FunctionComponent = () => {
|
||||||
const [previousView, setPreviousView] = useState<MainViewEnum>(MainViewEnum.PAGE_OBJECTS);
|
const [previousView, setPreviousView] = useState<MainViewEnum>(MainViewEnum.PAGE_OBJECTS);
|
||||||
@ -57,8 +56,6 @@ export const MainViewComponent: FunctionComponent = () => {
|
|||||||
return <DecryptComponent />;
|
return <DecryptComponent />;
|
||||||
case MainViewEnum.CALENDAR:
|
case MainViewEnum.CALENDAR:
|
||||||
return <CalendarComponent />;
|
return <CalendarComponent />;
|
||||||
case MainViewEnum.TASK:
|
|
||||||
return <TaskComponent />;
|
|
||||||
case MainViewEnum.BUG_REPORT:
|
case MainViewEnum.BUG_REPORT:
|
||||||
return <BugReportComponent cancelCallback={() => setCurrentView(MainViewEnum.PAGE_OBJECTS)} />;
|
return <BugReportComponent cancelCallback={() => setCurrentView(MainViewEnum.PAGE_OBJECTS)} />;
|
||||||
case MainViewEnum.NOTE:
|
case MainViewEnum.NOTE:
|
||||||
|
@ -18,14 +18,14 @@ import { COLOR_DEFAULT_BORDER, DEFAULT_BORDER_RADIUS } from '../../../../common/
|
|||||||
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import { EditorView } from 'prosemirror-view';
|
import { EditorView } from 'prosemirror-view';
|
||||||
import { ObjPageNoteDto } from '../../../../common/model/obj/obj-note.dto';
|
import { ObjNoteDataDto } from '../../../../common/model/obj/obj-note.dto';
|
||||||
import { PageNoteAddCommand } from '../../../../common/command/page-note/page-note-add.command';
|
import { PageNoteAddCommand } from '../../../../common/command/page-note/page-note-add.command';
|
||||||
import { PopupActiveTabStore } from '../../../store/popup-active-tab.store';
|
import { PopupActiveTabStore } from '../../../store/popup-active-tab.store';
|
||||||
import { StyledInput } from '../../../../common/components/react/styled.input';
|
import { StyledInput } from '../../../../common/components/react/styled.input';
|
||||||
import { WordFactory } from '../../../../common/text/word.factory';
|
import { WordFactory } from '../../../../common/text/word.factory';
|
||||||
import { createTextEditorState } from '../../../../common/components/text-editor/text.editor.state';
|
import { createTextEditorState } from '../../../../common/components/text-editor/text.editor.state';
|
||||||
import { defaultMarkdownSerializer } from 'prosemirror-markdown';
|
import { defaultMarkdownSerializer } from 'prosemirror-markdown';
|
||||||
import { fnSha256 } from '../../../../common/fn/fn-hash';
|
import { fnSha256Object } from '../../../../common/fn/fn-hash';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
addCallback: () => void;
|
addCallback: () => void;
|
||||||
@ -76,16 +76,21 @@ export const NoteAddComponent: FunctionComponent<Props> = (props) => {
|
|||||||
const description = LocalModel.description;
|
const description = LocalModel.description;
|
||||||
const words = new Set<string>([...WordFactory.toWordList(title), ...WordFactory.toWordList(description)]);
|
const words = new Set<string>([...WordFactory.toWordList(title), ...WordFactory.toWordList(description)]);
|
||||||
const dt = Date.now();
|
const dt = Date.now();
|
||||||
const hash = fnSha256(title + description + (url?.href || '') + dt.toString());
|
const data: ObjNoteDataDto = {
|
||||||
const note: ObjPageNoteDto = {
|
|
||||||
hash,
|
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
url,
|
|
||||||
words: Array.from(words),
|
words: Array.from(words),
|
||||||
hashtags: []
|
hashtags: []
|
||||||
};
|
};
|
||||||
await new PageNoteAddCommand(note, dt).execute();
|
const hash = fnSha256Object({ ...data, url, dt });
|
||||||
|
await new PageNoteAddCommand(
|
||||||
|
{
|
||||||
|
hash,
|
||||||
|
url,
|
||||||
|
data
|
||||||
|
},
|
||||||
|
dt
|
||||||
|
).execute();
|
||||||
props.addCallback();
|
props.addCallback();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class LocalModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const NoteEditComponent: FunctionComponent<Props> = (props) => {
|
export const NoteEditComponent: FunctionComponent<Props> = (props) => {
|
||||||
const [title, setTitle] = useState<string>(props.editNote.data.title);
|
const [title, setTitle] = useState<string>(props.editNote.data.data.title);
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -56,7 +56,7 @@ export const NoteEditComponent: FunctionComponent<Props> = (props) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const create = (el: HTMLDivElement): void => {
|
const create = (el: HTMLDivElement): void => {
|
||||||
let state = createTextEditorState(props.editNote.data.description);
|
let state = createTextEditorState(props.editNote.data.data.description);
|
||||||
LocalModel.editorView = new EditorView(el, {
|
LocalModel.editorView = new EditorView(el, {
|
||||||
state,
|
state,
|
||||||
handleKeyDown: (view: EditorView, event: KeyboardEvent) => {
|
handleKeyDown: (view: EditorView, event: KeyboardEvent) => {
|
||||||
|
@ -43,7 +43,7 @@ export const NoteElementComponent: FunctionComponent<Props> = ({ obj, editCallba
|
|||||||
);
|
);
|
||||||
const expandComponent = isExpanded ? <NoteListExpandComponent note={obj} /> : '';
|
const expandComponent = isExpanded ? <NoteListExpandComponent note={obj} /> : '';
|
||||||
|
|
||||||
const title = obj.data.title.length > 50 ? `${obj.data.title.substring(0, 50)}...` : obj.data.title;
|
const title = obj.data.data.title.length > 50 ? `${obj.data.data.title.substring(0, 50)}...` : obj.data.data.title;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -50,7 +50,7 @@ export const NoteListElementComponent: FunctionComponent<Props> = (props) => {
|
|||||||
);
|
);
|
||||||
const expandComponent = isExpanded ? <NoteListExpandComponent note={props.obj} /> : '';
|
const expandComponent = isExpanded ? <NoteListExpandComponent note={props.obj} /> : '';
|
||||||
|
|
||||||
const value = props.obj.data.title;
|
const value = props.obj.data.data.title;
|
||||||
const title = value.length > 30 ? `${value.substring(0, 30)}...` : value;
|
const title = value.length > 30 ? `${value.substring(0, 30)}...` : value;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -27,7 +27,8 @@ export const NoteListExpandComponent: FunctionComponent<PinExpandProps> = ({ not
|
|||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ref.current) return;
|
if (!ref.current) return;
|
||||||
ref.current.innerHTML = marked(note.data.description);
|
const { data } = note.data;
|
||||||
|
ref.current.innerHTML = marked(data.description);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -37,8 +37,8 @@ export const PdfListElementComponent: FunctionComponent<Props> = (props) => {
|
|||||||
const [isExpanded, setIsExpanded] = useState(false);
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
|
||||||
const handleNavigate = async (data: ObjDto<ObjPdfDto>): Promise<void> => {
|
const handleNavigate = async (data: ObjDto<ObjPdfDto>): Promise<void> => {
|
||||||
if (PopupActiveTabStore.url?.href !== data.data.url.href) {
|
if (PopupActiveTabStore.url?.href !== data.data.data.url.href) {
|
||||||
await BrowserApi.setActiveTabUrl(data.data.url.href);
|
await BrowserApi.setActiveTabUrl(data.data.data.url.href);
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -58,7 +58,7 @@ export const PdfListElementComponent: FunctionComponent<Props> = (props) => {
|
|||||||
);
|
);
|
||||||
const expandComponent = isExpanded ? <PdfListExpandComponent obj={props.obj}></PdfListExpandComponent> : '';
|
const expandComponent = isExpanded ? <PdfListExpandComponent obj={props.obj}></PdfListExpandComponent> : '';
|
||||||
|
|
||||||
const a = props.obj.data.url.pathname.split('/');
|
const a = props.obj.data.data.url.pathname.split('/');
|
||||||
let title = a[a.length - 1];
|
let title = a[a.length - 1];
|
||||||
title = title.length > 30 ? `${title.substring(0, 30)}...` : title;
|
title = title.length > 30 ? `${title.substring(0, 30)}...` : title;
|
||||||
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
|
|
||||||
export const TaskAddComponent: FunctionComponent = () => {
|
|
||||||
return <div>Task add</div>;
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import { ObjDto } from '../../../common/model/obj/obj.dto';
|
|
||||||
import { ObjTaskDto } from '../../../common/model/obj/obj-task.dto';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
editCallback: (obj: ObjDto<ObjTaskDto>) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TaskListComponent: FunctionComponent<Props> = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h2>List</h2>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the pinmenote-extension distribution (https://github.com/pinmenote/pinmenote-extension).
|
|
||||||
* Copyright (c) 2023 Michal Szczepanski.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* 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 React, { FunctionComponent, useState } from 'react';
|
|
||||||
import AddIcon from '@mui/icons-material/Add';
|
|
||||||
import IconButton from '@mui/material/IconButton';
|
|
||||||
import { TaskListComponent } from './task-list.component';
|
|
||||||
import { fnConsoleLog } from '../../../common/fn/fn-console';
|
|
||||||
|
|
||||||
enum CurrentView {
|
|
||||||
TASK_LIST = 'TASK_LIST',
|
|
||||||
TASK_ADD = 'TASK_ADD',
|
|
||||||
TASK_EDIT = 'TASK_EDIT'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TaskComponent: FunctionComponent = () => {
|
|
||||||
const [state, setState] = useState<CurrentView>(CurrentView.TASK_LIST);
|
|
||||||
const getComponent = (state: CurrentView) => {
|
|
||||||
switch (state) {
|
|
||||||
case CurrentView.TASK_LIST:
|
|
||||||
return (
|
|
||||||
<TaskListComponent
|
|
||||||
editCallback={() => {
|
|
||||||
fnConsoleLog('editCallback');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case CurrentView.TASK_ADD:
|
|
||||||
return 'TODO';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const component = getComponent(state);
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
|
||||||
<h2>Task</h2>
|
|
||||||
<IconButton onClick={() => setState(CurrentView.TASK_ADD)}>
|
|
||||||
<AddIcon />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
{component}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -17,8 +17,8 @@
|
|||||||
import { ObjDto, ObjTypeDto } from '../../../common/model/obj/obj.dto';
|
import { ObjDto, ObjTypeDto } from '../../../common/model/obj/obj.dto';
|
||||||
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
||||||
import { BoardStore } from '../../store/board.store';
|
import { BoardStore } from '../../store/board.store';
|
||||||
import { ObjNoteDto } from '../../../common/model/obj/obj-note.dto';
|
|
||||||
import { ObjPageDto } from '../../../common/model/obj/obj-page.dto';
|
import { ObjPageDto } from '../../../common/model/obj/obj-page.dto';
|
||||||
|
import { ObjPageNoteDto } from '../../../common/model/obj/obj-note.dto';
|
||||||
import { ObjPdfDto } from '../../../common/model/obj/obj-pdf.dto';
|
import { ObjPdfDto } from '../../../common/model/obj/obj-pdf.dto';
|
||||||
import { PageNoteElement } from './page-note/page-note.element';
|
import { PageNoteElement } from './page-note/page-note.element';
|
||||||
import { PageSnapshotElement } from './page-snapshot/page-snapshot.element';
|
import { PageSnapshotElement } from './page-snapshot/page-snapshot.element';
|
||||||
@ -84,7 +84,11 @@ export const BoardComponent: FunctionComponent = () => {
|
|||||||
}
|
}
|
||||||
case ObjTypeDto.PageNote: {
|
case ObjTypeDto.PageNote: {
|
||||||
boardElements.push(
|
boardElements.push(
|
||||||
<PageNoteElement key={obj.id} dto={obj as ObjDto<ObjNoteDto>} refreshBoardCallback={refreshBoardCallback} />
|
<PageNoteElement
|
||||||
|
key={obj.id}
|
||||||
|
dto={obj as ObjDto<ObjPageNoteDto>}
|
||||||
|
refreshBoardCallback={refreshBoardCallback}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,13 @@ interface Props {
|
|||||||
|
|
||||||
export const PageNoteElement: FunctionComponent<Props> = (props) => {
|
export const PageNoteElement: FunctionComponent<Props> = (props) => {
|
||||||
const [edit, setEdit] = useState<boolean>(false);
|
const [edit, setEdit] = useState<boolean>(false);
|
||||||
const [hashtags, setHashtags] = useState<string[]>(props.dto.data.hashtags);
|
const [hashtags, setHashtags] = useState<string[]>(props.dto.data.data.hashtags);
|
||||||
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ref.current) return;
|
if (!ref.current) return;
|
||||||
ref.current.innerHTML = marked(props.dto.data.description);
|
ref.current.innerHTML = marked(props.dto.data.data.description);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleEdit = () => {
|
const handleEdit = () => {
|
||||||
@ -51,14 +51,14 @@ export const PageNoteElement: FunctionComponent<Props> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleTagSave = (newTags: string[]) => {
|
const handleTagSave = (newTags: string[]) => {
|
||||||
props.dto.data.hashtags = newTags;
|
props.dto.data.data.hashtags = newTags;
|
||||||
setHashtags(newTags);
|
setHashtags(newTags);
|
||||||
fnConsoleLog('PageSnapshotElement->handleTagSave->newTags', newTags);
|
fnConsoleLog('PageSnapshotElement->handleTagSave->newTags', newTags);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BoardItem>
|
<BoardItem>
|
||||||
<BoardItemTitle title={props.dto.data.title} editCallback={handleEdit} removeCallback={handleRemove} />
|
<BoardItemTitle title={props.dto.data.data.title} editCallback={handleEdit} removeCallback={handleRemove} />
|
||||||
<div>
|
<div>
|
||||||
<div ref={ref}></div>
|
<div ref={ref}></div>
|
||||||
</div>
|
</div>
|
||||||
@ -66,9 +66,9 @@ export const PageNoteElement: FunctionComponent<Props> = (props) => {
|
|||||||
<BoardItemFooter
|
<BoardItemFooter
|
||||||
title="page note"
|
title="page note"
|
||||||
saveTags={handleTagSave}
|
saveTags={handleTagSave}
|
||||||
tags={props.dto.data.hashtags}
|
tags={props.dto.data.data.hashtags}
|
||||||
createdAt={props.dto.createdAt}
|
createdAt={props.dto.createdAt}
|
||||||
words={props.dto.data.words}
|
words={props.dto.data.data.words}
|
||||||
url={props.dto.data.url?.href}
|
url={props.dto.data.url?.href}
|
||||||
/>
|
/>
|
||||||
</BoardItem>
|
</BoardItem>
|
||||||
|
@ -30,9 +30,9 @@ interface Props {
|
|||||||
|
|
||||||
export const PdfElement: FunctionComponent<Props> = (props) => {
|
export const PdfElement: FunctionComponent<Props> = (props) => {
|
||||||
const [edit, setEdit] = useState<boolean>(false);
|
const [edit, setEdit] = useState<boolean>(false);
|
||||||
const [hashtags, setHashtags] = useState<string[]>(props.dto.data.hashtags || []);
|
const [hashtags, setHashtags] = useState<string[]>(props.dto.data.data.hashtags || []);
|
||||||
|
|
||||||
const a = props.dto.data.url.pathname.split('/');
|
const a = props.dto.data.data.url.pathname.split('/');
|
||||||
const title = a[a.length - 1];
|
const title = a[a.length - 1];
|
||||||
|
|
||||||
const handleEdit = () => {
|
const handleEdit = () => {
|
||||||
@ -50,7 +50,7 @@ export const PdfElement: FunctionComponent<Props> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleTagSave = (newTags: string[]) => {
|
const handleTagSave = (newTags: string[]) => {
|
||||||
props.dto.data.hashtags = newTags;
|
props.dto.data.data.hashtags = newTags;
|
||||||
setHashtags(newTags);
|
setHashtags(newTags);
|
||||||
fnConsoleLog('PageSnapshotElement->handleTagSave->newTags', newTags);
|
fnConsoleLog('PageSnapshotElement->handleTagSave->newTags', newTags);
|
||||||
};
|
};
|
||||||
@ -60,7 +60,7 @@ export const PdfElement: FunctionComponent<Props> = (props) => {
|
|||||||
<BoardItemTitle title={title} htmlCallback={handleHtml} editCallback={handleEdit} removeCallback={handleRemove} />
|
<BoardItemTitle title={title} htmlCallback={handleHtml} editCallback={handleEdit} removeCallback={handleRemove} />
|
||||||
<img
|
<img
|
||||||
style={{ height: '100%', width: '100%', objectFit: 'contain', maxHeight: 220 }}
|
style={{ height: '100%', width: '100%', objectFit: 'contain', maxHeight: 220 }}
|
||||||
src={props.dto.data.screenshot}
|
src={props.dto.data.data.screenshot}
|
||||||
/>
|
/>
|
||||||
<div style={{ display: 'flex', flexGrow: 1 }}></div>
|
<div style={{ display: 'flex', flexGrow: 1 }}></div>
|
||||||
<BoardItemFooter
|
<BoardItemFooter
|
||||||
@ -69,7 +69,7 @@ export const PdfElement: FunctionComponent<Props> = (props) => {
|
|||||||
createdAt={props.dto.createdAt}
|
createdAt={props.dto.createdAt}
|
||||||
tags={hashtags}
|
tags={hashtags}
|
||||||
words={[]}
|
words={[]}
|
||||||
url={props.dto.data.rawUrl}
|
url={props.dto.data.data.rawUrl}
|
||||||
/>
|
/>
|
||||||
</BoardItem>
|
</BoardItem>
|
||||||
);
|
);
|
||||||
|
@ -63,7 +63,7 @@ export const PdfPreviewComponent: FunctionComponent<Props> = (props) => {
|
|||||||
if (!pdfRef.current || !titleRef.current) return;
|
if (!pdfRef.current || !titleRef.current) return;
|
||||||
const obj = await new ObjGetCommand<ObjPdfDto>(id).execute();
|
const obj = await new ObjGetCommand<ObjPdfDto>(id).execute();
|
||||||
const data = await BrowserStorage.get<string | undefined>(`${ObjectStoreKeys.PDF_DATA}:${obj.data.hash}`);
|
const data = await BrowserStorage.get<string | undefined>(`${ObjectStoreKeys.PDF_DATA}:${obj.data.hash}`);
|
||||||
const a = obj.data.url.pathname.split('/');
|
const a = obj.data.data.url.pathname.split('/');
|
||||||
|
|
||||||
titleRef.current.innerText = `${a[a.length - 1]}`;
|
titleRef.current.innerText = `${a[a.length - 1]}`;
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ export const PdfPreviewComponent: FunctionComponent<Props> = (props) => {
|
|||||||
}
|
}
|
||||||
}, 250);
|
}, 250);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
fnConsoleLog('render->ERROR', e);
|
fnConsoleLog('render->ERROR', e);
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
pdfRef.current.innerHTML = `<h1>ERROR RENDERING PDF</h1><br /><p>${e.toString()}</p>`;
|
pdfRef.current.innerHTML = `<h1>ERROR RENDERING PDF</h1><br /><p>${e.toString()}</p>`;
|
||||||
|
@ -17,9 +17,11 @@
|
|||||||
export interface BeginTxResponse {
|
export interface BeginTxResponse {
|
||||||
tx: string;
|
tx: string;
|
||||||
locked: boolean;
|
locked: boolean;
|
||||||
lockedBy?: string;
|
|
||||||
lockExpire: number;
|
lockExpire: number;
|
||||||
|
lockedBy?: string;
|
||||||
lockReason?: string;
|
lockReason?: string;
|
||||||
|
refreshToken: boolean;
|
||||||
|
resetStorage: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum HashOperation {
|
enum HashOperation {
|
||||||
|
@ -29,37 +29,21 @@ export interface FileDataDto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ApiSegmentAddCommand extends ApiCallBase implements ICommand<Promise<boolean>> {
|
export class ApiSegmentAddCommand extends ApiCallBase implements ICommand<Promise<boolean>> {
|
||||||
constructor(private tx: BeginTxResponse, private file: string, private data: FileDataDto) {
|
constructor(private tx: BeginTxResponse, private file: string | Blob, private data: FileDataDto) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
async execute(): Promise<boolean> {
|
async execute(): Promise<boolean> {
|
||||||
await this.initTokenData();
|
await this.initTokenData();
|
||||||
if (!this.storeUrl) return false;
|
if (!this.storeUrl) return false;
|
||||||
if (await this.hasSegment()) return this.addRef();
|
if (await this.hasSegment()) return true;
|
||||||
return await this.addSegment();
|
return await this.addSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
async addRef(): Promise<boolean> {
|
|
||||||
if (!this.data.parent) return true;
|
|
||||||
const authHeaders = this.getAuthHeaders(false);
|
|
||||||
const resp = await FetchService.fetch<BeginTxResponse>(
|
|
||||||
`${this.storeUrl!}/api/v1/segment/ref/${this.tx.tx}/${this.data.hash}/${this.data.parent}`,
|
|
||||||
{
|
|
||||||
type: 'TEXT',
|
|
||||||
headers: {
|
|
||||||
...authHeaders
|
|
||||||
}
|
|
||||||
},
|
|
||||||
this.refreshParams()
|
|
||||||
);
|
|
||||||
fnConsoleLog('ApiSegmentAddCommand->addRef', resp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async hasSegment(): Promise<boolean> {
|
async hasSegment(): Promise<boolean> {
|
||||||
const authHeaders = this.getAuthHeaders();
|
const authHeaders = this.getAuthHeaders();
|
||||||
|
const params = this.data.parent ? `?parent=${this.data.parent}` : '';
|
||||||
const resp = await FetchService.fetch<BeginTxResponse>(
|
const resp = await FetchService.fetch<BeginTxResponse>(
|
||||||
`${this.storeUrl!}/api/v1/segment/${this.data.hash}/has`,
|
`${this.storeUrl!}/api/v1/segment/has/${this.tx.tx}/${this.data.hash}${params}`,
|
||||||
{
|
{
|
||||||
type: 'TEXT',
|
type: 'TEXT',
|
||||||
headers: {
|
headers: {
|
||||||
@ -73,7 +57,8 @@ export class ApiSegmentAddCommand extends ApiCallBase implements ICommand<Promis
|
|||||||
|
|
||||||
async addSegment(): Promise<boolean> {
|
async addSegment(): Promise<boolean> {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
const fileData = new Blob([this.file], { type: 'application/json' });
|
let fileData = this.file;
|
||||||
|
if (!(this.file instanceof Blob)) fileData = new Blob([this.file], { type: 'application/json' });
|
||||||
formData.append('file', fileData);
|
formData.append('file', fileData);
|
||||||
if (this.data.parent) formData.append('parent', this.data.parent);
|
if (this.data.parent) formData.append('parent', this.data.parent);
|
||||||
formData.append('key', this.data.key);
|
formData.append('key', this.data.key);
|
||||||
|
@ -26,7 +26,6 @@ export class SyncObjectCommand implements ICommand<Promise<void>> {
|
|||||||
constructor(private obj: ObjDto, private hash: string, private tx: BeginTxResponse) {}
|
constructor(private obj: ObjDto, private hash: string, private tx: BeginTxResponse) {}
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
fnConsoleLog('SyncObjectCommand', this.tx);
|
|
||||||
if (this.obj.server?.id) return;
|
if (this.obj.server?.id) return;
|
||||||
const resp: ObjAddResponse | ServerErrorDto = await new ApiObjAddCommand(this.obj, this.hash, this.tx).execute();
|
const resp: ObjAddResponse | ServerErrorDto = await new ApiObjAddCommand(this.obj, this.hash, this.tx).execute();
|
||||||
if ('serverId' in resp) {
|
if ('serverId' in resp) {
|
||||||
@ -34,6 +33,7 @@ export class SyncObjectCommand implements ICommand<Promise<void>> {
|
|||||||
} else if ('code' in resp && resp.code === ApiErrorCode.SYNC_DUPLICATED_HASH) {
|
} else if ('code' in resp && resp.code === ApiErrorCode.SYNC_DUPLICATED_HASH) {
|
||||||
return await this.setByHash();
|
return await this.setByHash();
|
||||||
}
|
}
|
||||||
|
fnConsoleLog('SyncObjectCommand', 'tx', this.tx, 'resp', resp);
|
||||||
throw new Error('PROBLEM !!!!!!!!!!!!!!!');
|
throw new Error('PROBLEM !!!!!!!!!!!!!!!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,20 +14,43 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
import { BrowserStorage } from '@pinmenote/browser-api';
|
||||||
import { ICommand } from '../../../../common/model/shared/common.dto';
|
import { ICommand } from '../../../../common/model/shared/common.dto';
|
||||||
import { ObjDto } from '../../../../common/model/obj/obj.dto';
|
import { ObjDto } from '../../../../common/model/obj/obj.dto';
|
||||||
import { ObjPageNoteDto } from '../../../../common/model/obj/obj-note.dto';
|
import { ObjPageNoteDto } from '../../../../common/model/obj/obj-note.dto';
|
||||||
import { SyncObjectCommand } from './sync-object.command';
|
import { SyncObjectCommand } from './sync-object.command';
|
||||||
import { SyncObjectStatus } from '../sync.model';
|
import { SyncHashType, SyncObjectStatus } from '../sync.model';
|
||||||
import { fnConsoleLog } from '../../../../common/fn/fn-console';
|
import { fnConsoleLog } from '../../../../common/fn/fn-console';
|
||||||
import { BeginTxResponse } from '../../api/store/api-store.model';
|
import { BeginTxResponse } from '../../api/store/api-store.model';
|
||||||
|
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
|
||||||
|
import { ApiSegmentAddCommand } from '../../api/store/segment/api-segment-add.command';
|
||||||
|
|
||||||
|
const TEMP_KEY = 'foo';
|
||||||
|
|
||||||
export class SyncPageNoteCommand implements ICommand<Promise<SyncObjectStatus>> {
|
export class SyncPageNoteCommand implements ICommand<Promise<SyncObjectStatus>> {
|
||||||
constructor(private obj: ObjDto<ObjPageNoteDto>, private tx: BeginTxResponse) {}
|
constructor(private obj: ObjDto<ObjPageNoteDto>, private tx: BeginTxResponse) {}
|
||||||
async execute(): Promise<SyncObjectStatus> {
|
async execute(): Promise<SyncObjectStatus> {
|
||||||
fnConsoleLog('SyncPageNoteCommand');
|
|
||||||
const data = this.obj.data;
|
const data = this.obj.data;
|
||||||
|
|
||||||
await new SyncObjectCommand(this.obj, data.hash, this.tx).execute();
|
await new SyncObjectCommand(this.obj, data.hash, this.tx).execute();
|
||||||
return SyncObjectStatus.SERVER_ERROR;
|
|
||||||
|
await this.syncNote(data);
|
||||||
|
|
||||||
|
return SyncObjectStatus.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async syncNote(data: ObjPageNoteDto): Promise<void> {
|
||||||
|
const content = JSON.stringify(data);
|
||||||
|
await new ApiSegmentAddCommand(this.tx, content, {
|
||||||
|
hash: data.hash,
|
||||||
|
parent: data.hash,
|
||||||
|
type: SyncHashType.ObjPdfDataDto,
|
||||||
|
key: TEMP_KEY
|
||||||
|
}).execute();
|
||||||
|
if (data.prev) {
|
||||||
|
const prevData = await BrowserStorage.get<ObjPageNoteDto>(`${ObjectStoreKeys.NOTE_HASH}:${data.prev}`);
|
||||||
|
fnConsoleLog('SyncPageNoteCommand->prev', data.prev, 'data', prevData);
|
||||||
|
await this.syncNote(prevData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,18 +16,50 @@
|
|||||||
*/
|
*/
|
||||||
import { ICommand } from '../../../../common/model/shared/common.dto';
|
import { ICommand } from '../../../../common/model/shared/common.dto';
|
||||||
import { ObjDto } from '../../../../common/model/obj/obj.dto';
|
import { ObjDto } from '../../../../common/model/obj/obj.dto';
|
||||||
import { ObjPdfDto } from '../../../../common/model/obj/obj-pdf.dto';
|
import { ObjPdfDataDto, ObjPdfDto } from '../../../../common/model/obj/obj-pdf.dto';
|
||||||
import { SyncObjectCommand } from './sync-object.command';
|
import { SyncObjectCommand } from './sync-object.command';
|
||||||
import { SyncObjectStatus } from '../sync.model';
|
import { SyncHashType, SyncObjectStatus } from '../sync.model';
|
||||||
import { fnConsoleLog } from '../../../../common/fn/fn-console';
|
import { fnConsoleLog } from '../../../../common/fn/fn-console';
|
||||||
import { BeginTxResponse } from '../../api/store/api-store.model';
|
import { BeginTxResponse } from '../../api/store/api-store.model';
|
||||||
|
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
|
||||||
|
import { BrowserStorage } from '@pinmenote/browser-api';
|
||||||
|
import { fnB64toBlob } from '../../../../common/fn/fn-b64-to-blob';
|
||||||
|
import { ApiSegmentAddCommand } from '../../api/store/segment/api-segment-add.command';
|
||||||
|
|
||||||
|
const TEMP_KEY = 'foo';
|
||||||
|
|
||||||
export class SyncPdfCommand implements ICommand<Promise<SyncObjectStatus>> {
|
export class SyncPdfCommand implements ICommand<Promise<SyncObjectStatus>> {
|
||||||
constructor(private obj: ObjDto<ObjPdfDto>, private tx: BeginTxResponse) {}
|
constructor(private obj: ObjDto<ObjPdfDto>, private tx: BeginTxResponse) {}
|
||||||
async execute(): Promise<SyncObjectStatus> {
|
async execute(): Promise<SyncObjectStatus> {
|
||||||
fnConsoleLog('SyncPdfCommand');
|
|
||||||
const data = this.obj.data;
|
const data = this.obj.data;
|
||||||
await new SyncObjectCommand(this.obj, data.hash, this.tx).execute();
|
await new SyncObjectCommand(this.obj, data.hash, this.tx).execute();
|
||||||
return SyncObjectStatus.SERVER_ERROR;
|
|
||||||
|
await this.syncPdf(data.hash);
|
||||||
|
await this.syncData(data.data, data.hash);
|
||||||
|
|
||||||
|
return SyncObjectStatus.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async syncData(data: ObjPdfDataDto, parent: string): Promise<void> {
|
||||||
|
const content = JSON.stringify(data);
|
||||||
|
await new ApiSegmentAddCommand(this.tx, content, {
|
||||||
|
hash: data.hash,
|
||||||
|
parent,
|
||||||
|
type: SyncHashType.ObjPdfDataDto,
|
||||||
|
key: TEMP_KEY
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async syncPdf(parent: string): Promise<void> {
|
||||||
|
const pdfData = await BrowserStorage.get<string | undefined>(`${ObjectStoreKeys.PDF_DATA}:${parent}`);
|
||||||
|
if (!pdfData) return;
|
||||||
|
const pdfBlob = fnB64toBlob(pdfData);
|
||||||
|
fnConsoleLog('SyncPdfCommand->syncPdf->blob', pdfBlob);
|
||||||
|
await new ApiSegmentAddCommand(this.tx, pdfBlob, {
|
||||||
|
hash: parent,
|
||||||
|
parent,
|
||||||
|
type: SyncHashType.ObjPdf,
|
||||||
|
key: TEMP_KEY
|
||||||
|
}).execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import { SegmentPage, SegmentType } from '@pinmenote/page-compute';
|
import { SegmentPage, SegmentType, SegmentImg } from '@pinmenote/page-compute';
|
||||||
import { ICommand } from '../../../../common/model/shared/common.dto';
|
import { ICommand } from '../../../../common/model/shared/common.dto';
|
||||||
import { ObjDto } from '../../../../common/model/obj/obj.dto';
|
import { ObjDto } from '../../../../common/model/obj/obj.dto';
|
||||||
import { ObjPageDto } from '../../../../common/model/obj/obj-page.dto';
|
import { ObjPageDto } from '../../../../common/model/obj/obj-page.dto';
|
||||||
@ -25,6 +25,7 @@ import { fnConsoleLog } from '../../../../common/fn/fn-console';
|
|||||||
import { BeginTxResponse } from '../../api/store/api-store.model';
|
import { BeginTxResponse } from '../../api/store/api-store.model';
|
||||||
import { PageSnapshotDto } from '../../../../common/model/obj/page-snapshot.dto';
|
import { PageSnapshotDto } from '../../../../common/model/obj/page-snapshot.dto';
|
||||||
import { ApiSegmentAddCommand } from '../../api/store/segment/api-segment-add.command';
|
import { ApiSegmentAddCommand } from '../../api/store/segment/api-segment-add.command';
|
||||||
|
import { fnB64toBlob } from '../../../../common/fn/fn-b64-to-blob';
|
||||||
|
|
||||||
const TEMP_KEY = 'foo';
|
const TEMP_KEY = 'foo';
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ export class SyncSnapshotCommand implements ICommand<Promise<SyncObjectStatus>>
|
|||||||
await this.syncSnapshot(snapshot, snapshot.hash);
|
await this.syncSnapshot(snapshot, snapshot.hash);
|
||||||
// TODO await this.syncComments(page.comments, snapshot.hash);
|
// TODO await this.syncComments(page.comments, snapshot.hash);
|
||||||
if (!snapshot.segment) {
|
if (!snapshot.segment) {
|
||||||
fnConsoleLog('SyncSnapshotCommand->OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO', snapshot.segment, this.obj);
|
fnConsoleLog('SyncSnapshotCommand->!!!!!!!!!!!!1SEGMENT->EMPTY', snapshot.segment, this.obj);
|
||||||
return SyncObjectStatus.OK;
|
return SyncObjectStatus.OK;
|
||||||
}
|
}
|
||||||
await this.syncSegment(snapshot.segment, snapshot.hash);
|
await this.syncSegment(snapshot.segment, snapshot.hash);
|
||||||
@ -73,14 +74,25 @@ export class SyncSnapshotCommand implements ICommand<Promise<SyncObjectStatus>>
|
|||||||
private async syncSegment(hash: string, parent: string) {
|
private async syncSegment(hash: string, parent: string) {
|
||||||
const segment = await new PageSegmentGetCommand(hash).execute();
|
const segment = await new PageSegmentGetCommand(hash).execute();
|
||||||
if (!segment) return;
|
if (!segment) return;
|
||||||
|
let content: string | Blob | undefined;
|
||||||
|
if (segment.type === (3 as SegmentType)) return;
|
||||||
|
if (segment.type == SegmentType.IMG) {
|
||||||
|
const src = (segment.content as SegmentImg).src;
|
||||||
|
if (src.startsWith('data:image/svg') || src === 'data:') {
|
||||||
|
content = src;
|
||||||
|
} else {
|
||||||
|
content = fnB64toBlob(src);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content = JSON.stringify(segment.content);
|
||||||
|
}
|
||||||
|
|
||||||
const isSynchronized = await new ApiSegmentAddCommand(this.tx, JSON.stringify(segment), {
|
await new ApiSegmentAddCommand(this.tx, content, {
|
||||||
hash,
|
hash,
|
||||||
parent,
|
parent,
|
||||||
type: this.convertSegmentTypeSyncHashType(segment.type),
|
type: this.convertSegmentTypeSyncHashType(segment.type),
|
||||||
key: TEMP_KEY
|
key: TEMP_KEY
|
||||||
}).execute();
|
}).execute();
|
||||||
if (isSynchronized) return;
|
|
||||||
|
|
||||||
switch (segment.type) {
|
switch (segment.type) {
|
||||||
case SegmentType.SNAPSHOT: {
|
case SegmentType.SNAPSHOT: {
|
||||||
@ -93,12 +105,11 @@ export class SyncSnapshotCommand implements ICommand<Promise<SyncObjectStatus>>
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 3 as SegmentType: // FIXME - remove later - SHADOW - obsolete - no longer exists
|
||||||
case SegmentType.CSS:
|
case SegmentType.CSS:
|
||||||
case SegmentType.IMG: {
|
case SegmentType.IMG: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3 as SegmentType: // FIXME - remove later - SHADOW - obsolete - no longer exists
|
|
||||||
return;
|
|
||||||
case SegmentType.IFRAME: {
|
case SegmentType.IFRAME: {
|
||||||
const content = segment.content as SegmentPage;
|
const content = segment.content as SegmentPage;
|
||||||
for (const css of content.css) {
|
for (const css of content.css) {
|
||||||
@ -126,6 +137,7 @@ export class SyncSnapshotCommand implements ICommand<Promise<SyncObjectStatus>>
|
|||||||
case SegmentType.SNAPSHOT:
|
case SegmentType.SNAPSHOT:
|
||||||
return SyncHashType.Snapshot;
|
return SyncHashType.Snapshot;
|
||||||
default:
|
default:
|
||||||
|
fnConsoleLog('convertSegmentTypeSyncHashType', type);
|
||||||
throw new Error('PROBLEM !!!!!!!!!!!!!!!!!!!!');
|
throw new Error('PROBLEM !!!!!!!!!!!!!!!!!!!!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,9 @@ export class SyncResetProgressCommand implements ICommand<Promise<void>> {
|
|||||||
});
|
});
|
||||||
await this.setList(yearMonth, newList);
|
await this.setList(yearMonth, newList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear tx
|
||||||
|
await BrowserStorage.remove(ObjectStoreKeys.SYNC_TX);
|
||||||
fnConsoleLog('SyncResetProgressCommand->complete in ', Date.now() - a);
|
fnConsoleLog('SyncResetProgressCommand->complete in ', Date.now() - a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ export class SyncIndexCommand implements ICommand<Promise<SyncObjectStatus>> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
fnConsoleLog('SyncObjectCommand->PROBLEM', obj.type, 'index', this.index);
|
fnConsoleLog('SyncObjectCommand->PROBLEM', obj, 'index', this.index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ export class SyncMonthCommand implements ICommand<Promise<SyncIndex>> {
|
|||||||
|
|
||||||
const indexListKey = `${ObjectStoreKeys.UPDATED_DT}:${this.yearMonth}`;
|
const indexListKey = `${ObjectStoreKeys.UPDATED_DT}:${this.yearMonth}`;
|
||||||
const indexList = await SyncTxHelper.getList(indexListKey);
|
const indexList = await SyncTxHelper.getList(indexListKey);
|
||||||
fnConsoleLog('SyncMonthCommand->syncList', indexList);
|
fnConsoleLog('SyncMonthCommand->syncList', this.yearMonth, 'size', indexList.length);
|
||||||
|
|
||||||
if (indexList.length === 0)
|
if (indexList.length === 0)
|
||||||
return { dt: this.progress.timestamp, id: this.progress.id, status: SyncObjectStatus.EMPTY_LIST };
|
return { dt: this.progress.timestamp, id: this.progress.id, status: SyncObjectStatus.EMPTY_LIST };
|
||||||
@ -64,8 +64,8 @@ export class SyncMonthCommand implements ICommand<Promise<SyncIndex>> {
|
|||||||
}
|
}
|
||||||
if ([SyncObjectStatus.INDEX_NOT_EXISTS, SyncObjectStatus.OBJECT_NOT_EXISTS].includes(status)) {
|
if ([SyncObjectStatus.INDEX_NOT_EXISTS, SyncObjectStatus.OBJECT_NOT_EXISTS].includes(status)) {
|
||||||
fnConsoleLog('syncIndex->PROBLEM !!!!!!!!!!!!!!!!!!!!!!!!', status, 'index', index);
|
fnConsoleLog('syncIndex->PROBLEM !!!!!!!!!!!!!!!!!!!!!!!!', status, 'index', index);
|
||||||
await SyncTxHelper.commit();
|
// await SyncTxHelper.commit();
|
||||||
throw new Error(`Status ERROR ${status}`);
|
// throw new Error(`Status ERROR ${status}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ export class SyncServerCommand implements ICommand<Promise<void>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dt.setMonth(dt.getMonth() + 1);
|
dt.setMonth(dt.getMonth() + 1);
|
||||||
fnConsoleLog('sync dt', dt, 'lastDay', lastDay, 'syncResult', syncResult);
|
// fnConsoleLog('sync dt', dt, 'lastDay', lastDay, 'syncResult', syncResult);
|
||||||
|
|
||||||
// reset id so we start next month from 0
|
// reset id so we start next month from 0
|
||||||
await new SyncSetProgressCommand({
|
await new SyncSetProgressCommand({
|
||||||
|
@ -36,5 +36,8 @@ export enum SyncHashType {
|
|||||||
IFrame = '3',
|
IFrame = '3',
|
||||||
Img = '4',
|
Img = '4',
|
||||||
Css = '5',
|
Css = '5',
|
||||||
Snapshot = '6'
|
Snapshot = '6',
|
||||||
|
ObjPdfDataDto = '7',
|
||||||
|
ObjPdf = '8',
|
||||||
|
ObjPageNoteDto = '9'
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user