Skip to content

Instantly share code, notes, and snippets.

@dbanksdesign
Last active February 26, 2025 16:43
Show Gist options
  • Save dbanksdesign/76debc7597b6ea185c2f766e6d5de4d5 to your computer and use it in GitHub Desktop.
Save dbanksdesign/76debc7597b6ea185c2f766e6d5de4d5 to your computer and use it in GitHub Desktop.
Storage Browser for S3 with a custom share action
import { getUrl } from '@aws-amplify/storage/internals';
import { ActionViewConfig, ActionHandler } from '@aws-amplify/ui-react-storage/browser';
type ShareHandler = ActionHandler<{ duration: number }, string>;
const handler: ShareHandler = ({ data, config }) => {
const result = getUrl({
path: data.key,
options: {
bucket: {
bucketName: config.bucket,
region: config.region
},
locationCredentialsProvider: config.credentials,
validateObjectExistence: true,
expiresIn: data.duration * 60,
}
}).then((res) => ({
status: 'COMPLETE' as const,
value: res.url.toString()
}))
return { result }
}
export const shareAction: ActionViewConfig<ShareHandler, 'ShareActionView'> = {
handler,
viewName: 'ShareActionView',
actionListItem: {
label: 'Share',
icon: 'download',
disable: (selected) => !selected?.length,
}
}
import { shareAction } from "@/actions/shareAction";
import { ACCOUNT_ID, REGION } from "@/constants";
import { getCredentials } from "@/utils/credentialsProvider";
import {
createManagedAuthAdapter,
createStorageBrowser,
} from "@aws-amplify/ui-react-storage/browser";
export const { StorageBrowser, useView, useAction } = createStorageBrowser({
config: createManagedAuthAdapter({
region: REGION,
accountId: ACCOUNT_ID,
registerAuthListener: () => {},
credentialsProvider: async () => {
const credentials = await getCredentials();
return credentials;
},
}),
actions: {
custom: {
shareAction,
},
},
});
import { ShareActionView } from "@/components/ShareAction";
import { StorageBrowser, useView } from "@/components/StorageBrowser";
import { theme } from "@/theme";
import { Flex, Link, ThemeProvider, View } from "@aws-amplify/ui-react";
import * as React from "react";
function LocationsView() {
const state = useView("Locations");
return (
<Flex direction="column">
{state.pageItems.map((item) => (
<Link
onClick={() => {
state.onNavigate(item);
}}
>
{item.bucket}/{item.prefix}
</Link>
))}
</Flex>
);
}
function LocationDetailView() {
const state = useView("LocationDetail");
const [action, setAction] = React.useState<string>();
const ref = React.useRef<HTMLDialogElement>(null);
if (!state.location.current) {
return <View>Select location</View>;
}
return (
<>
<StorageBrowser.LocationDetailView
key={action}
onActionSelect={(action) => {
setAction(action);
ref.current?.showModal();
}}
/>
<dialog ref={ref}>
{action === "shareAction" ? (
<ShareActionView
files={state.fileDataItems}
onExit={() => {
setAction(undefined);
ref.current?.close();
}}
/>
) : (
<StorageBrowser.LocationActionView
onExit={() => {
setAction(undefined);
ref.current?.close();
}}
/>
)}
</dialog>
</>
);
}
export default function StoragePage() {
return (
<ThemeProvider theme={theme}>
<StorageBrowser.Provider>
<Flex direction="row">
<LocationsView />
<LocationDetailView />
</Flex>
</StorageBrowser.Provider>
</ThemeProvider>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment