add service warnings

This commit is contained in:
刘浩远 2020-08-02 14:03:40 +08:00
parent fc0183a80d
commit c35efa04ba
9 changed files with 89 additions and 42 deletions

View File

@ -109,6 +109,10 @@ i.ms-Nav-chevron {
.ms-ActivityItem-timeStamp {
color: var(--neutralSecondaryAlt);
}
.ms-MessageBar {
user-select: none;
margin-bottom: 8px;
}
#root > nav {
height: var(--navHeight);

View File

@ -3,12 +3,13 @@ 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 } from "@fluentui/react"
TextField, PrimaryButton, DefaultButton, Dropdown, IDropdownOption, CommandBarButton, MarqueeSelection, IDragDropEvents, MessageBar, MessageBarType } 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,
@ -263,6 +264,9 @@ class GroupsTab extends React.Component<GroupsTabProps, GroupsTabState> {
render = () => (
<div className="tab-body">
{this.props.serviceOn && (
<MessageBar messageBarType={MessageBarType.info}>{intl.get("service.groupsWarning")}</MessageBar>
)}
{this.state.manageGroup && this.state.selectedGroup &&
<>
<Stack horizontal horizontalAlign="space-between" style={{height: 40}}>

View File

@ -95,14 +95,12 @@ class FeverConfigsTab extends React.Component<ServiceConfigsTabProps, FeverConfi
render() {
return <>
<Stack tokens={{childrenGap: 8}}>
{!this.state.existing && (
<MessageBar messageBarType={MessageBarType.warning}>{intl.get("service.overwriteWarning")}</MessageBar>
)}
{!this.state.existing && this.state.importGroups && (
<MessageBar messageBarType={MessageBarType.info}>{intl.get("service.groupsWarning")}</MessageBar>
)}
</Stack>
{!this.state.existing && (
<MessageBar messageBarType={MessageBarType.warning}>{intl.get("service.overwriteWarning")}</MessageBar>
)}
{!this.state.existing && this.state.importGroups && (
<MessageBar messageBarType={MessageBarType.info}>{intl.get("service.groupsWarning")}</MessageBar>
)}
<Stack horizontalAlign="center" style={{marginTop: 48}}>
<Icon iconName="Calories" style={{fontSize: 32, userSelect: "none"}} />
<Label style={{margin: "8px 0 36px"}}>Fever API</Label>

View File

@ -1,13 +1,15 @@
import * as React from "react"
import intl from "react-intl-universal"
import { Label, DefaultButton, TextField, Stack, PrimaryButton, DetailsList,
IColumn, SelectionMode, Selection, IChoiceGroupOption, ChoiceGroup, IDropdownOption, Dropdown } from "@fluentui/react"
IColumn, SelectionMode, Selection, IChoiceGroupOption, ChoiceGroup, IDropdownOption,
Dropdown, MessageBar, MessageBarType } from "@fluentui/react"
import { SourceState, RSSSource, SourceOpenTarget } from "../../scripts/models/source"
import { urlTest } from "../../scripts/utils"
import DangerButton from "../utils/danger-button"
type SourcesTabProps = {
sources: SourceState
serviceOn: boolean
addSource: (url: string) => void
updateSourceName: (source: RSSSource, name: string) => void
updateSourceIcon: (source: RSSSource, iconUrl: string) => Promise<void>
@ -154,6 +156,9 @@ class SourcesTab extends React.Component<SourcesTabProps, SourcesTabState> {
render = () => (
<div className="tab-body">
{this.props.serviceOn && (
<MessageBar messageBarType={MessageBarType.info}>{intl.get("sources.serviceWarning")}</MessageBar>
)}
<Label>{intl.get("sources.opmlFile")}</Label>
<Stack horizontal>
<Stack.Item>
@ -196,6 +201,9 @@ class SourcesTab extends React.Component<SourcesTabProps, SourcesTabState> {
selectionMode={SelectionMode.multiple} />
{this.state.selectedSource && <>
{this.state.selectedSource.serviceRef && (
<MessageBar messageBarType={MessageBarType.info}>{intl.get("sources.serviceManaged")}</MessageBar>
)}
<Label>{intl.get("sources.selected")}</Label>
<Stack horizontal>
<Stack.Item>
@ -251,34 +259,39 @@ class SourcesTab extends React.Component<SourcesTabProps, SourcesTabState> {
</>}
</Stack>
<Label>{intl.get("sources.fetchFrequency")}</Label>
<Stack>
<Stack.Item>
<Dropdown
options={this.fetchFrequencyOptions()}
selectedKey={this.state.selectedSource.fetchFrequency ? String(this.state.selectedSource.fetchFrequency) : "0"}
onChange={this.onFetchFrequencyChange}
style={{width: 200}} />
</Stack.Item>
</Stack>
{!this.state.selectedSource.serviceRef && <>
<Label>{intl.get("sources.fetchFrequency")}</Label>
<Stack>
<Stack.Item>
<Dropdown
options={this.fetchFrequencyOptions()}
selectedKey={this.state.selectedSource.fetchFrequency ? String(this.state.selectedSource.fetchFrequency) : "0"}
onChange={this.onFetchFrequencyChange}
style={{width: 200}} />
</Stack.Item>
</Stack>
</>}
<ChoiceGroup
label={intl.get("sources.openTarget")}
options={this.sourceOpenTargetChoices()}
selectedKey={String(this.state.selectedSource.openTarget)}
onChange={this.onOpenTargetChange} />
<Stack horizontal>
<Stack.Item>
<DangerButton
onClick={() => this.props.deleteSource(this.state.selectedSource)}
key={this.state.selectedSource.sid}
text={intl.get("sources.delete")} />
</Stack.Item>
<Stack.Item>
<span className="settings-hint">{intl.get("sources.deleteWarning")}</span>
</Stack.Item>
</Stack>
{!this.state.selectedSource.serviceRef && (
<Stack horizontal>
<Stack.Item>
<DangerButton
onClick={() => this.props.deleteSource(this.state.selectedSource)}
key={this.state.selectedSource.sid}
text={intl.get("sources.delete")} />
</Stack.Item>
<Stack.Item>
<span className="settings-hint">{intl.get("sources.deleteWarning")}</span>
</Stack.Item>
</Stack>
)}
</>}
{this.state.selectedSources && <>
{this.state.selectedSources && (this.state.selectedSources.filter(s => s.serviceRef).length === 0
? <>
<Label>{intl.get("sources.selectedMulti")}</Label>
<Stack horizontal>
<Stack.Item>
@ -290,7 +303,10 @@ class SourcesTab extends React.Component<SourcesTabProps, SourcesTabState> {
<span className="settings-hint">{intl.get("sources.deleteWarning")}</span>
</Stack.Item>
</Stack>
</>}
</>
: (
<MessageBar messageBarType={MessageBarType.info}>{intl.get("sources.serviceManaged")}</MessageBar>
))}
</div>
)
}

View File

@ -4,16 +4,18 @@ import { RootState } from "../../scripts/reducer"
import GroupsTab from "../../components/settings/groups"
import { createSourceGroup, updateSourceGroup, addSourceToGroup,
deleteSourceGroup, removeSourceFromGroup, reorderSourceGroups } from "../../scripts/models/group"
import { SourceGroup } from "../../schema-types"
import { SourceGroup, SyncService } from "../../schema-types"
const getSources = (state: RootState) => state.sources
const getGroups = (state: RootState) => state.groups
const getServiceOn = (state: RootState) => state.service.type !== SyncService.None
const mapStateToProps = createSelector(
[getSources, getGroups],
(sources, groups) => ({
[getSources, getGroups, getServiceOn],
(sources, groups, serviceOn) => ({
sources: sources,
groups: groups.map((g, i) => ({ ...g, index: i })),
serviceOn: serviceOn,
key: groups.length
})
)

View File

@ -7,13 +7,16 @@ import { addSource, RSSSource, updateSource, deleteSource, SourceOpenTarget, del
import { importOPML, exportOPML } from "../../scripts/models/group"
import { AppDispatch, validateFavicon } from "../../scripts/utils"
import { saveSettings } from "../../scripts/models/app"
import { SyncService } from "../../schema-types"
const getSources = (state: RootState) => state.sources
const getServiceOn = (state: RootState) => state.service.type !== SyncService.None
const mapStateToProps = createSelector(
[getSources],
(sources) => ({
sources: sources
[getSources, getServiceOn],
(sources, serviceOn) => ({
sources: sources,
serviceOn: serviceOn
})
)

View File

@ -32,7 +32,8 @@
"fetchFailure": "Failed to load source \"{name}\".",
"fetchSuccess": "Successfully fetched {count, plural, =1 {# article} other {# articles}}.",
"networkError": "A network error has occurred.",
"parseError": "An error has occurred when parsing the XML feed."
"parseError": "An error has occurred when parsing the XML feed.",
"syncFailure": "Failed to sync with service"
},
"nav": {
"menu": "Menu",
@ -112,6 +113,8 @@
"feedback": "Feedback"
},
"sources": {
"serviceWarning": "Sources imported or added here will not be synced with your service.",
"serviceManaged": "This source is managed by your service.",
"untitled": "Source",
"errorAdd": "An error has occured when adding the source.",
"errorParse": "An error has occurred when parsing the OPML file.",

View File

@ -32,7 +32,8 @@
"fetchFailure": "无法加载订阅源“{name}”",
"fetchSuccess": "成功加载 {count} 篇文章",
"networkError": "连接订阅源时出错",
"parseError": "解析XML信息流时出错"
"parseError": "解析XML信息流时出错",
"syncFailure": "无法与服务同步"
},
"nav": {
"menu": "菜单",
@ -110,6 +111,8 @@
"feedback": "反馈"
},
"sources": {
"serviceWarning": "此处导入或添加的订阅源将不会与服务端同步",
"serviceManaged": "该订阅源由服务端管理",
"untitled": "订阅源",
"errorAdd": "添加订阅源时出错",
"errorParse": "解析OPML文件时出错",
@ -187,7 +190,7 @@
"fetchLimit": "同步数量",
"fetchLimitNum": "最近 {count} 篇文章",
"importGroups": "导入分组",
"failure": "无法连接到服务",
"failure": "连接到服务时出错",
"failureHint": "请检查服务配置或网络连接"
},
"app": {

View File

@ -356,6 +356,19 @@ export function appReducer(
...state,
syncing: true
}
case ActionStatus.Failure: return {
...state,
syncing: false,
logMenu: {
...state.logMenu,
notify: true,
logs: [...state.logMenu.logs, new AppLog(
AppLogType.Failure,
intl.get("log.syncFailure"),
String(action.err)
)]
}
}
default: return {
...state,
syncing: false
@ -467,6 +480,7 @@ export function appReducer(
settings: {
...state.settings,
display: true,
changed: true,
saving: !state.settings.saving
}
}