瀏覽代碼

fix: Various typescript fixes

Owen Diffey 2 年之前
父節點
當前提交
a01393d727
共有 39 個文件被更改,包括 386 次插入245 次删除
  1. 32 35
      frontend/src/components/AdvancedTable.vue
  2. 13 3
      frontend/src/components/ModalManager.vue
  3. 1 1
      frontend/src/components/UserLink.vue
  4. 1 1
      frontend/src/components/modals/EditSong/Tabs/Reports.vue
  5. 3 3
      frontend/src/components/modals/EditSong/index.vue
  6. 10 12
      frontend/src/components/modals/ImportAlbum.vue
  7. 1 1
      frontend/src/components/modals/ViewReport.vue
  8. 4 4
      frontend/src/pages/Admin/News.vue
  9. 4 4
      frontend/src/pages/Admin/Playlists.vue
  10. 4 4
      frontend/src/pages/Admin/Reports.vue
  11. 4 4
      frontend/src/pages/Admin/Songs/Import.vue
  12. 4 4
      frontend/src/pages/Admin/Songs/index.vue
  13. 4 4
      frontend/src/pages/Admin/Stations.vue
  14. 4 4
      frontend/src/pages/Admin/Users/DataRequests.vue
  15. 4 4
      frontend/src/pages/Admin/Users/Punishments.vue
  16. 4 4
      frontend/src/pages/Admin/Users/index.vue
  17. 5 5
      frontend/src/pages/Admin/YouTube/Videos.vue
  18. 16 20
      frontend/src/pages/Admin/YouTube/index.vue
  19. 6 2
      frontend/src/stores/editPlaylist.ts
  20. 45 28
      frontend/src/stores/editSong.ts
  21. 5 2
      frontend/src/stores/editUser.ts
  22. 26 21
      frontend/src/stores/importAlbum.ts
  23. 9 1
      frontend/src/stores/longJobs.ts
  24. 21 7
      frontend/src/stores/manageStation.ts
  25. 12 23
      frontend/src/stores/modals.ts
  26. 3 1
      frontend/src/stores/removeAccount.ts
  27. 4 2
      frontend/src/stores/report.ts
  28. 6 3
      frontend/src/stores/settings.ts
  29. 31 11
      frontend/src/stores/station.ts
  30. 28 11
      frontend/src/stores/userAuth.ts
  31. 4 2
      frontend/src/stores/userPlaylists.ts
  32. 7 1
      frontend/src/stores/userPreferences.ts
  33. 12 1
      frontend/src/stores/viewApiRequest.ts
  34. 6 1
      frontend/src/stores/viewPunishment.ts
  35. 3 1
      frontend/src/stores/viewReport.ts
  36. 26 1
      frontend/src/stores/viewYoutubeVideo.ts
  37. 4 2
      frontend/src/stores/websockets.ts
  38. 4 1
      frontend/src/stores/whatIsNew.ts
  39. 6 6
      frontend/src/types/advancedTable.ts

+ 32 - 35
frontend/src/components/AdvancedTable.vue

@@ -47,7 +47,10 @@ const props = defineProps({
 	width: Width of column, e.g. 100px
 	maxWidth: Maximum width of column, e.g. 150px
 	*/
-	columnDefault: { type: Object as PropType<TableColumn>, default: () => {} },
+	columnDefault: {
+		type: Object as PropType<TableColumn>,
+		default: () => ({})
+	},
 	columns: {
 		type: Array as PropType<TableColumn[]>,
 		default: () => []
@@ -64,7 +67,7 @@ const props = defineProps({
 	events: { type: Object as PropType<TableEvents>, default: () => {} },
 	bulkActions: {
 		type: Object as PropType<TableBulkActions>,
-		default: () => {}
+		default: () => ({})
 	}
 });
 
@@ -669,50 +672,42 @@ const columnOrderChanged = () => {
 };
 
 const getTableSettings = () => {
-	const urlTableSettings = <
-		{
-			page: number;
-			pageSize: number;
-			shownColumns: string[];
-			columnOrder: string[];
-			columnWidths: {
-				name: string;
-				width: number;
-			}[];
-			columnSort: {
-				[name: string]: string;
-			};
-			filter: {
-				appliedFilters: TableFilter[];
-				appliedFilterOperator: string;
-			};
-		}
-	>{};
+	const urlTableSettings: {
+		page: number;
+		pageSize: number;
+		shownColumns: string[];
+		columnOrder: string[];
+		columnWidths: {
+			name: string;
+			width: number;
+		}[];
+		columnSort: {
+			[name: string]: string;
+		};
+		filter: {
+			appliedFilters: TableFilter[];
+			appliedFilterOperator: string;
+		};
+	} = {};
 	if (props.query) {
 		if (route.query.page)
-			urlTableSettings.page = Number.parseInt(<string>route.query.page);
+			urlTableSettings.page = Number.parseInt(route.query.page);
 		if (route.query.pageSize)
-			urlTableSettings.pageSize = Number.parseInt(
-				<string>route.query.pageSize
-			);
+			urlTableSettings.pageSize = Number.parseInt(route.query.pageSize);
 		if (route.query.shownColumns)
 			urlTableSettings.shownColumns = JSON.parse(
-				<string>route.query.shownColumns
+				route.query.shownColumns
 			);
 		if (route.query.columnOrder)
-			urlTableSettings.columnOrder = JSON.parse(
-				<string>route.query.columnOrder
-			);
+			urlTableSettings.columnOrder = JSON.parse(route.query.columnOrder);
 		if (route.query.columnWidths)
 			urlTableSettings.columnWidths = JSON.parse(
-				<string>route.query.columnWidths
+				route.query.columnWidths
 			);
 		if (route.query.columnSort)
-			urlTableSettings.columnSort = JSON.parse(
-				<string>route.query.columnSort
-			);
+			urlTableSettings.columnSort = JSON.parse(route.query.columnSort);
 		if (route.query.filter)
-			urlTableSettings.filter = JSON.parse(<string>route.query.filter);
+			urlTableSettings.filter = JSON.parse(route.query.filter);
 	}
 
 	const localStorageTableSettings = JSON.parse(
@@ -767,7 +762,9 @@ onMounted(async () => {
 
 	const columns = [
 		...props.columns.map(column => ({
-			...props.columnDefault,
+			...(typeof props.columnDefault === "object"
+				? props.columnDefault
+				: {}),
 			...column
 		})),
 		{

+ 13 - 3
frontend/src/components/ModalManager.vue

@@ -1,13 +1,23 @@
 <script setup lang="ts">
-import { shallowRef } from "vue";
+import { defineAsyncComponent, shallowRef } from "vue";
 import { storeToRefs } from "pinia";
-import { useModalsStore, useModalComponents } from "@/stores/modals";
+import { useModalsStore } from "@/stores/modals";
 
 const modalsStore = useModalsStore();
 const { modals, activeModals } = storeToRefs(modalsStore);
 
+const useModalComponents = (map: { [key: string]: string }) => {
+	const modalComponents: { [key: string]: string } = {};
+	Object.entries(map).forEach(([mapKey, mapValue]) => {
+		modalComponents[mapKey] = defineAsyncComponent(
+			() => import(`./modals/${mapValue}`)
+		);
+	});
+	return modalComponents;
+};
+
 const modalComponents = shallowRef(
-	useModalComponents("components/modals", {
+	useModalComponents({
 		editUser: "EditUser.vue",
 		login: "Login.vue",
 		register: "Register.vue",

+ 1 - 1
frontend/src/components/UserLink.vue

@@ -8,7 +8,7 @@ const props = defineProps({
 	link: { type: Boolean, default: true }
 });
 
-const user = ref(<{ name: string; username?: string }>{
+const user = ref<{ name: string; username?: string }>({
 	name: "Unknown"
 });
 

+ 1 - 1
frontend/src/components/modals/EditSong/Tabs/Reports.vue

@@ -50,7 +50,7 @@ const sortedByCategory = computed(() => {
 		})
 	);
 
-	return <any>categories;
+	return categories;
 });
 
 const { resolveReport } = editSongStore;

+ 3 - 3
frontend/src/components/modals/EditSong/index.vue

@@ -79,7 +79,7 @@ const songDeleted = ref(false);
 const youtubeError = ref(false);
 const youtubeErrorMessage = ref("");
 const youtubeVideoDuration = ref("0.000");
-const youtubeVideoCurrentTime = ref(<number | string>0);
+const youtubeVideoCurrentTime = ref<number | string>(0);
 const youtubeVideoNote = ref("");
 const useHTTPS = ref(false);
 const muted = ref(false);
@@ -136,13 +136,13 @@ const thumbnailLoadError = ref(false);
 const tabs = ref([]);
 const playerReady = ref(true);
 const interval = ref();
-const saveButtonRefs = ref(<any>[]);
+const saveButtonRefs = ref([]);
 const canvasElement = ref();
 const genreHelper = ref();
 const saveButtonRefName = ref();
 // EditSongs
 const items = ref([]);
-const currentSong = ref(<Song>{});
+const currentSong = ref<Song>({});
 const flagFilter = ref(false);
 const sidebarMobileActive = ref(false);
 const songItems = ref([]);

+ 10 - 12
frontend/src/components/modals/ImportAlbum.vue

@@ -81,18 +81,16 @@ const startEditingSongs = () => {
 			delete album.expanded;
 			delete album.gotMoreInfo;
 
-			const songToEdit = <
-				{
-					youtubeId: string;
-					prefill: {
-						discogs: typeof album;
-						title?: string;
-						thumbnail?: string;
-						genres?: string[];
-						artists?: string[];
-					};
-				}
-			>{
+			const songToEdit: {
+				youtubeId: string;
+				prefill: {
+					discogs: typeof album;
+					title?: string;
+					thumbnail?: string;
+					genres?: string[];
+					artists?: string[];
+				};
+			} = {
 				youtubeId: song.youtubeId,
 				prefill: {
 					discogs: album

+ 1 - 1
frontend/src/components/modals/ViewReport.vue

@@ -50,7 +50,7 @@ const icons = ref({
 	title: "title",
 	custom: "lightbulb"
 });
-const report = ref(<Report>{});
+const report = ref<Report>({});
 const song = ref();
 
 const resolve = value =>

+ 4 - 4
frontend/src/pages/Admin/News.vue

@@ -18,7 +18,7 @@ const UserLink = defineAsyncComponent(
 
 const { socket } = useWebsocketsStore();
 
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -27,7 +27,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 150,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -72,7 +72,7 @@ const columns = ref(<TableColumn[]>[
 		sortProperty: "markdown"
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "status",
 		displayName: "Status",
@@ -109,7 +109,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "contains"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "news",
 	updated: {
 		event: "admin.news.updated",

+ 4 - 4
frontend/src/pages/Admin/Playlists.vue

@@ -17,7 +17,7 @@ const UserLink = defineAsyncComponent(
 
 const { hasPermission } = useUserAuthStore();
 
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -26,7 +26,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 150,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -102,7 +102,7 @@ const columns = ref(<TableColumn[]>[
 		defaultWidth: 230
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "Playlist ID",
@@ -190,7 +190,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "contains"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "playlists",
 	updated: {
 		event: "admin.playlist.updated",

+ 4 - 4
frontend/src/pages/Admin/Reports.vue

@@ -13,7 +13,7 @@ const UserLink = defineAsyncComponent(
 	() => import("@/components/UserLink.vue")
 );
 
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -22,7 +22,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 150,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -84,7 +84,7 @@ const columns = ref(<TableColumn[]>[
 		defaultWidth: 150
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "Report ID",
@@ -135,7 +135,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "datetimeBefore"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "reports",
 	updated: {
 		event: "admin.report.updated",

+ 4 - 4
frontend/src/pages/Admin/Songs/Import.vue

@@ -28,7 +28,7 @@ const createImport = ref({
 	youtubeUrl: "",
 	isImportingOnlyMusic: false
 });
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -37,7 +37,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 200,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -123,7 +123,7 @@ const columns = ref(<TableColumn[]>[
 		defaultVisibility: "hidden"
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "Import ID",
@@ -230,7 +230,7 @@ const filters = ref(<TableFilter[]>[
 		]
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "import",
 	updated: {
 		event: "admin.importJob.updated",

+ 4 - 4
frontend/src/pages/Admin/Songs/index.vue

@@ -32,7 +32,7 @@ const { socket } = useWebsocketsStore();
 
 const { hasPermission } = useUserAuthStore();
 
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -41,7 +41,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 200,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -176,7 +176,7 @@ const columns = ref(<TableColumn[]>[
 		defaultVisibility: "hidden"
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "Song ID",
@@ -294,7 +294,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "numberLesser"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "songs",
 	updated: {
 		event: "admin.song.updated",

+ 4 - 4
frontend/src/pages/Admin/Stations.vue

@@ -23,7 +23,7 @@ const { socket } = useWebsocketsStore();
 
 const { hasPermission } = useUserAuthStore();
 
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -32,7 +32,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 150,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -151,7 +151,7 @@ const columns = ref(<TableColumn[]>[
 		defaultVisibility: "hidden"
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "Station ID",
@@ -287,7 +287,7 @@ const filters = ref(<TableFilter[]>[
 		]
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "stations",
 	updated: {
 		event: "station.updated",

+ 4 - 4
frontend/src/pages/Admin/Users/DataRequests.vue

@@ -11,7 +11,7 @@ const AdvancedTable = defineAsyncComponent(
 
 const { socket } = useWebsocketsStore();
 
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -20,7 +20,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 230,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -57,7 +57,7 @@ const columns = ref(<TableColumn[]>[
 		sortProperty: "_id"
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "Request ID",
@@ -80,7 +80,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "boolean"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "dataRequests",
 	updated: {
 		event: "admin.dataRequests.updated",

+ 4 - 4
frontend/src/pages/Admin/Users/Punishments.vue

@@ -23,7 +23,7 @@ const ipBan = ref({
 	reason: "",
 	expiresAt: "1h"
 });
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -32,7 +32,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 150,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -94,7 +94,7 @@ const columns = ref(<TableColumn[]>[
 		defaultVisibility: "hidden"
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "status",
 		displayName: "Status",
@@ -153,7 +153,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "datetimeBefore"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "punishments",
 	updated: {
 		event: "admin.punishment.updated",

+ 4 - 4
frontend/src/pages/Admin/Users/index.vue

@@ -14,7 +14,7 @@ const ProfilePicture = defineAsyncComponent(
 
 const route = useRoute();
 
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -23,7 +23,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 150,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -110,7 +110,7 @@ const columns = ref(<TableColumn[]>[
 		defaultWidth: 170
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "User ID",
@@ -186,7 +186,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "numberLesser"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "users",
 	updated: {
 		event: "admin.user.updated",

+ 5 - 5
frontend/src/pages/Admin/YouTube/Videos.vue

@@ -29,7 +29,7 @@ const { socket } = useWebsocketsStore();
 const userAuthStore = useUserAuthStore();
 const { hasPermission } = userAuthStore;
 
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -38,7 +38,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 200,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -119,7 +119,7 @@ const columns = ref(<TableColumn[]>[
 		defaultVisibility: "hidden"
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "Video ID",
@@ -183,7 +183,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "contains"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "youtubeVideos",
 	updated: {
 		event: "admin.youtubeVideo.updated",
@@ -195,7 +195,7 @@ const events = ref(<TableEvents>{
 		id: "videoId"
 	}
 });
-const bulkActions = ref(<TableBulkActions>{ width: 200 });
+const bulkActions = ref<TableBulkActions>({ width: 200 });
 const jobs = ref([]);
 if (hasPermission("media.recalculateAllRatings"))
 	jobs.value.push({

+ 16 - 20
frontend/src/pages/Admin/YouTube/index.vue

@@ -23,20 +23,16 @@ const route = useRoute();
 
 const { socket } = useWebsocketsStore();
 
-const quotaStatus = ref(
-	<
-		{
-			[key: string]: {
-				title: string;
-				quotaUsed: number;
-				limit: number;
-				quotaExceeded: boolean;
-			};
-		}
-	>{}
-);
+const quotaStatus = ref<{
+	[key: string]: {
+		title: string;
+		quotaUsed: number;
+		limit: number;
+		quotaExceeded: boolean;
+	};
+}>({});
 const fromDate = ref();
-const columnDefault = ref(<TableColumn>{
+const columnDefault = ref<TableColumn>({
 	sortable: true,
 	hidable: true,
 	defaultVisibility: "shown",
@@ -45,7 +41,7 @@ const columnDefault = ref(<TableColumn>{
 	minWidth: 150,
 	maxWidth: 600
 });
-const columns = ref(<TableColumn[]>[
+const columns = ref<TableColumn[]>([
 	{
 		name: "options",
 		displayName: "Options",
@@ -60,7 +56,7 @@ const columns = ref(<TableColumn[]>[
 		name: "quotaCost",
 		displayName: "Quota Cost",
 		properties: ["quotaCost"],
-		sortProperty: ["quotaCost"],
+		sortProperty: "quotaCost",
 		minWidth: 150,
 		defaultWidth: 150
 	},
@@ -68,7 +64,7 @@ const columns = ref(<TableColumn[]>[
 		name: "timestamp",
 		displayName: "Timestamp",
 		properties: ["date"],
-		sortProperty: ["date"],
+		sortProperty: "date",
 		minWidth: 150,
 		defaultWidth: 150
 	},
@@ -76,18 +72,18 @@ const columns = ref(<TableColumn[]>[
 		name: "url",
 		displayName: "URL",
 		properties: ["url"],
-		sortProperty: ["url"]
+		sortProperty: "url"
 	},
 	{
 		name: "_id",
 		displayName: "Request ID",
 		properties: ["_id"],
-		sortProperty: ["_id"],
+		sortProperty: "_id",
 		minWidth: 230,
 		defaultWidth: 230
 	}
 ]);
-const filters = ref(<TableFilter[]>[
+const filters = ref<TableFilter[]>([
 	{
 		name: "_id",
 		displayName: "Request ID",
@@ -123,7 +119,7 @@ const filters = ref(<TableFilter[]>[
 		defaultFilterType: "contains"
 	}
 ]);
-const events = ref(<TableEvents>{
+const events = ref<TableEvents>({
 	adminRoom: "youtube",
 	removed: {
 		event: "admin.youtubeApiRequest.removed",

+ 6 - 2
frontend/src/stores/editPlaylist.ts

@@ -3,10 +3,14 @@ import { Playlist } from "@/types/playlist";
 
 export const useEditPlaylistStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`editPlaylist-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			playlistId: string;
+			tab: string;
+			playlist: Playlist;
+		} => ({
 			playlistId: null,
 			tab: "settings",
-			playlist: <Playlist>{ songs: [] }
+			playlist: { songs: [] }
 		}),
 		actions: {
 			init({ playlistId }) {

+ 45 - 28
frontend/src/stores/editSong.ts

@@ -5,7 +5,48 @@ import { Report } from "@/types/report";
 
 export const useEditSongStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`editSong-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			video: {
+				player: any;
+				paused: boolean;
+				playerReady: boolean;
+				autoPlayed: boolean;
+				currentTime: number;
+				playbackRate: 0.5 | 1 | 2;
+			};
+			youtubeId: string;
+			song: Song;
+			reports: Report[];
+			tab: "discogs" | "reports" | "youtube" | "musare-songs";
+			newSong: boolean;
+			prefillData: any;
+			bulk: boolean;
+			youtubeIds: string[];
+			songPrefillData: any;
+			form: {
+				inputs: Ref<{
+					[key: string]:
+						| {
+								value: any;
+								originalValue: any;
+								validate?: (value: any) => boolean | string;
+								errors: string[];
+								ref: Ref;
+								sourceChanged: boolean;
+								required: boolean;
+								ignoreUnsaved: boolean;
+						  }
+						| any;
+				}>;
+				unsavedChanges: ComputedRef<string[]>;
+				save: (saveCb?: () => void) => void;
+				setValue: (
+					value: { [key: string]: any },
+					reset?: boolean
+				) => void;
+				setOriginalValue: (value: { [key: string]: any }) => void;
+			};
+		} => ({
 			video: {
 				player: null,
 				paused: true,
@@ -15,39 +56,15 @@ export const useEditSongStore = ({ modalUuid }: { modalUuid: string }) =>
 				playbackRate: 1
 			},
 			youtubeId: null,
-			song: <Song>{},
-			reports: <Report[]>[],
+			song: {},
+			reports: [],
 			tab: "discogs",
 			newSong: false,
 			prefillData: {},
 			bulk: false,
 			youtubeIds: [],
 			songPrefillData: {},
-			form: <
-				{
-					inputs: Ref<{
-						[key: string]:
-							| {
-									value: any;
-									originalValue: any;
-									validate?: (value: any) => boolean | string;
-									errors: string[];
-									ref: Ref;
-									sourceChanged: boolean;
-									required: boolean;
-									ignoreUnsaved: boolean;
-							  }
-							| any;
-					}>;
-					unsavedChanges: ComputedRef<string[]>;
-					save: (saveCb?: () => void) => void;
-					setValue: (
-						value: { [key: string]: any },
-						reset?: boolean
-					) => void;
-					setOriginalValue: (value: { [key: string]: any }) => void;
-				}
-			>{}
+			form: {}
 		}),
 		actions: {
 			init({ song, songs }) {

+ 5 - 2
frontend/src/stores/editUser.ts

@@ -3,9 +3,12 @@ import { User } from "@/types/user";
 
 export const useEditUserStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`editUser-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			userId: string;
+			user: User;
+		} => ({
 			userId: null,
-			user: <User>{}
+			user: {}
 		}),
 		actions: {
 			init({ userId }) {

+ 26 - 21
frontend/src/stores/importAlbum.ts

@@ -3,27 +3,32 @@ import { Song } from "@/types/song";
 
 export const useImportAlbumStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`importAlbum-${modalUuid}`, {
-		state: () => ({
-			discogsAlbum: <
-				{
-					album?: {
-						albumArt: string;
-						title: string;
-						type: string;
-						year: string;
-						artists: string[];
-						genres: string[];
-					};
-					dataQuality?: string;
-					tracks?: {
-						position: string;
-						title: string;
-					}[];
-					expanded?: boolean;
-				}
-			>{},
-			originalPlaylistSongs: <Song[]>[],
-			playlistSongs: <Song[]>[],
+		state: (): {
+			discogsAlbum: {
+				album?: {
+					albumArt: string;
+					title: string;
+					type: string;
+					year: string;
+					artists: string[];
+					genres: string[];
+				};
+				dataQuality?: string;
+				tracks?: {
+					position: string;
+					title: string;
+				}[];
+				expanded?: boolean;
+			};
+			originalPlaylistSongs: Song[];
+			playlistSongs: Song[];
+			editingSongs: boolean;
+			discogsTab: "search" | "selected";
+			prefillDiscogs: boolean;
+		} => ({
+			discogsAlbum: {},
+			originalPlaylistSongs: [],
+			playlistSongs: [],
 			editingSongs: false,
 			discogsTab: "search",
 			prefillDiscogs: false

+ 9 - 1
frontend/src/stores/longJobs.ts

@@ -1,7 +1,15 @@
 import { defineStore } from "pinia";
 
 export const useLongJobsStore = defineStore("longJobs", {
-	state: () => ({
+	state: (): {
+		activeJobs: {
+			id: string;
+			name: string;
+			status: string;
+			message: string;
+		}[];
+		removedJobIds: string[];
+	} => ({
 		activeJobs: [],
 		removedJobIds: []
 	}),

+ 21 - 7
frontend/src/stores/manageStation.ts

@@ -6,17 +6,31 @@ import { useWebsocketsStore } from "@/stores/websockets";
 
 export const useManageStationStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`manageStation-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			stationId: string;
+			sector: "station" | "home" | "admin";
+			tab: "settings" | "request" | "autofill" | "blacklist";
+			station: Station;
+			stationPlaylist: Playlist;
+			autofill: Playlist[];
+			blacklist: Playlist[];
+			songsList: Song[];
+			stationPaused: boolean;
+			currentSong: CurrentSong;
+			permissions: {
+				[permission: string]: boolean;
+			};
+		} => ({
 			stationId: null,
 			sector: "admin",
 			tab: "settings",
-			station: <Station>{},
-			stationPlaylist: <Playlist>{ songs: [] },
-			autofill: <Playlist[]>[],
-			blacklist: <Playlist[]>[],
-			songsList: <Song[]>[],
+			station: {},
+			stationPlaylist: { songs: [] },
+			autofill: [],
+			blacklist: [],
+			songsList: [],
 			stationPaused: true,
-			currentSong: <CurrentSong>{},
+			currentSong: {},
 			permissions: {}
 		}),
 		actions: {

+ 12 - 23
frontend/src/stores/modals.ts

@@ -1,5 +1,4 @@
 import { defineStore } from "pinia";
-import { defineAsyncComponent } from "vue";
 import utils from "@/utils";
 
 import { useWebsocketsStore } from "@/stores/websockets";
@@ -21,15 +20,18 @@ import { useViewYoutubeVideoStore } from "@/stores/viewYoutubeVideo";
 import { useWhatIsNewStore } from "@/stores/whatIsNew";
 
 export const useModalsStore = defineStore("modals", {
-	state: () => ({
-		modals: <
-			{
-				[key: string]: string;
-			}
-		>{},
-		activeModals: <string[]>[],
-		preventCloseUnsaved: <{ [uuid: string]: () => boolean }>{},
-		preventCloseCbs: <{ [uuid: string]: () => Promise<void> }>{}
+	state: (): {
+		modals: {
+			[key: string]: string;
+		};
+		activeModals: string[];
+		preventCloseUnsaved: { [uuid: string]: () => boolean };
+		preventCloseCbs: { [uuid: string]: () => Promise<void> };
+	} => ({
+		modals: {},
+		activeModals: [],
+		preventCloseUnsaved: {},
+		preventCloseCbs: {}
 	}),
 	actions: {
 		closeModal(uuid: string) {
@@ -158,16 +160,3 @@ export const useModalsStore = defineStore("modals", {
 		}
 	}
 });
-
-export const useModalComponents = (
-	baseDirectory: string,
-	map: { [key: string]: string }
-) => {
-	const modalComponents = <{ [key: string]: string }>{};
-	Object.entries(map).forEach(([mapKey, mapValue]) => {
-		modalComponents[mapKey] = defineAsyncComponent(
-			() => import(`@/${baseDirectory}/${mapValue}`)
-		);
-	});
-	return modalComponents;
-};

+ 3 - 1
frontend/src/stores/removeAccount.ts

@@ -2,7 +2,9 @@ import { defineStore } from "pinia";
 
 export const useRemoveAccountStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`removeAccount-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			githubLinkConfirmed: boolean;
+		} => ({
 			githubLinkConfirmed: false
 		}),
 		actions: {

+ 4 - 2
frontend/src/stores/report.ts

@@ -3,8 +3,10 @@ import { Song } from "@/types/song";
 
 export const useReportStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`report-${modalUuid}`, {
-		state: () => ({
-			song: <Song>{}
+		state: (): {
+			song: Song;
+		} => ({
+			song: {}
 		}),
 		actions: {
 			init({ song }) {

+ 6 - 3
frontend/src/stores/settings.ts

@@ -2,9 +2,12 @@ import { defineStore } from "pinia";
 import { User } from "@/types/user";
 
 export const useSettingsStore = defineStore("settings", {
-	state: () => ({
-		originalUser: <User>{},
-		modifiedUser: <User>{}
+	state: (): {
+		originalUser: User;
+		modifiedUser: User;
+	} => ({
+		originalUser: {},
+		modifiedUser: {}
 	}),
 	actions: {
 		updateOriginalUser(payload) {

+ 31 - 11
frontend/src/stores/station.ts

@@ -6,24 +6,44 @@ import { User } from "@/types/user";
 import { useWebsocketsStore } from "@/stores/websockets";
 
 export const useStationStore = defineStore("station", {
-	state: () => ({
-		station: <Station>{},
-		autoRequest: <Playlist[]>[],
+	state: (): {
+		station: Station;
+		autoRequest: Playlist[];
+		autoRequestLock: boolean;
+		userCount: number;
+		users: {
+			loggedIn: User[];
+			loggedOut: User[];
+		};
+		currentSong: CurrentSong | undefined;
+		nextSong: Song | undefined | null;
+		songsList: Song[];
+		stationPaused: boolean;
+		localPaused: boolean;
+		noSong: boolean;
+		autofill: Playlist[];
+		blacklist: Playlist[];
+		mediaModalPlayingAudio: boolean;
+		permissions: {
+			[permission: string]: boolean;
+		};
+	} => ({
+		station: {},
+		autoRequest: [],
 		autoRequestLock: false,
-		editing: {},
 		userCount: 0,
 		users: {
-			loggedIn: <User[]>[],
-			loggedOut: <User[]>[]
+			loggedIn: [],
+			loggedOut: []
 		},
-		currentSong: <CurrentSong | undefined>{},
-		nextSong: <Song | undefined | null>null,
-		songsList: <Song[]>[],
+		currentSong: {},
+		nextSong: null,
+		songsList: [],
 		stationPaused: true,
 		localPaused: false,
 		noSong: true,
-		autofill: <Playlist[]>[],
-		blacklist: <Playlist[]>[],
+		autofill: [],
+		blacklist: [],
 		mediaModalPlayingAudio: false,
 		permissions: {}
 	}),

+ 28 - 11
frontend/src/stores/userAuth.ts

@@ -4,17 +4,34 @@ import validation from "@/validation";
 import { useWebsocketsStore } from "@/stores/websockets";
 
 export const useUserAuthStore = defineStore("userAuth", {
-	state: () => ({
-		userIdMap: <{ [key: string]: { name: string; username: string } }>{},
-		userIdRequested: <{ [key: string]: boolean }>{},
-		pendingUserIdCallbacks: <
-			{
-				[key: string]: ((basicUser: {
-					name: string;
-					username: string;
-				}) => void)[];
-			}
-		>{},
+	state: (): {
+		userIdMap: { [key: string]: { name: string; username: string } };
+		userIdRequested: { [key: string]: boolean };
+		pendingUserIdCallbacks: {
+			[key: string]: ((basicUser: {
+				name: string;
+				username: string;
+			}) => void)[];
+		};
+		loggedIn: boolean;
+		role: "user" | "moderator" | "admin";
+		username: string;
+		email: string;
+		userId: string;
+		banned: boolean;
+		ban: {
+			reason: string;
+			expiresAt: number;
+		};
+		gotData: boolean;
+		gotPermissions: boolean;
+		permissions: {
+			[permission: string]: boolean;
+		};
+	} => ({
+		userIdMap: {},
+		userIdRequested: {},
+		pendingUserIdCallbacks: {},
 		loggedIn: false,
 		role: "",
 		username: "",

+ 4 - 2
frontend/src/stores/userPlaylists.ts

@@ -2,8 +2,10 @@ import { defineStore } from "pinia";
 import { Playlist } from "@/types/playlist";
 
 export const useUserPlaylistsStore = defineStore("userPlaylists", {
-	state: () => ({
-		playlists: <Playlist[]>[]
+	state: (): {
+		playlists: Playlist[];
+	} => ({
+		playlists: []
 	}),
 	actions: {
 		setPlaylists(playlists) {

+ 7 - 1
frontend/src/stores/userPreferences.ts

@@ -1,7 +1,13 @@
 import { defineStore } from "pinia";
 
 export const useUserPreferencesStore = defineStore("userPreferences", {
-	state: () => ({
+	state: (): {
+		nightmode: boolean;
+		autoSkipDisliked: boolean;
+		activityLogPublic: boolean;
+		anonymousSongRequests: boolean;
+		activityWatch: boolean;
+	} => ({
 		nightmode: false,
 		autoSkipDisliked: true,
 		activityLogPublic: false,

+ 12 - 1
frontend/src/stores/viewApiRequest.ts

@@ -2,7 +2,18 @@ import { defineStore } from "pinia";
 
 export const useViewApiRequestStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`viewApiRequest-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			requestId: string;
+			request: {
+				_id: string;
+				url: string;
+				params: object;
+				results: any;
+				date: number;
+				quotaCost: number;
+			};
+			removeAction: string | null;
+		} => ({
 			requestId: null,
 			request: {
 				_id: null,

+ 6 - 1
frontend/src/stores/viewPunishment.ts

@@ -2,7 +2,12 @@ import { defineStore } from "pinia";
 
 export const useViewPunishmentStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`viewPunishment-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			punishmentId: string;
+			punishment: {
+				_id: string;
+			};
+		} => ({
 			punishmentId: null,
 			punishment: {
 				_id: null

+ 3 - 1
frontend/src/stores/viewReport.ts

@@ -2,7 +2,9 @@ import { defineStore } from "pinia";
 
 export const useViewReportStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`viewReport-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			reportId: string;
+		} => ({
 			reportId: null
 		}),
 		actions: {

+ 26 - 1
frontend/src/stores/viewYoutubeVideo.ts

@@ -6,7 +6,32 @@ export const useViewYoutubeVideoStore = ({
 	modalUuid: string;
 }) =>
 	defineStore(`viewYoutubeVideo-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			videoId: string;
+			youtubeId: string;
+			video: {
+				_id: string;
+				youtubeId: string;
+				title: string;
+				author: string;
+				duration: number;
+			};
+			player: {
+				error: boolean;
+				errorMessage: string;
+				player: null;
+				paused: boolean;
+				playerReady: boolean;
+				autoPlayed: boolean;
+				duration: string;
+				currentTime: number;
+				playbackRate: number;
+				videoNote: string;
+				volume: number;
+				muted: boolean;
+				showRateDropdown: boolean;
+			};
+		} => ({
 			videoId: null,
 			youtubeId: null,
 			video: {

+ 4 - 2
frontend/src/stores/websockets.ts

@@ -2,8 +2,10 @@ import { defineStore } from "pinia";
 import SocketHandler from "@/classes/SocketHandler.class";
 
 export const useWebsocketsStore = defineStore("websockets", {
-	state: () => ({
-		socket: <SocketHandler>{
+	state: (): {
+		socket: SocketHandler;
+	} => ({
+		socket: {
 			dispatcher: {}
 		}
 	}),

+ 4 - 1
frontend/src/stores/whatIsNew.ts

@@ -1,8 +1,11 @@
+import { NewsModel } from "@musare_types/models/News";
 import { defineStore } from "pinia";
 
 export const useWhatIsNewStore = ({ modalUuid }: { modalUuid: string }) =>
 	defineStore(`whatIsNew-${modalUuid}`, {
-		state: () => ({
+		state: (): {
+			news: NewsModel;
+		} => ({
 			news: null
 		}),
 		actions: {

+ 6 - 6
frontend/src/types/advancedTable.ts

@@ -1,7 +1,7 @@
 export interface TableColumn {
-	name: string;
-	displayName: string;
-	properties: string[];
+	name?: string;
+	displayName?: string;
+	properties?: string[];
 	sortable?: boolean;
 	sortProperty?: string;
 	hidable?: boolean;
@@ -22,7 +22,7 @@ export interface TableFilter {
 	defaultFilterType: string;
 	autosuggest?: boolean;
 	autosuggestDataAction?: string;
-	dropdown?: [string[]];
+	dropdown?: [string | boolean | number, string][];
 }
 
 export interface TableEvents {
@@ -39,6 +39,6 @@ export interface TableEvents {
 }
 
 export interface TableBulkActions {
-	width: number;
-	height: number;
+	width?: number;
+	height?: number;
 }