interface: storage prop unifying gcp and s3

N.B. this boldly assumes that store state will always contain a valid
storage element that will contain gcp and s3 elements. This seems like a
fair assumption.
This commit is contained in:
J 2021-03-01 21:58:03 +00:00
parent ce1c69e0d1
commit f85ef9fcb4
33 changed files with 105 additions and 136 deletions

View File

@ -64,7 +64,7 @@ class GcpManager {
#consecutiveFailures: number = 0; #consecutiveFailures: number = 0;
private isConfigured() { private isConfigured() {
return this.#store.state.gcp.configured; return this.#store.state.storage.gcp.configured;
} }
private refreshLoop() { private refreshLoop() {
@ -88,7 +88,7 @@ class GcpManager {
} }
this.#api.gcp.getToken() this.#api.gcp.getToken()
.then(() => { .then(() => {
const token = this.#store.state.gcp?.token; const token = this.#store.state.storage.gcp?.token;
if (token) { if (token) {
this.#consecutiveFailures = 0; this.#consecutiveFailures = 0;
const interval = this.refreshInterval(token.expiresIn); const interval = this.refreshInterval(token.expiresIn);

View File

@ -1,6 +1,9 @@
import {useCallback, useMemo, useEffect, useRef, useState} from 'react'; import {useCallback, useMemo, useEffect, useRef, useState} from 'react';
import {S3State} from '../../types/s3-update'; import {
import {GcpState} from '../../types/gcp-state'; GcpState,
S3State,
StorageState
} from '../../types';
import S3 from "aws-sdk/clients/s3"; import S3 from "aws-sdk/clients/s3";
import GcpClient from './GcpClient'; import GcpClient from './GcpClient';
import {StorageClient, StorageAcl} from './StorageClient'; import {StorageClient, StorageAcl} from './StorageClient';
@ -15,7 +18,7 @@ export interface IuseStorage {
promptUpload: () => Promise<string | undefined>; promptUpload: () => Promise<string | undefined>;
} }
const useStorage = (s3: S3State, gcp: GcpState, const useStorage = ({gcp, s3}: StorageState,
{ accept = '*' } = { accept: '*' }): IuseStorage => { { accept = '*' } = { accept: '*' }): IuseStorage => {
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false);

View File

@ -13,7 +13,7 @@ export default class GcpReducer<S extends GcpState>{
reduceConfigured(json, state) { reduceConfigured(json, state) {
let data = json['gcp-configured']; let data = json['gcp-configured'];
if (data !== undefined) { if (data !== undefined) {
state.gcp.configured = data; state.storage.gcp.configured = data;
} }
} }
@ -26,7 +26,7 @@ export default class GcpReducer<S extends GcpState>{
setToken(data: any, state: S) { setToken(data: any, state: S) {
if (this.isToken(data)) { if (this.isToken(data)) {
state.gcp.token = data; state.storage.gcp.token = data;
} }
} }

View File

@ -23,14 +23,14 @@ export default class S3Reducer<S extends S3State> {
credentials(json: S3Update, state: S) { credentials(json: S3Update, state: S) {
const data = _.get(json, 'credentials', false); const data = _.get(json, 'credentials', false);
if (data) { if (data) {
state.s3.credentials = data; state.storage.s3.credentials = data;
} }
} }
configuration(json: S3Update, state: S) { configuration(json: S3Update, state: S) {
const data = _.get(json, 'configuration', false); const data = _.get(json, 'configuration', false);
if (data) { if (data) {
state.s3.configuration = { state.storage.s3.configuration = {
buckets: new Set(data.buckets), buckets: new Set(data.buckets),
currentBucket: data.currentBucket currentBucket: data.currentBucket
}; };
@ -39,44 +39,44 @@ export default class S3Reducer<S extends S3State> {
currentBucket(json: S3Update, state: S) { currentBucket(json: S3Update, state: S) {
const data = _.get(json, 'setCurrentBucket', false); const data = _.get(json, 'setCurrentBucket', false);
if (data && state.s3) { if (data && state.storage.s3) {
state.s3.configuration.currentBucket = data; state.storage.s3.configuration.currentBucket = data;
} }
} }
addBucket(json: S3Update, state: S) { addBucket(json: S3Update, state: S) {
const data = _.get(json, 'addBucket', false); const data = _.get(json, 'addBucket', false);
if (data) { if (data) {
state.s3.configuration.buckets = state.storage.s3.configuration.buckets =
state.s3.configuration.buckets.add(data); state.storage.s3.configuration.buckets.add(data);
} }
} }
removeBucket(json: S3Update, state: S) { removeBucket(json: S3Update, state: S) {
const data = _.get(json, 'removeBucket', false); const data = _.get(json, 'removeBucket', false);
if (data) { if (data) {
state.s3.configuration.buckets.delete(data); state.storage.s3.configuration.buckets.delete(data);
} }
} }
endpoint(json: S3Update, state: S) { endpoint(json: S3Update, state: S) {
const data = _.get(json, 'setEndpoint', false); const data = _.get(json, 'setEndpoint', false);
if (data && state.s3.credentials) { if (data && state.storage.s3.credentials) {
state.s3.credentials.endpoint = data; state.storage.s3.credentials.endpoint = data;
} }
} }
accessKeyId(json: S3Update , state: S) { accessKeyId(json: S3Update , state: S) {
const data = _.get(json, 'setAccessKeyId', false); const data = _.get(json, 'setAccessKeyId', false);
if (data && state.s3.credentials) { if (data && state.storage.s3.credentials) {
state.s3.credentials.accessKeyId = data; state.storage.s3.credentials.accessKeyId = data;
} }
} }
secretAccessKey(json: S3Update, state: S) { secretAccessKey(json: S3Update, state: S) {
const data = _.get(json, 'setSecretAccessKey', false); const data = _.get(json, 'setSecretAccessKey', false);
if (data && state.s3.credentials) { if (data && state.storage.s3.credentials) {
state.s3.credentials.secretAccessKey = data; state.storage.s3.credentials.secretAccessKey = data;
} }
} }
} }

View File

@ -73,13 +73,15 @@ export default class GlobalStore extends BaseStore<StoreState> {
}, },
weather: {}, weather: {},
userLocation: null, userLocation: null,
gcp: {}, storage: {
s3: { gcp: {},
configuration: { s3: {
buckets: new Set(), configuration: {
currentBucket: '' buckets: new Set(),
currentBucket: ''
},
credentials: null
}, },
credentials: null
}, },
isContactPublic: false, isContactPublic: false,
contacts: {}, contacts: {},

View File

@ -3,8 +3,7 @@ import { Invites } from '~/types/invite-update';
import { Associations } from '~/types/metadata-update'; import { Associations } from '~/types/metadata-update';
import { Rolodex } from '~/types/contact-update'; import { Rolodex } from '~/types/contact-update';
import { Groups } from '~/types/group-update'; import { Groups } from '~/types/group-update';
import { GcpState } from '~/types/gcp-state'; import { StorageState } from '~/types/storage-state';
import { S3State } from '~/types/s3-update';
import { LaunchState, WeatherState } from '~/types/launch-update'; import { LaunchState, WeatherState } from '~/types/launch-update';
import { ConnectionStatus } from '~/types/connection'; import { ConnectionStatus } from '~/types/connection';
import {Graphs} from '~/types/graph-update'; import {Graphs} from '~/types/graph-update';
@ -32,8 +31,7 @@ export interface StoreState {
groups: Groups; groups: Groups;
groupKeys: Set<Path>; groupKeys: Set<Path>;
nackedContacts: Set<Patp> nackedContacts: Set<Patp>
s3: S3State; storage: StorageState;
gcp: GcpState;
graphs: Graphs; graphs: Graphs;
graphKeys: Set<string>; graphKeys: Set<string>;

View File

@ -11,6 +11,7 @@ export * from './launch-update';
export * from './local-update'; export * from './local-update';
export * from './metadata-update'; export * from './metadata-update';
export * from './noun'; export * from './noun';
export * from './storage-state';
export * from './gcp-state'; export * from './gcp-state';
export * from './s3-update'; export * from './s3-update';
export * from './workspace'; export * from './workspace';

View File

@ -0,0 +1,8 @@
import {GcpState} from './gcp-state';
import {S3State} from './s3-update';
export interface StorageState {
gcp: GcpState;
s3: S3State;
};

View File

@ -179,8 +179,7 @@ export function ChatResource(props: ChatResourceProps) {
(!showBanner && hasLoadedAllowed) ? contacts : modifiedContacts (!showBanner && hasLoadedAllowed) ? contacts : modifiedContacts
} }
onUnmount={appendUnsent} onUnmount={appendUnsent}
gcp={props.gcp} storage={props.storage}
s3={props.s3}
placeholder="Message..." placeholder="Message..."
message={unsent[station] || ''} message={unsent[station] || ''}
deleteMessage={clearUnsent} deleteMessage={clearUnsent}

View File

@ -7,7 +7,7 @@ import { createPost } from '~/logic/api/graph';
import tokenizeMessage, { isUrl } from '~/logic/lib/tokenizeMessage'; import tokenizeMessage, { isUrl } from '~/logic/lib/tokenizeMessage';
import GlobalApi from '~/logic/api/global'; import GlobalApi from '~/logic/api/global';
import { Envelope } from '~/types/chat-update'; import { Envelope } from '~/types/chat-update';
import { Contacts, Content } from '~/types'; import { StorageState, Contacts, Content } from '~/types';
import { Row, BaseImage, Box, Icon, LoadingSpinner } from '@tlon/indigo-react'; import { Row, BaseImage, Box, Icon, LoadingSpinner } from '@tlon/indigo-react';
import withStorage from '~/views/components/withStorage'; import withStorage from '~/views/components/withStorage';
import { withLocalState } from '~/logic/state/local'; import { withLocalState } from '~/logic/state/local';
@ -20,8 +20,7 @@ type ChatInputProps = IuseStorage & {
envelopes: Envelope[]; envelopes: Envelope[];
contacts: Contacts; contacts: Contacts;
onUnmount(msg: string): void; onUnmount(msg: string): void;
gcp: any; storage: StorageState;
s3: any;
placeholder: string; placeholder: string;
message: string; message: string;
deleteMessage(): void; deleteMessage(): void;

View File

@ -34,8 +34,7 @@ export function LinkResource(props: LinkResourceProps) {
associations, associations,
graphKeys, graphKeys,
unreads, unreads,
gcp, storage,
s3,
history history
} = props; } = props;
@ -71,8 +70,7 @@ export function LinkResource(props: LinkResourceProps) {
render={(props) => { render={(props) => {
return ( return (
<LinkWindow <LinkWindow
gcp={gcp} storage={storage}
s3={s3}
association={resource} association={resource}
contacts={contacts} contacts={contacts}
resource={resourcePath} resource={resourcePath}

View File

@ -30,8 +30,7 @@ interface LinkWindowProps {
group: Group; group: Group;
path: string; path: string;
api: GlobalApi; api: GlobalApi;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
export function LinkWindow(props: LinkWindowProps) { export function LinkWindow(props: LinkWindowProps) {
const { graph, api, association } = props; const { graph, api, association } = props;
@ -67,7 +66,7 @@ export function LinkWindow(props: LinkWindowProps) {
return ( return (
<Col key={0} mx="auto" mt="4" maxWidth="768px" width="100%" flexShrink={0} px={3}> <Col key={0} mx="auto" mt="4" maxWidth="768px" width="100%" flexShrink={0} px={3}>
{ canWrite ? ( { canWrite ? (
<LinkSubmit gcp={props.gcp} s3={props.s3} name={name} ship={ship.slice(1)} api={api} /> <LinkSubmit storage={props.storage} name={name} ship={ship.slice(1)} api={api} />
) : ( ) : (
<Text>There are no links here yet. You do not have permission to post to this collection.</Text> <Text>There are no links here yet. You do not have permission to post to this collection.</Text>
) )
@ -98,7 +97,7 @@ export function LinkWindow(props: LinkWindowProps) {
return ( return (
<React.Fragment key={index.toString()}> <React.Fragment key={index.toString()}>
<Col key={index.toString()} mx="auto" mt="4" maxWidth="768px" width="100%" flexShrink={0} px={3}> <Col key={index.toString()} mx="auto" mt="4" maxWidth="768px" width="100%" flexShrink={0} px={3}>
<LinkSubmit gcp={props.gcp} s3={props.s3} name={name} ship={ship.slice(1)} api={api} /> <LinkSubmit storage={props.storage} name={name} ship={ship.slice(1)} api={api} />
</Col> </Col>
<LinkItem {...linkProps} /> <LinkItem {...linkProps} />
</React.Fragment> </React.Fragment>

View File

@ -3,22 +3,21 @@ import React, { useCallback, useState } from "react";
import GlobalApi from "~/logic/api/global"; import GlobalApi from "~/logic/api/global";
import { useFileDrag } from "~/logic/lib/useDrag"; import { useFileDrag } from "~/logic/lib/useDrag";
import useStorage from "~/logic/lib/useStorage"; import useStorage from "~/logic/lib/useStorage";
import { GcpState, S3State } from "~/types"; import { StorageState } from "~/types";
import SubmitDragger from "~/views/components/SubmitDragger"; import SubmitDragger from "~/views/components/SubmitDragger";
import { createPost } from "~/logic/api/graph"; import { createPost } from "~/logic/api/graph";
import { hasProvider } from "oembed-parser"; import { hasProvider } from "oembed-parser";
interface LinkSubmitProps { interface LinkSubmitProps {
api: GlobalApi; api: GlobalApi;
gcp: GcpState; storage: StorageState;
s3: S3State;
name: string; name: string;
ship: string; ship: string;
}; };
const LinkSubmit = (props: LinkSubmitProps) => { const LinkSubmit = (props: LinkSubmitProps) => {
let { canUpload, uploadDefault, uploading, promptUpload } = let { canUpload, uploadDefault, uploading, promptUpload } =
useStorage(props.s3, props.gcp); useStorage(props.storage);
const [submitFocused, setSubmitFocused] = useState(false); const [submitFocused, setSubmitFocused] = useState(false);
const [urlFocused, setUrlFocused] = useState(false); const [urlFocused, setUrlFocused] = useState(false);

View File

@ -114,15 +114,15 @@ export function EditProfile(props: any) {
<Input id="nickname" label="Name" mb={3} /> <Input id="nickname" label="Name" mb={3} />
<Col width="100%"> <Col width="100%">
<Text mb={2}>Description</Text> <Text mb={2}>Description</Text>
<MarkdownField id="bio" mb={3} gcp={props.gcp} s3={props.s3} /> <MarkdownField id="bio" mb={3} storage={props.storage} />
</Col> </Col>
<ColorInput id="color" label="Sigil Color" mb={3} /> <ColorInput id="color" label="Sigil Color" mb={3} />
<Row mb={3} width="100%"> <Row mb={3} width="100%">
<Col pr={2} width="50%"> <Col pr={2} width="50%">
<ImageInput id="cover" label="Cover Image" gcp={props.gcp} s3={props.s3} /> <ImageInput id="cover" label="Cover Image" storage={props.storage} />
</Col> </Col>
<Col pl={2} width="50%"> <Col pl={2} width="50%">
<ImageInput id="avatar" label="Profile Image" gcp={props.gcp} s3={props.s3} /> <ImageInput id="avatar" label="Profile Image" storage={props.storage} />
</Col> </Col>
</Row> </Row>
<Checkbox mb={3} id="isPublic" label="Public Profile" /> <Checkbox mb={3} id="isPublic" label="Public Profile" />

View File

@ -107,8 +107,7 @@ export function Profile(props: any) {
<EditProfile <EditProfile
ship={ship} ship={ship}
contact={contact} contact={contact}
gcp={props.gcp} storage={props.storage}
s3={props.s3}
api={props.api} api={props.api}
groups={props.groups} groups={props.groups}
associations={props.associations} associations={props.associations}

View File

@ -50,8 +50,7 @@ export default function ProfileScreen(props: any) {
groups={props.groups} groups={props.groups}
contact={contact} contact={contact}
api={props.api} api={props.api}
gcp={props.gcp} storage={props.storage}
s3={props.s3}
isEdit={isEdit} isEdit={isEdit}
isPublic={isPublic} isPublic={isPublic}
nackedContacts={props.nackedContacts} nackedContacts={props.nackedContacts}

View File

@ -37,8 +37,7 @@ export function PublishResource(props: PublishResourceProps) {
location={props.location} location={props.location}
unreads={props.unreads} unreads={props.unreads}
graphs={props.graphs} graphs={props.graphs}
gcp={props.gcp} storage={props.storage}
s3={props.s3}
/> />
</Box> </Box>
); );

View File

@ -4,7 +4,7 @@ import { PostFormSchema, PostForm } from "./NoteForm";
import { FormikHelpers } from "formik"; import { FormikHelpers } from "formik";
import GlobalApi from "~/logic/api/global"; import GlobalApi from "~/logic/api/global";
import { RouteComponentProps, useLocation } from "react-router-dom"; import { RouteComponentProps, useLocation } from "react-router-dom";
import { GraphNode, TextContent, Association, GcpState, S3State } from "~/types"; import { GraphNode, TextContent, Association, StorageState } from "~/types";
import { getLatestRevision, editPost } from "~/logic/lib/publish"; import { getLatestRevision, editPost } from "~/logic/lib/publish";
import {useWaitForProps} from "~/logic/lib/useWaitForProps"; import {useWaitForProps} from "~/logic/lib/useWaitForProps";
interface EditPostProps { interface EditPostProps {
@ -13,12 +13,11 @@ interface EditPostProps {
note: GraphNode; note: GraphNode;
api: GlobalApi; api: GlobalApi;
book: string; book: string;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
export function EditPost(props: EditPostProps & RouteComponentProps) { export function EditPost(props: EditPostProps & RouteComponentProps) {
const { note, book, noteId, api, ship, history, gcp, s3 } = props; const { note, book, noteId, api, ship, history, storage } = props;
const [revNum, title, body] = getLatestRevision(note); const [revNum, title, body] = getLatestRevision(note);
const location = useLocation(); const location = useLocation();
@ -55,8 +54,7 @@ export function EditPost(props: EditPostProps & RouteComponentProps) {
cancel cancel
history={history} history={history}
onSubmit={onSubmit} onSubmit={onSubmit}
gcp={gcp} storage={storage}
s3={s3}
submitLabel="Update" submitLabel="Update"
loadingText="Updating..." loadingText="Updating..."
/> />

View File

@ -17,7 +17,7 @@ import { Box } from "@tlon/indigo-react";
import { useFileDrag } from "~/logic/lib/useDrag"; import { useFileDrag } from "~/logic/lib/useDrag";
import SubmitDragger from "~/views/components/SubmitDragger"; import SubmitDragger from "~/views/components/SubmitDragger";
import useStorage from "~/logic/lib/useStorage"; import useStorage from "~/logic/lib/useStorage";
import { GcpState, S3State } from "~/types"; import { StorageState } from "~/types";
const MARKDOWN_CONFIG = { const MARKDOWN_CONFIG = {
name: "markdown", name: "markdown",
@ -28,8 +28,7 @@ interface MarkdownEditorProps {
value: string; value: string;
onChange: (s: string) => void; onChange: (s: string) => void;
onBlur?: (e: any) => void; onBlur?: (e: any) => void;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
const PromptIfDirty = () => { const PromptIfDirty = () => {
@ -75,7 +74,7 @@ export function MarkdownEditor(
[onBlur] [onBlur]
); );
const { uploadDefault, canUpload } = useStorage(props.s3, props.gcp); const { uploadDefault, canUpload } = useStorage(props.storage);
const onFileDrag = useCallback( const onFileDrag = useCallback(
async (files: FileList | File[], e: DragEvent) => { async (files: FileList | File[], e: DragEvent) => {

View File

@ -6,8 +6,7 @@ import { MarkdownEditor } from "./MarkdownEditor";
export const MarkdownField = ({ export const MarkdownField = ({
id, id,
gcp, storage,
s3,
...rest ...rest
}: { id: string } & Parameters<typeof Box>[0]) => { }: { id: string } & Parameters<typeof Box>[0]) => {
const [{ value, onBlur }, { error, touched }, { setValue }] = useField(id); const [{ value, onBlur }, { error, touched }, { setValue }] = useField(id);
@ -36,8 +35,7 @@ export const MarkdownField = ({
onBlur={handleBlur} onBlur={handleBlur}
value={value} value={value}
onChange={setValue} onChange={setValue}
gcp={gcp} storage={storage}
s3={s3}
/> />
<ErrorLabel mt="2" hasError={!!(error && touched)}> <ErrorLabel mt="2" hasError={!!(error && touched)}>
{error} {error}

View File

@ -21,8 +21,7 @@ interface PostFormProps {
) => Promise<any>; ) => Promise<any>;
submitLabel: string; submitLabel: string;
loadingText: string; loadingText: string;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
const formSchema = Yup.object({ const formSchema = Yup.object({
@ -36,7 +35,7 @@ export interface PostFormSchema {
} }
export function PostForm(props: PostFormProps) { export function PostForm(props: PostFormProps) {
const { initial, onSubmit, submitLabel, loadingText, gcp, s3, cancel, history } = props; const { initial, onSubmit, submitLabel, loadingText, storage, cancel, history } = props;
return ( return (
<Col width="100%" height="100%" p={[2, 4]}> <Col width="100%" height="100%" p={[2, 4]}>
@ -67,7 +66,7 @@ export function PostForm(props: PostFormProps) {
type="button">Cancel</Button>} type="button">Cancel</Button>}
</Row> </Row>
</Row> </Row>
<MarkdownField flexGrow={1} id="body" gcp={gcp} s3={s3} /> <MarkdownField flexGrow={1} id="body" storage={storage} />
</Form> </Form>
</Formik> </Formik>
</Col> </Col>

View File

@ -11,8 +11,7 @@ import {
Graph, Graph,
Contacts, Contacts,
Association, Association,
GcpState, StorageState,
S3State,
Group Group
} from "~/types"; } from "~/types";
@ -28,8 +27,7 @@ interface NoteRoutesProps {
baseUrl?: string; baseUrl?: string;
rootUrl?: string; rootUrl?: string;
group: Group; group: Group;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
export function NoteRoutes(props: NoteRoutesProps & RouteComponentProps) { export function NoteRoutes(props: NoteRoutesProps & RouteComponentProps) {

View File

@ -9,8 +9,7 @@ import {
Contacts, Contacts,
Rolodex, Rolodex,
Unreads, Unreads,
GcpState, StorageState
S3State
} from "~/types"; } from "~/types";
import { Center, LoadingSpinner } from "@tlon/indigo-react"; import { Center, LoadingSpinner } from "@tlon/indigo-react";
import bigInt from 'big-integer'; import bigInt from 'big-integer';
@ -34,8 +33,7 @@ interface NotebookRoutesProps {
rootUrl: string; rootUrl: string;
association: Association; association: Association;
associations: Associations; associations: Associations;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
export function NotebookRoutes( export function NotebookRoutes(
@ -82,8 +80,7 @@ export function NotebookRoutes(
association={props.association} association={props.association}
graph={graph} graph={graph}
baseUrl={baseUrl} baseUrl={baseUrl}
gcp={props.gcp} storage={props.storage}
s3={props.s3}
/> />
)} )}
/> />
@ -115,8 +112,7 @@ export function NotebookRoutes(
contacts={notebookContacts} contacts={notebookContacts}
association={props.association} association={props.association}
group={group} group={group}
gcp={props.gcp} storage={props.storage}
s3={props.s3}
{...routeProps} {...routeProps}
/> />
); );

View File

@ -16,8 +16,7 @@ interface NewPostProps {
graph: Graph; graph: Graph;
association: Association; association: Association;
baseUrl: string; baseUrl: string;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
export default function NewPost(props: NewPostProps & RouteComponentProps) { export default function NewPost(props: NewPostProps & RouteComponentProps) {
@ -54,8 +53,7 @@ export default function NewPost(props: NewPostProps & RouteComponentProps) {
onSubmit={onSubmit} onSubmit={onSubmit}
submitLabel="Publish" submitLabel="Publish"
loadingText="Posting..." loadingText="Posting..."
gcp={props.gcp} storage={props.storage}
s3={props.s3}
/> />
); );
} }

View File

@ -9,7 +9,7 @@ import {
} from "@tlon/indigo-react"; } from "@tlon/indigo-react";
import GlobalApi from "~/logic/api/global"; import GlobalApi from "~/logic/api/global";
import { GcpState, S3State } from "~/types"; import { StorageState, } from "~/types";
import { ImageInput } from "~/views/components/ImageInput"; import { ImageInput } from "~/views/components/ImageInput";
import {ColorInput} from "~/views/components/ColorInput"; import {ColorInput} from "~/views/components/ColorInput";
@ -19,14 +19,12 @@ export function BackgroundPicker({
bgType, bgType,
bgUrl, bgUrl,
api, api,
gcp, storage,
s3,
}: { }: {
bgType: BgType; bgType: BgType;
bgUrl?: string; bgUrl?: string;
api: GlobalApi; api: GlobalApi;
gcp: GcpState; storage: StorageState;
s3: S3State;
}) { }) {
const rowSpace = { my: 0, alignItems: 'center' }; const rowSpace = { my: 0, alignItems: 'center' };
@ -40,8 +38,7 @@ export function BackgroundPicker({
<ImageInput <ImageInput
ml="3" ml="3"
api={api} api={api}
gcp={gcp} storage={storage}
s3={s3}
id="bgUrl" id="bgUrl"
name="bgUrl" name="bgUrl"
label="URL" label="URL"

View File

@ -10,7 +10,7 @@ import * as Yup from 'yup';
import GlobalApi from '~/logic/api/global'; import GlobalApi from '~/logic/api/global';
import { uxToHex } from '~/logic/lib/util'; import { uxToHex } from '~/logic/lib/util';
import { GcpState, S3State, BackgroundConfig } from '~/types'; import { StorageState, BackgroundConfig } from '~/types';
import { BackgroundPicker, BgType } from './BackgroundPicker'; import { BackgroundPicker, BgType } from './BackgroundPicker';
import useLocalState, { LocalState } from '~/logic/state/local'; import useLocalState, { LocalState } from '~/logic/state/local';
@ -34,12 +34,11 @@ interface FormSchema {
interface DisplayFormProps { interface DisplayFormProps {
api: GlobalApi; api: GlobalApi;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
export default function DisplayForm(props: DisplayFormProps) { export default function DisplayForm(props: DisplayFormProps) {
const { api, gcp, s3 } = props; const { api, storage } = props;
const { hideAvatars, hideNicknames, background, set: setLocalState } = useLocalState(); const { hideAvatars, hideNicknames, background, set: setLocalState } = useLocalState();
@ -95,8 +94,7 @@ export default function DisplayForm(props: DisplayFormProps) {
bgType={props.values.bgType} bgType={props.values.bgType}
bgUrl={props.values.bgUrl} bgUrl={props.values.bgUrl}
api={api} api={api}
gcp={gcp} storage={storage}
s3={s3}
/> />
<Checkbox <Checkbox
label="Disable avatars" label="Disable avatars"

View File

@ -13,8 +13,7 @@ type ProfileProps = StoreState & { api: GlobalApi; ship: string };
export default function Settings({ export default function Settings({
api, api,
gcp, storage,
s3
}: ProfileProps) { }: ProfileProps) {
return ( return (
<Box <Box
@ -28,11 +27,10 @@ export default function Settings({
> >
<DisplayForm <DisplayForm
api={api} api={api}
gcp={gcp} storage={storage}
s3={s3}
/> />
<RemoteContentForm api={api} /> <RemoteContentForm api={api} />
<S3Form api={api} s3={s3} /> <S3Form api={api} s3={storage.s3} />
<SecuritySettings api={api} /> <SecuritySettings api={api} />
</Box> </Box>
); );

View File

@ -10,22 +10,20 @@ import {
BaseInput BaseInput
} from "@tlon/indigo-react"; } from "@tlon/indigo-react";
import { useField } from "formik"; import { useField } from "formik";
import { S3State } from "~/types/s3-update"; import { StorageState } from "~/types/storage-state";
import { GcpState } from "~/types/gcp-state";
import useStorage from "~/logic/lib/useStorage"; import useStorage from "~/logic/lib/useStorage";
type ImageInputProps = Parameters<typeof Box>[0] & { type ImageInputProps = Parameters<typeof Box>[0] & {
id: string; id: string;
label: string; label: string;
s3: S3State; storage: StorageState;
gcp: GcpState;
placeholder?: string; placeholder?: string;
}; };
export function ImageInput(props: ImageInputProps) { export function ImageInput(props: ImageInputProps) {
const { id, label, s3, gcp, caption, placeholder, ...rest } = props; const { id, label, storage, caption, placeholder, ...rest } = props;
const { uploadDefault, canUpload, uploading } = useStorage(s3, gcp); const { uploadDefault, canUpload, uploading } = useStorage(storage);
const [field, meta, { setValue, setError }] = useField(id); const [field, meta, { setValue, setError }] = useField(id);

View File

@ -3,7 +3,7 @@ import useStorage from "~/logic/lib/useStorage";
const withStorage = (Component, params = {}) => { const withStorage = (Component, params = {}) => {
return React.forwardRef((props: any, ref) => { return React.forwardRef((props: any, ref) => {
const storage = useStorage(props.s3, props.gcp, params); const storage = useStorage(props.storage, params);
return <Component ref={ref} {...storage} {...props} />; return <Component ref={ref} {...storage} {...props} />;
}); });

View File

@ -22,7 +22,7 @@ import { ColorInput } from "~/views/components/ColorInput";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { uxToHex } from "~/logic/lib/util"; import { uxToHex } from "~/logic/lib/util";
import {GcpState, S3State} from "~/types"; import {StorageState} from "~/types";
import {ImageInput} from "~/views/components/ImageInput"; import {ImageInput} from "~/views/components/ImageInput";
interface FormSchema { interface FormSchema {
@ -46,12 +46,11 @@ interface GroupAdminSettingsProps {
group: Group; group: Group;
association: Association; association: Association;
api: GlobalApi; api: GlobalApi;
gcp: GcpState; storage: StorageState;
s3: S3State;
} }
export function GroupAdminSettings(props: GroupAdminSettingsProps) { export function GroupAdminSettings(props: GroupAdminSettingsProps) {
const { group, association, gcp, s3 } = props; const { group, association, storage } = props;
const { metadata } = association; const { metadata } = association;
const history = useHistory(); const history = useHistory();
const currentPrivate = "invite" in props.group.policy; const currentPrivate = "invite" in props.group.policy;
@ -133,8 +132,7 @@ export function GroupAdminSettings(props: GroupAdminSettingsProps) {
caption="A picture for your group" caption="A picture for your group"
placeholder="Enter URL" placeholder="Enter URL"
disabled={disabled} disabled={disabled}
gcp={gcp} storage={storage}
s3={s3}
/> />
<Checkbox <Checkbox
id="isPrivate" id="isPrivate"

View File

@ -6,7 +6,7 @@ import GlobalApi from "~/logic/api/global";
import { GroupAdminSettings } from "./Admin"; import { GroupAdminSettings } from "./Admin";
import { GroupPersonalSettings } from "./Personal"; import { GroupPersonalSettings } from "./Personal";
import { GroupNotificationsConfig, GcpState, S3State } from "~/types"; import { GroupNotificationsConfig, StorageState } from "~/types";
import { GroupChannelSettings } from "./Channels"; import { GroupChannelSettings } from "./Channels";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import {resourceFromPath, roleForShip} from "~/logic/lib/group"; import {resourceFromPath, roleForShip} from "~/logic/lib/group";
@ -21,8 +21,7 @@ interface GroupSettingsProps {
associations: Associations; associations: Associations;
api: GlobalApi; api: GlobalApi;
notificationsGroupConfig: GroupNotificationsConfig; notificationsGroupConfig: GroupNotificationsConfig;
gcp: GcpState; storage: StorageState;
s3: S3State;
baseUrl: string; baseUrl: string;
} }
export function GroupSettings(props: GroupSettingsProps) { export function GroupSettings(props: GroupSettingsProps) {

View File

@ -71,8 +71,7 @@ export function GroupsPane(props: GroupsPaneProps) {
association={groupAssociation!} association={groupAssociation!}
group={group!} group={group!}
api={api} api={api}
gcp={props.gcp} storage={props.storage}
s3={props.s3}
notificationsGroupConfig={props.notificationsGroupConfig} notificationsGroupConfig={props.notificationsGroupConfig}
associations={associations} associations={associations}

View File

@ -6,12 +6,7 @@ import { Contacts, Contact } from "~/types/contact-update";
import { Group } from "~/types/group-update"; import { Group } from "~/types/group-update";
import { Association } from "~/types/metadata-update"; import { Association } from "~/types/metadata-update";
import GlobalApi from "~/logic/api/global"; import GlobalApi from "~/logic/api/global";
import { import { GroupNotificationsConfig, StorageState, Associations } from "~/types";
GroupNotificationsConfig,
GcpState,
S3State,
Associations
} from "~/types";
import { GroupSettings } from "./GroupSettings/GroupSettings"; import { GroupSettings } from "./GroupSettings/GroupSettings";
import { Participants } from "./Participants"; import { Participants } from "./Participants";
@ -28,8 +23,7 @@ export function PopoverRoutes(
group: Group; group: Group;
association: Association; association: Association;
associations: Associations; associations: Associations;
gcp: GcpState; storage: StorageState;
s3: S3State;
api: GlobalApi; api: GlobalApi;
notificationsGroupConfig: GroupNotificationsConfig; notificationsGroupConfig: GroupNotificationsConfig;
rootIdentity: Contact; rootIdentity: Contact;
@ -133,8 +127,7 @@ export function PopoverRoutes(
api={props.api} api={props.api}
notificationsGroupConfig={props.notificationsGroupConfig} notificationsGroupConfig={props.notificationsGroupConfig}
associations={props.associations} associations={props.associations}
gcp={props.gcp} storage={props.storage}
s3={props.s3}
/> />
)} )}
{view === "participants" && ( {view === "participants" && (