From 3d7f0bba108b6a5549cc658379135fee8abfe557 Mon Sep 17 00:00:00 2001 From: Hamcha Date: Tue, 16 Jul 2019 16:04:43 +0200 Subject: [PATCH] Add axios and state --- package.json | 5 ++- src/App.vue | 35 +++++++++++++-------- src/assets/styles/theme.css | 2 ++ src/main.ts | 4 ++- src/plugins/axios.js | 61 +++++++++++++++++++++++++++++++++++++ src/store.ts | 10 ------ src/store/actions.ts | 19 ++++++++++++ src/store/getters.ts | 17 +++++++++++ src/store/index.ts | 20 ++++++++++++ src/store/mutations.ts | 20 ++++++++++++ src/store/types.ts | 25 +++++++++++++++ src/types.ts | 1 + yarn.lock | 37 ++++++++++++++++++++++ 13 files changed, 232 insertions(+), 24 deletions(-) create mode 100644 src/plugins/axios.js delete mode 100644 src/store.ts create mode 100644 src/store/actions.ts create mode 100644 src/store/getters.ts create mode 100644 src/store/index.ts create mode 100644 src/store/mutations.ts create mode 100644 src/store/types.ts create mode 100644 src/types.ts diff --git a/package.json b/package.json index 63b9df7..a03ce6e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "vue-class-component": "^7.0.2", "vue-property-decorator": "^8.1.0", "vue-router": "^3.0.3", - "vuex": "^3.0.1" + "vuex": "^3.0.1", + "vuex-class": "^0.3.2" }, "devDependencies": { "@vue/cli-plugin-babel": "^3.8.0", @@ -28,10 +29,12 @@ "@vue/cli-service": "^3.8.0", "@vue/eslint-config-prettier": "^4.0.1", "@vue/eslint-config-typescript": "^4.0.0", + "axios": "^0.18.0", "babel-eslint": "^10.0.1", "eslint": "^5.16.0", "eslint-plugin-vue": "^5.0.0", "typescript": "^3.4.3", + "vue-cli-plugin-axios": "^0.0.4", "vue-cli-plugin-tailwindcss": "^0.1.1", "vue-template-compiler": "^2.6.10" } diff --git a/src/App.vue b/src/App.vue index afdab39..f47b4d0 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,10 +1,12 @@ @@ -13,18 +15,27 @@ @import "assets/styles/theme"; #app { - display: flex; + @apply flex; +} + +#navwrap { + @apply flex flex-1 flex-row px-2 justify-center; + background: var(--ink); } #topnav { - flex: 1; - display: flex; - flex-direction: row; - background: $ink; + @apply flex flex-auto flex-row w-full; + max-width: var(--maxwidth); } h1 { - font-size: 18pt; - font-weight: bolder; + @apply text-2xl font-bold; } + + diff --git a/src/assets/styles/theme.css b/src/assets/styles/theme.css index 64809ed..6d828fd 100644 --- a/src/assets/styles/theme.css +++ b/src/assets/styles/theme.css @@ -3,6 +3,8 @@ --ink: #062f4f; --posy: #813772; --embers: #b82601; + + --maxwidth: 960px; } body { diff --git a/src/main.ts b/src/main.ts index e4c32b2..2714d90 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,11 @@ import Vue from "vue"; +import "./plugins/axios"; import App from "./App.vue"; import router from "./router"; -import store from "./store"; +import store from "./store/index"; import "./registerServiceWorker"; import "@/assets/styles/main.css"; +import "@/assets/styles/theme.css"; Vue.config.productionTip = false; diff --git a/src/plugins/axios.js b/src/plugins/axios.js new file mode 100644 index 0000000..04f5cd3 --- /dev/null +++ b/src/plugins/axios.js @@ -0,0 +1,61 @@ +"use strict"; + +import Vue from "vue"; +import axios from "axios"; + +// Full config: https://github.com/axios/axios#request-config +// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || ''; +// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; +// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; + +let config = { + // baseURL: process.env.baseURL || process.env.apiUrl || "" + // timeout: 60 * 1000, // Timeout + // withCredentials: true, // Check cross-site Access-Control +}; + +const _axios = axios.create(config); + +_axios.interceptors.request.use( + function(config) { + // Do something before request is sent + return config; + }, + function(error) { + // Do something with request error + return Promise.reject(error); + } +); + +// Add a response interceptor +_axios.interceptors.response.use( + function(response) { + // Do something with response data + return response; + }, + function(error) { + // Do something with response error + return Promise.reject(error); + } +); + +Plugin.install = function(Vue, options) { + Vue.axios = _axios; + window.axios = _axios; + Object.defineProperties(Vue.prototype, { + axios: { + get() { + return _axios; + } + }, + $axios: { + get() { + return _axios; + } + } + }); +}; + +Vue.use(Plugin); + +export default Plugin; diff --git a/src/store.ts b/src/store.ts deleted file mode 100644 index bb02ce2..0000000 --- a/src/store.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Vue from "vue"; -import Vuex from "vuex"; - -Vue.use(Vuex); - -export default new Vuex.Store({ - state: {}, - mutations: {}, - actions: {} -}); diff --git a/src/store/actions.ts b/src/store/actions.ts new file mode 100644 index 0000000..949171a --- /dev/null +++ b/src/store/actions.ts @@ -0,0 +1,19 @@ +import { ActionTree } from "vuex"; +import { AppState } from "./types"; + +const actions: ActionTree = { + // Add one or more sources + addSources({ commit, dispatch }, sources: EventSource[]) { + // Commit to state immediately + commit("appendSources", sources); + // Start fetching from each new source + sources.forEach(x => dispatch("fetchFromSource", x.url)); + }, + + // Fetch events from a source url + async fetchFromSource({ commit }, url: string) { + //TODO + } +}; + +export default actions; diff --git a/src/store/getters.ts b/src/store/getters.ts new file mode 100644 index 0000000..3ca1892 --- /dev/null +++ b/src/store/getters.ts @@ -0,0 +1,17 @@ +import { GetterTree } from "vuex"; +import { AppState, Event, EventSource } from "./types"; + +const getters: GetterTree = { + events(state): Event[] { + return Object.values(state.status) + .filter(x => x.fetched && x.error == null) + .map(x => x.events) + .flat(); + }, + + sources(state): EventSource[] { + return state.sources; + } +}; + +export default getters; diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 0000000..7bb6427 --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,20 @@ +import Vue from "vue"; +import Vuex from "vuex"; +import { AppState } from "./types"; +import mutations from "./mutations"; +import actions from "./actions"; +import getters from "./getters"; + +Vue.use(Vuex); + +const state: AppState = { + sources: [], + status: {} +}; + +export default new Vuex.Store({ + state, + mutations, + actions, + getters +}); diff --git a/src/store/mutations.ts b/src/store/mutations.ts new file mode 100644 index 0000000..51affd6 --- /dev/null +++ b/src/store/mutations.ts @@ -0,0 +1,20 @@ +import { MutationTree } from "vuex"; +import { AppState, FetchStatus, EventSource } from "./types"; + +const mutations: MutationTree = { + appendSources(state, payload: EventSource[]) { + // Add sources to list + state.sources = state.sources.concat(payload); + + // Set "loading" state for all of them + payload.forEach(x => { + state.status[x.url] = { fetched: false }; + }); + }, + + setSourceStatus(state, payload: { url: string; status: FetchStatus }) { + state.status[payload.url] = payload.status; + } +}; + +export default mutations; diff --git a/src/store/types.ts b/src/store/types.ts new file mode 100644 index 0000000..cf304e5 --- /dev/null +++ b/src/store/types.ts @@ -0,0 +1,25 @@ +import { Dict } from "@/types"; + +export interface AppState { + sources: EventSource[]; + status: Dict; +} + +export interface EventSource { + url: string; +} + +export interface Event { + source: string; // Source URL + data: EventData; +} + +export interface EventData { + //TODO +} + +export interface FetchStatus { + fetched: boolean; + error?: Error; + events?: Event[]; +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..48ca4ed --- /dev/null +++ b/src/types.ts @@ -0,0 +1 @@ +export type Dict = { [key: string]: T }; diff --git a/yarn.lock b/yarn.lock index 62bec56..1ebd4dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1548,6 +1548,14 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +axios@^0.18.0: + version "0.18.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3" + integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" + babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -2712,6 +2720,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" +debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + debug@^3.1.0, debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -3717,6 +3732,13 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + follow-redirects@^1.0.0: version "1.7.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" @@ -4520,6 +4542,11 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-buffer@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" + integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== + is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" @@ -8343,6 +8370,11 @@ vue-class-component@^7.0.1, vue-class-component@^7.0.2: resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.1.0.tgz#b33efcb10e17236d684f70b1e96f1946ec793e87" integrity sha512-G9152NzUkz0i0xTfhk0Afc8vzdXxDR1pfN4dTwE72cskkgJtdXfrKBkMfGvDuxUh35U500g5Ve4xL8PEGdWeHg== +vue-cli-plugin-axios@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vue-cli-plugin-axios/-/vue-cli-plugin-axios-0.0.4.tgz#29d4eb48275c7fe15b92e1fd5d95fbe2a966436f" + integrity sha512-p2b/fvPJuPBnvU8027PAAuU5DiOzUn2lku8XLG/f6c8FU0N+/MXWZAlOuHhqd9e7+KIZitwe/c8qlmv7TglbTg== + vue-cli-plugin-tailwindcss@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/vue-cli-plugin-tailwindcss/-/vue-cli-plugin-tailwindcss-0.1.1.tgz#e961e6f70a621fdbbf7b86b72cf065e7631d4c93" @@ -8427,6 +8459,11 @@ vue@^2.6.10: resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ== +vuex-class@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/vuex-class/-/vuex-class-0.3.2.tgz#c7e96a076c1682137d4d23a8dcfdc63f220e17a8" + integrity sha512-m0w7/FMsNcwJgunJeM+wcNaHzK2KX1K1rw2WUQf7Q16ndXHo7pflRyOV/E8795JO/7fstyjH3EgqBI4h4n4qXQ== + vuex@^3.0.1: version "3.1.1" resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.1.tgz#0c264bfe30cdbccf96ab9db3177d211828a5910e"