-
Notifications
You must be signed in to change notification settings - Fork 306
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
feat(storage-browser): integrate browser navigation events #5941
Conversation
|
3a852c4
to
986d37d
Compare
...ages/react-storage/src/components/StorageBrowser/views/LocationActionView/UploadControls.tsx
Fixed
Show resolved
Hide resolved
986d37d
to
8ba14e6
Compare
@@ -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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✨
packages/react-storage/src/components/StorageBrowser/StorageBrowserDefault.tsx
Show resolved
Hide resolved
@@ -7,5 +7,9 @@ export interface ActionConfigsProviderProps { | |||
|
|||
const defaultValue: ActionConfigs = {}; | |||
|
|||
export interface ActionConfigsProviderProps { | |||
actions?: ActionConfigs; |
There was a problem hiding this comment.
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?:
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 🤷
packages/react-storage/src/components/StorageBrowser/actions/handlers/utils.ts
Show resolved
Hide resolved
} | ||
} | ||
|
||
return { bucket, id, permission, prefix, type }; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 😓
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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('/')); |
There was a problem hiding this comment.
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?)
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🫡
8ba14e6
to
65bb318
Compare
const [{ selected }] = useControl('LOCATION_ACTIONS'); | ||
const [type, setActionType] = React.useState<string | undefined>(undefined); |
There was a problem hiding this comment.
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({ |
There was a problem hiding this comment.
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 => { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
<LocationItemsProvider locationItems={locationItems}> | ||
<LocationItemsProvider> |
There was a problem hiding this comment.
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
// @todo: prefix should not be required to refresh | ||
prefix: current?.prefix ?? '', | ||
options: { reset: true }, |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
<button | ||
onClick={() => { | ||
row.remove(); | ||
}} | ||
> | ||
Remove | ||
</button> |
There was a problem hiding this comment.
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
...ages/react-storage/src/components/StorageBrowser/views/LocationActionView/UploadControls.tsx
Fixed
Show resolved
Hide resolved
_remove(); | ||
}; | ||
|
||
return { ...task, folder, key, progress: 0, remove, size, type }; |
There was a problem hiding this comment.
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
...omponents/StorageBrowser/providers/configuration/__tests__/useGetActionInputCallback.spec.ts
Show resolved
Hide resolved
|
||
const dispatchHandler: HandleStoreAction = React.useCallback( | ||
(action) => { | ||
switch (action.type) { |
There was a problem hiding this comment.
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.
packages/react-storage/src/components/StorageBrowser/tasks/useProcessTasks.ts
Show resolved
Hide resolved
packages/react-storage/src/components/StorageBrowser/views/Controls/Download.tsx
Show resolved
Hide resolved
packages/react-storage/src/components/StorageBrowser/views/Controls/Navigate.tsx
Show resolved
Hide resolved
functions: 83, | ||
lines: 91, | ||
statements: 90, | ||
branches: 80, |
There was a problem hiding this comment.
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', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer exists
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'); | ||
}); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
Description of changes
Issue #, if available
Add support for browser navigation through exposing of event callbacks on the
View
components and controlledprops
onStorageBrowser.Provider
default-auth/
andmanaged-auth
example apps:useProcessTasks
in toUploadView
actions
APIkey
on top level inputuseControl
in anticipation ofuseView
id
generation to all values kept in stateuseStore
UploadView
tasksKnown issues:
prefix
, the current data parsing logic will be addressed in a follow upDescription of how you validated changes
Example apps
Checklist
yarn test
passes and tests are updated/addeddocs
,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.