瀏覽代碼

feat(AdvancedTable): Advanced query improvements and filters prop

Owen Diffey 3 年之前
父節點
當前提交
f4a278e734
共有 3 個文件被更改,包括 128 次插入133 次删除
  1. 4 1
      frontend/src/App.vue
  2. 82 116
      frontend/src/components/AdvancedTable.vue
  3. 42 16
      frontend/src/pages/Admin/tabs/Test.vue

+ 4 - 1
frontend/src/App.vue

@@ -1163,7 +1163,10 @@ img {
 	box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
 	background-color: var(--white);
 	color: var(--dark-grey);
-	width: 500px;
+	width: 100% !important;
+	max-width: 1000px !important;
+	max-height: calc(100vh - 300px);
+	overflow-y: auto;
 
 	.tippy-content {
 		padding: 0;

+ 82 - 116
frontend/src/components/AdvancedTable.vue

@@ -28,7 +28,7 @@
 							ref="search"
 							trigger="click"
 						>
-							<a class="button is-info" click.prevent="true">
+							<a class="button is-info" @click.prevent="true">
 								<i class="material-icons icon-with-button"
 									>search</i
 								>
@@ -39,49 +39,61 @@
 								<div
 									v-for="(query, index) in advancedQuery"
 									:key="`query-${index}`"
-									class="control is-grouped"
+									class="advanced-query"
 								>
-									<p class="control is-expanded">
-										<input
-											v-model="query.query"
-											class="input"
-											type="text"
-										/>
-									</p>
 									<div class="control select">
-										<select v-model="query.column">
+										<select v-model="query.filter">
 											<option
-												v-for="column in columns.filter(
-													c => c.filterable
-												)"
-												:key="column.name"
-												:value="column.name"
+												v-for="f in filters"
+												:key="f.name"
+												:value="f"
 											>
-												{{ column.displayName }}
+												{{ f.displayName }}
 											</option>
 										</select>
 									</div>
+									<p class="control is-expanded">
+										<input
+											v-if="query.filter.type === 'regex'"
+											v-model="query.regex"
+											class="input"
+											type="text"
+											placeholder="Search value"
+											@keyup.enter="changeFilter()"
+										/>
+									</p>
 									<div class="control">
-										<i
+										<button
 											class="
+												button
 												material-icons
-												icon-with-button
+												is-success
 											"
 											@click="addQueryItem()"
-											>control_point</i
 										>
-										<i
-											v-if="advancedQuery.length > 1"
+											control_point
+										</button>
+									</div>
+									<div
+										v-if="advancedQuery.length > 1"
+										class="control"
+									>
+										<button
 											class="
+												button
 												material-icons
-												icon-with-button
+												is-danger
 											"
 											@click="removeQueryItem(index)"
-											>remove_circle_outline</i
 										>
+											remove_circle_outline
+										</button>
 									</div>
 								</div>
-								<a class="button is-info">
+								<a
+									class="button is-info"
+									@click="changeFilter()"
+								>
 									<i class="material-icons icon-with-button"
 										>search</i
 									>
@@ -119,80 +131,6 @@
 										<span>
 											{{ column.displayName }}
 										</span>
-										<tippy
-											v-if="column.filterable"
-											:touch="true"
-											:interactive="true"
-											placement="bottom"
-											theme="search"
-											ref="search"
-											trigger="click"
-										>
-											<i
-												class="
-													material-icons
-													action-dropdown-icon
-												"
-												:content="`Filter by ${column.displayName}`"
-												v-tippy
-												@click.prevent="true"
-												>search</i
-											>
-
-											<template #content>
-												<div
-													class="
-														control
-														is-grouped
-														input-with-button
-													"
-												>
-													<p
-														class="
-															control
-															is-expanded
-														"
-													>
-														<input
-															class="input"
-															type="text"
-															:placeholder="`Filter by ${column.displayName}`"
-															:value="
-																column.filterProperty !==
-																null
-																	? filter[
-																			column
-																				.filterProperty
-																	  ]
-																	: ''
-															"
-															@keyup.enter="
-																changeFilter(
-																	column,
-																	$event
-																)
-															"
-														/>
-													</p>
-													<p class="control">
-														<a
-															class="
-																button
-																is-info
-															"
-														>
-															<i
-																class="
-																	material-icons
-																	icon-with-button
-																"
-																>search</i
-															>
-														</a>
-													</p>
-												</div>
-											</template>
-										</tippy>
 										<span
 											v-if="column.sortable"
 											:content="`Sort by ${column.displayName}`"
@@ -354,8 +292,6 @@ export default {
 		properties: The properties this column needs to show data
 		sortable: Boolean for whether the order of a particular column can be changed 
 		sortProperty: The property the backend will sort on if this column gets sorted, e.g. title
-		filterable: Boolean for whether or not a column can use a filter
-		filterProperty: The property the backend will filter on, e.g. title
 		hidable: Boolean for whether a column can be hidden
 		defaultVisibility: Default visibility for a column, either "shown" or "hidden"
 		draggable: Boolean for whether a column can be dragged/reordered
@@ -364,6 +300,7 @@ export default {
 		maxWidth: Maximum width of column, e.g. 150px
 		*/
 		columns: { type: Array, default: null },
+		filters: { type: Array, default: null },
 		dataAction: { type: String, default: null }
 	},
 	data() {
@@ -388,8 +325,8 @@ export default {
 			},
 			advancedQuery: [
 				{
-					query: "",
-					column: ""
+					regex: "",
+					filter: {}
 				}
 			]
 		};
@@ -429,7 +366,6 @@ export default {
 				displayName: "",
 				properties: [],
 				sortable: false,
-				filterable: false,
 				hidable: false,
 				draggable: false
 			},
@@ -492,17 +428,17 @@ export default {
 				this.getData();
 			}
 		},
-		changeFilter(column, event) {
-			if (column.filterable) {
-				const { value } = event.target;
-				const { filterProperty } = column;
-				if (this.filter[filterProperty] !== undefined && value === "") {
-					delete this.filter[filterProperty];
-				} else if (this.filter[filterProperty] !== value) {
-					this.filter[filterProperty] = value;
-				} else return;
-				this.getData();
-			}
+		changeFilter() {
+			this.advancedQuery.forEach(query => {
+				const { regex } = query;
+				const { name } = query.filter;
+				if (this.filter[name] !== undefined && regex === "") {
+					delete this.filter[name];
+				} else if (this.filter[name] !== regex) {
+					this.filter[name] = regex;
+				}
+			});
+			this.getData();
 		},
 		toggleColumnVisibility(column) {
 			if (this.shownColumns.indexOf(column.name) !== -1) {
@@ -564,8 +500,8 @@ export default {
 		},
 		addQueryItem() {
 			this.advancedQuery.push({
-				query: "",
-				column: ""
+				regex: "",
+				filter: {}
 			});
 		},
 		removeQueryItem(index) {
@@ -737,4 +673,34 @@ export default {
 		}
 	}
 }
+
+.advanced-query {
+	display: flex;
+	margin-bottom: 5px;
+
+	& > .control {
+		& > input,
+		& > select,
+		& > .button {
+			border-radius: 0;
+		}
+		&:first-child {
+			& > input,
+			& > select,
+			& > .button {
+				border-radius: 5px 0 0 5px;
+			}
+		}
+		&:last-child {
+			& > input,
+			& > select,
+			& > .button {
+				border-radius: 0 5px 5px 0;
+			}
+		}
+		& > .button {
+			font-size: 22px;
+		}
+	}
+}
 </style>

+ 42 - 16
frontend/src/pages/Admin/tabs/Test.vue

@@ -2,7 +2,11 @@
 	<div>
 		<page-metadata title="Admin | Test" />
 		<div class="admin-container">
-			<advanced-table :columns="columns" data-action="songs.getData">
+			<advanced-table
+				:columns="columns"
+				:filters="filters"
+				data-action="songs.getData"
+			>
 				<template #column-thumbnailImage="slotProps">
 					<img
 						class="song-thumbnail"
@@ -66,7 +70,6 @@ export default {
 					displayName: "Thumb",
 					properties: ["thumbnail"],
 					sortable: false,
-					filterable: false,
 					hidable: true,
 					defaultVisibility: "shown",
 					width: "50px",
@@ -78,8 +81,6 @@ export default {
 					properties: ["_id"],
 					sortable: true,
 					sortProperty: "_id",
-					filterable: true,
-					filterProperty: "_id",
 					hidable: true,
 					defaultVisibility: "shown",
 					draggable: true
@@ -90,8 +91,6 @@ export default {
 					properties: ["youtubeId"],
 					sortable: true,
 					sortProperty: "youtubeId",
-					filterable: true,
-					filterProperty: "youtubeId",
 					hidable: true,
 					defaultVisibility: "shown",
 					draggable: true
@@ -102,8 +101,6 @@ export default {
 					properties: ["title"],
 					sortable: true,
 					sortProperty: "title",
-					filterable: true,
-					filterProperty: "title",
 					hidable: true,
 					defaultVisibility: "shown",
 					draggable: true
@@ -114,8 +111,6 @@ export default {
 					properties: ["artists"],
 					sortable: false,
 					sortProperty: "artists",
-					filterable: true,
-					filterProperty: "artists",
 					hidable: true,
 					defaultVisibility: "shown",
 					draggable: true
@@ -126,8 +121,6 @@ export default {
 					properties: ["genres"],
 					sortable: false,
 					sortProperty: "genres",
-					filterable: true,
-					filterProperty: "genres",
 					hidable: true,
 					defaultVisibility: "shown",
 					draggable: true
@@ -138,8 +131,6 @@ export default {
 					properties: ["thumbnail"],
 					sortable: true,
 					sortProperty: "thumbnail",
-					filterable: true,
-					filterProperty: "thumbnail",
 					hidable: true,
 					defaultVisibility: "hidden",
 					draggable: true
@@ -150,12 +141,47 @@ export default {
 					properties: ["requestedBy"],
 					sortable: true,
 					sortProperty: "requestedBy",
-					filterable: true,
-					filterProperty: "requestedBy",
 					hidable: true,
 					defaultVisibility: "shown",
 					draggable: true
 				}
+			],
+			filters: [
+				{
+					name: "_id",
+					displayName: "Musare ID",
+					type: "regex"
+				},
+				{
+					name: "youtubeId",
+					displayName: "YouTube ID",
+					type: "regex"
+				},
+				{
+					name: "title",
+					displayName: "Title",
+					type: "regex"
+				},
+				{
+					name: "artists",
+					displayName: "Artists",
+					type: "regex"
+				},
+				{
+					name: "genres",
+					displayName: "Genres",
+					type: "regex"
+				},
+				{
+					name: "thumbnailUrl",
+					displayName: "Thumbnail (URL)",
+					type: "regex"
+				},
+				{
+					name: "requestedBy",
+					displayName: "Requested By",
+					type: "regex"
+				}
 			]
 		};
 	},