Skip to content

Commit

Permalink
[MD] Refactor of credential editing page layout & refactor backend fi…
Browse files Browse the repository at this point in the history
…eld validation method (opensearch-project#2222)

* Refactor of credential editing page layout & refactor backend field validation method

* Resolved the comments & fix the multiple call for one operation

Signed-off-by: Yibo Wang <yibow@amazon.com>

Signed-off-by: Yibo Wang <yibow@amazon.com>
Signed-off-by: Kristen Tian <tyarong@amazon.com>
  • Loading branch information
yibow98 authored and kristenTian committed Sep 14, 2022
1 parent 0aabd8f commit dbda07d
Show file tree
Hide file tree
Showing 6 changed files with 416 additions and 252 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
EuiSpacer,
EuiText,
} from '@elastic/eui';
import { i18n } from '@osd/i18n';
import { FormattedMessage } from '@osd/i18n/react';
import { DocLinksStart } from 'src/core/public';
import { context as contextType } from '../../../../../../opensearch_dashboards_react/public';
Expand Down Expand Up @@ -150,11 +151,14 @@ export class CredentialForm extends React.Component<CredentialFormProps, Credent
}
};

createCredentialHeader = i18n.translate('credentialManagement.createIndexPatternHeader', {
defaultMessage: 'Create Stored Credential',
});
/* Render methods */

renderHeader() {
const { docLinks } = this.props;
return <Header docLinks={docLinks} />;
return <Header docLinks={docLinks} headerTitle={this.createCredentialHeader} />;
}

renderContent = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,58 +16,70 @@ import { CredentialManagementContext } from '../../../../types';
export const Header = ({
prompt,
docLinks,
headerTitle,
isBeta = false,
isCreateCredential = false,
}: {
prompt?: React.ReactNode;
docLinks: DocLinksStart;
docLinks?: DocLinksStart;
headerTitle: string;
isBeta?: boolean;
isCreateCredential: boolean;
}) => {
const changeTitle = useOpenSearchDashboards<CredentialManagementContext>().services.chrome
.docTitle.change;
const createCredentialHeader = i18n.translate('credentialManagement.createIndexPatternHeader', {
defaultMessage: 'Create Stored Credential',
});

changeTitle(createCredentialHeader);
changeTitle(headerTitle);

return (
<div>
<EuiTitle>
<h1>
{createCredentialHeader}
<>
{' '}
<EuiBetaBadge
label={i18n.translate('credentialManagement.createCredential.betaLabel', {
defaultMessage: 'Beta',
})}
/>
</>
{headerTitle}

{isBeta ? (
<>
<EuiBetaBadge
label={i18n.translate('credentialManagement.createCredential.betaLabel', {
defaultMessage: 'Beta',
})}
/>
</>
) : null}
</h1>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText>
<p>
<FormattedMessage
id="credentialManagement.createCredential.description"
defaultMessage="A credential can be attached to multiple sources. For example, {credential} can be attached to two data sources {first} and {second}."
values={{
credential: <EuiCode>username-password-credential</EuiCode>,
first: <EuiCode>os-service-log</EuiCode>,
second: <EuiCode>os-application-log</EuiCode>,
}}
/>
<br />
<EuiLink
href={docLinks.links.noDocumentation.indexPatterns.introduction}
target="_blank"
external
>
<FormattedMessage
id="credentialManagement.createCredential.documentation"
defaultMessage="Read documentation"
/>
</EuiLink>
</p>
</EuiText>

{isCreateCredential ? (
<>
<EuiText>
<p>
<FormattedMessage
id="credentialManagement.createCredential.description"
defaultMessage="A credential can be attached to multiple sources. For example, {credential} can be attached to two data sources {first} and {second}."
values={{
credential: <EuiCode>username-password-credential</EuiCode>,
first: <EuiCode>os-service-log</EuiCode>,
second: <EuiCode>os-application-log</EuiCode>,
}}
/>
<br />

<EuiLink
href={docLinks?.links.noDocumentation.indexPatterns.introduction}
target="_blank"
external
>
<FormattedMessage
id="credentialManagement.createCredential.documentation"
defaultMessage="Read documentation"
/>
</EuiLink>
</p>
</EuiText>
</>
) : null}

{prompt ? (
<>
<EuiSpacer size="m" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,24 @@ export const confirmButtonOnDeleteComfirmText = i18n.translate(
defaultMessage: 'Delete',
}
);

export const credentialEditPageAuthType = i18n.translate(
'credentialManagement.textContent.credentialEditPageAuthType',
{
defaultMessage: 'Username & password',
}
);

export const credentialEditPageAuthTitle = i18n.translate(
'credentialManagement.textContent.credentialEditPageAuthTitle',
{
defaultMessage: 'Authentication Details',
}
);

export const credentialEditPageInfoTitle = i18n.translate(
'credentialManagement.textContent.credentialEditPageInfoTitle',
{
defaultMessage: 'Saved Credential Information',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ import {
EuiBadgeGroup,
EuiPageContent,
EuiTitle,
EuiSearchBar,
EuiConfirmModal,
EuiLoadingSpinner,
EuiOverlayMask,
EuiGlobalToastList,
EuiGlobalToastListToast,
Query,
} from '@elastic/eui';

import {
Expand Down Expand Up @@ -66,23 +64,13 @@ interface Props extends RouteComponentProps {
export const CredentialsTable = ({ canSave, history }: Props) => {
const [credentials, setCredentials] = React.useState<CredentialsTableItem[]>([]);
const [selectedCredentials, setSelectedCredentials] = React.useState<CredentialsTableItem[]>([]);

const { setBreadcrumbs } = useOpenSearchDashboards<CredentialManagementContext>().services;

/* Update breadcrumb*/
useEffectOnce(() => {
setBreadcrumbs(getListBreadcrumbs());
});

const [isLoading, setIsLoading] = React.useState(false);
const [isDeleting, setIsDeleting] = React.useState(false);
const [confirmDeleteVisible, setConfirmDeleteVisible] = React.useState(false);
const [toasts, setToasts] = React.useState<EuiGlobalToastListToast[]>([]);
const [searchText, setSearchText] = React.useState('');

const { savedObjects, uiSettings } = useOpenSearchDashboards<
CredentialManagementContext
>().services;
const { savedObjects } = useOpenSearchDashboards<CredentialManagementContext>().services;

const columns = [
{
Expand Down Expand Up @@ -140,28 +128,6 @@ export const CredentialsTable = ({ canSave, history }: Props) => {
onSelectionChange,
};

const renderDeleteButton = () => {
let deleteButtonMsg = 'Delete';

if (selectedCredentials.length === 1) {
deleteButtonMsg = `${deleteButtonMsg} ${selectedCredentials.length} Credential`;
} else if (selectedCredentials.length > 1) {
deleteButtonMsg = `${deleteButtonMsg} ${selectedCredentials.length} Credentials`;
}
return (
<EuiButton
color="danger"
iconType="trash"
onClick={() => {
setConfirmDeleteVisible(true);
}}
disabled={selectedCredentials.length === 0}
>
{deleteButtonMsg}
</EuiButton>
);
};

const onClickDelete = async () => {
try {
setIsDeleting(true);
Expand Down Expand Up @@ -193,25 +159,72 @@ export const CredentialsTable = ({ canSave, history }: Props) => {
}
};

const deleteButton = renderDeleteButton();
const removeToast = (id: string) => {
setToasts(toasts.filter((toast) => toast.id !== id));
};

const createButton = canSave ? <CreateButton history={history} /> : <></>;

const renderDeleteButton = () => {
let deleteButtonMsg = 'Delete';

if (selectedCredentials.length === 1) {
deleteButtonMsg = `${deleteButtonMsg} ${selectedCredentials.length} Credential`;
} else if (selectedCredentials.length > 1) {
deleteButtonMsg = `${deleteButtonMsg} ${selectedCredentials.length} Credentials`;
}
return (
<EuiButton
color="danger"
iconType="trash"
onClick={() => {
setConfirmDeleteVisible(true);
}}
disabled={selectedCredentials.length === 0}
>
{deleteButtonMsg}
</EuiButton>
);
};

/* create a button to the right of search bar*/
const renderToolsRight = () => {
return (
<EuiFlexItem key="delete" grow={false}>
{renderDeleteButton()}
</EuiFlexItem>
);
};

React.useEffect(() => {
const search = {
toolsRight: renderToolsRight(),
box: {
incremental: true,
schema: {
fields: { title: { type: 'string' } },
},
},
};

/* Update breadcrumb*/
useEffectOnce(() => {
setBreadcrumbs(getListBreadcrumbs());
});

/* fetch credential*/
useEffectOnce(() => {
(async () => {
setIsLoading(true);

const fetchedCredentials: CredentialsTableItem[] = await getCredentials(savedObjects.client);
const fetchedCredentialsResults = fetchedCredentials.filter((row) => {
return row.title.includes(searchText);
});
setCredentials(fetchedCredentials);

setCredentials(fetchedCredentialsResults);
setIsLoading(false);
})();
}, [history.push, credentials.length, uiSettings, savedObjects.client, searchText]);

const createButton = canSave ? <CreateButton history={history} /> : <></>;
});

const tableRenderDeleteModal = () => {
/* render delete modal*/
const renderTableDeleteModal = () => {
return confirmDeleteVisible ? (
<EuiConfirmModal
title={LocalizedContent.deleteButtonOnConfirmText}
Expand All @@ -232,19 +245,6 @@ export const CredentialsTable = ({ canSave, history }: Props) => {
) : null;
};

const onSearchChange = ({
query,
}: {
query: Query | null;
error: { message: string } | null;
}) => {
setSearchText(query!.text);
};

const removeToast = (id: string) => {
setToasts(toasts.filter((toast) => toast.id !== id));
};

const renderContent = () => {
return (
<EuiPageContent data-test-subj="credentialsTable" role="region">
Expand Down Expand Up @@ -272,17 +272,7 @@ export const CredentialsTable = ({ canSave, history }: Props) => {
<EuiFlexItem grow={false}>{createButton}</EuiFlexItem>
</EuiFlexGroup>

<EuiSearchBar
box={{ 'data-test-subj': 'savedObjectSearchBar' }}
onChange={(e) => onSearchChange(e)}
toolsRight={[
<EuiFlexItem key="delete" grow={false}>
{deleteButton}
</EuiFlexItem>,
]}
/>

{tableRenderDeleteModal()}
{renderTableDeleteModal()}

<EuiSpacer />

Expand All @@ -295,6 +285,7 @@ export const CredentialsTable = ({ canSave, history }: Props) => {
columns={columns}
pagination={pagination}
sorting={sorting}
search={search}
loading={isLoading}
/>
</>
Expand Down
Loading

0 comments on commit dbda07d

Please sign in to comment.