From 3ab1e9063838d46eb6b4e2613542de630dd4010b Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 22 Jun 2019 21:36:01 -0400 Subject: [PATCH] Add loading indicator --- music_graph/src/MusicGraph.js | 7 +- music_graph/src/MusicGraphApi.js | 82 +++++++++---------- music_graph/src/components/AlbumCarousel.vue | 4 +- music_graph/src/components/ArtistInfo.vue | 7 +- music_graph/src/components/HelloWorld.vue | 17 +++- music_graph/src/components/InputBar.vue | 5 +- .../src/components/LoadingIndicator.vue | 26 ++++++ 7 files changed, 87 insertions(+), 61 deletions(-) create mode 100644 music_graph/src/components/LoadingIndicator.vue diff --git a/music_graph/src/MusicGraph.js b/music_graph/src/MusicGraph.js index 6789338..21fb784 100644 --- a/music_graph/src/MusicGraph.js +++ b/music_graph/src/MusicGraph.js @@ -1,6 +1,5 @@ import * as d3 from 'd3' import icons from './icons' -import {MusicGraphApi} from './MusicGraphApi' import {fitCaptionIntoCircle} from './graphGeometry' // TODO: export somewhere else @@ -22,13 +21,13 @@ export function MusicGraph(data) { const width = window.innerWidth - 7 const height = window.innerHeight - 7 this._data = data + this.api = this._data.api this.nodeById = new Map() this.expandedNodes = new Set() this.nodes = [] this.links = [] this._originSet = false - this.api = new MusicGraphApi() this.simulation = d3.forceSimulation() .force('charge', d3.forceManyBody()) @@ -43,7 +42,9 @@ export function MusicGraph(data) { } this.dismiss = () => { - this.menu.remove() + if (this.menu) { + this.menu.remove() + } const menuNode = this.nodes.find(d => d.menu) if (menuNode !== undefined) { menuNode.menu = null diff --git a/music_graph/src/MusicGraphApi.js b/music_graph/src/MusicGraphApi.js index 7b01170..bd3c726 100644 --- a/music_graph/src/MusicGraphApi.js +++ b/music_graph/src/MusicGraphApi.js @@ -52,22 +52,33 @@ const nodeUtils = { } } -export function MusicGraphApi() { +export function MusicGraphApi(data) { this.url = window.location.protocol + '//' + window.location.hostname + '/api' + this._data = data + + let loadWrapper = (fn) => { + return (...args) => { + this._data.loading = true + return fn(...args).then(x => { + this._data.loading = false + return x + }) + } + } this.resolveCoverUrl = function (mbid) { return this.url + '/cover/' + mbid } - this.getArtistDetails = function (mbid) { + this.getArtistDetails = loadWrapper((mbid) => { return d3.json(this.url + '/artist/details/' + mbid) - } + }) /** * Works in both directions * @returns {Promise<{newNodes: *, relations: *} | never>} */ - this.getGroupMembers = function (mbid, originId) { + this.getGroupMembers = loadWrapper((mbid, originId) => { return d3.json(this.url + '/artist/members/' + mbid) .then((r) => { return { @@ -81,29 +92,9 @@ export function MusicGraphApi() { }) } }) - } + }) - this.getArtistReleases = function (mbid, originId) { - return d3.json(this.url + '/artist/details/' + mbid) - .then((r) => { - const newNodes = r.releases - .map(nodeUtils.fromRawDict) - .filter(release => release.type === 'Album') - - return { - newNodes: newNodes, - relations: newNodes.map(t => { - return { - source: originId, - target: t.id, - weight: 0.8 - } - }) - } - }) - } - - this.getArtistLabels = function (mbid, originId) { + this.getArtistLabels = loadWrapper((mbid, originId) => { return d3.json(this.url + '/artist/details/' + mbid) .then((r) => { const newNodes = r.labels @@ -124,25 +115,25 @@ export function MusicGraphApi() { }) } }) - } + }) - this._filterTags = function (tags) { + this._filterTags = loadWrapper((tags) => { if (ONLY_GENRE_TAGS) { return tags.filter(tag => genres.has(tag.name)) } else if (IGNORE_DATES_TAG) { return tags.filter(tag => isNaN(tag.name) && isNaN(tag.name.slice(0, -1))) } return tags - } + }) - this._addTagLabel = function (objects) { + this._addTagLabel = loadWrapper((objects) => { return objects.map(tag => { tag.labels = ['Tag'] return tag }) - } + }) - this.getArtistTags = function (mbid, originId) { + this.getArtistTags = loadWrapper((mbid, originId) => { return d3.json(this.url + '/artist/details/' + mbid) .then((r) => { const tags = this._filterTags(r.tags) @@ -158,9 +149,9 @@ export function MusicGraphApi() { }) } }) - } + }) - this.getRelatedTags = function (tagId) { + this.getRelatedTags = loadWrapper((tagId) => { return d3.json(this.url + '/tag/tag/' + tagId) .then((r) => { const tags = this._filterTags(r.tags) @@ -182,9 +173,9 @@ export function MusicGraphApi() { relations: directedRelations } }) - } + }) - this.getRelatedByMbid = function (mbid) { + this.getRelatedByMbid = loadWrapper((mbid) => { return d3.json(this.url + '/artist/related/' + mbid) .then((r) => { let node = nodeUtils.fromRawDict(r.artists.find(a => a.mbid === mbid)) @@ -207,9 +198,9 @@ export function MusicGraphApi() { relations: directedRelations } }) - } + }) - this.getRelatedByTag = function (tagid) { + this.getRelatedByTag = loadWrapper((tagid) => { return d3.json(this.url + '/tag/related/' + tagid) .then((r) => { return { @@ -229,9 +220,9 @@ export function MusicGraphApi() { }) } }) - } + }) - this.getReleaseDetails = function (mbid, originId) { + this.getReleaseDetails = loadWrapper((mbid, originId) => { return d3.json(this.url + '/release/details/' + mbid) .then((r) => { const tags = this._filterTags(r.tags) @@ -247,12 +238,13 @@ export function MusicGraphApi() { }) } }) - } + }) - this.autoComplete = function (prefix) { - prefix = prefix.replace(/[^\w.\-!?& ]/g, '_').toUpperCase() - prefix = prefix.replace(/ /g, '+') + this.autoComplete = loadWrapper((prefix) => { + prefix = prefix + .replace(/[^\w.\-!?& ]/g, '_').toUpperCase() + .replace(/ /g, '+') return d3.json(this.url + '/autocomplete/' + prefix) - } + }) } diff --git a/music_graph/src/components/AlbumCarousel.vue b/music_graph/src/components/AlbumCarousel.vue index 5aab18a..588eccd 100644 --- a/music_graph/src/components/AlbumCarousel.vue +++ b/music_graph/src/components/AlbumCarousel.vue @@ -26,14 +26,12 @@ + +