From 8b27f9cb9955f020bc8c8372bd502d7b8555358f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B5=A9=E8=BF=9C?= Date: Thu, 6 Aug 2020 16:39:27 +0800 Subject: [PATCH] import groups from service & fix freshrss --- .gitattributes | 3 +- dist/styles/main.css | 3 ++ src/components/settings.tsx | 10 ++++--- src/components/settings/groups.tsx | 30 ++++++++++++-------- src/components/settings/services/fever.tsx | 3 -- src/containers/settings/groups-container.tsx | 7 +++-- src/index.html | 2 +- src/schema-types.ts | 1 + src/scripts/i18n/en-US.json | 2 +- src/scripts/i18n/zh-CN.json | 2 +- src/scripts/models/service.ts | 12 ++++++++ src/scripts/models/services/fever.ts | 20 +++++++++---- 12 files changed, 65 insertions(+), 30 deletions(-) diff --git a/.gitattributes b/.gitattributes index 946ae51..b22e6d8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -dist/article/article.js text eol=lf \ No newline at end of file +dist/article/article.js text eol=lf +dist/article/mercury.web.js text eol=lf \ No newline at end of file diff --git a/dist/styles/main.css b/dist/styles/main.css index 72a7264..33f6890 100644 --- a/dist/styles/main.css +++ b/dist/styles/main.css @@ -96,6 +96,9 @@ div[role="tabpanel"] { .settings .loading .ms-Spinner { margin-top: 180px; } +.settings .loading .ms-Spinner:focus { + outline: none; +} .tab-body .ms-StackItem { margin-right: 6px; margin-bottom: 12px; diff --git a/src/components/settings.tsx b/src/components/settings.tsx index 7a67f46..3034fb4 100644 --- a/src/components/settings.tsx +++ b/src/components/settings.tsx @@ -3,7 +3,7 @@ import intl from "react-intl-universal" import { Icon } from "@fluentui/react/lib/Icon" import { AnimationClassNames } from "@fluentui/react/lib/Styling" import AboutTab from "./settings/about" -import { Pivot, PivotItem, Spinner } from "@fluentui/react" +import { Pivot, PivotItem, Spinner, FocusTrapZone } from "@fluentui/react" import SourcesTabContainer from "../containers/settings/sources-container" import GroupsTabContainer from "../containers/settings/groups-container" import AppTabContainer from "../containers/settings/app-container" @@ -30,9 +30,11 @@ class Settings extends React.Component {
- {this.props.blocked &&
- -
} + {this.props.blocked && ( + + + + )} diff --git a/src/components/settings/groups.tsx b/src/components/settings/groups.tsx index 135be72..e1ecc17 100644 --- a/src/components/settings/groups.tsx +++ b/src/components/settings/groups.tsx @@ -3,19 +3,20 @@ import intl from "react-intl-universal" import { SourceGroup } from "../../schema-types" import { SourceState, RSSSource } from "../../scripts/models/source" import { IColumn, Selection, SelectionMode, DetailsList, Label, Stack, - TextField, PrimaryButton, DefaultButton, Dropdown, IDropdownOption, CommandBarButton, MarqueeSelection, IDragDropEvents, MessageBar, MessageBarType } from "@fluentui/react" + TextField, PrimaryButton, DefaultButton, Dropdown, IDropdownOption, CommandBarButton, MarqueeSelection, IDragDropEvents, MessageBar, MessageBarType, MessageBarButton } from "@fluentui/react" import DangerButton from "../utils/danger-button" type GroupsTabProps = { - sources: SourceState, - groups: SourceGroup[], - serviceOn: boolean, - createGroup: (name: string) => void, - updateGroup: (group: SourceGroup) => void, - addToGroup: (groupIndex: number, sid: number) => void, - deleteGroup: (groupIndex: number) => void, - removeFromGroup: (groupIndex: number, sids: number[]) => void, + sources: SourceState + groups: SourceGroup[] + serviceOn: boolean + createGroup: (name: string) => void + updateGroup: (group: SourceGroup) => void + addToGroup: (groupIndex: number, sid: number) => void + deleteGroup: (groupIndex: number) => void + removeFromGroup: (groupIndex: number, sids: number[]) => void reorderGroups: (groups: SourceGroup[]) => void + importGroups: () => Promise } type GroupsTabState = { @@ -264,9 +265,6 @@ class GroupsTab extends React.Component { render = () => (
- {this.props.serviceOn && ( - {intl.get("service.groupsWarning")} - )} {this.state.manageGroup && this.state.selectedGroup && <> @@ -295,6 +293,14 @@ class GroupsTab extends React.Component { } {(!this.state.manageGroup || !this.state.selectedGroup) ?<> + {this.props.serviceOn && ( + }> + {intl.get("service.groupsWarning")} + + )}
diff --git a/src/components/settings/services/fever.tsx b/src/components/settings/services/fever.tsx index 5983ef2..3712157 100644 --- a/src/components/settings/services/fever.tsx +++ b/src/components/settings/services/fever.tsx @@ -98,9 +98,6 @@ class FeverConfigsTab extends React.Component{intl.get("service.overwriteWarning")} )} - {!this.state.existing && this.state.importGroups && ( - {intl.get("service.groupsWarning")} - )} diff --git a/src/containers/settings/groups-container.tsx b/src/containers/settings/groups-container.tsx index 174518e..5d9c8ae 100644 --- a/src/containers/settings/groups-container.tsx +++ b/src/containers/settings/groups-container.tsx @@ -5,6 +5,8 @@ import GroupsTab from "../../components/settings/groups" import { createSourceGroup, updateSourceGroup, addSourceToGroup, deleteSourceGroup, removeSourceFromGroup, reorderSourceGroups } from "../../scripts/models/group" import { SourceGroup, SyncService } from "../../schema-types" +import { importGroups } from "../../scripts/models/service" +import { AppDispatch } from "../../scripts/utils" const getSources = (state: RootState) => state.sources const getGroups = (state: RootState) => state.groups @@ -20,13 +22,14 @@ const mapStateToProps = createSelector( }) ) -const mapDispatchToProps = dispatch => ({ +const mapDispatchToProps = (dispatch: AppDispatch) => ({ createGroup: (name: string) => dispatch(createSourceGroup(name)), updateGroup: (group: SourceGroup) => dispatch(updateSourceGroup(group)), addToGroup: (groupIndex: number, sid: number) => dispatch(addSourceToGroup(groupIndex, sid)), deleteGroup: (groupIndex: number) => dispatch(deleteSourceGroup(groupIndex)), removeFromGroup: (groupIndex: number, sids: number[]) => dispatch(removeSourceFromGroup(groupIndex, sids)), - reorderGroups: (groups: SourceGroup[]) => dispatch(reorderSourceGroups(groups)) + reorderGroups: (groups: SourceGroup[]) => dispatch(reorderSourceGroups(groups)), + importGroups: () => dispatch(importGroups()), }) const GroupsTabContainer = connect(mapStateToProps, mapDispatchToProps)(GroupsTab) diff --git a/src/index.html b/src/index.html index e730066..b52da52 100644 --- a/src/index.html +++ b/src/index.html @@ -2,7 +2,7 @@ - + Fluent Reader diff --git a/src/schema-types.ts b/src/schema-types.ts index f33ee6c..4ce99aa 100644 --- a/src/schema-types.ts +++ b/src/schema-types.ts @@ -41,6 +41,7 @@ export const enum SyncService { } export interface ServiceConfigs { type: SyncService + importGroups?: boolean } export type SchemaTypes = { diff --git a/src/scripts/i18n/en-US.json b/src/scripts/i18n/en-US.json index d024366..696bfe4 100644 --- a/src/scripts/i18n/en-US.json +++ b/src/scripts/i18n/en-US.json @@ -185,7 +185,7 @@ "select": "Select a service", "suggest": "Suggest a new service", "overwriteWarning": "Local sources will be deleted if they exist in the service.", - "groupsWarning": "Groups are only imported on the first sync and will not stay synced.", + "groupsWarning": "Groups aren't automatically synced with the service.", "endpoint": "Endpoint", "username": "Username", "password": "Password", diff --git a/src/scripts/i18n/zh-CN.json b/src/scripts/i18n/zh-CN.json index 3f13761..cd6c312 100644 --- a/src/scripts/i18n/zh-CN.json +++ b/src/scripts/i18n/zh-CN.json @@ -183,7 +183,7 @@ "select": "选择服务", "suggest": "建议一项新服务", "overwriteWarning": "若本地与服务端存在URL相同的订阅源,则本地订阅源将被删除", - "groupsWarning": "分组仅在第一次同步时导入而不会与服务端保持同步", + "groupsWarning": "分组不会自动与服务端保持同步", "endpoint": "端点", "username": "用户名", "password": "密码", diff --git a/src/scripts/models/service.ts b/src/scripts/models/service.ts index e1e83c2..b54e9eb 100644 --- a/src/scripts/models/service.ts +++ b/src/scripts/models/service.ts @@ -61,6 +61,18 @@ export function syncWithService(background = false): AppThunk> { } } +export function importGroups(): AppThunk> { + return async (dispatch, getState) => { + const configs = getState().service + if (configs.type !== SyncService.None) { + dispatch(saveSettings()) + configs.importGroups = true + dispatch(saveServiceConfigs(configs)) + await dispatch(syncWithService()) + } + } +} + export function removeService(): AppThunk> { return async (dispatch, getState) => { dispatch(saveSettings()) diff --git a/src/scripts/models/services/fever.ts b/src/scripts/models/services/fever.ts index c93e3ee..940dca9 100644 --- a/src/scripts/models/services/fever.ts +++ b/src/scripts/models/services/fever.ts @@ -17,7 +17,7 @@ export interface FeverConfigs extends ServiceConfigs { apiKey: string fetchLimit: number lastId?: number - importGroups?: boolean + useInt32?: boolean } async function fetchAPI(configs: FeverConfigs, params="", postparams="") { @@ -150,14 +150,24 @@ export const feverServiceHooks: ServiceHooks = { const configs = state.service as FeverConfigs const items = new Array() configs.lastId = configs.lastId || 0 - let min = 2147483647 + let min = configs.useInt32 ? 2147483647 : Number.MAX_SAFE_INTEGER let response do { response = await fetchAPI(configs, `&items&max_id=${min}`) if (response.items === undefined) throw APIError() items.push(...response.items.filter(i => i.id > configs.lastId)) - min = response.items.reduce((m, n) => Math.min(m, n.id), min) - } while (min > configs.lastId && response.items.length >= 50 && items.length < configs.fetchLimit) + if (response.items.length === 0 && min === Number.MAX_SAFE_INTEGER) { + configs.useInt32 = true + min = 2147483647 + response = undefined + } else { + min = response.items.reduce((m, n) => Math.min(m, n.id), min) + } + } while ( + min > configs.lastId && + (response === undefined || response.items.length >= 50) && + items.length < configs.fetchLimit + ) configs.lastId = items.reduce((m, n) => Math.max(m, n.id), configs.lastId) if (items.length > 0) { const fidMap = new Map() @@ -178,7 +188,7 @@ export const feverServiceHooks: ServiceHooks = { snippet: htmlDecode(i.html).trim(), creator: i.author, hasRead: Boolean(i.is_read), - serviceRef: i.id + serviceRef: typeof i.id === "string" ? parseInt(i.id) : i.id, } as RSSItem if (i.is_saved) item.starred = true // Try to get the thumbnail of the item