Forráskód Böngészése

Migrated import-album to Vue 3, fixed some merge issues

Kristian Vos 4 éve
szülő
commit
ac0265751e

+ 5 - 3
backend/logic/actions/songs.js

@@ -695,7 +695,7 @@ export default {
 					"SONGS_REQUEST",
 					`Requesting song "${youtubeId}" failed for user ${session.userId}. "${err}"`
 				);
-				return cb({ status: "error", message: err, song: (returnSong && _err.data) ? _err.data.song : null });
+				return cb({ status: "error", message: err, song: returnSong && _err.data ? _err.data.song : null });
 			});
 	}),
 
@@ -956,8 +956,10 @@ export default {
 						},
 						() => {
 							if (returnSongs)
-								songs = Object.keys(songs).sort().map(key => songs[key]);
-							
+								songs = Object.keys(songs)
+									.sort()
+									.map(key => songs[key]);
+
 							next(null, { successful, failed, alreadyInDatabase, songs });
 						}
 					);

+ 7 - 7
backend/logic/songs.js

@@ -13,11 +13,10 @@ let PlaylistsModule;
 
 class ErrorWithData extends Error {
 	constructor(message, data) {
-	  super(message);
-	  this.data = data;
+		super(message);
+		this.data = data;
 	}
-  }
-
+}
 
 class _SongsModule extends CoreClass {
 	// eslint-disable-next-line require-jsdoc
@@ -974,15 +973,16 @@ class _SongsModule extends CoreClass {
 						status
 					};
 
-					if (err && err === "This song is already in the database.") return reject(new ErrorWithData(err, { song: trimmedSong }));
-					
+					if (err && err === "This song is already in the database.")
+						return reject(new ErrorWithData(err, { song: trimmedSong }));
+
 					SongsModule.runJob("UPDATE_SONG", { songId: song._id });
 
 					CacheModule.runJob("PUB", {
 						channel: "song.newUnverifiedSong",
 						value: song._id
 					});
-					
+
 					return resolve({ song: trimmedSong });
 				}
 			);

+ 4 - 1
frontend/src/components/modals/EditSong/index.vue

@@ -332,7 +332,10 @@
 				</div>
 			</template>
 			<template #footer>
-				<save-button ref="saveButton" @clicked="save(song, false, false)" />
+				<save-button
+					ref="saveButton"
+					@clicked="save(song, false, false)"
+				/>
 				<save-button
 					ref="saveAndCloseButton"
 					type="save-and-close"

+ 268 - 262
frontend/src/components/modals/ImportAlbum.vue

@@ -1,7 +1,7 @@
 <template>
 	<div>
 		<modal title="Import Album" class="import-album-modal">
-			<div slot="body" class="import-album-modal-body">
+			<template #body>
 				<div class="search-discogs-album">
 					<p class="control is-expanded">
 						<label class="label">Search query</label>
@@ -210,18 +210,18 @@
 						v-if="playlistSongs.length > 0"
 						group="songs"
 						v-model="playlistSongs"
+						item-key="_id"
 						@start="drag = true"
 						@end="drag = false"
 						@change="log"
 					>
-						<!-- <transition-group> -->
-						<song-item
-							v-for="song in playlistSongs"
-							:key="`playlist-song-${song._id}`"
-							:song="song"
-						>
-						</song-item>
-						<!-- </transition-group> -->
+						<template #item="{element}">
+							<song-item
+								:key="`playlist-song-${element._id}`"
+								:song="element"
+							>
+							</song-item>
+						</template>
 					</draggable>
 				</div>
 				<div
@@ -241,30 +241,30 @@
 							class="track-box-songs-drag-area"
 							group="songs"
 							v-model="trackSongs[index]"
+							item-key="_id"
 							@start="drag = true"
 							@end="drag = false"
 							@change="log"
 						>
-							<!-- <transition-group> -->
-							<song-item
-								v-for="song in trackSongs[index]"
-								:key="`track-song-${song._id}`"
-								:song="song"
-							>
-							</song-item>
-							<!-- </transition-group> -->
+							<template #item="{element}">
+								<song-item
+									:key="`track-song-${element._id}`"
+									:song="element"
+								>
+								</song-item>
+							</template>
 						</draggable>
 					</div>
 				</div>
-			</div>
-			<div slot="footer">
+			</template>
+			<template #footer>
 				<button class="button is-primary" @click="tryToAutoMove()">
 					Try to auto move
 				</button>
 				<button class="button is-primary" @click="editSongs()">
 					Edit songs
 				</button>
-			</div>
+			</template>
 		</modal>
 	</div>
 </template>
@@ -336,7 +336,7 @@ export default {
 		}
 		/* eslint-enable */
 	},
-	beforeDestroy() {
+	beforeUnmount() {
 		this.selectDiscogsAlbum({});
 		this.setPlaylistSongs([]);
 	},
@@ -364,12 +364,15 @@ export default {
 		},
 		editNextSong() {
 			if (this.editingSongs) {
-				this.editSong({
-					_id: this.songsToEdit[this.currentEditSongIndex].songId,
-					discogs: this.songsToEdit[this.currentEditSongIndex].discogs
-				});
-				this.currentEditSongIndex += 1;
-				this.openModal("editSong");
+				setTimeout(() => {
+					this.editSong({
+						_id: this.songsToEdit[this.currentEditSongIndex].songId,
+						discogs: this.songsToEdit[this.currentEditSongIndex]
+							.discogs
+					});
+					this.currentEditSongIndex += 1;
+					this.openModal("editSong");
+				}, 500);
 			}
 		},
 		log(evt) {
@@ -410,7 +413,6 @@ export default {
 				true,
 				res => {
 					this.isImportingPlaylist = false;
-					console.log(111, res);
 					const songs = res.songs.filter(
 						song => song.status !== "verified"
 					);
@@ -577,12 +579,23 @@ export default {
 		margin-left: 24px;
 	}
 
+	// .import-album-modal-body {
+	// 	display: flex;
+	// 	flex-direction: row;
+	// 	flex-wrap: wrap;
+	// 	justify-content: space-evenly;
+	// }
+
 	.modal-card {
 		width: 100%;
 		height: 100%;
 
 		.modal-card-body {
 			padding: 16px;
+			display: flex;
+			flex-direction: row;
+			flex-wrap: wrap;
+			justify-content: space-evenly;
 		}
 
 		.modal-card-foot {
@@ -604,301 +617,234 @@ export default {
 </style>
 
 <style lang="scss" scoped>
-.import-album-modal-body {
-	display: flex;
-	flex-direction: row;
-	flex-wrap: wrap;
-	justify-content: space-evenly;
-
-	.break {
-		flex-basis: 100%;
-		height: 0;
-		border: 1px solid var(--dark-grey);
-		margin-top: 16px;
-		margin-bottom: 16px;
+.break {
+	flex-basis: 100%;
+	height: 0;
+	border: 1px solid var(--dark-grey);
+	margin-top: 16px;
+	margin-bottom: 16px;
+}
+
+.search-discogs-album {
+	width: 376px;
+	background-color: var(--light-grey);
+	border: 1px rgba(163, 224, 255, 0.75) solid;
+	border-radius: 5px;
+	padding: 16px;
+	overflow: auto;
+	height: 100%;
+
+	> label {
+		margin-top: 12px;
 	}
 
-	.search-discogs-album {
-		width: 376px;
-		background-color: var(--light-grey);
-		border: 1px rgba(163, 224, 255, 0.75) solid;
-		border-radius: 5px;
-		padding: 16px;
-		overflow: auto;
-		height: 100%;
+	.top-container {
+		display: flex;
 
-		> label {
-			margin-top: 12px;
+		img {
+			height: 85px;
+			width: 85px;
 		}
 
-		.top-container {
+		.right-container {
+			padding: 8px;
 			display: flex;
+			flex-direction: column;
+			flex: 1;
 
-			img {
-				height: 85px;
-				width: 85px;
+			.album-title {
+				flex: 1;
+				font-weight: 600;
 			}
 
-			.right-container {
-				padding: 8px;
+			.bottom-row {
 				display: flex;
-				flex-direction: column;
-				flex: 1;
+				flex-flow: row;
+				line-height: 15px;
 
-				.album-title {
+				img {
+					height: 15px;
+					align-self: end;
 					flex: 1;
-					font-weight: 600;
+					user-select: none;
+					-moz-user-select: none;
+					-ms-user-select: none;
+					-webkit-user-select: none;
+					cursor: pointer;
 				}
 
-				.bottom-row {
-					display: flex;
-					flex-flow: row;
-					line-height: 15px;
-
-					img {
-						height: 15px;
-						align-self: end;
-						flex: 1;
-						user-select: none;
-						-moz-user-select: none;
-						-ms-user-select: none;
-						-webkit-user-select: none;
-						cursor: pointer;
-					}
-
-					p {
-						text-align: right;
-					}
+				p {
+					text-align: right;
+				}
 
-					.type-year {
-						font-size: 13px;
-						align-self: end;
-					}
+				.type-year {
+					font-size: 13px;
+					align-self: end;
 				}
 			}
 		}
+	}
 
-		.bottom-container {
-			padding: 12px;
+	.bottom-container {
+		padding: 12px;
 
-			.bottom-container-field {
-				line-height: 16px;
-				margin-bottom: 8px;
-				font-weight: 600;
-
-				span {
-					font-weight: 400;
-				}
-			}
+		.bottom-container-field {
+			line-height: 16px;
+			margin-bottom: 8px;
+			font-weight: 600;
 
-			.bottom-container-field:last-of-type {
-				margin-bottom: 8px;
+			span {
+				font-weight: 400;
 			}
 		}
 
-		.api-result {
-			background-color: var(--white);
-			border: 0.5px solid var(--primary-color);
-			border-radius: 5px;
-			margin-bottom: 16px;
-		}
-
-		button {
-			&:focus,
-			&:hover {
-				filter: contrast(0.75);
-			}
+		.bottom-container-field:last-of-type {
+			margin-bottom: 8px;
 		}
+	}
 
-		.tracks {
-			margin-top: 12px;
-
-			.track:first-child {
-				margin-top: 0;
-				border-radius: 3px 3px 0 0;
-			}
-
-			.track:last-child {
-				border-radius: 0 0 3px 3px;
-			}
+	.api-result {
+		background-color: var(--white);
+		border: 0.5px solid var(--primary-color);
+		border-radius: 5px;
+		margin-bottom: 16px;
+	}
 
-			.track {
-				border: 0.5px solid var(--black);
-				margin-top: -1px;
-				line-height: 16px;
-				display: flex;
+	button {
+		&:focus,
+		&:hover {
+			filter: contrast(0.75);
+		}
+	}
 
-				span {
-					font-weight: 600;
-					display: inline-block;
-					margin-top: 7px;
-					margin-bottom: 7px;
-					margin-left: 7px;
-				}
+	.tracks {
+		margin-top: 12px;
 
-				p {
-					display: inline-block;
-					margin: 7px;
-					flex: 1;
-				}
-			}
+		.track:first-child {
+			margin-top: 0;
+			border-radius: 3px 3px 0 0;
 		}
 
-		.discogs-load-more {
-			margin-bottom: 8px;
+		.track:last-child {
+			border-radius: 0 0 3px 3px;
 		}
-	}
 
-	.discogs-album {
-		width: 376px;
-		background-color: var(--light-grey);
-		border: 1px rgba(163, 224, 255, 0.75) solid;
-		border-radius: 5px;
-		padding: 16px;
-		overflow: auto;
-		height: 100%;
-
-		.top-container {
+		.track {
+			border: 0.5px solid var(--black);
+			margin-top: -1px;
+			line-height: 16px;
 			display: flex;
 
-			img {
-				height: 85px;
-				width: 85px;
+			span {
+				font-weight: 600;
+				display: inline-block;
+				margin-top: 7px;
+				margin-bottom: 7px;
+				margin-left: 7px;
 			}
 
-			.right-container {
-				padding: 8px;
-				display: flex;
-				flex-direction: column;
+			p {
+				display: inline-block;
+				margin: 7px;
 				flex: 1;
-
-				.album-title {
-					flex: 1;
-					font-weight: 600;
-				}
-
-				.bottom-row {
-					display: flex;
-					flex-flow: row;
-					line-height: 15px;
-
-					img {
-						height: 15px;
-						align-self: end;
-						flex: 1;
-						user-select: none;
-						-moz-user-select: none;
-						-ms-user-select: none;
-						-webkit-user-select: none;
-						cursor: pointer;
-					}
-
-					p {
-						text-align: right;
-					}
-
-					.type-year {
-						font-size: 13px;
-						align-self: end;
-					}
-				}
 			}
 		}
+	}
 
-		.bottom-container {
-			padding: 12px;
+	.discogs-load-more {
+		margin-bottom: 8px;
+	}
+}
 
-			.bottom-container-field {
-				line-height: 16px;
-				margin-bottom: 8px;
-				font-weight: 600;
+.discogs-album {
+	width: 376px;
+	background-color: var(--light-grey);
+	border: 1px rgba(163, 224, 255, 0.75) solid;
+	border-radius: 5px;
+	padding: 16px;
+	overflow: auto;
+	height: 100%;
+
+	.top-container {
+		display: flex;
+
+		img {
+			height: 85px;
+			width: 85px;
+		}
 
-				span {
-					font-weight: 400;
-				}
-			}
+		.right-container {
+			padding: 8px;
+			display: flex;
+			flex-direction: column;
+			flex: 1;
 
-			.bottom-container-field:last-of-type {
-				margin-bottom: 0;
+			.album-title {
+				flex: 1;
+				font-weight: 600;
 			}
 
-			.tracks {
-				margin-top: 12px;
-
-				.track:first-child {
-					margin-top: 0;
-					border-radius: 3px 3px 0 0;
-				}
+			.bottom-row {
+				display: flex;
+				flex-flow: row;
+				line-height: 15px;
 
-				.track:last-child {
-					border-radius: 0 0 3px 3px;
+				img {
+					height: 15px;
+					align-self: end;
+					flex: 1;
+					user-select: none;
+					-moz-user-select: none;
+					-ms-user-select: none;
+					-webkit-user-select: none;
+					cursor: pointer;
 				}
 
-				.track {
-					border: 0.5px solid var(--black);
-					margin-top: -1px;
-					line-height: 16px;
-					display: flex;
-
-					span {
-						font-weight: 600;
-						display: inline-block;
-						margin-top: 7px;
-						margin-bottom: 7px;
-						margin-left: 7px;
-					}
-
-					p {
-						display: inline-block;
-						margin: 7px;
-						flex: 1;
-					}
+				p {
+					text-align: right;
 				}
 
-				.track:hover,
-				.track:focus {
-					background-color: var(--light-grey);
+				.type-year {
+					font-size: 13px;
+					align-self: end;
 				}
 			}
 		}
 	}
 
-	.import-youtube-playlist {
-		width: 376px;
-		background-color: var(--light-grey);
-		border: 1px rgba(163, 224, 255, 0.75) solid;
-		border-radius: 5px;
-		padding: 16px;
-		overflow: auto;
-		height: 100%;
-	}
+	.bottom-container {
+		padding: 12px;
 
-	.track-boxes {
-		width: 376px;
-		background-color: var(--light-grey);
-		border: 1px rgba(163, 224, 255, 0.75) solid;
-		border-radius: 5px;
-		padding: 16px;
-		overflow: auto;
-		height: 100%;
+		.bottom-container-field {
+			line-height: 16px;
+			margin-bottom: 8px;
+			font-weight: 600;
 
-		.track-box:first-child {
-			margin-top: 0;
-			border-radius: 3px 3px 0 0;
+			span {
+				font-weight: 400;
+			}
 		}
 
-		.track-box:last-child {
-			border-radius: 0 0 3px 3px;
+		.bottom-container-field:last-of-type {
+			margin-bottom: 0;
 		}
 
-		.track-box {
-			border: 0.5px solid var(--black);
-			margin-top: -1px;
-			line-height: 16px;
-			display: flex;
-			flex-flow: column;
+		.tracks {
+			margin-top: 12px;
 
-			.track-position-title {
+			.track:first-child {
+				margin-top: 0;
+				border-radius: 3px 3px 0 0;
+			}
+
+			.track:last-child {
+				border-radius: 0 0 3px 3px;
+			}
+
+			.track {
+				border: 0.5px solid var(--black);
+				margin-top: -1px;
+				line-height: 16px;
 				display: flex;
 
 				span {
@@ -916,11 +862,71 @@ export default {
 				}
 			}
 
-			.track-box-songs-drag-area {
+			.track:hover,
+			.track:focus {
+				background-color: var(--light-grey);
+			}
+		}
+	}
+}
+
+.import-youtube-playlist {
+	width: 376px;
+	background-color: var(--light-grey);
+	border: 1px rgba(163, 224, 255, 0.75) solid;
+	border-radius: 5px;
+	padding: 16px;
+	overflow: auto;
+	height: 100%;
+}
+
+.track-boxes {
+	width: 376px;
+	background-color: var(--light-grey);
+	border: 1px rgba(163, 224, 255, 0.75) solid;
+	border-radius: 5px;
+	padding: 16px;
+	overflow: auto;
+	height: 100%;
+
+	.track-box:first-child {
+		margin-top: 0;
+		border-radius: 3px 3px 0 0;
+	}
+
+	.track-box:last-child {
+		border-radius: 0 0 3px 3px;
+	}
+
+	.track-box {
+		border: 0.5px solid var(--black);
+		margin-top: -1px;
+		line-height: 16px;
+		display: flex;
+		flex-flow: column;
+
+		.track-position-title {
+			display: flex;
+
+			span {
+				font-weight: 600;
+				display: inline-block;
+				margin-top: 7px;
+				margin-bottom: 7px;
+				margin-left: 7px;
+			}
+
+			p {
+				display: inline-block;
+				margin: 7px;
 				flex: 1;
-				min-height: 100px;
 			}
 		}
+
+		.track-box-songs-drag-area {
+			flex: 1;
+			min-height: 100px;
+		}
 	}
 }
 </style>

+ 0 - 245
frontend/src/components/modals/ManageStationOwen/Tabs/Search.vue

@@ -1,245 +0,0 @@
-<template>
-	<div class="search">
-		<div class="musare-search">
-			<label class="label"> Search for a song on Musare </label>
-			<div class="control is-grouped input-with-button">
-				<p class="control is-expanded">
-					<input
-						class="input"
-						type="text"
-						placeholder="Enter your song query here..."
-						v-model="musareSearch.query"
-						@keyup.enter="searchForMusareSongs(1)"
-					/>
-				</p>
-				<p class="control">
-					<a class="button is-info" @click="searchForMusareSongs(1)"
-						><i class="material-icons icon-with-button">search</i
-						>Search</a
-					>
-				</p>
-			</div>
-			<div v-if="musareSearch.results.length > 0">
-				<song-item
-					v-for="song in musareSearch.results"
-					:key="song._id"
-					:song="song"
-				>
-					<div class="song-actions" slot="actions">
-						<i
-							class="material-icons add-to-queue-icon"
-							v-if="station.partyMode && !station.locked"
-							@click="addSongToQueue(song.youtubeId)"
-							content="Add Song to Queue"
-							v-tippy
-							>queue</i
-						>
-					</div>
-				</song-item>
-				<button
-					v-if="resultsLeftCount > 0"
-					class="button is-primary load-more-button"
-					@click="searchForMusareSongs(musareSearch.page + 1)"
-				>
-					Load {{ nextPageResultsCount }} more results
-				</button>
-			</div>
-		</div>
-		<div class="youtube-search">
-			<label class="label"> Search for a song on YouTube </label>
-			<div class="control is-grouped input-with-button">
-				<p class="control is-expanded">
-					<input
-						class="input"
-						type="text"
-						placeholder="Enter your YouTube query here..."
-						v-model="search.songs.query"
-						autofocus
-						@keyup.enter="searchForSongs()"
-					/>
-				</p>
-				<p class="control">
-					<a class="button is-info" @click.prevent="searchForSongs()"
-						><i class="material-icons icon-with-button">search</i
-						>Search</a
-					>
-				</p>
-			</div>
-
-			<div v-if="search.songs.results.length > 0" id="song-query-results">
-				<search-query-item
-					v-for="(result, index) in search.songs.results"
-					:key="result.id"
-					:result="result"
-				>
-					<div slot="actions">
-						<transition name="search-query-actions" mode="out-in">
-							<a
-								class="button is-success"
-								v-if="result.isAddedToQueue"
-								key="added-to-queue"
-							>
-								<i class="material-icons icon-with-button"
-									>done</i
-								>
-								Added to queue
-							</a>
-							<a
-								class="button is-dark"
-								v-else
-								@click.prevent="
-									addSongToQueue(result.id, index)
-								"
-								key="add-to-queue"
-							>
-								<i class="material-icons icon-with-button"
-									>add</i
-								>
-								Add to queue
-							</a>
-						</transition>
-					</div>
-				</search-query-item>
-
-				<a
-					class="button is-primary load-more-button"
-					@click.prevent="loadMoreSongs()"
-				>
-					Load more...
-				</a>
-			</div>
-		</div>
-	</div>
-</template>
-
-<script>
-import { mapState, mapGetters } from "vuex";
-
-import Toast from "toasters";
-import SearchYoutube from "@/mixins/SearchYoutube.vue";
-
-import SongItem from "@/components/SongItem.vue";
-import SearchQueryItem from "../../../SearchQueryItem.vue";
-
-export default {
-	components: {
-		SongItem,
-		SearchQueryItem
-	},
-	mixins: [SearchYoutube],
-	data() {
-		return {
-			musareSearch: {
-				query: "",
-				searchedQuery: "",
-				page: 0,
-				count: 0,
-				resultsLeft: 0,
-				results: []
-			}
-		};
-	},
-	computed: {
-		resultsLeftCount() {
-			return this.musareSearch.count - this.musareSearch.results.length;
-		},
-		nextPageResultsCount() {
-			return Math.min(this.musareSearch.pageSize, this.resultsLeftCount);
-		},
-		...mapState("modals/manageStation", {
-			station: state => state.station,
-			originalStation: state => state.originalStation
-		}),
-		...mapGetters({
-			socket: "websockets/getSocket"
-		})
-	},
-	methods: {
-		addSongToQueue(youtubeId, index) {
-			if (this.station.type === "community") {
-				this.socket.dispatch(
-					"stations.addToQueue",
-					this.station._id,
-					youtubeId,
-					res => {
-						if (res.status !== "success")
-							new Toast(`Error: ${res.message}`);
-						else {
-							if (index)
-								this.search.songs.results[
-									index
-								].isAddedToQueue = true;
-
-							new Toast(res.message);
-						}
-					}
-				);
-			} else {
-				this.socket.dispatch("songs.request", youtubeId, false, res => {
-					if (res.status !== "success")
-						new Toast(`Error: ${res.message}`);
-					else {
-						this.search.songs.results[index].isAddedToQueue = true;
-
-						new Toast(res.message);
-					}
-				});
-			}
-		},
-		searchForMusareSongs(page) {
-			if (
-				this.musareSearch.page >= page ||
-				this.musareSearch.searchedQuery !== this.musareSearch.query
-			) {
-				this.musareSearch.results = [];
-				this.musareSearch.page = 0;
-				this.musareSearch.count = 0;
-				this.musareSearch.resultsLeft = 0;
-				this.musareSearch.pageSize = 0;
-			}
-
-			this.musareSearch.searchedQuery = this.musareSearch.query;
-			this.socket.dispatch(
-				"songs.searchOfficial",
-				this.musareSearch.query,
-				page,
-				res => {
-					const { data } = res;
-					const { count, pageSize, songs } = data;
-					if (res.status === "success") {
-						this.musareSearch.results = [
-							...this.musareSearch.results,
-							...songs
-						];
-						this.musareSearch.page = page;
-						this.musareSearch.count = count;
-						this.musareSearch.resultsLeft =
-							count - this.musareSearch.results.length;
-						this.musareSearch.pageSize = pageSize;
-					} else if (res.status === "error") {
-						this.musareSearch.results = [];
-						this.musareSearch.page = 0;
-						this.musareSearch.count = 0;
-						this.musareSearch.resultsLeft = 0;
-						this.musareSearch.pageSize = 0;
-						new Toast(res.message);
-					}
-				}
-			);
-		}
-	}
-};
-</script>
-
-<style lang="scss">
-.search {
-	.musare-search,
-	.universal-item:not(:last-of-type) {
-		margin-bottom: 10px;
-	}
-	.load-more-button {
-		width: 100%;
-		margin-top: 10px;
-	}
-}
-</style>

+ 1 - 0
frontend/src/store/modules/modalVisibility.js

@@ -52,6 +52,7 @@ const mutations = {
 	},
 	closeCurrentModal(state) {
 		// remove any websocket listeners for the modal
+		console.log(`Closing current modal (${state.currentlyActive[0]})`);
 		ws.destroyModalListeners(state.currentlyActive[0]);
 
 		state.modals[state.currentlyActive[0]] = false;