Skip to content

Commit

Permalink
feat(note): Merge user and note tools (#182)
Browse files Browse the repository at this point in the history
* Merge user and note tools

* Fix build

* Remove line

* Add note dto

* Update src/application/services/useTools.ts

Co-authored-by: Peter Savchenko <[email protected]>

---------

Co-authored-by: Peter Savchenko <[email protected]>
  • Loading branch information
TatianaFomina and neSpecc authored Apr 17, 2024
1 parent 1d300e2 commit 0ca0e6a
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 80 deletions.
20 changes: 14 additions & 6 deletions src/application/services/useNote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ import { onMounted, ref, type Ref, type MaybeRefOrGetter, computed, toValue, wat
import { noteService } from '@/domain';
import type { Note, NoteContent, NoteId } from '@/domain/entities/Note';
import { useRouter } from 'vue-router';

/**
* On new note creation, we use predefined structure of the Editor: header + paragraph
* We call it NoteDraft
*/
type NoteDraft = Pick<Note, 'content'>;
import type { NoteDraft } from '@/domain/entities/NoteDraft';
import type EditorTool from '@/domain/entities/EditorTool';

/**
* Creates base structure for the empty note:
Expand Down Expand Up @@ -46,6 +42,11 @@ interface UseNoteComposableState {
*/
note: Ref<Note | NoteDraft | null>;

/**
* List of tools used in the note
*/
noteTools: Ref<EditorTool[]>;

/**
* Creates/updates the note
*/
Expand Down Expand Up @@ -102,6 +103,11 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
*/
const note = ref<Note | NoteDraft | null>(currentId.value === null ? createDraft() : null);

/**
* List of tools used in the note
*/
const noteTools = ref<EditorTool[]>([]);

/**
* Router instance used to replace the current route with note id
*/
Expand Down Expand Up @@ -149,6 +155,7 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt

note.value = response.note;
canEdit.value = response.accessRights.canEdit;
noteTools.value = response.tools;
parentNote.value = response.parentNote;
}

Expand Down Expand Up @@ -244,6 +251,7 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt

return {
note,
noteTools,
noteTitle,
canEdit,
resolveHostname,
Expand Down
82 changes: 82 additions & 0 deletions src/application/services/useTools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { type Ref, ref, watch } from 'vue';
import { useAppState } from './useAppState';
import type EditorTool from '@/domain/entities/EditorTool';
import { loadScript } from '@/infrastructure/utils/load-script';
import type { EditorConfig } from '@editorjs/editorjs';

/**
* Downloaded tools data structure
*/
type DownloadedTools = EditorConfig['tools'];

/**
* Service for load editor tools
*
* @param noteTools - note tools
*/
export function useTools(noteTools: Ref<EditorTool[]>): {
tools: Ref<DownloadedTools | undefined>;
} {
/**
* User notes tools
*/
const { userEditorTools } = useAppState();
const tools = ref<DownloadedTools | undefined>();

/**
* Download all the user tools and return a map
*
* @param toolsList - tools data
*/
async function downloadTools(toolsList: EditorTool[]): Promise<DownloadedTools> {
const downloadedTools: DownloadedTools = {};

for (const tool of toolsList) {
if (tool.source.cdn === undefined) {
continue;
}

await loadScript(tool.source.cdn);

downloadedTools[tool.name] = window[tool.exportName as keyof typeof window];
}

return downloadedTools;
}

/**
* Merge two arrays of tools, removing duplicates
*
* @param toolsA – first array of tools
* @param toolsB – second array of tools
*/
function mergeTools(toolsA: EditorTool[], toolsB: EditorTool[]): EditorTool[] {
const uniqueTools = new Map<string, EditorTool>();

[...toolsA, ...toolsB].forEach((tool) => {
uniqueTools.set(tool.name, tool);
});

return Array.from(uniqueTools.values());
}

watch(
[userEditorTools, noteTools],
async () => {
const allTools = mergeTools(userEditorTools.value || [], noteTools.value);

/**
* If tools are not loaded yet or empty, skip downloading their scripts
*/
if (allTools.length === 0) {
return;
}
tools.value = await downloadTools(allTools);
},
{ immediate: true }
);

return {
tools,
};
}
62 changes: 0 additions & 62 deletions src/application/services/useUserTools.ts

This file was deleted.

28 changes: 28 additions & 0 deletions src/domain/entities/NoteDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type EditorTool from './EditorTool';
import type { Note } from './Note';
import type NoteAccessRights from './NoteAccessRights';

/**
* Note Datsa Transfer Object used to pass Note data between layers
*/
export interface NoteDTO {
/**
* Note data
*/
note: Note;

/**
* Note access rights
*/
accessRights: NoteAccessRights;

/**
* Parent note if exists
*/
parentNote: Note | undefined;

/**
* Editor tools
*/
tools: EditorTool[];
}
7 changes: 7 additions & 0 deletions src/domain/entities/NoteDraft.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Note } from './Note';

/**
* On new note creation, we use predefined structure of the Editor: header + paragraph
* We call it NoteDraft
*/
export type NoteDraft = Pick<Note, 'content'>;
3 changes: 2 additions & 1 deletion src/domain/note.repository.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Note, NoteContent, NoteId } from '@/domain/entities/Note';
import type { NoteList } from './entities/NoteList';
import type NoteAccessRights from '@/domain/entities/NoteAccessRights';
import type { NoteDTO } from './entities/NoteDTO';

/**
* Repository interface describes the methods that required by domain for its business logic implementation
Expand All @@ -13,7 +14,7 @@ export default interface NoteRepositoryInterface {
* @returns {{ note: Note, accessRights: NoteAccessRights, parentNote: Note | undefined }} - Returns a Note, NoteAccessRights and parent note (if exists) by id
* @throws NotFoundError
*/
getNoteById(publicId: string): Promise<{ note: Note; accessRights: NoteAccessRights; parentNote: Note | undefined }>;
getNoteById(publicId: string): Promise<NoteDTO>;

/**
* Returns a Note and NoteAccessRights by hostname
Expand Down
5 changes: 2 additions & 3 deletions src/domain/note.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type NoteRepository from '@/domain/note.repository.interface';
import type { Note, NoteContent, NoteId } from '@/domain/entities/Note';
import type NoteAccessRights from '@/domain/entities/NoteAccessRights';
import type { NoteDTO } from './entities/NoteDTO';

/**
* Note Service
Expand Down Expand Up @@ -28,9 +29,7 @@ export default class NoteService {
* @returns {{ note: Note, accessRights: NoteAccessRights, parentNote: Note | undefined }} - note data, accessRights data
* and parent note data if exists
*/
public async getNoteById(
id: string
): Promise<{ note: Note; accessRights: NoteAccessRights; parentNote: Note | undefined }> {
public async getNoteById(id: string): Promise<NoteDTO> {
return await this.noteRepository.getNoteById(id);
}

Expand Down
5 changes: 2 additions & 3 deletions src/infrastructure/note.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type NoteStorage from '@/infrastructure/storage/note.js';
import type NotesApiTransport from '@/infrastructure/transport/notes-api';
import type { GetNoteResponsePayload } from '@/infrastructure/transport/notes-api/types/GetNoteResponsePayload';
import type { NoteList } from '@/domain/entities/NoteList';
import type { NoteDTO } from '@/domain/entities/NoteDTO';

/**
* Note repository
Expand Down Expand Up @@ -39,9 +40,7 @@ export default class NoteRepository implements NoteRepositoryInterface {
* @returns {{ note: Note, accessRights: NoteAccessRights, parentNote }} - Note instance, NoteAccessRights instance
* and parent note, if exists
*/
public async getNoteById(
id: string
): Promise<{ note: Note; accessRights: NoteAccessRights; parentNote: Note | undefined }> {
public async getNoteById(id: string): Promise<NoteDTO> {
/**
* Get note data from API
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type EditorTool from '@/domain/entities/EditorTool';
import type { Note } from '@/domain/entities/Note';
import type NoteAccessRights from '@/domain/entities/NoteAccessRights.ts';

Expand All @@ -8,4 +9,5 @@ export type GetNoteResponsePayload = {
note: Note;
accessRights: NoteAccessRights;
parentNote: Note | undefined;
tools: EditorTool[];
};
12 changes: 7 additions & 5 deletions src/presentation/pages/Note.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
>
{{ t('note.createChildNote') }}
</Button>

<Button
v-if="parentNote != undefined"
@click="unlinkButton"
Expand All @@ -17,9 +18,9 @@
</div>

<Editor
v-if="userTools !== undefined"
v-if="tools !== undefined"
ref="editor"
:tools="userTools"
:tools="tools"
:content="note.content"
:read-only="!canEdit"
@change="noteChanged"
Expand All @@ -31,14 +32,13 @@
import { ref, toRef, watch } from 'vue';
import { Button, Editor } from 'codex-ui/vue';
import useNote from '@/application/services/useNote';
import { useUserTools } from '@/application/services/useUserTools.ts';
import { useTools } from '@/application/services/useTools.ts';
import { useRouter } from 'vue-router';
import { NoteContent } from '@/domain/entities/Note';
import { useHead } from 'unhead';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const { userTools } = useUserTools();
const router = useRouter();
Expand All @@ -56,10 +56,12 @@ const props = defineProps<{
const noteId = toRef(props, 'id');
const { note, save, noteTitle, canEdit, unlinkParent, parentNote } = useNote({
const { note, noteTools, save, noteTitle, canEdit, unlinkParent, parentNote } = useNote({
id: noteId,
});
const { tools } = useTools(noteTools);
/**
* Editor component reference
*/
Expand Down

0 comments on commit 0ca0e6a

Please sign in to comment.