Skip to content

Commit

Permalink
Add new tab for ServiceAccounts in NS admin UI
Browse files Browse the repository at this point in the history
  • Loading branch information
radhikav1 committed Sep 12, 2023
1 parent c9acc3b commit 477d5b5
Show file tree
Hide file tree
Showing 5 changed files with 446 additions and 0 deletions.
7 changes: 7 additions & 0 deletions app/cdap/components/NamespaceAdmin/AdminTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import Tab from '@material-ui/core/Tab';
import TabContext from '@material-ui/lab/TabContext';
import styled from 'styled-components';
import { useLocation } from 'react-router';
import ServiceAccounts from './ServiceAccounts';

const StyledTabs = styled(Tabs)`
border-bottom: 1px solid #e8e8e8;
Expand Down Expand Up @@ -91,6 +92,11 @@ export const AdminTabs = () => {
value={`${baseNSPath}/connections`}
/>
<LinkTab label="Drivers" to={`${baseNSPath}/drivers`} value={`${baseNSPath}/drivers`} />
<LinkTab
label="Service Accounts"
to={`${baseNSPath}/serviceaccounts`}
value={`${baseNSPath}/serviceaccounts`}
/>
{sourceControlManagementEnabled && (
<LinkTab
label="Source Control Management"
Expand All @@ -108,6 +114,7 @@ export const AdminTabs = () => {
<Route exact path={`${basepath}/connections`} component={Connections} />
<Route exact path={`${basepath}/drivers`} component={Drivers} />
<Route exact path={`${basepath}/scm`} component={SourceControlManagement} />
<Route exact path={`${basepath}/serviceaccounts`} component={ServiceAccounts} />
</Switch>
</div>
</>
Expand Down
249 changes: 249 additions & 0 deletions app/cdap/components/NamespaceAdmin/ServiceAccounts/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/*
* Copyright © 2023 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

import React, { useState } from 'react';
import { connect } from 'react-redux';

import Table from 'components/shared/Table';
import TableHeader from 'components/shared/Table/TableHeader';
import TableRow from 'components/shared/Table/TableRow';
import TableCell from 'components/shared/Table/TableCell';
import TableBody from 'components/shared/Table/TableBody';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import ActionsPopover, { IAction } from 'components/shared/ActionsPopover';
import T from 'i18n-react';
import InputAdornment from '@material-ui/core/InputAdornment';
import HelpIcon from '@material-ui/icons/Help';
import Box from '@material-ui/core/Box';
import styled from 'styled-components';
import IconButton from '@material-ui/core/IconButton';
import { ConfirmDialog } from 'components/shared/ConfirmDialog';

const PREFIX = 'features.ServiceAccounts';

const SubTitleBox = styled(Box)`
margin-bottom: 15px;
`;

const StyledTextField = styled(TextField)`
& .MuiInputLabel-shrink {
font-size: 15px;
}
& .MuiOutlinedInput-notchedOutline {
font-size: 14px;
border-color: #80868b;
}
& .MuiFormHelperText-root {
margin-left: 0px;
font-size: 12px;
}
`;

const ServiceAccountsView = ({ serviceacnts }) => {
// mock data
// serviceacnts = [{ name: 'serviceaccount1' }, { name: 'serviceaccount2' }];

const [showPopover, setShowPopover] = useState(false);
const [isDeleteModalOpen, setDeleteModalOpen] = useState(false);
const [selectedServiceAcnt, setSelectedServiceAcnt] = useState(null);
const [open, setOpen] = React.useState(false);
const [deleteErrorMsg, setDeleteErrorMsg] = useState(null);
const [extendedErrorMsg, setExtendedErrorMsg] = useState(null);
const [saveErrorMsg, setSaveErrorMsg] = useState(null);
const [saveErrorDetails, setSaveErrorDetails] = useState(null);

const handleClose = () => {
setOpen(false);
setSaveErrorMsg(null);
setSaveErrorDetails(null);
};

const handleSave = () => {
// alert('saving ' + selectedServiceAcnt);
// setSaveErrorMsg(T.translate(`${PREFIX}.saveErrorMessage`));
// setSaveErrorDetails({
// response:
// 'Sample Error message for testing : Error occurred as save is not intergrated with API',
// });
};

const addHandler = () => {
setOpen(true);
setSelectedServiceAcnt(null);
};

const deleteHanlder = (serviceAcnt) => {
// alert('delete');
// const sampleError =
// 'Error occurred : ' +
// "Exception in thread 'main' java.util.InputMismatchException" +
// 'at java.base/java.util.Scanner.throwFor(Scanner.java:939)' +
// 'at java.base/java.util.Scanner.next(Scanner.java:1594)' +
// 'at java.base/java.util.Scanner.nextFloat(Scanner.java:2496)' +
// 'at java.base/java.util.Scanner.throwFor(Scanner.java:939)' +
// 'at java.base/java.util.Scanner.next(Scanner.java:1594)' +
// 'at java.base/java.util.Scanner.nextFloat(Scanner.java:2496)' +
// 'at java.base/java.util.Scanner.throwFor(Scanner.java:939)' +
// 'at java.base/java.util.Scanner.next(Scanner.java:1594)' +
// 'at java.base/java.util.Scanner.nextFloat(Scanner.java:2496)';
// setExtendedErrorMsg(sampleError);
// setDeleteErrorMsg(T.translate(`${PREFIX}.deleteErrorMessage`));
};

const handleShowHelp = () => {
// to do
};

function showEditDialog(serviceAcnt) {
setSelectedServiceAcnt(serviceAcnt.name);
setOpen(true);
setShowPopover(!showPopover);
}

const closeDeleteConfirmation = () => {
setDeleteModalOpen(false);
setDeleteErrorMsg(null);
};

const showDeleteConfirmation = (serviceAcnt) => {
setSelectedServiceAcnt(serviceAcnt.name);
setShowPopover(!showPopover);
setDeleteModalOpen(true);
};

const renderDeleteConfirm = () => {
return (
<ConfirmDialog
headerTitle={T.translate(`${PREFIX}.deleteTitle`)}
confirmationElem={T.translate(`${PREFIX}.deleteConfirmation`, {
serviceaccount: selectedServiceAcnt,
})}
cancelButtonText={T.translate(`${PREFIX}.cancelButtonText`)}
confirmButtonText={T.translate(`${PREFIX}.deleteButtonText`)}
confirmFn={deleteHanlder}
cancelFn={closeDeleteConfirmation}
isOpen={isDeleteModalOpen}
severity="error"
statusMessage={deleteErrorMsg}
extendedMessage={extendedErrorMsg}
></ConfirmDialog>
);
};

const getEditDialogContent = () => {
return (
<StyledTextField
label={T.translate(`${PREFIX}.editInputLabel`)}
defaultValue={selectedServiceAcnt}
helperText={T.translate(`${PREFIX}.inputHelperText`)}
variant="outlined"
margin="dense"
fullWidth
color="primary"
onChange={(ev) => {
setSelectedServiceAcnt(ev.target.value);
}}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={handleShowHelp} size="small">
<HelpIcon />
</IconButton>
</InputAdornment>
),
}}
/>
);
};

const renderEditDialog = () => {
return (
<ConfirmDialog
headerTitle={T.translate(`${PREFIX}.serviceAccount`)}
confirmationElem={getEditDialogContent()}
cancelButtonText={T.translate('commons.cancel')}
confirmButtonText={T.translate('commons.save')}
confirmFn={handleSave}
cancelFn={handleClose}
disableAction={!selectedServiceAcnt ? true : false}
isOpen={open}
severity="error"
statusMessage={saveErrorMsg}
extendedMessage={saveErrorDetails}
></ConfirmDialog>
);
};

return (
<div>
{!serviceacnts && (
<SubTitleBox>
<Button variant="contained" color="primary" onClick={addHandler}>
{T.translate(`${PREFIX}.addServiceAccount`)}
</Button>
</SubTitleBox>
)}
<Table columnTemplate="1fr 100px">
<TableHeader>
<TableRow>
<TableCell>{T.translate(`${PREFIX}.serviceAccount`)}</TableCell>
<TableCell />
</TableRow>
</TableHeader>

<TableBody>
{serviceacnts &&
serviceacnts.map((serviceAcnt) => {
const actions: IAction[] = [
{
label: T.translate('commons.edit'),
actionFn: () => showEditDialog(serviceAcnt),
},
{
label: 'separator',
},
{
label: T.translate('commons.delete'),
actionFn: () => showDeleteConfirmation(serviceAcnt),
},
];

return (
<TableRow key={`${serviceAcnt.name}`}>
<TableCell>{serviceAcnt.name}</TableCell>
<TableCell>
<ActionsPopover actions={actions} />
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
{renderDeleteConfirm()}
{renderEditDialog()}
</div>
);
};

const mapStateToProps = (state) => {
return {
serviceacnts: state.serviceacnts,
};
};

const ServiceAccounts = connect(mapStateToProps)(ServiceAccountsView);
export default ServiceAccounts;
Loading

0 comments on commit 477d5b5

Please sign in to comment.