feeds-fun 1.11.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/DiscoveryForm.vue +5 -2
- package/src/components/FeedForList.vue +19 -7
- package/src/components/{OpenaiTokensUsage.vue → TokensCost.vue} +19 -9
- package/src/components/UserSettingForNotification.vue +1 -1
- package/src/components/collections/Block.vue +97 -0
- package/src/components/collections/BlockItem.vue +45 -0
- package/src/components/collections/DetailedItem.vue +115 -0
- package/src/components/collections/FeedItem.vue +62 -0
- package/src/components/collections/Notification.vue +11 -0
- package/src/components/collections/SubscribingProgress.vue +41 -0
- package/src/components/collections/Warning.vue +70 -0
- package/src/components/notifications/ApiKey.vue +42 -0
- package/src/components/notifications/Block.vue +61 -0
- package/src/components/{NotificationCreateRuleHelp.vue → notifications/CreateRuleHelp.vue} +2 -2
- package/src/layouts/SidePanelLayout.vue +38 -7
- package/src/logic/api.ts +31 -7
- package/src/logic/settings.ts +6 -0
- package/src/logic/types.ts +108 -11
- package/src/main.ts +26 -12
- package/src/stores/collections.ts +53 -0
- package/src/stores/feeds.ts +48 -0
- package/src/style.css +20 -10
- package/src/views/CollectionsView.vue +21 -4
- package/src/views/DiscoveryView.vue +6 -0
- package/src/views/FeedsView.vue +11 -12
- package/src/views/MainView.vue +7 -0
- package/src/views/NewsView.vue +3 -2
- package/src/views/SettingsView.vue +29 -21
- package/src/components/FeedsCollections.vue +0 -102
- package/src/components/NotificationCollections.vue +0 -7
- package/src/components/NotificationOpenaiApiKey.vue +0 -28
- package/src/components/Notifications.vue +0 -43
|
@@ -2,9 +2,20 @@
|
|
|
2
2
|
<side-panel-layout :reload-button="false">
|
|
3
3
|
<template #main-header> Collections </template>
|
|
4
4
|
|
|
5
|
-
<
|
|
5
|
+
<div class="ffun-info-attention">
|
|
6
|
+
<p
|
|
7
|
+
>We've prepared some ready-to-use thematic collections just for you. All the feeds in them are fully tagged
|
|
8
|
+
free of charge.</p
|
|
9
|
+
>
|
|
10
|
+
<p>Subscribe to some and enjoy the full power of Feeds Fun!</p>
|
|
11
|
+
</div>
|
|
6
12
|
|
|
7
|
-
<
|
|
13
|
+
<div
|
|
14
|
+
v-for="collectionId in collections.collectionsOrder"
|
|
15
|
+
:key="collectionId"
|
|
16
|
+
class="collection-block pb-4">
|
|
17
|
+
<collections-detailed-item :collectionId="collectionId" />
|
|
18
|
+
</div>
|
|
8
19
|
</side-panel-layout>
|
|
9
20
|
</template>
|
|
10
21
|
|
|
@@ -15,11 +26,17 @@
|
|
|
15
26
|
import * as t from "@/logic/types";
|
|
16
27
|
import * as e from "@/logic/enums";
|
|
17
28
|
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
18
|
-
import {
|
|
29
|
+
import {useCollectionsStore} from "@/stores/collections";
|
|
19
30
|
|
|
20
31
|
const globalSettings = useGlobalSettingsStore();
|
|
21
32
|
|
|
33
|
+
const collections = useCollectionsStore();
|
|
34
|
+
|
|
22
35
|
globalSettings.mainPanelMode = e.MainPanelMode.Collections;
|
|
23
36
|
</script>
|
|
24
37
|
|
|
25
|
-
<style
|
|
38
|
+
<style scoped>
|
|
39
|
+
.collection-block:not(:last-child) {
|
|
40
|
+
border-bottom-width: 1px;
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
<side-panel-layout :reload-button="false">
|
|
3
3
|
<template #main-header> Discovery </template>
|
|
4
4
|
|
|
5
|
+
<notifications
|
|
6
|
+
:create-rule-help="false"
|
|
7
|
+
:api-key="false"
|
|
8
|
+
:collections-notification_="false"
|
|
9
|
+
:collections-warning_="true" />
|
|
10
|
+
|
|
5
11
|
<h2>Lood feeds from an OPML file</h2>
|
|
6
12
|
|
|
7
13
|
<opml-upload />
|
package/src/views/FeedsView.vue
CHANGED
|
@@ -32,8 +32,10 @@
|
|
|
32
32
|
|
|
33
33
|
<notifications
|
|
34
34
|
v-if="sortedFeeds !== null"
|
|
35
|
-
:
|
|
36
|
-
:
|
|
35
|
+
:create-rule-help="false"
|
|
36
|
+
:api-key="false"
|
|
37
|
+
:collections-notification_="sortedFeeds === null || sortedFeeds.length == 0"
|
|
38
|
+
:collections-warning_="true" />
|
|
37
39
|
|
|
38
40
|
<feeds-list
|
|
39
41
|
v-if="sortedFeeds"
|
|
@@ -48,26 +50,23 @@
|
|
|
48
50
|
import {computed, ref, onUnmounted, watch} from "vue";
|
|
49
51
|
import {computedAsync} from "@vueuse/core";
|
|
50
52
|
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
53
|
+
import {useFeedsStore} from "@/stores/feeds";
|
|
51
54
|
import * as api from "@/logic/api";
|
|
52
55
|
import type * as t from "@/logic/types";
|
|
53
56
|
import * as e from "@/logic/enums";
|
|
54
57
|
|
|
55
58
|
const globalSettings = useGlobalSettingsStore();
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
const feedsStore = useFeedsStore();
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
// force refresh
|
|
61
|
-
globalSettings.dataVersion;
|
|
62
|
-
return await api.getFeeds();
|
|
63
|
-
}, null);
|
|
62
|
+
globalSettings.mainPanelMode = e.MainPanelMode.Feeds;
|
|
64
63
|
|
|
65
64
|
const sortedFeeds = computed(() => {
|
|
66
|
-
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
65
|
+
let sorted = Object.values(feedsStore.feeds);
|
|
69
66
|
|
|
70
|
-
|
|
67
|
+
if (sorted.length === 0) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
71
70
|
|
|
72
71
|
const orderProperties = e.FeedsOrderProperties.get(globalSettings.feedsOrder);
|
|
73
72
|
|
package/src/views/MainView.vue
CHANGED
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
<li>Filter and sort news how you want ⇒ read only what you want.</li>
|
|
19
19
|
</ul>
|
|
20
20
|
|
|
21
|
+
<h2>Curated collections of feeds</h2>
|
|
22
|
+
|
|
23
|
+
<ul class="list-disc list-inside text-left">
|
|
24
|
+
<li>We handpick the most interesting feeds into thematic collections.</li>
|
|
25
|
+
<li>Feeds in the collections are tagged for free.</li>
|
|
26
|
+
</ul>
|
|
27
|
+
|
|
21
28
|
<h2>You are in control</h2>
|
|
22
29
|
|
|
23
30
|
<ul class="list-disc list-inside text-left">
|
package/src/views/NewsView.vue
CHANGED
|
@@ -48,8 +48,9 @@
|
|
|
48
48
|
<notifications
|
|
49
49
|
v-if="entriesStore.loadedEntriesReport !== null"
|
|
50
50
|
:create-rule-help="hasEntries && !hasRules"
|
|
51
|
-
:
|
|
52
|
-
:collections="!hasEntries"
|
|
51
|
+
:api-key="true"
|
|
52
|
+
:collections-notification_="!hasEntries"
|
|
53
|
+
:collections-warning_="false" />
|
|
53
54
|
|
|
54
55
|
<entries-list
|
|
55
56
|
:entriesIds="entriesReport"
|
|
@@ -14,47 +14,44 @@
|
|
|
14
14
|
|
|
15
15
|
<hr />
|
|
16
16
|
|
|
17
|
-
<template v-for="
|
|
17
|
+
<template v-for="kind of settingsOrder">
|
|
18
18
|
<user-setting :kind="kind" />
|
|
19
19
|
<hr />
|
|
20
20
|
</template>
|
|
21
21
|
|
|
22
|
-
<
|
|
22
|
+
<h3>API usage</h3>
|
|
23
23
|
|
|
24
|
-
<p>
|
|
24
|
+
<p>Estimated tokens cost for your API keys usage per month.</p>
|
|
25
25
|
|
|
26
26
|
<ul class="list-disc list-inside">
|
|
27
|
-
<li> <strong>Used
|
|
27
|
+
<li> <strong>Estimated Used USD</strong> — the estimated cost of tokens in processed requests. </li>
|
|
28
28
|
<li>
|
|
29
|
-
<strong>Reserved
|
|
30
|
-
were not processed correctly.
|
|
31
|
-
</li>
|
|
32
|
-
<li>
|
|
33
|
-
<strong>Total tokens</strong> — the total number of tokens used in the month. Should be not less than the
|
|
34
|
-
actual used tokens, but can be bigger because we reserve more tokens than actually use.
|
|
29
|
+
<strong>Estimated Reserved USD</strong> — the estimated cost of tokens reserved for requests that currently are
|
|
30
|
+
processing or were not processed correctly.
|
|
35
31
|
</li>
|
|
32
|
+
<li> <strong>Estimated Total USD</strong> — the estimated total cost of tokens used in the month. </li>
|
|
36
33
|
</ul>
|
|
37
34
|
|
|
38
|
-
<p v-if="
|
|
35
|
+
<p v-if="tokensCostData == null">Loading...</p>
|
|
39
36
|
|
|
40
37
|
<table
|
|
41
38
|
v-else
|
|
42
39
|
class="border border-gray-300 rounded-lg">
|
|
43
40
|
<thead class="bg-slate-200">
|
|
44
41
|
<tr>
|
|
45
|
-
<th class="
|
|
46
|
-
<th class="
|
|
47
|
-
<th class="
|
|
48
|
-
<th class="
|
|
49
|
-
<th class="
|
|
42
|
+
<th class="w-32">Period</th>
|
|
43
|
+
<th class="w-48">Estimated Used USD </th>
|
|
44
|
+
<th class="w-48">Estimated Reserved USD</th>
|
|
45
|
+
<th class="w-48">Estimated Total USD</th>
|
|
46
|
+
<th class="w-48">% From Maximum</th>
|
|
50
47
|
</tr>
|
|
51
48
|
</thead>
|
|
52
49
|
<tbody>
|
|
53
|
-
<
|
|
50
|
+
<tokens-cost
|
|
54
51
|
:usage="usage"
|
|
55
|
-
v-for="usage of
|
|
52
|
+
v-for="usage of tokensCostData" />
|
|
56
53
|
|
|
57
|
-
<tr v-if="
|
|
54
|
+
<tr v-if="tokensCostData.length == 0">
|
|
58
55
|
<td class="text-center">—</td>
|
|
59
56
|
<td class="text-center">—</td>
|
|
60
57
|
<td class="text-center">—</td>
|
|
@@ -78,8 +75,8 @@
|
|
|
78
75
|
|
|
79
76
|
globalSettings.mainPanelMode = e.MainPanelMode.Settings;
|
|
80
77
|
|
|
81
|
-
const
|
|
82
|
-
return await api.getResourceHistory({kind: "
|
|
78
|
+
const tokensCostData = computedAsync(async () => {
|
|
79
|
+
return await api.getResourceHistory({kind: "tokens_cost"});
|
|
83
80
|
}, null);
|
|
84
81
|
|
|
85
82
|
const userId = computed(() => {
|
|
@@ -89,6 +86,17 @@
|
|
|
89
86
|
|
|
90
87
|
return globalSettings.info.userId;
|
|
91
88
|
});
|
|
89
|
+
|
|
90
|
+
// TODO: refactor, this is the temporary code to display settings in the right order
|
|
91
|
+
const settingsOrder = [
|
|
92
|
+
"openai_api_key",
|
|
93
|
+
"gemini_api_key",
|
|
94
|
+
"max_tokens_cost_in_month",
|
|
95
|
+
"process_entries_not_older_than",
|
|
96
|
+
"hide_message_about_setting_up_key",
|
|
97
|
+
"hide_message_about_adding_collections",
|
|
98
|
+
"hide_message_check_your_feed_urls"
|
|
99
|
+
];
|
|
92
100
|
</script>
|
|
93
101
|
|
|
94
102
|
<style></style>
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<form @submit.prevent="subscribe">
|
|
4
|
-
<ul class="mb-1">
|
|
5
|
-
<li v-for="item in collections">
|
|
6
|
-
<input
|
|
7
|
-
class="ffun-checkbox"
|
|
8
|
-
type="checkbox"
|
|
9
|
-
:id="item"
|
|
10
|
-
:name="item"
|
|
11
|
-
:value="item"
|
|
12
|
-
v-model="selectedCollections"
|
|
13
|
-
checked />
|
|
14
|
-
<label
|
|
15
|
-
class="ml-2"
|
|
16
|
-
:for="item"
|
|
17
|
-
>{{ item }}</label
|
|
18
|
-
>
|
|
19
|
-
</li>
|
|
20
|
-
</ul>
|
|
21
|
-
|
|
22
|
-
<button
|
|
23
|
-
type="submit"
|
|
24
|
-
class="ffun-form-button"
|
|
25
|
-
>Subscribe</button
|
|
26
|
-
>
|
|
27
|
-
</form>
|
|
28
|
-
|
|
29
|
-
<p
|
|
30
|
-
v-if="loading"
|
|
31
|
-
class="ffun-info-attention"
|
|
32
|
-
>subscribing...</p
|
|
33
|
-
>
|
|
34
|
-
|
|
35
|
-
<p
|
|
36
|
-
v-if="loaded"
|
|
37
|
-
class="ffun-info-good"
|
|
38
|
-
>Feeds added!</p
|
|
39
|
-
>
|
|
40
|
-
|
|
41
|
-
<p
|
|
42
|
-
v-if="error"
|
|
43
|
-
class="ffun-info-bad"
|
|
44
|
-
>Unknown error occurred! Please, try later.</p
|
|
45
|
-
>
|
|
46
|
-
</div>
|
|
47
|
-
</template>
|
|
48
|
-
|
|
49
|
-
<script lang="ts" setup>
|
|
50
|
-
import {computed, ref} from "vue";
|
|
51
|
-
import type * as t from "@/logic/types";
|
|
52
|
-
import * as e from "@/logic/enums";
|
|
53
|
-
import * as api from "@/logic/api";
|
|
54
|
-
import {computedAsync} from "@vueuse/core";
|
|
55
|
-
import DOMPurify from "dompurify";
|
|
56
|
-
import {useEntriesStore} from "@/stores/entries";
|
|
57
|
-
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
58
|
-
|
|
59
|
-
const loading = ref(false);
|
|
60
|
-
const loaded = ref(false);
|
|
61
|
-
const error = ref(false);
|
|
62
|
-
|
|
63
|
-
const selectedCollections = ref<t.FeedsCollectionId[]>([]);
|
|
64
|
-
|
|
65
|
-
const globalSettings = useGlobalSettingsStore();
|
|
66
|
-
|
|
67
|
-
const collections = computedAsync(async () => {
|
|
68
|
-
const collections = await api.getFeedsCollections();
|
|
69
|
-
|
|
70
|
-
for (const collectionId of collections) {
|
|
71
|
-
selectedCollections.value.push(collectionId);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return collections;
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
async function subscribe() {
|
|
78
|
-
loading.value = true;
|
|
79
|
-
loaded.value = false;
|
|
80
|
-
error.value = false;
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
await api.subscribeToFeedsCollections({
|
|
84
|
-
collectionsIds: selectedCollections.value
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
loading.value = false;
|
|
88
|
-
loaded.value = true;
|
|
89
|
-
error.value = false;
|
|
90
|
-
} catch (e) {
|
|
91
|
-
console.error(e);
|
|
92
|
-
|
|
93
|
-
loading.value = false;
|
|
94
|
-
loaded.value = false;
|
|
95
|
-
error.value = true;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
globalSettings.updateDataVersion();
|
|
99
|
-
}
|
|
100
|
-
</script>
|
|
101
|
-
|
|
102
|
-
<style scoped></style>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="ffun-info-attention">
|
|
3
|
-
<p>
|
|
4
|
-
Because, for now, our service is free to use and OpenAI API costs money, we politely ask you to set up your own
|
|
5
|
-
OpenAI API key.
|
|
6
|
-
</p>
|
|
7
|
-
<p>
|
|
8
|
-
You can do this on the
|
|
9
|
-
<a
|
|
10
|
-
href="#"
|
|
11
|
-
@click.prevent="router.push({name: e.MainPanelMode.Settings, params: {}})"
|
|
12
|
-
>settings</a
|
|
13
|
-
>
|
|
14
|
-
page.
|
|
15
|
-
</p>
|
|
16
|
-
|
|
17
|
-
<user-setting-for-notification
|
|
18
|
-
kind="openai_hide_message_about_setting_up_key"
|
|
19
|
-
button-text="Hide this message" />
|
|
20
|
-
</div>
|
|
21
|
-
</template>
|
|
22
|
-
|
|
23
|
-
<script lang="ts" setup>
|
|
24
|
-
import {useRouter} from "vue-router";
|
|
25
|
-
import * as e from "@/logic/enums";
|
|
26
|
-
|
|
27
|
-
const router = useRouter();
|
|
28
|
-
</script>
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<notification-openai-api-key v-if="showOpenAIKeyNotification" />
|
|
3
|
-
<notification-collections v-if="showCollectionsNotification" />
|
|
4
|
-
<notification-create-rule-help v-if="showCreateRuleHelpNotification" />
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script lang="ts" setup>
|
|
8
|
-
import {computed, ref, onUnmounted, watch} from "vue";
|
|
9
|
-
import {useGlobalSettingsStore} from "@/stores/globalSettings";
|
|
10
|
-
|
|
11
|
-
const properties = defineProps<{
|
|
12
|
-
openaiApiKey: boolean;
|
|
13
|
-
collections: boolean;
|
|
14
|
-
createRuleHelp: boolean;
|
|
15
|
-
}>();
|
|
16
|
-
|
|
17
|
-
const globalSettings = useGlobalSettingsStore();
|
|
18
|
-
|
|
19
|
-
const showApiKeyMessage = computed(() => {
|
|
20
|
-
return (
|
|
21
|
-
globalSettings.userSettings &&
|
|
22
|
-
!globalSettings.userSettings.openai_api_key.value &&
|
|
23
|
-
!globalSettings.userSettings.openai_hide_message_about_setting_up_key.value
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const showCollectionsNotification = computed(() => {
|
|
28
|
-
return properties.collections;
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const showCreateRuleHelpNotification = computed(() => {
|
|
32
|
-
return !showCollectionsNotification.value && properties.createRuleHelp;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const showOpenAIKeyNotification = computed(() => {
|
|
36
|
-
return (
|
|
37
|
-
!showCollectionsNotification.value &&
|
|
38
|
-
!showCreateRuleHelpNotification.value &&
|
|
39
|
-
properties.openaiApiKey &&
|
|
40
|
-
showApiKeyMessage.value
|
|
41
|
-
);
|
|
42
|
-
});
|
|
43
|
-
</script>
|