refactor: improve route typing

Signed-off-by: Varun Patil <radialapps@gmail.com>
pull/877/head
Varun Patil 2023-10-16 12:42:18 -07:00
parent c7f7d98d4f
commit 75881b33d0
21 changed files with 77 additions and 105 deletions

View File

@ -192,7 +192,7 @@ export default defineComponent({
}, },
onlyRouterView(): boolean { onlyRouterView(): boolean {
return ['nxsetup'].includes(this.$route.name ?? ''); return this.routeIsNxSetup;
}, },
isFirstStart(): boolean { isFirstStart(): boolean {
@ -224,12 +224,6 @@ export default defineComponent({
}, },
}, },
watch: {
route() {
this.doRouteChecks();
},
},
created() { created() {
// No real need to unbind these, as the app is never destroyed // No real need to unbind these, as the app is never destroyed
const onResize = () => { const onResize = () => {
@ -249,7 +243,6 @@ export default defineComponent({
}, },
mounted() { mounted() {
this.doRouteChecks();
this.refreshNav(); this.refreshNav();
// Store CSS variables modified // Store CSS variables modified
@ -409,28 +402,6 @@ export default defineComponent({
} }
}, },
doRouteChecks() {
if (this.$route.name?.endsWith('-share')) {
this.putShareToken(<string>this.$route.params.token);
}
},
putShareToken(token: string) {
// Viewer looks for an input with ID sharingToken with the value as the token
// Create this element or update it otherwise files not gonna open
// https://github.com/nextcloud/viewer/blob/a8c46050fb687dcbb48a022a15a5d1275bf54a8e/src/utils/davUtils.js#L61
let tokenInput = document.getElementById('sharingToken') as HTMLInputElement;
if (!tokenInput) {
tokenInput = document.createElement('input');
tokenInput.id = 'sharingToken';
tokenInput.type = 'hidden';
tokenInput.style.display = 'none';
document.body.appendChild(tokenInput);
}
tokenInput.value = token;
},
showSettings() { showSettings() {
this.settingsOpen = true; this.settingsOpen = true;
}, },

View File

@ -12,7 +12,7 @@ import XLoadingIcon from './components/XLoadingIcon.vue';
import VueVirtualScroller from 'vue-virtual-scroller'; import VueVirtualScroller from 'vue-virtual-scroller';
// Locals // Locals
import router from './router'; import router, { routes } from './router';
import { constants, initstate } from './services/utils'; import { constants, initstate } from './services/utils';
// CSS for components // CSS for components
@ -28,6 +28,7 @@ globalThis._m = {
get route() { get route() {
return router.currentRoute; return router.currentRoute;
}, },
routes: routes,
modals: {} as any, modals: {} as any,
sidebar: {} as any, sidebar: {} as any,

View File

@ -100,8 +100,10 @@ export default defineComponent({
this.items = await dav.getAlbums(this.config.album_list_sort); this.items = await dav.getAlbums(this.config.album_list_sort);
} else if (this.routeIsTags) { } else if (this.routeIsTags) {
this.items = await dav.getTags(); this.items = await dav.getTags();
} else if (this.routeIsPeople) { } else if (this.routeIsRecognize) {
this.items = await dav.getFaceList(<any>this.$route.name); this.items = await dav.getFaceList('recognize');
} else if (this.routeIsFaceRecognition) {
this.items = await dav.getFaceList('facerecognition');
} else if (this.routeIsPlaces) { } else if (this.routeIsPlaces) {
this.items = await dav.getPlaces(); this.items = await dav.getPlaces();
} }

View File

@ -840,9 +840,7 @@ export default defineComponent({
async removeSelectionFromPerson(selection: Selection) { async removeSelectionFromPerson(selection: Selection) {
// Make sure route is valid // Make sure route is valid
const { user, name } = this.$route.params; const { user, name } = this.$route.params;
if (this.$route.name !== 'recognize' || !user || !name) { if (!this.routeIsRecognize || !user || !name) return;
return;
}
// Check photo ownership // Check photo ownership
if (this.$route.params.user !== utils.uid) { if (this.$route.params.user !== utils.uid) {

View File

@ -63,10 +63,10 @@ export default defineComponent({
primary() { primary() {
switch (this.$route.name) { switch (this.$route.name) {
case 'map': case _m.routes.Map.name:
return MapSplitMatter; return MapSplitMatter;
default: default:
return 'None'; return null;
} }
}, },

View File

@ -594,8 +594,7 @@ export default defineComponent({
} }
// Albums // Albums
const user = <string>this.$route.params.user; const { user, name } = this.$route.params;
const name = <string>this.$route.params.name;
if (this.routeIsAlbums) { if (this.routeIsAlbums) {
if (!user || !name) { if (!user || !name) {
throw new Error('Invalid album route'); throw new Error('Invalid album route');
@ -606,7 +605,7 @@ export default defineComponent({
// People // People
if (this.routeIsPeople) { if (this.routeIsPeople) {
if (!user || !name) { if (!user || !name) {
throw new Error('Invalid album route'); throw new Error('Invalid face route');
} }
// name is "recognize" or "facerecognition" // name is "recognize" or "facerecognition"
@ -625,7 +624,7 @@ export default defineComponent({
throw new Error('Invalid place route'); throw new Error('Invalid place route');
} }
const id = <string>name.split('-', 1)[0]; const id = name.split('-', 1)[0];
set(DaysFilterType.PLACE, id); set(DaysFilterType.PLACE, id);
} }
@ -690,7 +689,7 @@ export default defineComponent({
const startState = this.state; const startState = this.state;
let data: IDay[] = []; let data: IDay[] = [];
if (this.$route.name === 'thisday') { if (this.routeIsThisDay) {
data = await dav.getOnThisDayData(); data = await dav.getOnThisDayData();
} else if (dav.isSingleItem()) { } else if (dav.isSingleItem()) {
data = await dav.getSingleItemData(); data = await dav.getSingleItemData();
@ -793,7 +792,7 @@ export default defineComponent({
}; };
// Special headers // Special headers
if (this.$route.name === 'thisday' && (!prevDay || Math.abs(prevDay.dayid - day.dayid) > 30)) { if (this.routeIsThisDay && (!prevDay || Math.abs(prevDay.dayid - day.dayid) > 30)) {
// thisday view with new year title // thisday view with new year title
head.size = 67; head.size = 67;
head.super = utils.getFromNowStr(utils.dayIdToDate(day.dayid)); head.super = utils.getFromNowStr(utils.dayIdToDate(day.dayid));

View File

@ -46,7 +46,7 @@ export default defineComponent({
async open(edit: boolean) { async open(edit: boolean) {
if (edit) { if (edit) {
try { try {
this.album = await dav.getAlbum(<string>this.$route.params.user, <string>this.$route.params.name); this.album = await dav.getAlbum(this.$route.params.user, this.$route.params.name);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
showError(this.t('photos', 'Could not load the selected album')); showError(this.t('photos', 'Could not load the selected album'));

View File

@ -65,8 +65,7 @@ export default defineComponent({
async open() { async open() {
this.show = true; this.show = true;
this.loadingAddCollaborators = true; this.loadingAddCollaborators = true;
const user = <string>this.$route.params.user || ''; const { user, name } = this.$route.params;
const name = <string>this.$route.params.name || '';
this.album = await dav.getAlbum(user, name); this.album = await dav.getAlbum(user, name);
this.loadingAddCollaborators = false; this.loadingAddCollaborators = false;
}, },

View File

@ -72,13 +72,13 @@ export default defineComponent({
}, },
refreshParams() { refreshParams() {
this.user = <string>this.$route.params.user || ''; this.user = this.$route.params.user;
this.name = <string>this.$route.params.name || ''; this.name = this.$route.params.name;
}, },
async save() { async save() {
try { try {
if (this.$route.name === 'recognize') { if (this.routeIsRecognize) {
await dav.recognizeDeleteFace(this.user, this.name); await dav.recognizeDeleteFace(this.user, this.name);
} else { } else {
await dav.faceRecognitionSetPersonVisibility(this.name, false); await dav.faceRecognitionSetPersonVisibility(this.name, false);

View File

@ -103,7 +103,7 @@ export default defineComponent({
if (!this.canSave) return; if (!this.canSave) return;
try { try {
if (this.$route.name === 'recognize') { if (this.routeIsRecognize) {
await dav.recognizeRenameFace(this.user, this.oldName, this.name); await dav.recognizeRenameFace(this.user, this.oldName, this.name);
} else { } else {
await dav.faceRecognitionRenamePerson(this.oldName, this.name); await dav.faceRecognitionRenamePerson(this.oldName, this.name);

View File

@ -85,12 +85,15 @@ export default defineComponent({
methods: { methods: {
async refreshParams() { async refreshParams() {
this.user = <string>this.$route.params.user || ''; this.user = this.$route.params.user;
this.name = <string>this.$route.params.name || ''; this.name = this.$route.params.name;
this.list = null; this.list = null;
this.search = ''; this.search = '';
const faces = await dav.getFaceList(this.$route.name as any); const backend = this.routeIsRecognize ? 'recognize' : this.routeIsFaceRecognition ? 'facerecognition' : null;
console.assert(backend, '[BUG] Invalid route for FaceList');
const faces = await dav.getFaceList(backend!);
this.list = faces.filter((c: IFace) => c.user_id === this.user && String(c.name || c.cluster_id) !== this.name); this.list = faces.filter((c: IFace) => c.user_id === this.user && String(c.name || c.cluster_id) !== this.name);
this.fuse = new Fuse(this.list, { keys: ['name'] }); this.fuse = new Fuse(this.list, { keys: ['name'] });

View File

@ -180,9 +180,7 @@ export default defineComponent({
}, },
async downloadAlbum() { async downloadAlbum() {
const res = await axios.post( const res = await axios.post(API.ALBUM_DOWNLOAD(this.$route.params.user, this.$route.params.name));
API.ALBUM_DOWNLOAD(<string>this.$route.params.user, <string>this.$route.params.name),
);
if (res.status === 200 && res.data.handle) { if (res.status === 200 && res.data.handle) {
downloadWithHandle(res.data.handle); downloadWithHandle(res.data.handle);
} }

View File

@ -29,14 +29,14 @@ export default defineComponent({
computed: { computed: {
viewname(): string { viewname(): string {
return strings.viewName(this.$route.name); return strings.viewName(this.$route.name!);
}, },
name(): string | null { name(): string | null {
switch (this.$route.name) { switch (this.$route.name) {
case 'tags': case _m.routes.Tags.name:
return this.t('recognize', this.$route.params.name); return this.t('recognize', this.$route.params.name);
case 'places': case _m.routes.Places.name:
return this.$route.params.name?.split('-').slice(1).join('-'); return this.$route.params.name?.split('-').slice(1).join('-');
default: default:
return null; return null;

View File

@ -63,7 +63,7 @@ export default defineComponent({
return ''; return '';
} }
return strings.viewName(this.$route.name); return strings.viewName(this.$route.name!);
}, },
}, },

View File

@ -38,7 +38,7 @@ export default defineComponent({
computed: { computed: {
emptyViewDescription(): string { emptyViewDescription(): string {
return strings.emptyDescription(this.$route.name); return strings.emptyDescription(this.$route.name!);
}, },
}, },
}); });

View File

@ -44,15 +44,15 @@ export default defineComponent({
computed: { computed: {
currentmatter() { currentmatter() {
switch (this.$route.name) { switch (this.$route.name) {
case 'folders': case _m.routes.Folders.name:
return FolderTopMatter; return FolderTopMatter;
case 'albums': case _m.routes.Albums.name:
return AlbumTopMatter; return AlbumTopMatter;
case 'tags': case _m.routes.Tags.name:
case 'places': case _m.routes.Places.name:
return ClusterTopMatter; return ClusterTopMatter;
case 'recognize': case _m.routes.Recognize.name:
case 'facerecognition': case _m.routes.FaceRecognition.name:
return FaceTopMatter; return FaceTopMatter;
default: default:
return null; return null;

3
src/globals.d.ts vendored
View File

@ -8,7 +8,7 @@ import type videojsType from 'video.js';
import type { IPhoto, IRow } from './types'; import type { IPhoto, IRow } from './types';
import type { constants, initstate } from './services/utils'; import type { constants, initstate } from './services/utils';
import type { GlobalRouteCheckers } from './router'; import type { GlobalRouteCheckers, routes } from './router';
// Global exposed variables // Global exposed variables
declare global { declare global {
@ -32,6 +32,7 @@ declare global {
var _m: { var _m: {
mode: 'admin' | 'user'; mode: 'admin' | 'user';
route: Route; route: Route;
routes: typeof routes;
modals: { modals: {
editMetadata: (photos: IPhoto[], sections?: number[]) => void; editMetadata: (photos: IPhoto[], sections?: number[]) => void;

View File

@ -31,7 +31,7 @@ export type RouteId =
| 'Explore' | 'Explore'
| 'NxSetup'; | 'NxSetup';
const routes: { [key in RouteId]: RouteConfig } = { export const routes: { [key in RouteId]: RouteConfig } = {
Base: { Base: {
path: '/', path: '/',
component: Timeline, component: Timeline,
@ -176,15 +176,17 @@ function defineRouteChecker(key: keyof GlobalRouteCheckers, condition: (route?:
}); });
} }
// Defined routes // Build basic route checkers
for (const [key, value] of Object.entries(routes)) { for (const [key, value] of Object.entries(routes)) {
defineRouteChecker(`routeIs${<keyof typeof routes>key}`, (route) => route?.name === value.name); defineRouteChecker(`routeIs${<keyof typeof routes>key}`, (route) => route?.name === value.name);
} }
// Extra route checkers // Extra route checkers
defineRouteChecker('routeIsPublic', (route) => route?.name?.endsWith('-share') ?? false); defineRouteChecker('routeIsPublic', (route) => route?.name?.endsWith('-share') ?? false);
defineRouteChecker('routeIsPeople', (route) => ['recognize', 'facerecognition'].includes(route?.name ?? '')); defineRouteChecker('routeIsPeople', (route) =>
[routes.Recognize.name, routes.FaceRecognition.name].includes(route?.name ?? ''),
);
defineRouteChecker( defineRouteChecker(
'routeIsRecognizeUnassigned', 'routeIsRecognizeUnassigned',
(route) => route?.name === 'recognize' && route.params.name === c.FACE_NULL, (route) => route?.name === routes.Recognize.name && route!.params.name === c.FACE_NULL,
); );

View File

@ -7,11 +7,11 @@ const gen = generateUrl;
/** Add auth token to this URL */ /** Add auth token to this URL */
function tok(url: string) { function tok(url: string) {
const token = <string>_m.route.params.token; const { token } = _m.route.params;
switch (_m.route.name) { switch (_m.route.name) {
case 'folder-share': case _m.routes.FolderShare.name:
return API.Q(url, { token }); return API.Q(url, { token });
case 'album-share': case _m.routes.AlbumShare.name:
return API.Q(url, { token, albums: token }); return API.Q(url, { token, albums: token });
} }
return url; return url;

View File

@ -29,8 +29,8 @@ type GetFilesOpts = {
export async function getFiles(photos: IPhoto[], opts?: GetFilesOpts): Promise<IFileInfo[]> { export async function getFiles(photos: IPhoto[], opts?: GetFilesOpts): Promise<IFileInfo[]> {
// Some routes may have special handling of filenames // Some routes may have special handling of filenames
if (!opts?.ignoreRoute) { if (!opts?.ignoreRoute) {
if (_m.route.name === 'albums') { if (_m.route.name === _m.routes.Albums.name) {
return getAlbumFileInfos(photos, <string>_m.route.params.user, <string>_m.route.params.name); return getAlbumFileInfos(photos, _m.route.params.user, _m.route.params.name);
} }
} }
@ -192,7 +192,7 @@ export async function* deletePhotos(photos: IPhoto[], confirm: boolean = true) {
if (photos.length === 0) return; if (photos.length === 0) return;
// Extend with Live Photos unless this is an album // Extend with Live Photos unless this is an album
const routeIsAlbums = _m.route.name === 'albums'; const routeIsAlbums = _m.route.name === _m.routes.Albums.name;
if (!routeIsAlbums) { if (!routeIsAlbums) {
photos = await extendWithLivePhotos(photos); photos = await extendWithLivePhotos(photos);
} }

View File

@ -1,59 +1,57 @@
import staticConfig from './static-config'; import staticConfig from './static-config';
import { translate as t } from '@nextcloud/l10n'; import { translate as t } from '@nextcloud/l10n';
type RouteNameType = string | null | undefined; export function emptyDescription(routeName: string): string {
export function emptyDescription(routeName: RouteNameType): string {
switch (routeName) { switch (routeName) {
case 'timeline': case _m.routes.Base.name:
return t('memories', 'Upload some photos and make sure the timeline path is configured'); return t('memories', 'Upload some photos and make sure the timeline path is configured');
case 'favorites': case _m.routes.Favorites.name:
return t('memories', 'Mark photos as favorite to find them easily'); return t('memories', 'Mark photos as favorite to find them easily');
case 'thisday': case _m.routes.ThisDay.name:
return t('memories', 'Memories from past years will appear here'); return t('memories', 'Memories from past years will appear here');
case 'facerecognition': case _m.routes.Recognize.name:
return t('memories', 'Recognize is still working on your photos');
case _m.routes.FaceRecognition.name:
return staticConfig.getSync('facerecognition_enabled') return staticConfig.getSync('facerecognition_enabled')
? t('memories', 'You will find your friends soon. Please be patient') ? t('memories', 'You will find your friends soon. Please be patient')
: t('memories', 'Face Recognition is disabled. Enable in settings to find your friends'); : t('memories', 'Face Recognition is disabled. Enable in settings to find your friends');
case 'videos': case _m.routes.Videos.name:
return t('memories', 'Your videos will appear here'); return t('memories', 'Your videos will appear here');
case 'albums': case _m.routes.Albums.name:
return _m.route.params.name return _m.route.params.name
? t('memories', 'Add photos to albums by selecting them on your timeline.') ? t('memories', 'Add photos to albums by selecting them on your timeline.')
: t('memories', 'Create an album to get started'); : t('memories', 'Create an album to get started');
case 'archive': case _m.routes.Archive.name:
return t('memories', "Archive photos you don't want to see in your timeline"); return t('memories', "Archive photos you don't want to see in your timeline");
case 'tags': case _m.routes.Tags.name:
return t('memories', 'Tag photos to find them easily'); return t('memories', 'Tag photos to find them easily');
case 'recognize': case _m.routes.Places.name:
return t('memories', 'Recognize is still working on your photos');
case 'places':
return t('memories', 'Places you have been to will appear here'); return t('memories', 'Places you have been to will appear here');
default: default:
return ''; return String();
} }
} }
export function viewName(routeName: RouteNameType): string { export function viewName(routeName: string): string {
switch (routeName) { switch (routeName) {
case 'favorites': case _m.routes.Favorites.name:
return t('memories', 'Favorites'); return t('memories', 'Favorites');
case 'recognize': case _m.routes.Recognize.name:
case 'facerecognition': case _m.routes.FaceRecognition.name:
return t('memories', 'People'); return t('memories', 'People');
case 'videos': case _m.routes.Videos.name:
return t('memories', 'Videos'); return t('memories', 'Videos');
case 'albums': case _m.routes.Albums.name:
return t('memories', 'Albums'); return t('memories', 'Albums');
case 'archive': case _m.routes.Archive.name:
return t('memories', 'Archive'); return t('memories', 'Archive');
case 'thisday': case _m.routes.ThisDay.name:
return t('memories', 'On this day'); return t('memories', 'On this day');
case 'tags': case _m.routes.Tags.name:
return t('memories', 'Tags'); return t('memories', 'Tags');
case 'places': case _m.routes.Places.name:
return t('memories', 'Places'); return t('memories', 'Places');
default: default:
return ''; return String();
} }
} }