feeds-fun 1.20.3 → 1.20.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feeds-fun",
3
- "version": "1.20.3",
3
+ "version": "1.20.5",
4
4
  "author": "Aliaksei Yaletski (Tiendil) <a.eletsky@gmail.com> (https://tiendil.org/)",
5
5
  "description": "Frontend for the Feeds Fun — web-based news reader",
6
6
  "keywords": [
package/src/logic/api.ts CHANGED
@@ -71,10 +71,13 @@ export async function getFeeds() {
71
71
  return feeds;
72
72
  }
73
73
 
74
- export async function getLastEntries({period}: {period: number}) {
74
+ export async function getLastEntries({period, minTagCount}: {period: number; minTagCount: number}) {
75
75
  const response = await post({
76
76
  url: API_GET_LAST_ENTRIES,
77
- data: {period: period}
77
+ data: {
78
+ period: period,
79
+ minTagCount: minTagCount
80
+ }
78
81
  });
79
82
 
80
83
  const entries = [];
@@ -89,14 +92,16 @@ export async function getLastEntries({period}: {period: number}) {
89
92
 
90
93
  export async function getLastCollectionEntries({
91
94
  period,
92
- collectionSlug
95
+ collectionSlug,
96
+ minTagCount
93
97
  }: {
94
98
  period: number;
95
99
  collectionSlug: t.CollectionSlug | null;
100
+ minTagCount: number;
96
101
  }) {
97
102
  const response = await post({
98
103
  url: API_GET_LAST_COLLECTION_ENTRIES,
99
- data: {period: period, collectionSlug: collectionSlug}
104
+ data: {period: period, collectionSlug: collectionSlug, minTagCount: minTagCount}
100
105
  });
101
106
 
102
107
  const entries = [];
@@ -5,6 +5,10 @@ export type AnyEnum = {
5
5
  [key in keyof any]: string | number;
6
6
  };
7
7
 
8
+ ///////////////////
9
+ // Main panel modes
10
+ ///////////////////
11
+
8
12
  export enum MainPanelMode {
9
13
  Entries = "entries",
10
14
  Feeds = "feeds",
@@ -30,6 +34,10 @@ export const MainPanelModeProperties = new Map<MainPanelMode, MainPanelModePrope
30
34
  [MainPanelMode.Settings, {text: "Settings", showInMenu: true}]
31
35
  ]);
32
36
 
37
+ //////////////////////
38
+ // Last entries period
39
+ //////////////////////
40
+
33
41
  export enum LastEntriesPeriod {
34
42
  Hour1 = "hour1",
35
43
  Hour3 = "hour3",
@@ -68,6 +76,10 @@ export const LastEntriesPeriodProperties = new Map<LastEntriesPeriod, LastEntrie
68
76
  [LastEntriesPeriod.AllTime, {text: "all time", seconds: c.infinity}]
69
77
  ]);
70
78
 
79
+ ////////////////
80
+ // Entries order
81
+ ////////////////
82
+
71
83
  export enum EntriesOrder {
72
84
  Score = "score",
73
85
  ScoreToZero = "score-to-zero",
@@ -91,6 +103,35 @@ export const EntriesOrderProperties = new Map<EntriesOrder, EntriesOrderProperty
91
103
  [EntriesOrder.Cataloged, {text: "cataloged", orderField: "catalogedAt", timeField: "catalogedAt", direction: 1}]
92
104
  ]);
93
105
 
106
+ ////////////////
107
+ // Min news tag count
108
+ ////////////////
109
+
110
+ export enum MinNewsTagCount {
111
+ One = "one",
112
+ Two = "two",
113
+ Three = "three",
114
+ Four = "four",
115
+ Five = "five"
116
+ }
117
+
118
+ export type MinNewsTagCountProperty = {
119
+ readonly text: string;
120
+ readonly count: number;
121
+ };
122
+
123
+ export const MinNewsTagCountProperties = new Map<MinNewsTagCount, MinNewsTagCountProperty>([
124
+ [MinNewsTagCount.One, {text: "all", count: 1}],
125
+ [MinNewsTagCount.Two, {text: "if in 2+ news", count: 2}],
126
+ [MinNewsTagCount.Three, {text: "if in 3+ news", count: 3}],
127
+ [MinNewsTagCount.Four, {text: "if in 4+ news", count: 4}],
128
+ [MinNewsTagCount.Five, {text: "if in 5+ news", count: 5}]
129
+ ]);
130
+
131
+ /////////
132
+ // Marker
133
+ /////////
134
+
94
135
  export enum Marker {
95
136
  Read = "read"
96
137
  }
@@ -99,6 +140,10 @@ export const reverseMarker: {[key: string]: Marker} = {
99
140
  read: Marker.Read
100
141
  };
101
142
 
143
+ //////////////
144
+ // Feeds order
145
+ //////////////
146
+
102
147
  export enum FeedsOrder {
103
148
  Title = "title",
104
149
  Url = "url",
@@ -113,6 +158,10 @@ export const FeedsOrderProperties = new Map<FeedsOrder, {text: string; orderFiel
113
158
  [FeedsOrder.Linked, {text: "added", orderField: "linkedAt", orderDirection: "desc"}]
114
159
  ]);
115
160
 
161
+ //////////////
162
+ // Rules order
163
+ //////////////
164
+
116
165
  export enum RulesOrder {
117
166
  Tags = "tags",
118
167
  Score = "score",
@@ -124,7 +124,7 @@ export class Entry {
124
124
  readonly feedId: FeedId;
125
125
  readonly title: string;
126
126
  readonly url: URL;
127
- readonly tags: string[];
127
+ tags: string[];
128
128
  readonly markers: e.Marker[];
129
129
  readonly score: number;
130
130
  readonly scoreContributions: {[key: string]: number};
@@ -188,6 +188,10 @@ export class Entry {
188
188
  hasMarker(marker: e.Marker): boolean {
189
189
  return this.markers.includes(marker);
190
190
  }
191
+
192
+ hasTags(): boolean {
193
+ return this.tags.length > 0;
194
+ }
191
195
  }
192
196
 
193
197
  export function entryFromJSON(
@@ -80,18 +80,28 @@ export const useEntriesStore = defineStore("entriesStore", () => {
80
80
 
81
81
  // We bulk update entries to avoid performance degradation
82
82
  // on triggering multiple reactivity updates for each entry
83
- function registerEntries(newEntries: t.Entry[]) {
83
+ function registerEntries({newEntries, updateTags}: {newEntries: t.Entry[]; updateTags: boolean}) {
84
84
  let delta: {[key: t.EntryId]: t.Entry} = {};
85
85
 
86
86
  for (const entry of newEntries) {
87
87
  if (entry.id in entries.value) {
88
- if (entry.body === null && entries.value[entry.id].body !== null) {
89
- entry.body = entries.value[entry.id].body;
88
+ let existingEntry = entries.value[entry.id];
89
+
90
+ if (entry.body === null && existingEntry.body !== null) {
91
+ entry.body = existingEntry.body;
92
+ }
93
+
94
+ if (!updateTags) {
95
+ entry.tags = _.cloneDeep(existingEntry.tags);
90
96
  }
91
97
  }
92
98
  delta[entry.id] = entry;
93
99
  }
94
100
 
101
+ if (_.isEmpty(delta)) {
102
+ return;
103
+ }
104
+
95
105
  entries.value = {...entries.value, ...delta};
96
106
  }
97
107
 
@@ -104,16 +114,24 @@ export const useEntriesStore = defineStore("entriesStore", () => {
104
114
 
105
115
  const period = periodProperties.seconds;
106
116
 
117
+ const minTagCount = e.MinNewsTagCountProperties.get(globalSettings.minTagCount)?.count;
118
+
119
+ if (minTagCount === undefined) {
120
+ throw new Error(`Unknown min tag count ${globalSettings.minTagCount}`);
121
+ }
122
+
107
123
  if (mode.value === Mode.News) {
108
124
  return await api.getLastEntries({
109
- period: period
125
+ period: period,
126
+ minTagCount: minTagCount
110
127
  });
111
128
  }
112
129
 
113
130
  if (mode.value === Mode.PublicCollection) {
114
131
  return await api.getLastCollectionEntries({
115
132
  period: period,
116
- collectionSlug: modePublicCollectionSlug.value
133
+ collectionSlug: modePublicCollectionSlug.value,
134
+ minTagCount: minTagCount
117
135
  });
118
136
  }
119
137
 
@@ -133,7 +151,10 @@ export const useEntriesStore = defineStore("entriesStore", () => {
133
151
 
134
152
  const report = [];
135
153
 
136
- registerEntries(loadedEntries);
154
+ registerEntries({
155
+ newEntries: loadedEntries,
156
+ updateTags: true
157
+ });
137
158
 
138
159
  for (const entry of loadedEntries) {
139
160
  report.push(entry.id);
@@ -187,9 +208,16 @@ export const useEntriesStore = defineStore("entriesStore", () => {
187
208
  return;
188
209
  }
189
210
 
211
+ // We do not request tags for full entries
212
+ // Because we have no approach to control which tags to exclude because of minTagCount filter
213
+ // This method loads an additional info for a subset of entries
214
+ // => we have no clear tag statistics on the backend
190
215
  const loadedEntries = await api.getEntriesByIds({ids: ids});
191
216
 
192
- registerEntries(loadedEntries);
217
+ registerEntries({
218
+ newEntries: loadedEntries,
219
+ updateTags: false
220
+ });
193
221
 
194
222
  requestedEntries.value = {};
195
223
  }
@@ -18,6 +18,7 @@ export const useGlobalSettingsStore = defineStore("globalSettings", () => {
18
18
  // Entries
19
19
  const lastEntriesPeriod = ref(e.LastEntriesPeriod.Day3);
20
20
  const entriesOrder = ref(e.EntriesOrder.Score);
21
+ const minTagCount = ref(e.MinNewsTagCount.Two);
21
22
  const showRead = ref(true);
22
23
 
23
24
  const entriesOrderProperties = computed(() => {
@@ -63,6 +64,7 @@ export const useGlobalSettingsStore = defineStore("globalSettings", () => {
63
64
  mainPanelMode,
64
65
  lastEntriesPeriod,
65
66
  entriesOrder,
67
+ minTagCount,
66
68
  showRead,
67
69
  entriesOrderProperties,
68
70
  dataVersion,
@@ -18,6 +18,13 @@
18
18
  </template>
19
19
 
20
20
  <template #side-menu-item-3>
21
+ Show tags
22
+ <config-selector
23
+ :values="e.MinNewsTagCountProperties"
24
+ v-model:property="globalSettings.minTagCount" />
25
+ </template>
26
+
27
+ <template #side-menu-item-4>
21
28
  Show read
22
29
 
23
30
  <config-flag
@@ -23,6 +23,13 @@
23
23
  </template>
24
24
 
25
25
  <template #side-menu-item-3>
26
+ Show tags
27
+ <config-selector
28
+ :values="e.MinNewsTagCountProperties"
29
+ v-model:property="globalSettings.minTagCount" />
30
+ </template>
31
+
32
+ <template #side-menu-item-4>
26
33
  Show read
27
34
 
28
35
  <config-flag