Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(storage-browser): integrate browser navigation events #5941

Merged

Conversation

calebpollman
Copy link
Member

@calebpollman calebpollman commented Oct 23, 2024

Description of changes

Issue #, if available

Add support for browser navigation through exposing of event callbacks on the View components and controlled props on StorageBrowser.Provider

  • add "routed" default-auth/ and managed-auth example apps:
  • integrate useProcessTasks in to UploadView
  • integrate updated store context/state and remove dead code
  • add do-not-import-from-here directory containing modules that will be replaced with the new actions API
  • update task action handlers to receive key on top level input
  • remove as many duplicated types and temp workarounds as possible
  • remove useControl in anticipation of useView
  • add unique id generation to all values kept in state
  • consolidate store context hooks in to useStore
  • dedupe store "RESET" action types/improve clarity of other store event types
  • add remove support to the UploadView tasks

Known issues:

  • progress rendering on uploads is currently unsupported
  • breadcrumbs currently render the full prefix, the current data parsing logic will be addressed in a follow up

Description of how you validated changes

Example apps

Checklist

  • Have read the Pull Request Guidelines
  • PR description included
  • yarn test passes and tests are updated/added
  • PR title and commit messages follow conventional commit syntax
  • If this change should result in a version bump, changeset added (This can be done after creating the PR.) This does not apply to changes made to docs, e2e, examples, or other private packages.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Copy link

changeset-bot bot commented Oct 23, 2024

⚠️ No Changeset found

Latest commit: a5b5816

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@calebpollman calebpollman force-pushed the feat-storage-browser/browser-navigation branch 6 times, most recently from 3a852c4 to 986d37d Compare October 23, 2024 23:49
@calebpollman calebpollman force-pushed the feat-storage-browser/browser-navigation branch from 986d37d to 8ba14e6 Compare October 24, 2024 00:20
@@ -12,16 +12,14 @@ import { useControl } from './context/control';
export function StorageBrowserDefault(): React.JSX.Element {
const { LocationActionView, LocationDetailView, LocationsView } = useViews();

const [{ location }] = useControl('NAVIGATE');
const [{ selected }] = useControl('LOCATION_ACTIONS');
const [{ actionType, history }] = useStore();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -7,5 +7,9 @@ export interface ActionConfigsProviderProps {

const defaultValue: ActionConfigs = {};

export interface ActionConfigsProviderProps {
actions?: ActionConfigs;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the type is ActionConfigs, shouldn't the prop just match? i.e. actionConfigs?:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually yes but this will most like be actions on the createStorageBrowser API but also okay with changing it here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof. What is the DX going to look like there? I don't know if I love providing configuration via some API property that does not imply configuration. Especially when it then unexpectedly translates to configuration internally - one more mental mapping we have to keep track of, albeit just early on in the sequence

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's in a config object, can discuss offline

@@ -19,9 +19,10 @@ export interface CopyHandlerOutput extends TaskHandlerOutput {}
export interface CopyHandler
extends TaskHandler<CopyHandlerInput, CopyHandlerOutput> {}

export const copyHandler: CopyHandler = ({ config, options, prefix, data }) => {
export const copyHandler: CopyHandler = (input) => {
const { config, key, options, prefix, data } = input;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: What was the issue with just destructuring the param?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal preference to keep them on one line 🤷

}
}

return { bucket, id, permission, prefix, type };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could return within the cases to avoid having to break or use let

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what i normally what i would do here but am trying to actually use let instead of forcing const everywhere 😓

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I'm curious what the rationale for that is. let is a perfectly acceptable pattern when it is necessary but why wouldn't we discourage it when it isn't necessary but does introduce potential sharp edges?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure i see sharp edges here, would be more concerned if the assignment was an array or object

}
case 'PREFIX': {
// { scope: 's3://bucket/path/*', type: 'PREFIX', },
bucket = sanitizedScope.slice(0, sanitizedScope.indexOf('/'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for indexOf to return -1? (and is that desirable?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question - we have an open issue to filter out PREFIX locations that do not end with a trailing slash which should prevent the possibility of indexOf resolving to -1. Probably makse sense to address it here tho as well, can address in a follow up

@@ -1,6 +1,6 @@
import { LocationCredentialsProvider } from '../storage-internal';

import { ActionState } from '../context/actions/createActionStateContext';
import { ActionState } from '../do-not-import-from-here/actions/createActionStateContext';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫡

@calebpollman calebpollman force-pushed the feat-storage-browser/browser-navigation branch from 8ba14e6 to 65bb318 Compare October 24, 2024 01:06
const [{ selected }] = useControl('LOCATION_ACTIONS');
const [type, setActionType] = React.useState<string | undefined>(undefined);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useControl has been removed from createStorageBrowser and will be replaced with useView. In the meantime updated this app to work with the new event callbacks

* @param {UseIsSignedInParams} params `onSignIn` and `onSignOut` event callbacks
* @returns {UseIsSignedIn} Outputs `isSignedIn`
*/
export default function useIsSignedIn({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from an internal file

@@ -50,3 +52,43 @@ export const constructBucket = ({
bucketName: string;
region: string;
} => ({ bucketName, region });

export const parseLocationAccess = (location: LocationAccess): LocationData => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migrated with existing unit tests from a deleted module

import {
AuthConfigAdapter,
CreateManagedAuthConfigAdapterInput,
} from '../storage-internal';

export interface StorageBrowserAuthAdapter extends AuthConfigAdapter {
accountId?: string;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added accountId to the return of the adapters to allow for it to passthrough directly to the input of createStorageBrowser

Comment on lines -26 to +23
<LocationItemsProvider locationItems={locationItems}>
<LocationItemsProvider>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed locationItems from the StorageBrowser.Provider interface, can be revisited if it makes sense to add it

Comment on lines +106 to +108
// @todo: prefix should not be required to refresh
prefix: current?.prefix ?? '',
options: { reset: true },
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be addressed in a follow up when moving to the actions API

// reset hook state on exit, use empty string for prefix to keep TS happy
// @todo: this needs to be addressed
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously noted, but needs to be addressed with the actions API migration

Comment on lines +125 to +131
<button
onClick={() => {
row.remove();
}}
>
Remove
</button>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just added an HTML button as this will need to be replaced during DataTable integration

_remove();
};

return { ...task, folder, key, progress: 0, remove, size, type };
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

progress support is currently missing and will be addressed in a targeted follow to useProcessTasks

@calebpollman calebpollman changed the title [WIP] feat(storage-browser): integrate browser navigation events feat(storage-browser): integrate browser navigation events Oct 24, 2024
@calebpollman calebpollman marked this pull request as ready for review October 24, 2024 01:11
@calebpollman calebpollman requested a review from a team as a code owner October 24, 2024 01:11

const dispatchHandler: HandleStoreAction = React.useCallback(
(action) => {
switch (action.type) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Is type guaranteed to be unique by the typing? Marking this nit since it's kind of an edge case either way.

functions: 83,
lines: 91,
statements: 90,
branches: 80,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor drop in branch coverage but will be addressed in other migration PRs

@@ -74,15 +74,3 @@ describe('isCancelableOutput', () => {
expect(result).toBe(false);
});
});

describe('hasExistingTask', () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer exists

Comment on lines -98 to -159
it('opens the file picker when the add files button is clicked and uses the file selection dialog', async () => {
const user = userEvent.setup();
const files = [
new File(['content1'], 'file1.txt', { type: 'text/plain' }),
new File(['content2'], 'file2.txt', { type: 'text/plain' }),
new File(['content3'], 'file3.txt', {
type: 'text/plain',
}),
];

render(
<Provider>
<UploadControls />
</Provider>
);

const button = screen.getByRole('button', { name: 'Add files' });
const input: HTMLInputElement = screen.getByTestId('amplify-file-select');

expect(input).toHaveAttribute('multiple');

await act(async () => {
await user.click(button);
await user.upload(input, files);
});

expect(input.files).toHaveLength(3);
});

it('adds files dragged into the drop zone to the file list', async () => {
const files = [new File(['content'], 'file.txt', { type: 'text/plain' })];

render(
<Provider>
<UploadControls />
</Provider>
);

const dropzone = screen.getByTestId('storage-browser-table');

fireEvent.drop(dropzone, {
dataTransfer: {
files,
},
});

await waitFor(() => {
expect(screen.getByText('file.txt')).toBeInTheDocument();
});
});

it('has the webkitdirectory attribute for the input select for folders', () => {
render(
<Provider>
<UploadControls />
</Provider>
);

const input: HTMLInputElement = screen.getByTestId('amplify-folder-select');

expect(input).toHaveAttribute('webkitdirectory');
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed these tests as they were testing the logic of underlying components and will be covered by the upcoming DropZone composable

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved these in to their own test file from /LocationDetailView.spec.tsx

@calebpollman calebpollman merged commit 9881be4 into feat-storage-browser/main Oct 25, 2024
32 checks passed
@calebpollman calebpollman deleted the feat-storage-browser/browser-navigation branch October 25, 2024 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants