Skip to content

Commit

Permalink
Merge branch 'master' into brig/client2-switch
Browse files Browse the repository at this point in the history
  • Loading branch information
brig authored Oct 12, 2023
2 parents a6993c3 + 147b0c3 commit 7169495
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 180 deletions.
194 changes: 59 additions & 135 deletions console2/src/components/organisms/NewSecretActivity/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,88 +18,69 @@
* =====
*/

import * as copyToClipboard from 'copy-to-clipboard';
import copyToClipboard from 'copy-to-clipboard';
import * as React from 'react';
import { connect } from 'react-redux';
import { AnyAction, Dispatch } from 'redux';
import { push as pushHistory } from 'connected-react-router';
import { Button, Message, Modal, TextArea } from 'semantic-ui-react';
import {Button, Message, TextArea} from 'semantic-ui-react';

import { ConcordKey, RequestError } from '../../../api/common';
import {ConcordKey} from '../../../api/common';
import {
NewSecretEntry,
SecretStoreType,
SecretTypeExt,
SecretVisibility
} from '../../../api/org/secret';
import { validatePassword } from '../../../api/service/console';
import { actions, State } from '../../../state/data/secrets';
import { CreateSecretResponse } from '../../../state/data/secrets';
import { passwordTooWeakError } from '../../../validation';
import { NewSecretForm, NewSecretFormValues, RequestErrorMessage } from '../../molecules';
import {CreateSecretResponse} from '../../../state/data/secrets';
import {
NewSecretFormValues
} from '../../molecules';

import './styles.css';
import { RequestErrorActivity } from '../index';

interface OwnState {
showPasswordConfirm: boolean;
currentEntry?: NewSecretEntry;
}
import {RequestErrorActivity} from '../index';
import NewSecretForm from '../../molecules/NewSecretForm';
import {LoadingDispatch} from "../../../App";
import {useCallback, useState} from "react";
import {create as apiCreate} from "../../../api/org/secret";
import {useApi} from "../../../hooks/useApi";
import {useHistory} from "react-router";

interface ExternalProps {
orgName: ConcordKey;
}

interface StateProps {
submitting: boolean;
error: RequestError;
response?: CreateSecretResponse;
const INIT_VALUES: NewSecretFormValues = {
name: '',
visibility: SecretVisibility.PRIVATE,
type: SecretTypeExt.NEW_KEY_PAIR,
storeType: SecretStoreType.CONCORD
}

interface DispatchProps {
submit: (values: NewSecretFormValues) => void;
reset: () => void;
done: (secretName: ConcordKey) => void;
}
const NewSecretActivity = (props: ExternalProps) => {
const history = useHistory();

type Props = ExternalProps & StateProps & DispatchProps;
const {orgName} = props;

class NewSecretActivity extends React.Component<Props, OwnState> {
constructor(props: Props) {
super(props);
this.state = { showPasswordConfirm: false };
}

componentDidMount() {
this.props.reset();
}

async handleSubmit(entry: NewSecretEntry, confirm?: boolean) {
if (confirm) {
this.setState({ showPasswordConfirm: false });
} else if (entry.type === SecretTypeExt.USERNAME_PASSWORD && entry.password) {
const valid = await validatePassword(entry.password);
if (!valid) {
this.setState({ showPasswordConfirm: true, currentEntry: entry });
return;
}
}

this.props.submit(entry);
}
const dispatch = React.useContext(LoadingDispatch);
const [values, setValues] = useState(INIT_VALUES);

renderResponse() {
const { response, done, error } = this.props;
const postQuery = useCallback(() => {
return apiCreate(orgName, values);
}, [orgName, values]);

if (!response) {
return;
}
const {error, isLoading, data, fetch} = useApi<CreateSecretResponse>(postQuery, {
fetchOnMount: false,
requestByFetch: true,
dispatch: dispatch
});

if (error) {
return <RequestErrorMessage error={error} />;
}
const handleSubmit = useCallback(
(values: NewSecretFormValues) => {
setValues(values);
fetch();
},
[fetch]
);

const { name: secretName, publicKey, password } = response;
if (data) {
const {publicKey, password} = data;

return (
<>
Expand All @@ -115,7 +96,7 @@ class NewSecretActivity extends React.Component<Props, OwnState> {
basic={true}
onClick={() => (copyToClipboard as any)(publicKey)}
/>
<TextArea className="secretData" value={publicKey} rows={5} />
<TextArea className="secretData" value={publicKey} rows={5}/>
</div>
)}

Expand All @@ -128,86 +109,29 @@ class NewSecretActivity extends React.Component<Props, OwnState> {
basic={true}
onClick={() => (copyToClipboard as any)(password)}
/>
<TextArea className="secretData" value={password} rows={2} />
<TextArea className="secretData" value={password} rows={2}/>
</div>
)}
</Message>

<Button primary={true} content={'Done'} onClick={() => done(secretName)} />
</>
);
<Button primary={true} content={'Done'}
onClick={() => history.push(`/org/${orgName}/secret/${values.name}`)}/>
</>);
}

renderPasswordWarning() {
return (
<Modal open={this.state.showPasswordConfirm} dimmer="inverted">
<Modal.Content>{passwordTooWeakError()}</Modal.Content>
<Modal.Actions>
<Button
color="grey"
onClick={() => this.setState({ showPasswordConfirm: false })}
content="Cancel"
/>
<Button
color="yellow"
onClick={() => this.handleSubmit(this.state.currentEntry!, true)}
content="Ignore"
/>
</Modal.Actions>
</Modal>
);
}

render() {
const { error, submitting, orgName, response } = this.props;
return (
<>
{error && <RequestErrorActivity error={error}/>}

if (!error && response) {
return this.renderResponse();
}
<NewSecretForm
orgName={orgName}
submitting={isLoading}
onSubmit={handleSubmit}
initial={INIT_VALUES}
/>
</>
);

return (
<>
{error && <RequestErrorActivity error={error} />}

{this.renderPasswordWarning()}

<NewSecretForm
orgName={orgName}
submitting={submitting}
onSubmit={(entry) => this.handleSubmit(entry)}
initial={{
name: '',
visibility: SecretVisibility.PRIVATE,
type: SecretTypeExt.NEW_KEY_PAIR,
storeType: SecretStoreType.CONCORD
}}
/>
</>
);
}
}

const mapStateToProps = ({ secrets }: { secrets: State }): StateProps => ({
submitting: secrets.createSecret.running,
error: secrets.createSecret.error,
response: secrets.createSecret.response as CreateSecretResponse
});

const mapDispatchToProps = (
dispatch: Dispatch<AnyAction>,
{ orgName }: ExternalProps
): DispatchProps => ({
submit: (entry: NewSecretEntry) => {
dispatch(actions.createSecret(orgName, entry));
},

reset: () => {
dispatch(actions.reset());
},

done: (secretName: ConcordKey) => {
dispatch(pushHistory(`/org/${orgName}/secret/${secretName}`));
}
});
};

export default connect(mapStateToProps, mapDispatchToProps)(NewSecretActivity);
export default NewSecretActivity;
45 changes: 1 addition & 44 deletions console2/src/state/data/secrets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ import { all, call, put, takeLatest } from 'redux-saga/effects';

import { ConcordId, ConcordKey, GenericOperationResult } from '../../../api/common';
import {
create as apiCreate,
deleteSecret as apiDelete,
getSecretAccess,
get as apiGet,
list as apiList,
NewSecretEntry,
renameSecret as apiRenameSecret,
updateSecretAccess,
updateSecretVisibility as apiUpdateSecretVisibility,
Expand All @@ -46,8 +44,6 @@ import {
nullReducer
} from '../common';
import {
CreateSecretRequest,
CreateSecretState,
DeleteSecretRequest,
DeleteSecretState,
GetSecretRequest,
Expand All @@ -64,8 +60,7 @@ import {
UpdateSecretVisibilityResponse,
UpdateSecretVisibilityRequest,
UpdateSecretVisiblityState,
SecretTeamAccessState,
CreateSecretResponse
SecretTeamAccessState
} from './types';
import { UpdateSecretTeamAccessRequest } from './types';
import { ResourceAccessEntry } from '../../../api/org';
Expand All @@ -80,9 +75,6 @@ const actionTypes = {
LIST_SECRETS_REQUEST: `${NAMESPACE}/list/request`,
SECRET_DATA_RESPONSE: `${NAMESPACE}/data/response`,

CREATE_SECRET_REQUEST: `${NAMESPACE}/create/request`,
CREATE_SECRET_RESPONSE: `${NAMESPACE}/create/response`,

DELETE_SECRET_REQUEST: `${NAMESPACE}/delete/request`,
DELETE_SECRET_RESPONSE: `${NAMESPACE}/delete/response`,

Expand Down Expand Up @@ -119,12 +111,6 @@ export const actions = {
filter
}),

createSecret: (orgName: ConcordKey, entry: NewSecretEntry): CreateSecretRequest => ({
type: actionTypes.CREATE_SECRET_REQUEST,
orgName,
entry
}),

deleteSecret: (orgName: ConcordKey, secretName: ConcordKey): DeleteSecretRequest => ({
type: actionTypes.DELETE_SECRET_REQUEST,
orgName,
Expand Down Expand Up @@ -227,18 +213,6 @@ const listSecretsReducer = combineReducers<ListSecretsState>({
response: nullReducer()
});

const createSecretReducer = combineReducers<CreateSecretState>({
running: makeLoadingReducer(
[actionTypes.CREATE_SECRET_REQUEST],
[actionTypes.RESET_SECRET, actionTypes.CREATE_SECRET_RESPONSE]
),
error: makeErrorReducer(
[actionTypes.RESET_SECRET, actionTypes.CREATE_SECRET_REQUEST],
[actionTypes.CREATE_SECRET_RESPONSE]
),
response: makeResponseReducer(actionTypes.CREATE_SECRET_RESPONSE, actionTypes.RESET_SECRET)
});

const deleteSecretReducers = combineReducers<DeleteSecretState>({
running: makeLoadingReducer(
[actionTypes.DELETE_SECRET_REQUEST],
Expand Down Expand Up @@ -306,7 +280,6 @@ export const reducers = combineReducers<State>({
secretById, // TODO use makeEntityByIdReducer

listSecrets: listSecretsReducer,
createSecret: createSecretReducer,
deleteSecret: deleteSecretReducers,
renameSecret: renameSecretReducers,
updateSecretVisibility: updateSecretVisibilityReducers,
Expand Down Expand Up @@ -366,21 +339,6 @@ function* onList({ orgName, pagination, filter }: ListSecretsRequest) {
}
}

function* onCreate({ orgName, entry }: CreateSecretRequest) {
try {
const response: CreateSecretResponse = yield call(apiCreate, orgName, entry);
yield put({
type: actionTypes.CREATE_SECRET_RESPONSE,
orgName,
name: entry.name,
password: response.password,
publicKey: response.publicKey
});
} catch (e) {
yield handleErrors(actionTypes.CREATE_SECRET_RESPONSE, e);
}
}

function* onDelete({ orgName, secretName }: DeleteSecretRequest) {
try {
const response: GenericOperationResult = yield call(apiDelete, orgName, secretName);
Expand Down Expand Up @@ -454,7 +412,6 @@ export const sagas = function*() {
yield all([
takeLatest(actionTypes.LIST_SECRETS_REQUEST, onList),
takeLatest(actionTypes.GET_SECRET_REQUEST, onGet),
takeLatest(actionTypes.CREATE_SECRET_REQUEST, onCreate),
takeLatest(actionTypes.DELETE_SECRET_REQUEST, onDelete),
takeLatest(actionTypes.RENAME_SECRET_REQUEST, onRename),
takeLatest(actionTypes.UPDATE_SECRET_VISIBLITY_REQUEST, onUpdateVisibility),
Expand Down
1 change: 0 additions & 1 deletion console2/src/state/data/secrets/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ export interface State {
secretById: PaginatedSecrets;

listSecrets: ListSecretsState;
createSecret: CreateSecretState;
deleteSecret: DeleteSecretState;
renameSecret: RenameSecretState;
secretTeamAccess: SecretTeamAccessState;
Expand Down

0 comments on commit 7169495

Please sign in to comment.