diff --git a/api/config.go b/api/config.go index 9be9325..5297fef 100644 --- a/api/config.go +++ b/api/config.go @@ -65,7 +65,7 @@ func (a *API) updateConfig(c echo.Context) error { // @Summary Check Application Setup completed // @Tags config // @Accept json -// @Success 200 {object} map[string]bool +// @Success 200 {object} map[string]interface{} // @Router /api/config/setup [get] func (a *API) checkSetupCompleted(c echo.Context) error { cfg, err := a.db.GetCurrentConfig() @@ -73,8 +73,9 @@ func (a *API) checkSetupCompleted(c echo.Context) error { return echo.NewHTTPError(http.StatusInternalServerError, err) } - return c.JSON(http.StatusOK, map[string]bool{ - "status": cfg.SetupCompleted(), + return c.JSON(http.StatusOK, map[string]interface{}{ + "completed": cfg.SetupCompleted(), + "login_type": cfg.LoginType, }) } diff --git a/api/dashboard.go b/api/dashboard.go index 8bfba94..8d15f7d 100644 --- a/api/dashboard.go +++ b/api/dashboard.go @@ -213,7 +213,7 @@ func (a *API) createComponent(c echo.Context) error { type componentInput struct { Name string `json:"name" validate:"required" err:"name is required"` - Type models.ComponentType `json:"type" validate:"type" err:"name is required"` + Type models.ComponentType `json:"type" validate:"required" err:"name is required"` Configs interface{} `json:"configs"` Query string `json:"query" validate:"required" err:"query is required"` } diff --git a/api/docs/docs.go b/api/docs/docs.go index 3d026f5..c650308 100644 --- a/api/docs/docs.go +++ b/api/docs/docs.go @@ -329,9 +329,7 @@ const docTemplate = `{ "description": "OK", "schema": { "type": "object", - "additionalProperties": { - "type": "boolean" - } + "additionalProperties": true } } } diff --git a/api/docs/swagger.json b/api/docs/swagger.json index 5f6e0dd..efed493 100644 --- a/api/docs/swagger.json +++ b/api/docs/swagger.json @@ -318,9 +318,7 @@ "description": "OK", "schema": { "type": "object", - "additionalProperties": { - "type": "boolean" - } + "additionalProperties": true } } } diff --git a/api/docs/swagger.yaml b/api/docs/swagger.yaml index 789012e..c9b3a3b 100644 --- a/api/docs/swagger.yaml +++ b/api/docs/swagger.yaml @@ -711,8 +711,7 @@ paths: "200": description: OK schema: - additionalProperties: - type: boolean + additionalProperties: true type: object summary: Check Application Setup completed tags: diff --git a/ui/src/App.vue b/ui/src/App.vue index c3d168f..5b4e9a0 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -2,7 +2,7 @@
- +
@@ -11,6 +11,7 @@ import Toast from 'primevue/toast'; import ConfirmDialog from 'primevue/confirmdialog'; import AppHeader from './components/AppHeader.vue'; +import { useUserStore } from '@/store/user'; export default { components: { @@ -18,5 +19,15 @@ export default { Toast, ConfirmDialog, }, + setup() { + return { + user: useUserStore(), + }; + }, + computed: { + showHeader() { + return !['Login', 'Setup'].includes(this.$route.name); + }, + }, }; diff --git a/ui/src/components/AppHeader.vue b/ui/src/components/AppHeader.vue index c019533..49d66bd 100644 --- a/ui/src/components/AppHeader.vue +++ b/ui/src/components/AppHeader.vue @@ -6,7 +6,7 @@ diff --git a/ui/src/components/ComponentModal.vue b/ui/src/components/ComponentModal.vue index 8451e98..582e0ae 100644 --- a/ui/src/components/ComponentModal.vue +++ b/ui/src/components/ComponentModal.vue @@ -199,6 +199,10 @@ export default { type: Boolean, default: false, }, + accessToken: { + type: String, + required: true, + }, }, components: { Dialog, @@ -303,7 +307,8 @@ export default { this.$emit('set-loading', true); const task = await waitAsyncTask( - await runQuery({ + this.accessToken, + await runQuery(this.accessToken, { query: this.form.query, }) ); diff --git a/ui/src/pages/ActivitiesPage.vue b/ui/src/pages/ActivitiesPage.vue index a30b098..d193658 100644 --- a/ui/src/pages/ActivitiesPage.vue +++ b/ui/src/pages/ActivitiesPage.vue @@ -36,15 +36,15 @@ :style="{ width: '50rem' }" >
+ + To download GPX file, you need to logged in to with Strava +
@@ -63,8 +63,9 @@ import Skeleton from 'primevue/skeleton'; import VueJsonPretty from 'vue-json-pretty'; import Dialog from 'primevue/dialog'; import Button from 'primevue/button'; +import Message from 'primevue/message'; import { useHead } from '@unhead/vue'; -import { mapState } from 'pinia'; +import { useStravaStore } from '@/store/strava'; import { useUserStore } from '@/store/user'; export default { @@ -77,9 +78,15 @@ export default { Button, VueJsonPretty, Skeleton, + Message, }, setup() { useHead({ title: 'Activities' }); + + return { + strava: useStravaStore(), + user: useUserStore(), + }; }, data() { return { @@ -88,6 +95,7 @@ export default { currentPage: 1, count: 0, modal: { + loading: false, show: false, data: {}, }, @@ -96,9 +104,6 @@ export default { mounted() { this.fetch(); }, - computed: { - ...mapState(useUserStore, ['accessToken']), - }, methods: { athleteName(row) { return `${row.athlete.firstname} ${row.athlete.lastname}`; @@ -110,7 +115,10 @@ export default { async fetch() { try { this.loading = true; - const response = await fetchActivities(this.currentPage); + const response = await fetchActivities( + this.user.accessToken, + this.currentPage + ); this.activities = response.results; this.count = response.count; } catch (error) { @@ -121,11 +129,17 @@ export default { }, async downloadGPXFile() { try { - this.loading = true; - const fileName = `activity_${this.modal.data.id}.gpx`; + this.modal.loading = true; + + const blob = await getActivityGPX( + this.modal.data.id, + this.strava.accessToken, + this.user.accessToken + ); - const blob = await getActivityGPX(this.modal.data.id, this.accessToken); + const fileName = `activity_${this.modal.data.id}.gpx`; const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); link.href = url; link.setAttribute('download', fileName); @@ -135,7 +149,7 @@ export default { } catch (error) { this.onError(error); } finally { - this.loading = false; + this.modal.loading = false; } }, onError(err) { @@ -149,6 +163,7 @@ export default { onRowSelect(event) { this.modal.data = event.data; this.modal.show = true; + this.modal.loading = false; }, }, }; diff --git a/ui/src/pages/AthletesPage.vue b/ui/src/pages/AthletesPage.vue index e5a8533..387dfa3 100644 --- a/ui/src/pages/AthletesPage.vue +++ b/ui/src/pages/AthletesPage.vue @@ -49,6 +49,7 @@ import VueJsonPretty from 'vue-json-pretty'; import Dialog from 'primevue/dialog'; import { useHead } from '@unhead/vue'; import Skeleton from 'primevue/skeleton'; +import { useUserStore } from '@/store/user'; export default { name: 'AthletesPage', @@ -62,6 +63,10 @@ export default { }, setup() { useHead({ title: 'Athletes' }); + + return { + user: useUserStore(), + }; }, data() { return { @@ -86,7 +91,10 @@ export default { async fetch() { try { this.loading = true; - const response = await fetchAthletes(this.currentPage); + const response = await fetchAthletes( + this.user.accessToken, + this.currentPage + ); this.athletes = response.results; this.count = response.count; } catch (error) { diff --git a/ui/src/pages/DashboardDetail.vue b/ui/src/pages/DashboardDetail.vue index feff4fd..cdb04f1 100644 --- a/ui/src/pages/DashboardDetail.vue +++ b/ui/src/pages/DashboardDetail.vue @@ -47,6 +47,7 @@ :visible="modal.showComponent" :loading="modal.loading" :row="modal.form" + :access-token="user.accessToken" @save="onSaveComponent" @close="closeModal" @set-loading="(v) => (this.modal.loading = v)" @@ -77,6 +78,7 @@ import { useHead } from '@unhead/vue'; import ComponentGrid from '@/components/ComponentGrid'; import DashboardModal from '@/components/DashboardModal'; import ComponentModal from '@/components/ComponentModal'; +import { useUserStore } from '@/store/user'; export default { name: 'DashboardDetail', @@ -88,6 +90,13 @@ export default { DashboardModal, ComponentModal, }, + setup() { + useHead({ title: 'Dashboard' }); + + return { + user: useUserStore(), + }; + }, data() { return { componentTypes, @@ -145,10 +154,10 @@ export default { const dashId = this.$route.params.id; try { this.loading = true; - this.dashboard = await getDashboard(dashId); + this.dashboard = await getDashboard(this.user.accessToken, dashId); useHead({ title: this.dashboard.name }); - const resp = await fetchComponents(dashId); + const resp = await fetchComponents(this.user.accessToken, dashId); this.components = resp.results; } catch (error) { this.$router.push('/'); @@ -164,13 +173,21 @@ export default { try { this.loading = true; - const task = await waitAsyncTask(await runDashboard(this.dashboard.id)); - task.result.map((row) => { - const component = this.components.find((comp) => comp.id === row.id); - if (component) { - component.results = row.results; - } - }); + const task = await waitAsyncTask( + this.user.accessToken, + await runDashboard(this.user.accessToken, this.dashboard.id) + ); + + if (task.result) { + task.result.map((row) => { + const component = this.components.find( + (comp) => comp.id === row.id + ); + if (component) { + component.results = row.results; + } + }); + } } catch (error) { this.onError(error); } finally { @@ -189,7 +206,7 @@ export default { accept: async () => { try { this.loading = true; - await deleteDashboard(this.dashboard.id); + await deleteDashboard(this.user.accessToken, this.dashboard.id); this.$router.push('/'); } catch (error) { this.onError(error); @@ -203,7 +220,7 @@ export default { try { this.modal.loading = true; - await updateDashboard(this.dashboard.id, { + await updateDashboard(this.user.accessToken, this.dashboard.id, { name: form.name, }); @@ -233,9 +250,14 @@ export default { try { if (form.id) { - await updateComponent(this.dashboard.id, form.id, data); + await updateComponent( + this.user.accessToken, + this.dashboard.id, + form.id, + data + ); } else { - await createComponent(this.dashboard.id, data); + await createComponent(this.user.accessToken, this.dashboard.id, data); } this.$toast.add({ @@ -257,7 +279,12 @@ export default { comp.loading = true; const task = await waitAsyncTask( - await runComponent(this.dashboard.id, component.id) + this.user.accessToken, + await runComponent( + this.user.accessToken, + this.dashboard.id, + component.id + ) ); const cmp = this.components.find((comp) => comp.id === component.id); if (cmp) { @@ -285,7 +312,11 @@ export default { accept: async () => { try { this.loading = true; - await deleteComponent(this.dashboard.id, component.id); + await deleteComponent( + this.user.accessToken, + this.dashboard.id, + component.id + ); } catch (error) { this.onError(error); } finally { diff --git a/ui/src/pages/GearsPage.vue b/ui/src/pages/GearsPage.vue index fd3ab4c..88823cb 100644 --- a/ui/src/pages/GearsPage.vue +++ b/ui/src/pages/GearsPage.vue @@ -48,6 +48,7 @@ import Dialog from 'primevue/dialog'; import Skeleton from 'primevue/skeleton'; import VueJsonPretty from 'vue-json-pretty'; import { useHead } from '@unhead/vue'; +import { useUserStore } from '@/store/user'; export default { name: 'GearsPage', @@ -61,6 +62,10 @@ export default { }, setup() { useHead({ title: 'Gears' }); + + return { + user: useUserStore(), + }; }, data() { return { @@ -91,7 +96,10 @@ export default { async fetch() { try { this.loading = true; - const response = await fetchGears(this.currentPage); + const response = await fetchGears( + this.user.accessToken, + this.currentPage + ); this.gears = response.results; this.count = response.count; } catch (error) { diff --git a/ui/src/pages/HomePage.vue b/ui/src/pages/HomePage.vue index d3484ae..e2c7f33 100644 --- a/ui/src/pages/HomePage.vue +++ b/ui/src/pages/HomePage.vue @@ -49,6 +49,7 @@ import Column from 'primevue/column'; import Button from 'primevue/button'; import Skeleton from 'primevue/skeleton'; import DashboardModal from '@/components/DashboardModal'; +import { useUserStore } from '@/store/user'; export default { name: 'HomePage', @@ -61,6 +62,10 @@ export default { }, setup() { useHead({ title: 'Dashboard' }); + + return { + user: useUserStore(), + }; }, mounted() { this.fetch(); @@ -76,7 +81,7 @@ export default { async fetch() { try { this.loading = true; - const response = await fetchDashboards(); + const response = await fetchDashboards(this.user.accessToken); this.dashboards = response.results; } catch (error) { this.onError(error); @@ -86,9 +91,10 @@ export default { }, async onCreateDashboard(form) { try { - await createDashboard({ + await createDashboard(this.user.accessToken, { name: form.name, }); + this.$toast.add({ severity: 'success', summary: 'Success', diff --git a/ui/src/pages/LoginPage.vue b/ui/src/pages/LoginPage.vue index ebf0361..e14d845 100644 --- a/ui/src/pages/LoginPage.vue +++ b/ui/src/pages/LoginPage.vue @@ -1,82 +1,76 @@ + + diff --git a/ui/src/pages/SettingsPage.vue b/ui/src/pages/SettingsPage.vue index 2a150ff..49ffb3c 100644 --- a/ui/src/pages/SettingsPage.vue +++ b/ui/src/pages/SettingsPage.vue @@ -13,7 +13,7 @@