-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Discover] Tentatively implement Create Database screen (#1372)
* Extract reusable label creating logic to own component * Add new database endpoints (create and update)
- Loading branch information
Showing
14 changed files
with
585 additions
and
147 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* Copyright 2022 Gravitational, 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 from 'react'; | ||
import { MemoryRouter } from 'react-router'; | ||
|
||
import { CreateDatabaseView } from './CreateDatabase'; | ||
|
||
import type { State } from './useCreateDatabase'; | ||
|
||
export default { | ||
title: 'Teleport/Discover/Database/CreateDatabase', | ||
}; | ||
|
||
export const Init = () => ( | ||
<MemoryRouter> | ||
<CreateDatabaseView {...props} /> | ||
</MemoryRouter> | ||
); | ||
|
||
export const Processing = () => ( | ||
<MemoryRouter> | ||
<CreateDatabaseView {...props} attempt={{ status: 'processing' }} /> | ||
</MemoryRouter> | ||
); | ||
|
||
export const Failed = () => ( | ||
<MemoryRouter> | ||
<CreateDatabaseView | ||
{...props} | ||
attempt={{ status: 'failed', statusText: 'some error message' }} | ||
/> | ||
</MemoryRouter> | ||
); | ||
|
||
const props: State = { | ||
attempt: { status: '' }, | ||
createDbAndQueryDb: () => null, | ||
}; |
115 changes: 115 additions & 0 deletions
115
web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/** | ||
* Copyright 2022 Gravitational, 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 { Text, Box } from 'design'; | ||
import { Danger } from 'design/Alert'; | ||
import Validation, { Validator } from 'shared/components/Validation'; | ||
import FieldInput from 'shared/components/FieldInput'; | ||
import { requiredField } from 'shared/components/Validation/rules'; | ||
|
||
import { | ||
ActionButtons, | ||
HeaderSubtitle, | ||
Header, | ||
LabelsCreater, | ||
} from '../../Shared'; | ||
|
||
import { useCreateDatabase, State } from './useCreateDatabase'; | ||
|
||
import type { AgentStepProps } from '../../types'; | ||
import type { AgentLabel } from 'teleport/services/agents'; | ||
|
||
export function CreateDatabase(props: AgentStepProps) { | ||
const state = useCreateDatabase(props); | ||
return <CreateDatabaseView {...state} />; | ||
} | ||
|
||
export function CreateDatabaseView({ attempt, createDbAndQueryDb }: State) { | ||
const [dbName, setDbName] = useState(''); | ||
const [dbUri, setDbUri] = useState(''); | ||
const [labels, setLabels] = useState<AgentLabel[]>([]); | ||
|
||
// TODO (lisa or ryan): these depend on if user chose AWS options: | ||
// const [awsAccountId, setAwsAccountId] = useState('') | ||
// const [awsResourceId, setAwsResourceId] = useState('') | ||
|
||
function handleOnProceed(validator: Validator) { | ||
if (!validator.validate()) { | ||
return; | ||
} | ||
|
||
// TODO (lisa or ryan): preserve "self hosted" or "aws" | ||
// and protocol on first step, and use it here. | ||
createDbAndQueryDb({ | ||
labels, | ||
name: dbName, | ||
uri: dbUri, | ||
// TODO (lisa or ryan) hard coded for now as example. | ||
protocol: 'postgres', | ||
// TODO (lisa or ryan) add AWS fields | ||
}); | ||
} | ||
|
||
return ( | ||
<Validation> | ||
{({ validator }) => ( | ||
<Box> | ||
<Header>Register a Database</Header> | ||
<HeaderSubtitle>Lorem ipsum dolores</HeaderSubtitle> | ||
{attempt.status === 'failed' && ( | ||
<Danger children={attempt.statusText} /> | ||
)} | ||
<Box width="500px" mb={2}> | ||
<FieldInput | ||
label="Database Name" | ||
rule={requiredField('database name is required')} | ||
autoFocus | ||
value={dbName} | ||
placeholder="Enter database name" | ||
onChange={e => setDbName(e.target.value)} | ||
/> | ||
</Box> | ||
<Box width="500px" mb={6}> | ||
<FieldInput | ||
label="Database Connection Endpoint" | ||
rule={requiredField('database connection endpoint is required')} | ||
autoFocus | ||
value={dbUri} | ||
placeholder="Enter database connection endpoint" | ||
onChange={e => setDbUri(e.target.value)} | ||
/> | ||
</Box> | ||
{/* TODO (lisa or ryan): add AWS input fields */} | ||
<Box> | ||
<Text bold>Labels (optional)</Text> | ||
<LabelsCreater | ||
labels={labels} | ||
setLabels={setLabels} | ||
isLabelOptional={true} | ||
disableBtns={attempt.status === 'processing'} | ||
/> | ||
</Box> | ||
<ActionButtons | ||
onProceed={() => handleOnProceed(validator)} | ||
// On failure, allow user to attempt again. | ||
disableProceed={attempt.status === 'processing'} | ||
/> | ||
</Box> | ||
)} | ||
</Validation> | ||
); | ||
} |
17 changes: 17 additions & 0 deletions
17
web/packages/teleport/src/Discover/Database/CreateDatabase/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** | ||
* Copyright 2022 Gravitational, 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. | ||
*/ | ||
|
||
export { CreateDatabase } from './CreateDatabase'; |
76 changes: 76 additions & 0 deletions
76
web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/** | ||
* Copyright 2022 Gravitational, 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 useAttempt from 'shared/hooks/useAttemptNext'; | ||
|
||
import useTeleport from 'teleport/useTeleport'; | ||
|
||
import type { AgentStepProps } from '../../types'; | ||
import type { CreateDatabaseRequest } from 'teleport/services/databases'; | ||
|
||
export function useCreateDatabase(props: AgentStepProps) { | ||
const ctx = useTeleport(); | ||
const { attempt, setAttempt } = useAttempt('processing'); | ||
|
||
async function createDbAndQueryDb(db: CreateDatabaseRequest) { | ||
setAttempt({ status: 'processing' }); | ||
try { | ||
const clusterId = ctx.storeUser.getClusterId(); | ||
// Create the Database. | ||
await ctx.databaseService.createDatabase(clusterId, db); | ||
|
||
// Query for the created database by searching through database services. | ||
// As discussed, if a service was already available, the new db should be | ||
// picked up immediately. | ||
let numSteps; | ||
const request = { | ||
search: db.name, | ||
limit: 1, | ||
}; | ||
const queryResult = await ctx.databaseService.fetchDatabases( | ||
clusterId, | ||
request | ||
); | ||
|
||
// If an agent was found, skip the next step that requires you | ||
// to set up the db service, and set the database we queried to | ||
// refer to it in later steps (this queried db will include current | ||
// db users and db names). | ||
const queriedDb = queryResult.agents[0]; | ||
if (queriedDb) { | ||
numSteps = 2; | ||
props.updateAgentMeta({ | ||
...props.agentMeta, | ||
resourceName: queriedDb.name, | ||
db: queriedDb, | ||
}); | ||
} | ||
props.nextStep(numSteps); | ||
} catch (err) { | ||
let message; | ||
if (err instanceof Error) message = err.message; | ||
else message = String(err); | ||
setAttempt({ status: 'failed', statusText: message }); | ||
} | ||
} | ||
|
||
return { | ||
attempt, | ||
createDbAndQueryDb, | ||
}; | ||
} | ||
|
||
export type State = ReturnType<typeof useCreateDatabase>; |
Oops, something went wrong.