-
Notifications
You must be signed in to change notification settings - Fork 8.6k
[SR] Repository list and details UI #33367
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
Changes from 8 commits
732ac39
d2c66ca
d608daa
93be6bf
93770e5
2accbf9
f11bcaa
89072a6
bf6cb2e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,3 +17,5 @@ export const PLUGIN = { | |
| }); | ||
| }, | ||
| }; | ||
|
|
||
| export const API_BASE_PATH = '/api/snapshot_restore/'; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| /* | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not very keen on mixing in the same file constant values and types. Also, the way those are used is still a bit of our old js old patterns, I'll explain 😊 We don't need to declare constants to save guard us from tipos or value update. So we don't need to set a value for Another thing is that I would make use of Enum for the different doc URLs. This (and all) enums should go in the export enum RepositoryDocs {
fs = 'modules-snapshots.html#_shared_file_system_repository',
readOnly = 'modules-snapshots.html#_read_only_url_repository',
...
}Then we'd only have 1 import, and the above example (in she screenshot) would end up something like this The change from export const FSRepositoryType = 'fs';
export const ReadonlyRepositoryType = 'url';
export const SourceRepositoryType = 'source';
...
// after
export type FSRepository = 'fs'; // no need to add a "Type" at the end, as it can only be used as a type
export type ReadonlyRepository = 'url';
export type SourceRepository = 'source';
...
export type RepositoryType = FSRepository | ReadonlyRepository | SourceRepositoryOne last thing 😊 (this is more a style guide to agree on), should we create a folder for types and then exposed them all in a barel file? So this file would be in import { SomeType} from ../common/types |
||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License; | ||
| * you may not use this file except in compliance with the Elastic License. | ||
| */ | ||
|
|
||
| export const FSRepositoryType = 'fs'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like we talked yesterday, this list of constants would be better written with an Enum export enum RepositoryTypes {
URL = 'url',
SOURCE = 'source',
S3 = 's3',
...
}
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you are viewing an outdated file 😄 I moved this to
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah sorry! I wrote the comment before you merged it. Then left the review for a while and we got a race condition! 😄 |
||
| export const ReadonlyRepositoryType = 'url'; | ||
| export const SourceRepositoryType = 'source'; | ||
| export const S3RepositoryType = 's3'; | ||
| export const HDFSRepositoryType = 'hdfs'; | ||
| export const AzureRepositoryType = 'azure'; | ||
| export const GCSRepositoryType = 'gcs'; | ||
|
|
||
| export const RepositoryTypeDocPath = 'modules-snapshots.html'; | ||
| export const FSRepositoryTypeDocPath = 'modules-snapshots.html#_shared_file_system_repository'; | ||
| export const ReadonlyRepositoryTypeDocPath = 'modules-snapshots.html#_read_only_url_repository'; | ||
| export const SourceRepositoryTypeDocPath = 'modules-snapshots.html#_source_only_repository'; | ||
| export const S3RepositoryTypeDocPath = 'repository-s3.html'; | ||
| export const HDFSRepositoryTypeDocPath = 'repository-hdfs.html'; | ||
| export const AzureRepositoryTypeDocPath = 'repository-azure.html'; | ||
| export const GCSRepositoryTypeDocPath = 'repository-gcs.html'; | ||
|
|
||
| export type RepositoryType = | ||
| | typeof FSRepositoryType | ||
| | typeof ReadonlyRepositoryType | ||
| | typeof SourceRepositoryType | ||
| | typeof S3RepositoryType | ||
| | typeof HDFSRepositoryType | ||
| | typeof AzureRepositoryType | ||
| | typeof GCSRepositoryType; | ||
|
|
||
| export interface FSRepository { | ||
| name: string; | ||
| type: typeof FSRepositoryType; | ||
| settings: { | ||
| location: string; | ||
| compress?: boolean; | ||
| chunk_size?: string | null; | ||
| max_restore_bytes_per_sec?: string; | ||
| max_snapshot_bytes_per_sec?: string; | ||
| readonly?: boolean; | ||
| }; | ||
| } | ||
|
|
||
| export interface ReadonlyRepository { | ||
| name: string; | ||
| type: typeof ReadonlyRepositoryType; | ||
| settings: { | ||
| url: string; | ||
| }; | ||
| } | ||
|
|
||
| export interface S3Repository { | ||
| name: string; | ||
| type: typeof S3RepositoryType; | ||
| settings: { | ||
| bucket: string; | ||
| client?: string; | ||
| base_path?: string; | ||
| compress?: boolean; | ||
| chunk_size?: string | null; | ||
| server_side_encryption?: boolean; | ||
| buffer_size?: string; | ||
| canned_acl?: string; | ||
| storage_class?: string; | ||
| }; | ||
| } | ||
|
|
||
| export interface HDFSRepository { | ||
| name: string; | ||
| type: typeof HDFSRepositoryType; | ||
| settings: { | ||
| uri: string; | ||
| path: string; | ||
| load_defaults?: boolean; | ||
| compress?: boolean; | ||
| chunk_size?: string | null; | ||
| ['security.principal']?: string; | ||
| [key: string]: any; // For conf.* settings | ||
| }; | ||
| } | ||
|
|
||
| export interface AzureRepository { | ||
| name: string; | ||
| type: typeof AzureRepositoryType; | ||
| settings: { | ||
| client?: string; | ||
| container?: string; | ||
| base_path?: string; | ||
| compress?: boolean; | ||
| chunk_size?: string | null; | ||
| readonly?: boolean; | ||
| location_mode?: string; | ||
| }; | ||
| } | ||
|
|
||
| export interface GCSRepository { | ||
| name: string; | ||
| type: typeof GCSRepositoryType; | ||
| settings: { | ||
| bucket: string; | ||
| client?: string; | ||
| base_path?: string; | ||
| compress?: boolean; | ||
| chunk_size?: string | null; | ||
| }; | ||
| } | ||
|
|
||
| export interface SourceRepository<T> { | ||
| name: string; | ||
| type: typeof SourceRepositoryType; | ||
| settings: SourceRepositorySettings<T>; | ||
| } | ||
|
|
||
| export type SourceRepositorySettings<T> = T extends typeof FSRepositoryType | ||
| ? FSRepository['settings'] | ||
| : T extends typeof S3RepositoryType | ||
| ? S3Repository['settings'] | ||
| : T extends typeof HDFSRepositoryType | ||
| ? HDFSRepository['settings'] | ||
| : T extends typeof AzureRepositoryType | ||
| ? AzureRepository['settings'] | ||
| : T extends typeof GCSRepositoryType | ||
| ? GCSRepository['settings'] | ||
| : any & { | ||
| delegate_type: T; | ||
| }; | ||
|
|
||
| export type Repository<T = null> = | ||
| | FSRepository | ||
| | ReadonlyRepository | ||
| | S3Repository | ||
| | HDFSRepository | ||
| | AzureRepository | ||
| | GCSRepository | ||
| | SourceRepository<T>; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License; | ||
| * you may not use this file except in compliance with the Elastic License. | ||
| */ | ||
|
|
||
| import React, { Fragment, useState } from 'react'; | ||
| import { Repository } from '../../../common/repository_types'; | ||
|
|
||
| interface Props { | ||
| children: any; | ||
| } | ||
|
|
||
| export const RepositoryDeleteProvider = ({ children }: Props) => { | ||
| const [repositoryNames, setRepositoryNames] = useState<Array<Repository['name']>>([]); | ||
| const [isModalOpen, setIsModalOpen] = useState<boolean>(false); | ||
| const deleteRepository = (names: Array<Repository['name']>): void => { | ||
| setIsModalOpen(true); | ||
| setRepositoryNames(names); | ||
| }; | ||
|
|
||
| if (isModalOpen && repositoryNames.length) { | ||
| /* placeholder */ | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is how I would have typed the children props: interface Props {
children: (fun: deleteRepositoryFunction) => ReactNode;
}
type deleteRepositoryFunction = (names: Array<Repository['name']>) => void;
export const RepositoryDeleteProvider = ({ children }: Props) => {
const [repositoryNames, setRepositoryNames] = useState<Array<Repository['name']>>([]);
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const deleteRepository: deleteRepositoryFunction = names => {
setIsModalOpen(true);
setRepositoryNames(names);
};
... |
||
| return <Fragment>{children(deleteRepository)}</Fragment>; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License; | ||
| * you may not use this file except in compliance with the Elastic License. | ||
| */ | ||
|
|
||
| import React, { Fragment } from 'react'; | ||
| import { | ||
| AzureRepositoryType, | ||
| FSRepositoryType, | ||
| GCSRepositoryType, | ||
| HDFSRepositoryType, | ||
| ReadonlyRepositoryType, | ||
| RepositoryType, | ||
| S3RepositoryType, | ||
| SourceRepositoryType, | ||
| } from '../../../common/repository_types'; | ||
| import { AppStateInterface, useAppState } from '../services/app_context'; | ||
|
|
||
| interface Props { | ||
| type: RepositoryType; | ||
| delegateType?: RepositoryType; | ||
| } | ||
|
|
||
| export const RepositoryTypeName = ({ type, delegateType }: Props) => { | ||
| const [ | ||
| { | ||
| core: { | ||
| i18n: { FormattedMessage }, | ||
| }, | ||
| }, | ||
| ] = useAppState() as [AppStateInterface]; | ||
|
|
||
| const typeNameMap: { [key in RepositoryType]: JSX.Element } = { | ||
| [FSRepositoryType]: ( | ||
| <FormattedMessage | ||
| id="xpack.snapshotRestore.repositoryType.fileSystemTypeName" | ||
| defaultMessage="Shared File System" | ||
| /> | ||
| ), | ||
| [ReadonlyRepositoryType]: ( | ||
| <FormattedMessage | ||
| id="xpack.snapshotRestore.repositoryType.readonlyTypeName" | ||
| defaultMessage="Read-only URL" | ||
| /> | ||
| ), | ||
| [S3RepositoryType]: ( | ||
| <FormattedMessage | ||
| id="xpack.snapshotRestore.repositoryType.s3TypeName" | ||
| defaultMessage="AWS S3" | ||
| /> | ||
| ), | ||
| [HDFSRepositoryType]: ( | ||
| <FormattedMessage | ||
| id="xpack.snapshotRestore.repositoryType.hdfsTypeName" | ||
| defaultMessage="HDFS File System" | ||
| /> | ||
| ), | ||
| [AzureRepositoryType]: ( | ||
| <FormattedMessage | ||
| id="xpack.snapshotRestore.repositoryType.azureTypeName" | ||
| defaultMessage="Azure" | ||
| /> | ||
| ), | ||
| [GCSRepositoryType]: ( | ||
| <FormattedMessage | ||
| id="xpack.snapshotRestore.repositoryType.gcsTypeName" | ||
| defaultMessage="Google Cloud Storage" | ||
| /> | ||
| ), | ||
| [SourceRepositoryType]: ( | ||
| <FormattedMessage | ||
| id="xpack.snapshotRestore.repositoryType.sourceTypeName" | ||
| defaultMessage="Source" | ||
| /> | ||
| ), | ||
| }; | ||
|
|
||
| const getTypeName = (repositoryType: RepositoryType): JSX.Element => { | ||
| return typeNameMap[repositoryType] || <Fragment>{type}</Fragment>; | ||
| }; | ||
|
|
||
| if (type === SourceRepositoryType && delegateType) { | ||
| return ( | ||
| <Fragment> | ||
| <FormattedMessage | ||
| id="xpack.snapshotRestore.repositoryType.sourceTypeWithDelegateName" | ||
| defaultMessage="Source ({delegateType})" | ||
| values={{ | ||
| delegateType: getTypeName(delegateType), | ||
| }} | ||
| /> | ||
| </Fragment> | ||
| ); | ||
| } | ||
|
|
||
| return getTypeName(type); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License; | ||
| * you may not use this file except in compliance with the Elastic License. | ||
| */ | ||
|
|
||
| import { EuiCallOut, EuiSpacer } from '@elastic/eui'; | ||
| import React, { Fragment } from 'react'; | ||
|
|
||
| interface Props { | ||
| title: React.ReactNode; | ||
| error: { | ||
| data: { | ||
| error: string; | ||
| cause: string[]; | ||
| message: string; | ||
| }; | ||
| }; | ||
| } | ||
|
|
||
| export function SectionError({ title, error }: Props) { | ||
| const { | ||
| error: errorString, | ||
| cause, // wrapEsError() on the server adds a "cause" array | ||
| message, | ||
| } = error.data; | ||
|
|
||
| return ( | ||
| <EuiCallOut title={title} color="danger" iconType="alert"> | ||
| <div>{message || errorString}</div> | ||
| {cause && ( | ||
| <Fragment> | ||
| <EuiSpacer size="m" /> | ||
| <ul> | ||
| {cause.map((causeMsg, i) => ( | ||
| <li key={i}>{causeMsg}</li> | ||
| ))} | ||
| </ul> | ||
| </Fragment> | ||
| )} | ||
| </EuiCallOut> | ||
| ); | ||
| } |



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.
VSCode was complaining about missing props on
EuiInMemoryTable, it used the definition from here