feeds-fun 1.20.6 → 1.20.7
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/ConfigFlag.vue +7 -2
- package/src/components/ConfigSelector.vue +11 -2
- package/src/components/TokensCost.vue +2 -2
- package/src/components/UserSetting.vue +5 -5
- package/src/components/UserSettingForNotification.vue +4 -5
- package/src/components/notifications/Block.vue +8 -8
- package/src/components/side_pannel/CollapseButton.vue +8 -4
- package/src/css/inputs.css +1 -1
- package/src/layouts/SidePanelLayout.vue +6 -2
- package/src/logic/enums.ts +27 -10
- package/src/logic/types.ts +4 -4
- package/src/stores/entries.ts +14 -6
- package/src/stores/globalSettings.ts +196 -28
- package/src/views/FeedsView.vue +1 -1
- package/src/views/NewsView.vue +1 -1
- package/src/views/PublicCollectionView.vue +3 -3
- package/src/views/RulesView.vue +1 -1
- package/src/views/SettingsView.vue +1 -1
package/package.json
CHANGED
|
@@ -2,13 +2,18 @@
|
|
|
2
2
|
<button
|
|
3
3
|
class="ffun-config-flag"
|
|
4
4
|
@click="emit('update:flag', !flag)">
|
|
5
|
-
<span v-if="
|
|
5
|
+
<span v-if="!flagDefined"> </span>
|
|
6
|
+
<span v-else-if="flag">{{ offText }}</span>
|
|
6
7
|
<span v-else>{{ onText }}</span>
|
|
7
8
|
</button>
|
|
8
9
|
</template>
|
|
9
10
|
|
|
10
11
|
<script setup lang="ts">
|
|
11
|
-
|
|
12
|
+
import {computed} from "vue";
|
|
13
|
+
|
|
14
|
+
const properties = defineProps<{flag: boolean | null; onText: string; offText: string}>();
|
|
15
|
+
|
|
16
|
+
const flagDefined = computed(() => properties.flag !== null && properties.flag !== undefined);
|
|
12
17
|
|
|
13
18
|
const emit = defineEmits(["update:flag"]);
|
|
14
19
|
</script>
|
|
@@ -2,19 +2,28 @@
|
|
|
2
2
|
<select
|
|
3
3
|
class="ffun-input"
|
|
4
4
|
@change="updateProperty($event)">
|
|
5
|
+
<option
|
|
6
|
+
v-if="!propertyDefined"
|
|
7
|
+
value=""
|
|
8
|
+
selected>
|
|
9
|
+
</option>
|
|
10
|
+
|
|
5
11
|
<option
|
|
6
12
|
v-for="[value, props] of values"
|
|
7
13
|
:value="value"
|
|
8
|
-
:selected="value === property">
|
|
14
|
+
:selected="value === property && propertyDefined">
|
|
9
15
|
{{ props.text }}
|
|
10
16
|
</option>
|
|
11
17
|
</select>
|
|
12
18
|
</template>
|
|
13
19
|
|
|
14
20
|
<script lang="ts" setup>
|
|
21
|
+
import {computed} from "vue";
|
|
15
22
|
import * as e from "@/logic/enums";
|
|
16
23
|
|
|
17
|
-
const properties = defineProps<{values: any; property: string}>();
|
|
24
|
+
const properties = defineProps<{values: any; property: string | null}>();
|
|
25
|
+
|
|
26
|
+
const propertyDefined = computed(() => properties.property !== null && properties.property !== undefined);
|
|
18
27
|
|
|
19
28
|
const emit = defineEmits(["update:property"]);
|
|
20
29
|
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
const k = 2;
|
|
30
30
|
|
|
31
31
|
const percents = computed(() => {
|
|
32
|
-
if (globalSettings.
|
|
32
|
+
if (!globalSettings.userSettingsPresent) {
|
|
33
33
|
return "—";
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const setting = globalSettings.
|
|
36
|
+
const setting = globalSettings.max_tokens_cost_in_month;
|
|
37
37
|
|
|
38
38
|
if (!setting) {
|
|
39
39
|
return "—";
|
|
@@ -68,11 +68,11 @@
|
|
|
68
68
|
return null;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
if (globalSettings.
|
|
71
|
+
if (!globalSettings.userSettingsPresent) {
|
|
72
72
|
return null;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
return globalSettings
|
|
75
|
+
return (globalSettings as any)[properties.kind];
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
const verboseValue = computed(() => {
|
|
@@ -98,13 +98,13 @@
|
|
|
98
98
|
return v;
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
function save() {
|
|
102
102
|
if (value.value === null) {
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
globalSettings.setUserSettings(properties.kind, value.value);
|
|
107
|
+
|
|
108
108
|
editing.value = false;
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
if (globalSettings.
|
|
30
|
+
if (!globalSettings.userSettingsPresent) {
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
return globalSettings
|
|
34
|
+
return (globalSettings as any)[properties.kind];
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
const text = computed(() => {
|
|
@@ -46,13 +46,12 @@
|
|
|
46
46
|
return setting.value.name;
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
function save() {
|
|
50
50
|
if (value.value === null) {
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
globalSettings.updateDataVersion();
|
|
54
|
+
globalSettings.setUserSettings(properties.kind, value.value);
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
async function updateFlag(newValue: any) {
|
|
@@ -27,18 +27,18 @@
|
|
|
27
27
|
|
|
28
28
|
const showApiKeyMessage = computed(() => {
|
|
29
29
|
return (
|
|
30
|
-
globalSettings.
|
|
31
|
-
!globalSettings.
|
|
32
|
-
!globalSettings.
|
|
33
|
-
!globalSettings.
|
|
30
|
+
globalSettings.userSettingsPresent &&
|
|
31
|
+
!globalSettings.openai_api_key?.value &&
|
|
32
|
+
!globalSettings.gemini_api_key?.value &&
|
|
33
|
+
!globalSettings.hide_message_about_setting_up_key?.value
|
|
34
34
|
);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
const showCollectionsNotification = computed(() => {
|
|
38
38
|
return (
|
|
39
39
|
properties.collectionsNotification_ &&
|
|
40
|
-
globalSettings.
|
|
41
|
-
!globalSettings.
|
|
40
|
+
globalSettings.userSettingsPresent &&
|
|
41
|
+
!globalSettings.hide_message_about_adding_collections?.value &&
|
|
42
42
|
!tagsStates?.value.hasSelectedTags &&
|
|
43
43
|
settings.hasCollections
|
|
44
44
|
);
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
return (
|
|
62
62
|
properties.collectionsWarning_ &&
|
|
63
63
|
!showCollectionsNotification.value &&
|
|
64
|
-
globalSettings.
|
|
65
|
-
!globalSettings.
|
|
64
|
+
globalSettings.userSettingsPresent &&
|
|
65
|
+
!globalSettings.hide_message_check_your_feed_urls?.value
|
|
66
66
|
);
|
|
67
67
|
});
|
|
68
68
|
</script>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<a
|
|
3
3
|
href="#"
|
|
4
|
-
class="ffun-page-header-link py-2 flex items-center justify-center"
|
|
4
|
+
class="ffun-page-header-link py-2 flex items-center justify-center relative"
|
|
5
5
|
:title="title"
|
|
6
6
|
@click.prevent="onClick">
|
|
7
7
|
<icon
|
|
8
|
-
v-if="
|
|
8
|
+
v-if="showSidebar"
|
|
9
9
|
icon="sidebar-left-collapse"
|
|
10
10
|
size="large" />
|
|
11
11
|
<icon
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
<span
|
|
17
17
|
v-if="showPoint"
|
|
18
|
-
class="absolute top-
|
|
18
|
+
class="absolute top-1.5 right-1.5 h-2 w-2 rounded-full bg-red-500 border border-white"></span>
|
|
19
19
|
</a>
|
|
20
20
|
</template>
|
|
21
21
|
|
|
@@ -40,8 +40,12 @@
|
|
|
40
40
|
return globalSettings.showSidebar ? "Hide sidebar" : "Show sidebar";
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
const showSidebar = computed(() => {
|
|
44
|
+
return globalSettings.showSidebar || !globalSettings.userSettingsPresent;
|
|
45
|
+
});
|
|
46
|
+
|
|
43
47
|
const showPoint = computed(() => {
|
|
44
|
-
return !
|
|
48
|
+
return !showSidebar.value && globalSettings.showSidebarPoint;
|
|
45
49
|
});
|
|
46
50
|
|
|
47
51
|
function onClick() {
|
package/src/css/inputs.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="ffun-side-panel-layout">
|
|
3
3
|
<div
|
|
4
|
-
v-if="
|
|
4
|
+
v-if="showSidebar"
|
|
5
5
|
class="ffun-side-panel">
|
|
6
6
|
<div class="ffun-page-header pr-0 mr-0 flex min-w-full">
|
|
7
7
|
<div class="ffun-page-header-title grow">
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
<div class="ffun-body-panel">
|
|
54
54
|
<div class="ffun-page-header">
|
|
55
55
|
<div class="ffun-page-header-left-block">
|
|
56
|
-
<side-panel-collapse-button v-if="!
|
|
56
|
+
<side-panel-collapse-button v-if="!showSidebar" />
|
|
57
57
|
|
|
58
58
|
<page-header-home-button v-if="homeButton" />
|
|
59
59
|
|
|
@@ -162,6 +162,10 @@
|
|
|
162
162
|
return !!slots[`side-menu-item-${index}`];
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
const showSidebar = computed(() => {
|
|
166
|
+
return globalSettings.showSidebar || !globalSettings.userSettingsPresent;
|
|
167
|
+
});
|
|
168
|
+
|
|
165
169
|
watchEffect(() => {
|
|
166
170
|
if (!properties.loginRequired) {
|
|
167
171
|
return;
|
package/src/logic/enums.ts
CHANGED
|
@@ -57,6 +57,7 @@ export enum LastEntriesPeriod {
|
|
|
57
57
|
export type LastEntriesPeriodProperty = {
|
|
58
58
|
readonly text: string;
|
|
59
59
|
readonly seconds: number;
|
|
60
|
+
readonly default?: boolean;
|
|
60
61
|
};
|
|
61
62
|
|
|
62
63
|
// Map preserves the order of the keys
|
|
@@ -66,7 +67,7 @@ export const LastEntriesPeriodProperties = new Map<LastEntriesPeriod, LastEntrie
|
|
|
66
67
|
[LastEntriesPeriod.Hour6, {text: "6 hours", seconds: 6 * c.hour}],
|
|
67
68
|
[LastEntriesPeriod.Hour12, {text: "12 hours", seconds: 12 * c.hour}],
|
|
68
69
|
[LastEntriesPeriod.Day1, {text: "1 day", seconds: c.day}],
|
|
69
|
-
[LastEntriesPeriod.Day3, {text: "3 days", seconds: 3 * c.day}],
|
|
70
|
+
[LastEntriesPeriod.Day3, {text: "3 days", seconds: 3 * c.day, default: true}],
|
|
70
71
|
[LastEntriesPeriod.Week, {text: "1 week", seconds: c.week}],
|
|
71
72
|
[LastEntriesPeriod.Week2, {text: "2 weeks", seconds: 2 * c.week}],
|
|
72
73
|
[LastEntriesPeriod.Month1, {text: "1 month", seconds: c.month}],
|
|
@@ -83,7 +84,7 @@ export const LastEntriesPeriodProperties = new Map<LastEntriesPeriod, LastEntrie
|
|
|
83
84
|
export enum EntriesOrder {
|
|
84
85
|
Score = "score",
|
|
85
86
|
ScoreToZero = "score-to-zero",
|
|
86
|
-
ScoreBackward = "score-
|
|
87
|
+
ScoreBackward = "score-backward",
|
|
87
88
|
Published = "published",
|
|
88
89
|
Cataloged = "cataloged"
|
|
89
90
|
}
|
|
@@ -93,19 +94,20 @@ export type EntriesOrderProperty = {
|
|
|
93
94
|
readonly orderField: string;
|
|
94
95
|
readonly timeField: string;
|
|
95
96
|
readonly direction: number;
|
|
97
|
+
readonly default?: boolean;
|
|
96
98
|
};
|
|
97
99
|
|
|
98
100
|
export const EntriesOrderProperties = new Map<EntriesOrder, EntriesOrderProperty>([
|
|
99
|
-
[EntriesOrder.Score, {text: "score", orderField: "score", timeField: "catalogedAt", direction: 1}],
|
|
101
|
+
[EntriesOrder.Score, {text: "score", orderField: "score", timeField: "catalogedAt", direction: 1, default: true}],
|
|
100
102
|
[EntriesOrder.ScoreToZero, {text: "score ~ 0", orderField: "scoreToZero", timeField: "catalogedAt", direction: 1}],
|
|
101
103
|
[EntriesOrder.ScoreBackward, {text: "score backward", orderField: "score", timeField: "catalogedAt", direction: -1}],
|
|
102
104
|
[EntriesOrder.Published, {text: "published", orderField: "publishedAt", timeField: "publishedAt", direction: 1}],
|
|
103
105
|
[EntriesOrder.Cataloged, {text: "cataloged", orderField: "catalogedAt", timeField: "catalogedAt", direction: 1}]
|
|
104
106
|
]);
|
|
105
107
|
|
|
106
|
-
|
|
108
|
+
/////////////////////
|
|
107
109
|
// Min news tag count
|
|
108
|
-
|
|
110
|
+
/////////////////////
|
|
109
111
|
|
|
110
112
|
export enum MinNewsTagCount {
|
|
111
113
|
One = "one",
|
|
@@ -118,11 +120,12 @@ export enum MinNewsTagCount {
|
|
|
118
120
|
export type MinNewsTagCountProperty = {
|
|
119
121
|
readonly text: string;
|
|
120
122
|
readonly count: number;
|
|
123
|
+
readonly default?: boolean;
|
|
121
124
|
};
|
|
122
125
|
|
|
123
126
|
export const MinNewsTagCountProperties = new Map<MinNewsTagCount, MinNewsTagCountProperty>([
|
|
124
127
|
[MinNewsTagCount.One, {text: "all", count: 1}],
|
|
125
|
-
[MinNewsTagCount.Two, {text: "if in 2+ news", count: 2}],
|
|
128
|
+
[MinNewsTagCount.Two, {text: "if in 2+ news", count: 2, default: true}],
|
|
126
129
|
[MinNewsTagCount.Three, {text: "if in 3+ news", count: 3}],
|
|
127
130
|
[MinNewsTagCount.Four, {text: "if in 4+ news", count: 4}],
|
|
128
131
|
[MinNewsTagCount.Five, {text: "if in 5+ news", count: 5}]
|
|
@@ -151,8 +154,15 @@ export enum FeedsOrder {
|
|
|
151
154
|
Linked = "linked"
|
|
152
155
|
}
|
|
153
156
|
|
|
154
|
-
export
|
|
155
|
-
|
|
157
|
+
export type FeedsOrderProperty = {
|
|
158
|
+
readonly text: string;
|
|
159
|
+
readonly orderField: string;
|
|
160
|
+
readonly orderDirection: string;
|
|
161
|
+
readonly default?: boolean;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const FeedsOrderProperties = new Map<FeedsOrder, FeedsOrderProperty>([
|
|
165
|
+
[FeedsOrder.Title, {text: "title", orderField: "title", orderDirection: "asc", default: true}],
|
|
156
166
|
[FeedsOrder.Url, {text: "url", orderField: "url", orderDirection: "asc"}],
|
|
157
167
|
[FeedsOrder.Loaded, {text: "loaded", orderField: "loadedAt", orderDirection: "desc"}],
|
|
158
168
|
[FeedsOrder.Linked, {text: "added", orderField: "linkedAt", orderDirection: "desc"}]
|
|
@@ -169,8 +179,15 @@ export enum RulesOrder {
|
|
|
169
179
|
Updated = "updated"
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
export
|
|
173
|
-
|
|
182
|
+
export type RulesOrderProperty = {
|
|
183
|
+
readonly text: string;
|
|
184
|
+
readonly orderField: string;
|
|
185
|
+
readonly orderDirection: string;
|
|
186
|
+
readonly default?: boolean;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export const RulesOrderProperties = new Map<RulesOrder, RulesOrderProperty>([
|
|
190
|
+
[RulesOrder.Tags, {text: "tags", orderField: "tags", orderDirection: "asc", default: true}],
|
|
174
191
|
[RulesOrder.Score, {text: "score", orderField: "score", orderDirection: "desc"}],
|
|
175
192
|
[RulesOrder.Created, {text: "created", orderField: "createdAt", orderDirection: "desc"}],
|
|
176
193
|
[RulesOrder.Updated, {text: "updated", orderField: "updatedAt", orderDirection: "desc"}]
|
package/src/logic/types.ts
CHANGED
|
@@ -358,10 +358,12 @@ export function fakeTag({uid, name, link, categories}: TagInfo): TagInfo {
|
|
|
358
358
|
return {uid, name, link, categories};
|
|
359
359
|
}
|
|
360
360
|
|
|
361
|
+
export type UserSettingsValue = string | number | boolean;
|
|
362
|
+
|
|
361
363
|
export type UserSetting = {
|
|
362
364
|
readonly kind: string;
|
|
363
365
|
readonly type: string;
|
|
364
|
-
value:
|
|
366
|
+
value: UserSettingsValue;
|
|
365
367
|
readonly name: string;
|
|
366
368
|
};
|
|
367
369
|
|
|
@@ -369,14 +371,12 @@ export function userSettingFromJSON({
|
|
|
369
371
|
kind,
|
|
370
372
|
type,
|
|
371
373
|
value,
|
|
372
|
-
name
|
|
373
|
-
description
|
|
374
|
+
name
|
|
374
375
|
}: {
|
|
375
376
|
kind: string;
|
|
376
377
|
type: string;
|
|
377
378
|
value: string | number | boolean;
|
|
378
379
|
name: string;
|
|
379
|
-
description: string;
|
|
380
380
|
}): UserSetting {
|
|
381
381
|
return {
|
|
382
382
|
kind,
|
package/src/stores/entries.ts
CHANGED
|
@@ -52,14 +52,19 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
52
52
|
globalSettings.updateDataVersion();
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
const readyToLoadNews = computed(() => {
|
|
56
|
+
return (globalSettings.userSettingsPresent || !globalState.isLoggedIn) && mode.value !== null;
|
|
57
|
+
});
|
|
58
|
+
|
|
55
59
|
// Public collections uses fixed sorting order
|
|
56
60
|
// News uses dynamic sorting order and should keep it between switching views
|
|
57
61
|
// So, if we set globalSettings.entriesOrderProperties in PublicCollection view
|
|
58
62
|
// we'll break News view sorting and confuse users
|
|
59
63
|
// => we hardcode specific order properties for PublicCollection mode
|
|
60
64
|
const activeOrderProperties = computed(() => {
|
|
61
|
-
if (
|
|
62
|
-
//
|
|
65
|
+
if (!readyToLoadNews.value) {
|
|
66
|
+
// We can not load or process entries until everything is ready
|
|
67
|
+
// => Return most general order
|
|
63
68
|
return e.EntriesOrderProperties.get(e.EntriesOrder.Published) as unknown as e.EntriesOrderProperty;
|
|
64
69
|
}
|
|
65
70
|
|
|
@@ -106,7 +111,7 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
106
111
|
}
|
|
107
112
|
|
|
108
113
|
async function loadEntriesAccordingToMode() {
|
|
109
|
-
const periodProperties = e.LastEntriesPeriodProperties.get(globalSettings.lastEntriesPeriod);
|
|
114
|
+
const periodProperties = e.LastEntriesPeriodProperties.get(globalSettings.lastEntriesPeriod as any);
|
|
110
115
|
|
|
111
116
|
if (periodProperties === undefined) {
|
|
112
117
|
throw new Error(`Unknown period ${globalSettings.lastEntriesPeriod}`);
|
|
@@ -114,7 +119,7 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
114
119
|
|
|
115
120
|
const period = periodProperties.seconds;
|
|
116
121
|
|
|
117
|
-
const minTagCount = e.MinNewsTagCountProperties.get(globalSettings.minTagCount)?.count;
|
|
122
|
+
const minTagCount = e.MinNewsTagCountProperties.get(globalSettings.minTagCount as any)?.count;
|
|
118
123
|
|
|
119
124
|
if (minTagCount === undefined) {
|
|
120
125
|
throw new Error(`Unknown min tag count ${globalSettings.minTagCount}`);
|
|
@@ -142,8 +147,7 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
142
147
|
// force refresh
|
|
143
148
|
globalSettings.dataVersion;
|
|
144
149
|
|
|
145
|
-
if (
|
|
146
|
-
// Do nothing until the mode is set
|
|
150
|
+
if (!readyToLoadNews.value) {
|
|
147
151
|
return null;
|
|
148
152
|
}
|
|
149
153
|
|
|
@@ -164,6 +168,10 @@ export const useEntriesStore = defineStore("entriesStore", () => {
|
|
|
164
168
|
}, null);
|
|
165
169
|
|
|
166
170
|
const _sortedEntries = computed(() => {
|
|
171
|
+
if (!readyToLoadNews.value) {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
167
175
|
if (loadedEntriesReport.value === null) {
|
|
168
176
|
return [];
|
|
169
177
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import _ from "lodash";
|
|
1
2
|
import {ref, computed} from "vue";
|
|
2
3
|
import {defineStore} from "pinia";
|
|
3
4
|
import {computedAsync} from "@vueuse/core";
|
|
4
5
|
import {useGlobalState} from "@/stores/globalState";
|
|
5
6
|
|
|
6
7
|
import * as e from "@/logic/enums";
|
|
8
|
+
import * as t from "@/logic/types";
|
|
7
9
|
import * as api from "@/logic/api";
|
|
8
10
|
|
|
9
11
|
export const useGlobalSettingsStore = defineStore("globalSettings", () => {
|
|
@@ -12,33 +14,13 @@ export const useGlobalSettingsStore = defineStore("globalSettings", () => {
|
|
|
12
14
|
// General
|
|
13
15
|
const mainPanelMode = ref(e.MainPanelMode.Entries);
|
|
14
16
|
const dataVersion = ref(0);
|
|
15
|
-
const showSidebar = ref(true);
|
|
16
|
-
const showSidebarPoint = ref(false);
|
|
17
|
-
|
|
18
|
-
// Entries
|
|
19
|
-
const lastEntriesPeriod = ref(e.LastEntriesPeriod.Day3);
|
|
20
|
-
const entriesOrder = ref(e.EntriesOrder.Score);
|
|
21
|
-
const minTagCount = ref(e.MinNewsTagCount.Two);
|
|
22
|
-
const showRead = ref(true);
|
|
23
|
-
|
|
24
|
-
const entriesOrderProperties = computed(() => {
|
|
25
|
-
return e.EntriesOrderProperties.get(entriesOrder.value);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Feeds
|
|
29
|
-
const showFeedsDescriptions = ref(true);
|
|
30
|
-
const feedsOrder = ref(e.FeedsOrder.Title);
|
|
31
|
-
const failedFeedsFirst = ref(false);
|
|
32
|
-
|
|
33
|
-
// Rules
|
|
34
|
-
const rulesOrder = ref(e.RulesOrder.Tags);
|
|
35
17
|
|
|
36
18
|
function updateDataVersion() {
|
|
37
19
|
dataVersion.value++;
|
|
38
20
|
}
|
|
39
21
|
|
|
40
|
-
//
|
|
41
|
-
const
|
|
22
|
+
// TODO: We may want to remove this API and move user_id to the user settings API
|
|
23
|
+
const info = computedAsync(async () => {
|
|
42
24
|
if (!globalState.isLoggedIn) {
|
|
43
25
|
return null;
|
|
44
26
|
}
|
|
@@ -46,20 +28,195 @@ export const useGlobalSettingsStore = defineStore("globalSettings", () => {
|
|
|
46
28
|
// force refresh
|
|
47
29
|
dataVersion.value;
|
|
48
30
|
|
|
49
|
-
return await api.
|
|
31
|
+
return await api.getInfo();
|
|
50
32
|
}, null);
|
|
51
33
|
|
|
52
|
-
|
|
34
|
+
///////////////////////////////////////////////////////////
|
|
35
|
+
// Functionality for interaction with backend side settings
|
|
36
|
+
///////////////////////////////////////////////////////////
|
|
37
|
+
|
|
38
|
+
const _userSettings = computedAsync(async () => {
|
|
53
39
|
if (!globalState.isLoggedIn) {
|
|
54
40
|
return null;
|
|
55
41
|
}
|
|
56
42
|
|
|
57
|
-
// force refresh
|
|
58
43
|
dataVersion.value;
|
|
59
44
|
|
|
60
|
-
|
|
45
|
+
let settings = await api.getUserSettings();
|
|
46
|
+
|
|
47
|
+
settingsOverrides.value = {};
|
|
48
|
+
|
|
49
|
+
return settings;
|
|
61
50
|
}, null);
|
|
62
51
|
|
|
52
|
+
const userSettingsPresent = computed(() => {
|
|
53
|
+
return _userSettings.value !== null && _userSettings.value !== undefined;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
function userSettingInfo(kind: string) {
|
|
57
|
+
return computed(() => {
|
|
58
|
+
if (!_userSettings.value || !(kind in _userSettings.value)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const setting = _userSettings.value[kind];
|
|
63
|
+
|
|
64
|
+
let value = setting.value;
|
|
65
|
+
|
|
66
|
+
if (kind in settingsOverrides.value) {
|
|
67
|
+
value = settingsOverrides.value[kind];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
kind: setting.kind,
|
|
72
|
+
name: setting.name,
|
|
73
|
+
type: setting.type,
|
|
74
|
+
value: value
|
|
75
|
+
} as t.UserSetting;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function _backgroundSetUserSetting(kind: string, value: t.UserSettingsValue) {
|
|
80
|
+
api.setUserSetting({kind: kind, value: value}).catch((error) => {
|
|
81
|
+
console.error(`Error in API call setUserSetting for kind "${kind}":`, error);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// This dict is used for two purposes:
|
|
86
|
+
// - To store settings that anonymous user changes while using the site.
|
|
87
|
+
// - To close fast reactive loop after calling backendSettings.set.
|
|
88
|
+
// Without this, setting a setting will cause weired and complex chain
|
|
89
|
+
// of (re)loading data from the backend.
|
|
90
|
+
var settingsOverrides = ref<{[key in keyof any]: t.UserSettingsValue}>({});
|
|
91
|
+
|
|
92
|
+
function setUserSettings(kind: string, newValue: t.UserSettingsValue) {
|
|
93
|
+
settingsOverrides.value[kind] = newValue;
|
|
94
|
+
|
|
95
|
+
if (globalState.isLoggedIn) {
|
|
96
|
+
_backgroundSetUserSetting(kind, newValue);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (_userSettings.value) {
|
|
100
|
+
_userSettings.value[kind].value = newValue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// We do not call updateDataVersion() here
|
|
104
|
+
// Because it causes request of the user settings from the backen
|
|
105
|
+
// which is not required
|
|
106
|
+
// All reactive code should be triggered by changes in settingsOverrides
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function backendSettings(kind: string, validator: any, defaultValue: t.UserSettingsValue) {
|
|
110
|
+
return computed({
|
|
111
|
+
get() {
|
|
112
|
+
if (kind in settingsOverrides.value) {
|
|
113
|
+
return settingsOverrides.value[kind];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!globalState.isLoggedIn) {
|
|
117
|
+
return defaultValue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!_userSettings.value) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const setting = _userSettings.value[kind];
|
|
125
|
+
|
|
126
|
+
if (!validator(setting.value)) {
|
|
127
|
+
_backgroundSetUserSetting(kind, defaultValue);
|
|
128
|
+
return defaultValue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return setting.value;
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
set(newValue) {
|
|
135
|
+
if (newValue === null || newValue === undefined) {
|
|
136
|
+
console.warn(`Setting "${kind}" is set to null or undefined. This is not allowed.`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
setUserSettings(kind, newValue);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function boolBackendSettings(kind: string, defaultValue: t.UserSettingsValue) {
|
|
145
|
+
return backendSettings(
|
|
146
|
+
kind,
|
|
147
|
+
(rawValue: t.UserSettingsValue) => {
|
|
148
|
+
return typeof rawValue === "boolean";
|
|
149
|
+
},
|
|
150
|
+
defaultValue
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function enumBackendSettings(kind: string, enumProperties: any) {
|
|
155
|
+
const defaultEntry = _.find([...enumProperties], ([, prop]) => prop.default);
|
|
156
|
+
|
|
157
|
+
if (!defaultEntry) {
|
|
158
|
+
throw new Error(`No default entry found for enum "${kind}"`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let defaultValue = defaultEntry[0];
|
|
162
|
+
|
|
163
|
+
return backendSettings(
|
|
164
|
+
kind,
|
|
165
|
+
(rawValue: t.UserSettingsValue) => {
|
|
166
|
+
return enumProperties.has(rawValue);
|
|
167
|
+
},
|
|
168
|
+
defaultValue
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
///////////////////////
|
|
173
|
+
// News filter settings
|
|
174
|
+
///////////////////////
|
|
175
|
+
|
|
176
|
+
const lastEntriesPeriod = enumBackendSettings("view_news_filter_interval", e.LastEntriesPeriodProperties);
|
|
177
|
+
const entriesOrder = enumBackendSettings("view_news_filter_sort_by", e.EntriesOrderProperties);
|
|
178
|
+
const minTagCount = enumBackendSettings("view_news_filter_min_tags_count", e.MinNewsTagCountProperties);
|
|
179
|
+
const showRead = boolBackendSettings("view_news_filter_show_read", true);
|
|
180
|
+
|
|
181
|
+
const entriesOrderProperties = computed(() => {
|
|
182
|
+
return e.EntriesOrderProperties.get(entriesOrder.value as any);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
////////////////////////
|
|
186
|
+
// Feeds filter settings
|
|
187
|
+
////////////////////////
|
|
188
|
+
|
|
189
|
+
const showFeedsDescriptions = boolBackendSettings("view_feeds_show_feed_descriptions", true);
|
|
190
|
+
const feedsOrder = enumBackendSettings("view_feeds_feed_order", e.FeedsOrderProperties);
|
|
191
|
+
const failedFeedsFirst = boolBackendSettings("view_feeds_failed_feeds_first", false);
|
|
192
|
+
|
|
193
|
+
////////////////////////
|
|
194
|
+
// Rules filter settings
|
|
195
|
+
////////////////////////
|
|
196
|
+
|
|
197
|
+
const rulesOrder = enumBackendSettings("view_rules_order", e.RulesOrderProperties);
|
|
198
|
+
|
|
199
|
+
///////////////////
|
|
200
|
+
// Sidebar settings
|
|
201
|
+
///////////////////
|
|
202
|
+
|
|
203
|
+
const showSidebar = boolBackendSettings("show_sidebar", true);
|
|
204
|
+
const showSidebarPoint = ref(false);
|
|
205
|
+
|
|
206
|
+
////////////////
|
|
207
|
+
// User settings
|
|
208
|
+
////////////////
|
|
209
|
+
|
|
210
|
+
const hide_message_about_setting_up_key = userSettingInfo("hide_message_about_setting_up_key");
|
|
211
|
+
const hide_message_about_adding_collections = userSettingInfo("hide_message_about_adding_collections");
|
|
212
|
+
const hide_message_check_your_feed_urls = userSettingInfo("hide_message_check_your_feed_urls");
|
|
213
|
+
|
|
214
|
+
const openai_api_key = userSettingInfo("openai_api_key");
|
|
215
|
+
const gemini_api_key = userSettingInfo("gemini_api_key");
|
|
216
|
+
|
|
217
|
+
const max_tokens_cost_in_month = userSettingInfo("max_tokens_cost_in_month");
|
|
218
|
+
const process_entries_not_older_than = userSettingInfo("process_entries_not_older_than");
|
|
219
|
+
|
|
63
220
|
return {
|
|
64
221
|
mainPanelMode,
|
|
65
222
|
lastEntriesPeriod,
|
|
@@ -70,12 +227,23 @@ export const useGlobalSettingsStore = defineStore("globalSettings", () => {
|
|
|
70
227
|
dataVersion,
|
|
71
228
|
updateDataVersion,
|
|
72
229
|
showFeedsDescriptions,
|
|
73
|
-
|
|
230
|
+
userSettingsPresent,
|
|
74
231
|
info,
|
|
75
232
|
feedsOrder,
|
|
76
233
|
failedFeedsFirst,
|
|
77
234
|
rulesOrder,
|
|
78
235
|
showSidebar,
|
|
79
|
-
showSidebarPoint
|
|
236
|
+
showSidebarPoint,
|
|
237
|
+
setUserSettings,
|
|
238
|
+
|
|
239
|
+
hide_message_about_setting_up_key,
|
|
240
|
+
hide_message_about_adding_collections,
|
|
241
|
+
hide_message_check_your_feed_urls,
|
|
242
|
+
|
|
243
|
+
openai_api_key,
|
|
244
|
+
gemini_api_key,
|
|
245
|
+
|
|
246
|
+
max_tokens_cost_in_month,
|
|
247
|
+
process_entries_not_older_than
|
|
80
248
|
};
|
|
81
249
|
});
|
package/src/views/FeedsView.vue
CHANGED
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
return [];
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
const orderProperties = e.FeedsOrderProperties.get(globalSettings.feedsOrder);
|
|
83
|
+
const orderProperties = e.FeedsOrderProperties.get(globalSettings.feedsOrder as any);
|
|
84
84
|
|
|
85
85
|
if (!orderProperties) {
|
|
86
86
|
throw new Error(`Invalid order properties: ${globalSettings.feedsOrder}`);
|
package/src/views/NewsView.vue
CHANGED
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
|
|
65
65
|
<notifications-loaded-old-news
|
|
66
66
|
:entries="entriesStore.loadedEntriesReport || []"
|
|
67
|
-
:period="e.LastEntriesPeriodProperties.get(globalSettings.lastEntriesPeriod)" />
|
|
67
|
+
:period="e.LastEntriesPeriodProperties.get(globalSettings.lastEntriesPeriod as any)" />
|
|
68
68
|
|
|
69
69
|
<entries-list
|
|
70
70
|
:loading="entriesStore.loading"
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
|
|
87
87
|
<notifications-loaded-old-news
|
|
88
88
|
:entries="entriesStore.loadedEntriesReport || []"
|
|
89
|
-
:period="e.LastEntriesPeriodProperties.get(globalSettings.lastEntriesPeriod)" />
|
|
89
|
+
:period="e.LastEntriesPeriodProperties.get(globalSettings.lastEntriesPeriod as any)" />
|
|
90
90
|
|
|
91
91
|
<entries-list
|
|
92
92
|
:loading="entriesStore.loading"
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
|
|
199
199
|
const medianTag1: ComputedRef<string> = computed(() => {
|
|
200
200
|
// do not change tag when the filter changed
|
|
201
|
-
if (tagsStates.value.hasSelectedTags) {
|
|
201
|
+
if (tagsStates.value.hasSelectedTags && medianTag1.value) {
|
|
202
202
|
return medianTag1.value;
|
|
203
203
|
}
|
|
204
204
|
|
|
@@ -215,7 +215,7 @@
|
|
|
215
215
|
|
|
216
216
|
const medianTag2: ComputedRef<string> = computed(() => {
|
|
217
217
|
// do not change tag when the filter changed
|
|
218
|
-
if (tagsStates.value.hasSelectedTags) {
|
|
218
|
+
if (tagsStates.value.hasSelectedTags && medianTag2.value) {
|
|
219
219
|
return medianTag2.value;
|
|
220
220
|
}
|
|
221
221
|
|
package/src/views/RulesView.vue
CHANGED
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
|
|
93
93
|
sorted = tagsStates.value.filterByTags(sorted, (rule) => rule.tags);
|
|
94
94
|
|
|
95
|
-
const orderProperties = e.RulesOrderProperties.get(globalSettings.rulesOrder);
|
|
95
|
+
const orderProperties = e.RulesOrderProperties.get(globalSettings.rulesOrder as any);
|
|
96
96
|
|
|
97
97
|
if (!orderProperties) {
|
|
98
98
|
throw new Error(`Invalid order properties: ${globalSettings.rulesOrder}`);
|