mirror of
https://github.com/urbit/shrub.git
synced 2024-11-28 13:54:20 +03:00
grid: distinguish app sync from system install
By using `%kiln-install` instead of `%kiln-sync` for System Updates, this ensures that the `%kids` desk is also updated. Also, address UX feedback: render the entire source ship's patp to avoid ambiguity. (as opposed to truncating a moon's name).
This commit is contained in:
parent
280c1cb19a
commit
1bd0f4be77
@ -3,11 +3,12 @@ import React, { HTMLAttributes } from 'react';
|
|||||||
|
|
||||||
type ShipNameProps = {
|
type ShipNameProps = {
|
||||||
name: string;
|
name: string;
|
||||||
|
truncate?: boolean;
|
||||||
} & HTMLAttributes<HTMLSpanElement>;
|
} & HTMLAttributes<HTMLSpanElement>;
|
||||||
|
|
||||||
export const ShipName = ({ name, ...props }: ShipNameProps) => {
|
export const ShipName = ({ name, truncate = true, ...props }: ShipNameProps) => {
|
||||||
const separator = /([_^-])/;
|
const separator = /([_^-])/;
|
||||||
const citedName = cite(name);
|
const citedName = truncate ? cite(name) : name;
|
||||||
|
|
||||||
if (!citedName) {
|
if (!citedName) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,34 +1,39 @@
|
|||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { useAsyncCall } from '../logic/useAsyncCall';
|
import { useAsyncCall } from '../logic/useAsyncCall';
|
||||||
import useKilnState from '../state/kiln';
|
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
import { ShipName } from './ShipName';
|
import { ShipName } from './ShipName';
|
||||||
import { Spinner } from './Spinner';
|
import { Spinner } from './Spinner';
|
||||||
|
|
||||||
interface SourceSyncerProps {
|
interface SourceSetterProps {
|
||||||
appName: string;
|
appName: string;
|
||||||
|
srcDesk: string;
|
||||||
|
srcShip?: string;
|
||||||
title: string;
|
title: string;
|
||||||
syncDesk: string;
|
toggleSrc: (desk: string, ship: string) => Promise<void>;
|
||||||
syncShip?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SourceSyncer({ appName, title, syncDesk, syncShip }: SourceSyncerProps) {
|
export default function SourceSetter({
|
||||||
const [newSyncShip, setNewSyncShip] = useState(syncShip ?? '');
|
appName,
|
||||||
const { toggleSync } = useKilnState();
|
srcDesk,
|
||||||
const { status: requestStatus, call: setSync } = useAsyncCall(toggleSync);
|
srcShip,
|
||||||
const syncDirty = newSyncShip !== syncShip;
|
title,
|
||||||
|
toggleSrc
|
||||||
|
}: SourceSetterProps) {
|
||||||
|
const [newSyncShip, setNewSyncShip] = useState(srcShip ?? '');
|
||||||
|
const { status: requestStatus, call: handleSubmit } = useAsyncCall(toggleSrc);
|
||||||
|
const syncDirty = newSyncShip !== srcShip;
|
||||||
|
|
||||||
const onUnsync = useCallback(() => {
|
const onUnset = useCallback(() => {
|
||||||
if (!syncShip) {
|
if (!srcShip) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
// eslint-disable-next-line no-alert, no-restricted-globals
|
// eslint-disable-next-line no-alert, no-restricted-globals
|
||||||
confirm(`Are you sure you want to unsync ${appName}? You will no longer receive updates.`)
|
confirm(`Are you sure you want to unsync ${appName}? You will no longer receive updates.`)
|
||||||
) {
|
) {
|
||||||
toggleSync(syncDesk, syncShip);
|
toggleSrc(srcDesk, srcShip);
|
||||||
}
|
}
|
||||||
}, [syncShip, syncDesk, toggleSync]);
|
}, [srcShip, srcDesk]);
|
||||||
|
|
||||||
const handleSourceChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleSourceChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { target } = e;
|
const { target } = e;
|
||||||
@ -39,26 +44,27 @@ export default function SourceSyncer({ appName, title, syncDesk, syncShip }: Sou
|
|||||||
const onSubmit = useCallback(
|
const onSubmit = useCallback(
|
||||||
async (e: React.FormEvent<HTMLFormElement>) => {
|
async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await setSync(syncDesk, newSyncShip);
|
await handleSubmit(srcDesk, newSyncShip);
|
||||||
},
|
},
|
||||||
[syncDesk, newSyncShip, toggleSync]
|
[srcDesk, newSyncShip]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h2 className="h3 mb-7">{title}</h2>
|
<h2 className="h3 mb-7">{title}</h2>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{syncShip ? (
|
{srcShip ? (
|
||||||
<>
|
<>
|
||||||
<h3 className="flex items-center h4 mb-2">Automatic Updates</h3>
|
<h3 className="flex items-center h4 mb-2">Automatic Updates</h3>
|
||||||
<p>Automatically download and apply updates to keep {appName} up to date.</p>
|
<p>Automatically download and apply updates to keep {appName} up to date.</p>
|
||||||
<div className="flex-1 flex flex-col justify-center space-y-6">
|
<div className="flex-1 flex flex-col justify-center space-y-6">
|
||||||
<p>
|
<p>
|
||||||
OTA Source: <ShipName name={syncShip} className="font-semibold font-mono" />
|
OTA Source:{' '}
|
||||||
|
<ShipName name={srcShip} truncate={false} className="font-semibold font-mono" />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<Button onClick={onUnsync} variant="destructive">
|
<Button onClick={onUnset} variant="destructive">
|
||||||
Unsync Updates for {appName}...
|
Unsync Updates for {appName}...
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
@ -1,23 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { RouteComponentProps } from 'react-router-dom';
|
import { RouteComponentProps } from 'react-router-dom';
|
||||||
|
import SourceSetter from '../../components/SourceSetter';
|
||||||
import { useCharge } from '../../state/docket';
|
import { useCharge } from '../../state/docket';
|
||||||
import { usePike } from '../../state/kiln';
|
import useKilnState, { usePike } from '../../state/kiln';
|
||||||
import { getAppName } from '../../state/util';
|
import { getAppName } from '../../state/util';
|
||||||
import SourceSyncer from '../../components/SourceSyncer';
|
|
||||||
|
|
||||||
export const AppPrefs = ({ match }: RouteComponentProps<{ desk: string }>) => {
|
export const AppPrefs = ({ match }: RouteComponentProps<{ desk: string }>) => {
|
||||||
const { desk } = match.params;
|
const { desk } = match.params;
|
||||||
const charge = useCharge(desk);
|
const charge = useCharge(desk);
|
||||||
const appName = getAppName(charge);
|
const appName = getAppName(charge);
|
||||||
const pike = usePike(desk);
|
const pike = usePike(desk);
|
||||||
const syncShip = pike?.sync?.ship;
|
const srcShip = pike?.sync?.ship;
|
||||||
|
const { toggleSync } = useKilnState();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SourceSyncer
|
<SourceSetter
|
||||||
appName={appName}
|
appName={appName}
|
||||||
|
toggleSrc={toggleSync}
|
||||||
|
srcDesk={desk}
|
||||||
|
srcShip={srcShip}
|
||||||
title={`${appName} Settings`}
|
title={`${appName} Settings`}
|
||||||
syncDesk={desk}
|
|
||||||
syncShip={syncShip}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SourceSyncer from '../../components/SourceSyncer';
|
import SourceSetter from '../../components/SourceSetter';
|
||||||
import { usePike } from '../../state/kiln';
|
import useKilnState, { usePike } from '../../state/kiln';
|
||||||
|
|
||||||
export const SystemUpdatePrefs = () => {
|
export const SystemUpdatePrefs = () => {
|
||||||
const desk = 'base';
|
const desk = 'base';
|
||||||
const appName = 'your Urbit';
|
const appName = 'your Urbit';
|
||||||
const pike = usePike(desk);
|
const pike = usePike(desk);
|
||||||
const syncShip = pike?.sync?.ship;
|
const srcShip = pike?.sync?.ship;
|
||||||
|
const { toggleInstall } = useKilnState();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SourceSyncer appName={appName} title="System Updates" syncDesk={desk} syncShip={syncShip} />
|
<SourceSetter
|
||||||
|
appName={appName}
|
||||||
|
toggleSrc={toggleInstall}
|
||||||
|
srcDesk={desk}
|
||||||
|
srcShip={srcShip}
|
||||||
|
title="System Updates"
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
import { scryLag, getPikes, Pikes, Pike, kilnUnsync, kilnSync } from '@urbit/api';
|
import {
|
||||||
|
scryLag,
|
||||||
|
getPikes,
|
||||||
|
Pikes,
|
||||||
|
Pike,
|
||||||
|
kilnUnsync,
|
||||||
|
kilnSync,
|
||||||
|
kilnUninstall,
|
||||||
|
kilnInstall
|
||||||
|
} from '@urbit/api';
|
||||||
import create from 'zustand';
|
import create from 'zustand';
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
@ -12,6 +21,7 @@ interface KilnState {
|
|||||||
lag: boolean;
|
lag: boolean;
|
||||||
fetchLag: () => Promise<void>;
|
fetchLag: () => Promise<void>;
|
||||||
fetchPikes: () => Promise<void>;
|
fetchPikes: () => Promise<void>;
|
||||||
|
toggleInstall: (desk: string, ship: string) => Promise<void>;
|
||||||
toggleSync: (desk: string, ship: string) => Promise<void>;
|
toggleSync: (desk: string, ship: string) => Promise<void>;
|
||||||
set: (s: KilnState) => void;
|
set: (s: KilnState) => void;
|
||||||
initializeKiln: () => Promise<void>;
|
initializeKiln: () => Promise<void>;
|
||||||
@ -33,6 +43,13 @@ const useKilnState = create<KilnState>((set, get) => ({
|
|||||||
const lag = await api.scry<boolean>(scryLag);
|
const lag = await api.scry<boolean>(scryLag);
|
||||||
set({ lag });
|
set({ lag });
|
||||||
},
|
},
|
||||||
|
toggleInstall: async (desk: string, ship: string) => {
|
||||||
|
const synced = !!get().pikes[desk].sync;
|
||||||
|
await (useMockData
|
||||||
|
? fakeRequest('')
|
||||||
|
: api.poke(synced ? kilnUninstall(desk) : kilnInstall(ship, desk)));
|
||||||
|
await get().fetchPikes();
|
||||||
|
},
|
||||||
toggleSync: async (desk: string, ship: string) => {
|
toggleSync: async (desk: string, ship: string) => {
|
||||||
const synced = !!get().pikes[desk].sync;
|
const synced = !!get().pikes[desk].sync;
|
||||||
await (useMockData
|
await (useMockData
|
||||||
|
Loading…
Reference in New Issue
Block a user