mirror of
https://github.com/urbit/shrub.git
synced 2024-12-19 16:51:42 +03:00
Merge pull request #4845 from urbit/m/version-notification
landscape: version negotiation notification
This commit is contained in:
commit
b9d73e693b
@ -191,9 +191,14 @@
|
||||
^- (unit (unit cage))
|
||||
?. (team:title our.bowl src.bowl) ~
|
||||
?+ path [~ ~]
|
||||
[%x %tiles ~] ``noun+!>([tiles tile-ordering])
|
||||
[%x %first-time ~] ``noun+!>(first-time)
|
||||
[%x %keys ~] ``noun+!>(~(key by tiles))
|
||||
[%x %tiles ~] ``noun+!>([tiles tile-ordering])
|
||||
[%x %first-time ~] ``noun+!>(first-time)
|
||||
[%x %keys ~] ``noun+!>(~(key by tiles))
|
||||
::
|
||||
[%x %runtime-lag ~]
|
||||
:^ ~ ~ %json
|
||||
!> ^- json
|
||||
b+.^(? //(scot %p our.bowl)//(scot %da now.bowl)/zen/lag)
|
||||
==
|
||||
::
|
||||
++ on-arvo
|
||||
|
@ -8,6 +8,12 @@ export default class LocalApi extends BaseApi<StoreState> {
|
||||
});
|
||||
}
|
||||
|
||||
getRuntimeLag() {
|
||||
return this.scry<boolean>('launch', '/runtime-lag').then((runtimeLag) => {
|
||||
this.store.handleEvent({ data: { runtimeLag } });
|
||||
});
|
||||
}
|
||||
|
||||
dehydrate() {
|
||||
this.store.dehydrate();
|
||||
}
|
||||
|
@ -38,6 +38,13 @@ export default class LaunchReducer {
|
||||
state.baseHash = baseHash;
|
||||
})
|
||||
}
|
||||
|
||||
const runtimeLag = _.get(json, 'runtimeLag', null);
|
||||
if (runtimeLag !== null) {
|
||||
useLaunchState.getState().set(state => {
|
||||
state.runtimeLag = runtimeLag;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ export interface LaunchState extends BaseState<LaunchState> {
|
||||
weather: WeatherState | null | Record<string, never> | boolean,
|
||||
userLocation: string | null;
|
||||
baseHash: string | null;
|
||||
runtimeLag: boolean;
|
||||
};
|
||||
|
||||
const useLaunchState = createState<LaunchState>('Launch', {
|
||||
@ -20,7 +21,8 @@ const useLaunchState = createState<LaunchState>('Launch', {
|
||||
tiles: {},
|
||||
weather: null,
|
||||
userLocation: null,
|
||||
baseHash: null
|
||||
baseHash: null,
|
||||
runtimeLag: false,
|
||||
});
|
||||
|
||||
|
||||
|
@ -13,6 +13,10 @@ interface LocalUpdateBaseHash {
|
||||
baseHash: string;
|
||||
}
|
||||
|
||||
interface LocalUpdateRuntimeLag {
|
||||
runtimeLag: boolean;
|
||||
}
|
||||
|
||||
interface LocalUpdateBackgroundConfig {
|
||||
backgroundConfig: BackgroundConfig;
|
||||
}
|
||||
@ -51,6 +55,7 @@ export type BackgroundConfig = BackgroundConfigUrl | BackgroundConfigColor | und
|
||||
export type LocalUpdate =
|
||||
| LocalUpdateSetDark
|
||||
| LocalUpdateBaseHash
|
||||
| LocalUpdateRuntimeLag
|
||||
| LocalUpdateBackgroundConfig
|
||||
| LocalUpdateHideAvatars
|
||||
| LocalUpdateHideNicknames
|
||||
|
@ -106,6 +106,7 @@ class App extends React.Component {
|
||||
this.updateTheme(this.themeWatcher);
|
||||
}, 500);
|
||||
this.api.local.getBaseHash();
|
||||
this.api.local.getRuntimeLag(); //TODO consider polling periodically
|
||||
this.api.settings.getAll();
|
||||
gcpManager.start();
|
||||
Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => {
|
||||
|
@ -47,7 +47,7 @@ const tutSelector = f.pick(['tutorialProgress', 'nextTutStep', 'hideGroups']);
|
||||
|
||||
export default function LaunchApp(props) {
|
||||
const { connection } = props;
|
||||
const baseHash = useLaunchState(state => state.baseHash);
|
||||
const { baseHash, runtimeLag } = useLaunchState(state => state);
|
||||
const [hashText, setHashText] = useState(baseHash);
|
||||
const [exitingTut, setExitingTut] = useState(false);
|
||||
const seen = useSettingsState(s => s?.tutorial?.seen) ?? true;
|
||||
@ -82,7 +82,10 @@ export default function LaunchApp(props) {
|
||||
}, 2000);
|
||||
}}
|
||||
>
|
||||
<Box backgroundColor="washedGray" p={2}>
|
||||
<Box
|
||||
backgroundColor={runtimeLag ? 'yellow' : 'washedGray'}
|
||||
p={2}
|
||||
>
|
||||
<Text mono bold>{hashText || baseHash}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -4,7 +4,15 @@ import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { BigInteger } from 'big-integer';
|
||||
|
||||
import { Col, Center, Box, Text, LoadingSpinner } from '@tlon/indigo-react';
|
||||
import {
|
||||
Col,
|
||||
Center,
|
||||
Box,
|
||||
Text,
|
||||
LoadingSpinner,
|
||||
Icon
|
||||
} from '@tlon/indigo-react';
|
||||
|
||||
import {
|
||||
Associations,
|
||||
Notifications,
|
||||
@ -23,6 +31,7 @@ import GlobalApi from '~/logic/api/global';
|
||||
import { Notification } from './notification';
|
||||
import { Invites } from './invites';
|
||||
import { useLazyScroll } from '~/logic/lib/useLazyScroll';
|
||||
import useLaunchState from '~/logic/state/launch';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import useInviteState from '~/logic/state/invite';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
@ -65,6 +74,8 @@ export default function Inbox(props: {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const runtimeLag = useLaunchState(state => state.runtimeLag);
|
||||
|
||||
const ready = useHarkState(
|
||||
s => Object.keys(s.unreads.graph).length > 0
|
||||
);
|
||||
@ -122,6 +133,16 @@ export default function Inbox(props: {
|
||||
|
||||
return (
|
||||
<Col p="1" ref={scrollRef} position="relative" height="100%" overflowY="auto">
|
||||
|
||||
{runtimeLag && (
|
||||
<Box bg="yellow" borderRadius={2} p={2} m={2}>
|
||||
<Icon verticalAlign="middle" mr={2} icon="Tutorial" />
|
||||
<Text verticalAlign="middle">
|
||||
Update your binary to continue receiving updates.
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Invites pendingJoin={props.pendingJoin} api={api} />
|
||||
{[...notificationsByDayMap.keys()].sort().reverse().map((day, index) => {
|
||||
const timeboxes = notificationsByDayMap.get(day)!;
|
||||
|
@ -18,6 +18,7 @@ import { uxToHex } from '~/logic/lib/util';
|
||||
import { ProfileStatus } from './ProfileStatus';
|
||||
import { useTutorialModal } from './useTutorialModal';
|
||||
|
||||
import useLaunchState from '~/logic/state/launch';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import useInviteState from '~/logic/state/invite';
|
||||
import useContactState from '~/logic/state/contact';
|
||||
@ -30,6 +31,7 @@ const localSel = selectLocalState(['toggleOmnibox']);
|
||||
const StatusBar = (props) => {
|
||||
const { api, ship } = props;
|
||||
const history = useHistory();
|
||||
const runtimeLag = useLaunchState(state => state.runtimeLag);
|
||||
const ourContact = useContactState((state) => state.contacts[`~${ship}`]);
|
||||
const notificationsCount = useHarkState((state) => state.notificationsCount);
|
||||
const doNotDisturb = useHarkState((state) => state.doNotDisturb);
|
||||
@ -86,6 +88,11 @@ const StatusBar = (props) => {
|
||||
<Icon icon='Dashboard' color='black' />
|
||||
</Button>
|
||||
<StatusBarItem float={floatLeap} mr={2} onClick={() => toggleOmnibox()}>
|
||||
{!doNotDisturb && runtimeLag && (
|
||||
<Box display='block' right='-8px' top='-8px' position='absolute'>
|
||||
<Icon color='yellow' icon='Bullet' />
|
||||
</Box>
|
||||
)}
|
||||
{!doNotDisturb && (notificationsCount > 0 || invites.length > 0) && (
|
||||
<Box display='block' right='-8px' top='-8px' position='absolute'>
|
||||
<Icon color='blue' icon='Bullet' />
|
||||
|
@ -4,6 +4,7 @@ import defaultApps from '~/logic/lib/default-apps';
|
||||
import Sigil from '~/logic/lib/sigil';
|
||||
import { uxToHex, cite } from '~/logic/lib/util';
|
||||
import withState from '~/logic/lib/withState';
|
||||
import useLaunchState from '~/logic/state/launch';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import useContactState from '~/logic/state/contact';
|
||||
import useInviteState from '~/logic/state/invite';
|
||||
@ -31,11 +32,13 @@ export class OmniboxResult extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
getIcon(icon, selected, link, invites, notifications, text, color) {
|
||||
getIcon(icon, selected, link, invites, notifications, lag, text, color) {
|
||||
const iconFill =
|
||||
this.state.hovered || selected === link ? 'white' : 'black';
|
||||
const bulletFill =
|
||||
this.state.hovered || selected === link ? 'white' : 'blue';
|
||||
const lagFill =
|
||||
this.state.hovered || selected === link ? 'white' : 'yellow';
|
||||
|
||||
const inviteCount = [].concat(
|
||||
...Object.values(invites).map((obj) => Object.values(obj))
|
||||
@ -70,6 +73,14 @@ export class OmniboxResult extends Component {
|
||||
size='18px'
|
||||
color={iconFill}
|
||||
/>
|
||||
{lag && (
|
||||
<Icon
|
||||
display='inline-block'
|
||||
icon='Bullet'
|
||||
style={{ position: 'absolute', top: -5, left: 5 }}
|
||||
color={lagFill}
|
||||
/>
|
||||
)}
|
||||
{(notifications > 0 || inviteCount.length > 0) && (
|
||||
<Icon
|
||||
display='inline-block'
|
||||
@ -178,6 +189,7 @@ export class OmniboxResult extends Component {
|
||||
selected,
|
||||
invites,
|
||||
notificationsCount,
|
||||
runtimeLag,
|
||||
contacts,
|
||||
setSelection
|
||||
} = this.props;
|
||||
@ -191,6 +203,7 @@ export class OmniboxResult extends Component {
|
||||
link,
|
||||
invites,
|
||||
notificationsCount,
|
||||
runtimeLag,
|
||||
text,
|
||||
color
|
||||
);
|
||||
@ -252,6 +265,7 @@ export class OmniboxResult extends Component {
|
||||
}
|
||||
|
||||
export default withState(OmniboxResult, [
|
||||
[useLaunchState, ['runtimeLag']],
|
||||
[useInviteState],
|
||||
[useHarkState, ['notificationsCount']],
|
||||
[useContactState]
|
||||
|
Loading…
Reference in New Issue
Block a user