Actually get the feeds
This commit is contained in:
parent
3d7f0bba10
commit
8257347a09
|
@ -13,6 +13,7 @@
|
|||
"postcss-nested": "^4.1.2",
|
||||
"postcss-smart-import": "^0.7.6",
|
||||
"register-service-worker": "^1.6.2",
|
||||
"rss-parser": "^3.7.2",
|
||||
"tailwindcss": "^1.0.4",
|
||||
"vue": "^2.6.10",
|
||||
"vue-class-component": "^7.0.2",
|
||||
|
@ -22,6 +23,7 @@
|
|||
"vuex-class": "^0.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/xml2js": "^0.4.4",
|
||||
"@vue/cli-plugin-babel": "^3.8.0",
|
||||
"@vue/cli-plugin-eslint": "^3.8.0",
|
||||
"@vue/cli-plugin-pwa": "^3.8.0",
|
||||
|
|
22
src/components/EventList/EventCard.vue
Normal file
22
src/components/EventList/EventCard.vue
Normal file
|
@ -0,0 +1,22 @@
|
|||
<template>
|
||||
<div class="card">{{ event.data.guid }}</div>
|
||||
</template>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
.card {
|
||||
@apply p-2;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
import { FeedEvent } from "@/store/types";
|
||||
|
||||
@Component({
|
||||
components: {}
|
||||
})
|
||||
export default class EventCard extends Vue {
|
||||
@Prop()
|
||||
private event!: FeedEvent;
|
||||
}
|
||||
</script>
|
27
src/components/EventList/ListView.vue
Normal file
27
src/components/EventList/ListView.vue
Normal file
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<div class="list">
|
||||
<EventCard v-for="event in events" :key="event.data.guid" :event="event" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
.list {
|
||||
@apply p-2;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
import { Getter } from "vuex-class";
|
||||
import EventCard from "./EventCard.vue";
|
||||
import { FeedEvent } from "@/store/types";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
EventCard
|
||||
}
|
||||
})
|
||||
export default class ListView extends Vue {
|
||||
@Getter("events") private events!: FeedEvent[];
|
||||
}
|
||||
</script>
|
|
@ -1,9 +1,12 @@
|
|||
import { ActionTree } from "vuex";
|
||||
import { AppState } from "./types";
|
||||
import { AppState, EventFeed, FeedEvent } from "./types";
|
||||
import { toEvent } from "./feed";
|
||||
import Parser from "rss-parser";
|
||||
import { mustArray } from "@/utils";
|
||||
|
||||
const actions: ActionTree<AppState, AppState> = {
|
||||
// Add one or more sources
|
||||
addSources({ commit, dispatch }, sources: EventSource[]) {
|
||||
addSources({ commit, dispatch }, sources: EventFeed[]) {
|
||||
// Commit to state immediately
|
||||
commit("appendSources", sources);
|
||||
// Start fetching from each new source
|
||||
|
@ -12,7 +15,27 @@ const actions: ActionTree<AppState, AppState> = {
|
|||
|
||||
// Fetch events from a source url
|
||||
async fetchFromSource({ commit }, url: string) {
|
||||
//TODO
|
||||
try {
|
||||
const parser = new Parser();
|
||||
const feed = await parser.parseURL(url);
|
||||
// Parse events
|
||||
const events: FeedEvent[] = mustArray(feed.items)
|
||||
.map(toEvent)
|
||||
.map(x => ({
|
||||
source: url,
|
||||
data: x
|
||||
}));
|
||||
commit("setSourceStatus", {
|
||||
url,
|
||||
info: { title: feed.title, description: feed.description },
|
||||
status: { fetched: true, events }
|
||||
});
|
||||
} catch (e) {
|
||||
commit("setSourceStatus", {
|
||||
url,
|
||||
status: { fetched: true, error: e }
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
8
src/store/feed.ts
Normal file
8
src/store/feed.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { FeedEvent, FeedEventData } from "./types";
|
||||
import { Item } from "rss-parser";
|
||||
|
||||
export function toEvent(item: Item): FeedEventData {
|
||||
return {
|
||||
guid: item.guid || item.link || item.title || Math.random().toString(32)
|
||||
};
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
import { GetterTree } from "vuex";
|
||||
import { AppState, Event, EventSource } from "./types";
|
||||
import { AppState, FeedEvent, EventFeed } from "./types";
|
||||
|
||||
const getters: GetterTree<AppState, AppState> = {
|
||||
events(state): Event[] {
|
||||
events(state): FeedEvent[] {
|
||||
return Object.values(state.status)
|
||||
.filter(x => x.fetched && x.error == null)
|
||||
.map(x => x.events)
|
||||
.flat();
|
||||
},
|
||||
|
||||
sources(state): EventSource[] {
|
||||
sources(state): EventFeed[] {
|
||||
return state.sources;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { MutationTree } from "vuex";
|
||||
import { AppState, FetchStatus, EventSource } from "./types";
|
||||
import { AppState, FetchStatus, EventFeed, FeedInfo } from "./types";
|
||||
|
||||
const mutations: MutationTree<AppState> = {
|
||||
appendSources(state, payload: EventSource[]) {
|
||||
appendSources(state, payload: EventFeed[]) {
|
||||
// Add sources to list
|
||||
state.sources = state.sources.concat(payload);
|
||||
|
||||
|
@ -12,8 +12,17 @@ const mutations: MutationTree<AppState> = {
|
|||
});
|
||||
},
|
||||
|
||||
setSourceStatus(state, payload: { url: string; status: FetchStatus }) {
|
||||
setSourceStatus(
|
||||
state,
|
||||
payload: { url: string; info?: FeedInfo; status: FetchStatus }
|
||||
) {
|
||||
state.status[payload.url] = payload.status;
|
||||
if (payload.info) {
|
||||
let source = state.sources.find(x => x.url == payload.url);
|
||||
if (source) {
|
||||
source.info = payload.info;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
import { Dict } from "@/types";
|
||||
|
||||
export interface AppState {
|
||||
sources: EventSource[];
|
||||
sources: EventFeed[];
|
||||
status: Dict<FetchStatus>;
|
||||
}
|
||||
|
||||
export interface EventSource {
|
||||
export interface EventFeed {
|
||||
url: string;
|
||||
info?: FeedInfo;
|
||||
}
|
||||
|
||||
export interface Event {
|
||||
export interface FeedInfo {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface FeedEvent {
|
||||
source: string; // Source URL
|
||||
data: EventData;
|
||||
data: FeedEventData;
|
||||
}
|
||||
|
||||
export interface EventData {
|
||||
//TODO
|
||||
export interface FeedEventData {
|
||||
guid: string;
|
||||
}
|
||||
|
||||
export interface FetchStatus {
|
||||
|
|
13
src/utils.ts
Normal file
13
src/utils.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
export function must<T>(val?: T): T {
|
||||
if (val) {
|
||||
return val;
|
||||
}
|
||||
throw "must assertion failed";
|
||||
}
|
||||
|
||||
export function mustArray<T>(val?: T[]): T[] {
|
||||
if (val) {
|
||||
return val;
|
||||
}
|
||||
return [];
|
||||
}
|
|
@ -1,12 +1,17 @@
|
|||
<template>
|
||||
<div class="home"></div>
|
||||
<div class="home">
|
||||
<ListView />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
import ListView from "@/components/EventList/ListView.vue";
|
||||
|
||||
@Component({
|
||||
components: {}
|
||||
components: {
|
||||
ListView
|
||||
}
|
||||
})
|
||||
export default class Home extends Vue {}
|
||||
</script>
|
||||
|
|
30
yarn.lock
30
yarn.lock
|
@ -774,6 +774,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.9.tgz#a67287861c928ebf4159a908d1fb1a2a34d4097a"
|
||||
integrity sha512-p8zp5xqkly3g4cCmo2mKOHI9+Z/kObmDj0BmjbDDJQlgDTiEGTbm17MEwTAusV6XceCy+bNw9q/ZHXHyKo3zkg==
|
||||
|
||||
"@types/xml2js@^0.4.4":
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.4.tgz#2093d94359a201806d997dccefc80153db311c66"
|
||||
integrity sha512-O6Xgai01b9PB3IGA0lRIp1Ex3JBcxGDhdO0n3NIIpCyDOAjxcIGQFmkvgJpP8anTrthxOUQjBfLdRRi0Zn/TXA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^1.1.0":
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.11.0.tgz#870f752c520db04db6d3668af7479026a6f2fb9a"
|
||||
|
@ -7149,6 +7156,14 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
|||
hash-base "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
|
||||
rss-parser@^3.7.2:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/rss-parser/-/rss-parser-3.7.2.tgz#9f5b7d4944d4f7a190b469e31a8353aedb17c052"
|
||||
integrity sha512-kx0VIFelgwBk5qA4n32U6cx40anAU7TwlRXjyxLDFgMlg8/UcJ64x+Hj5oRX1Kjos+OeFGOmnd5YXH5ES+bmzg==
|
||||
dependencies:
|
||||
entities "^1.1.1"
|
||||
xml2js "^0.4.19"
|
||||
|
||||
run-async@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
|
||||
|
@ -7199,7 +7214,7 @@ safe-regex@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
sax@^1.2.4, sax@~1.2.4:
|
||||
sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
@ -8834,6 +8849,19 @@ ws@^6.0.0:
|
|||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
xml2js@^0.4.19:
|
||||
version "0.4.19"
|
||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
|
||||
integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==
|
||||
dependencies:
|
||||
sax ">=0.6.0"
|
||||
xmlbuilder "~9.0.1"
|
||||
|
||||
xmlbuilder@~9.0.1:
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
|
||||
integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
|
||||
|
||||
xtend@^4.0.0, xtend@~4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
|
|
Loading…
Reference in New Issue
Block a user