This repository was archived by the owner on Apr 18, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
settings: Add organization and user settings (PROJQUAY-4553) #171
Open
jonathankingfc
wants to merge
19
commits into
main
Choose a base branch
from
PROJQUAY-4553
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
bf72610
install dependencies
jonathankingfc 0558d16
use hooks for auth
jonathankingfc ca147e3
use hooks for orgs
jonathankingfc 756fe5d
use hooks for repos
jonathankingfc 043b1e5
misc
jonathankingfc 1ed1f31
add settings to repo page
jonathankingfc 09a7055
update repos list components to use pagination from hooks
jonathankingfc 167de13
address requested changes
jonathankingfc 2c5340e
disable retries on queries
jonathankingfc ccf99ab
fix visibility not refreshing
jonathankingfc 7975f76
fix error modals for organization and repo delete
jonathankingfc 1176a64
fix member count for user org showing skeleton
jonathankingfc a4da9c8
small fixes
jonathankingfc cbfa535
settings: Add organization and user settings (PROJQUAY-4553)
jonathankingfc 72874e3
Merge branch 'main' into add_react_query_for_config
jonathankingfc a08ecbb
fix superusers returning undefined username
jonathankingfc de1635f
fix keys
jonathankingfc f471f54
Merge branch 'add_react_query_for_config' into PROJQUAY-4553
jonathankingfc 7a940ac
rebase
jonathankingfc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or 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
This file contains hidden or 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,81 @@ | ||
| import {Modal, ModalVariant, Button, TextInput} from '@patternfly/react-core'; | ||
| import {useState} from 'react'; | ||
| import FormError from 'src/components/errors/FormError'; | ||
| import {addDisplayError} from 'src/resources/ErrorHandling'; | ||
| import {useCreateClientKey} from 'src/hooks/UseCreateClientKey'; | ||
|
|
||
| export function GenerateEncryptedPassword(props: ConfirmationModalProps) { | ||
| const [err, setErr] = useState<string>(); | ||
|
|
||
| const [password, setPassword] = useState(''); | ||
| const [step, setStep] = useState(1); | ||
| const {createClientKey, clientKey} = useCreateClientKey({ | ||
| onError: (error) => { | ||
| console.error(error); | ||
| setErr(addDisplayError('Error', error)); | ||
| }, | ||
| onSuccess: () => { | ||
| setStep(step + 1); | ||
| }, | ||
| }); | ||
|
|
||
| const handleModalConfirm = async () => { | ||
| createClientKey(password); | ||
| }; | ||
|
|
||
| return ( | ||
| <Modal | ||
| variant={ModalVariant.small} | ||
| title={props.title} | ||
| isOpen={props.modalOpen} | ||
| onClose={props.toggleModal} | ||
| actions={ | ||
| step == 1 | ||
| ? [ | ||
| <Button | ||
| key="confirm" | ||
| variant="primary" | ||
| onClick={handleModalConfirm} | ||
| > | ||
| {props.buttonText} | ||
| </Button>, | ||
| <Button key="cancel" variant="link" onClick={props.toggleModal}> | ||
| Cancel | ||
| </Button>, | ||
| ] | ||
| : [ | ||
| <Button key="cancel" variant="link" onClick={props.toggleModal}> | ||
| Done | ||
| </Button>, | ||
| ] | ||
| } | ||
| > | ||
| {step == 1 && ( | ||
| <> | ||
| <FormError message={err} setErr={setErr} /> | ||
| <TextInput | ||
| id="delete-confirmation-input" | ||
| value={password} | ||
| type="password" | ||
| onChange={(value) => setPassword(value)} | ||
| aria-label="text input example" | ||
| label="Password" | ||
| /> | ||
| Please enter your password in order to generate | ||
| </> | ||
| )} | ||
| {step == 2 && ( | ||
| <> | ||
| Your encrypted password is: <br /> {clientKey} | ||
| </> | ||
| )} | ||
| </Modal> | ||
| ); | ||
| } | ||
|
|
||
| type ConfirmationModalProps = { | ||
| title: string; | ||
| modalOpen: boolean; | ||
| buttonText: string; | ||
| toggleModal: () => void; | ||
| }; |
This file contains hidden or 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,142 @@ | ||
| import { | ||
| Button, | ||
| Modal, | ||
| ModalVariant, | ||
| PageSection, | ||
| PageSectionVariants, | ||
| TextInput, | ||
| Toolbar, | ||
| ToolbarContent, | ||
| ToolbarItem, | ||
| } from '@patternfly/react-core'; | ||
| import { | ||
| TableComposable, | ||
| Tbody, | ||
| Td, | ||
| Th, | ||
| Thead, | ||
| Tr, | ||
| } from '@patternfly/react-table'; | ||
| import {useState} from 'react'; | ||
| import {ToolbarPagination} from 'src/components/toolbar/ToolbarPagination'; | ||
| import {IOrganization} from 'src/resources/OrganizationResource'; | ||
|
|
||
| export const UserConvertConflictsModal = ( | ||
| props: UserConvertConflictsModal, | ||
| ): JSX.Element => { | ||
| const [itemsMarkedForDelete, setItemsMarkedForDelete] = useState< | ||
| IOrganization[] | ||
| >(props.items); | ||
|
|
||
| const [searchInput, setSearchInput] = useState<string>(''); | ||
|
|
||
| const [bulkModalPerPage, setBulkModalPerPage] = useState<number>(10); | ||
| const [bulkModalPage, setBulkModalPage] = useState<number>(1); | ||
|
|
||
| const paginatedBulkItemsList = itemsMarkedForDelete.slice( | ||
| bulkModalPage * bulkModalPerPage - bulkModalPerPage, | ||
| bulkModalPage * bulkModalPerPage - bulkModalPerPage + bulkModalPerPage, | ||
| ); | ||
|
|
||
| const onSearch = (value: string) => { | ||
| setSearchInput(value); | ||
| if (value === '') { | ||
| setItemsMarkedForDelete(props.items); | ||
| } else { | ||
| /* Note: This search filter assumes that the search is always based on the 1st column, | ||
| hence we do "colNames[0]" */ | ||
| const filteredTableRow = props.items.filter((item) => | ||
| item.name?.toLowerCase().includes(value.toLowerCase()), | ||
| ); | ||
| setItemsMarkedForDelete(filteredTableRow); | ||
| } | ||
| }; | ||
|
|
||
| return ( | ||
| <Modal | ||
| title={`Change account type`} | ||
| id="bulk-delete-modal" | ||
| titleIconVariant="warning" | ||
| aria-label={`Change account type`} | ||
| variant={ModalVariant.medium} | ||
| isOpen={props.isModalOpen} | ||
| onClose={props.handleModalToggle} | ||
| actions={[ | ||
| <Button | ||
| key="cancel" | ||
| id="delete-org-cancel" | ||
| variant="link" | ||
| onClick={props.handleModalToggle} | ||
| > | ||
| Close | ||
| </Button>, | ||
| ]} | ||
| > | ||
| <span> | ||
| This account cannot be converted into an organization, as it is a member | ||
| of another organization. Please leave the following organization(s) | ||
| first: | ||
| </span> | ||
| <PageSection variant={PageSectionVariants.light}> | ||
| <Toolbar> | ||
| <ToolbarContent> | ||
| <ToolbarItem> | ||
| <TextInput | ||
| isRequired | ||
| type="search" | ||
| id="modal-with-form-form-name" | ||
| name="search input" | ||
| placeholder="Search" | ||
| iconVariant="search" | ||
| value={searchInput} | ||
| onChange={onSearch} | ||
| /> | ||
| </ToolbarItem> | ||
| <ToolbarPagination | ||
| page={bulkModalPage} | ||
| perPage={bulkModalPerPage} | ||
| itemsList={props.items} | ||
| setPage={setBulkModalPage} | ||
| setPerPage={setBulkModalPerPage} | ||
| /> | ||
| </ToolbarContent> | ||
| </Toolbar> | ||
| <TableComposable aria-label="Simple table" variant="compact"> | ||
| <Thead> | ||
| <Tr> | ||
| <Th>Organization</Th> | ||
| <Th>Role</Th> | ||
| </Tr> | ||
| </Thead> | ||
| <Tbody> | ||
| {paginatedBulkItemsList.map((item, idx) => ( | ||
| <Tr key={idx}> | ||
| <Td>{item.name}</Td> | ||
| <Td>{item.is_org_admin ? 'Admin' : 'User'}</Td> | ||
| </Tr> | ||
| ))} | ||
| </Tbody> | ||
| </TableComposable> | ||
| <Toolbar> | ||
| <ToolbarPagination | ||
| page={bulkModalPage} | ||
| perPage={bulkModalPerPage} | ||
| itemsList={props.items} | ||
| setPage={setBulkModalPage} | ||
| setPerPage={setBulkModalPerPage} | ||
| bottom={true} | ||
| /> | ||
| </Toolbar> | ||
| </PageSection> | ||
| </Modal> | ||
| ); | ||
| }; | ||
|
|
||
| type UserConvertConflictsModal = { | ||
| mapOfColNamesToTableData: { | ||
| [key: string]: {label?: string; transformFunc?: (value) => any}; | ||
| }; | ||
| isModalOpen: boolean; | ||
| handleModalToggle?: () => void; | ||
| items: IOrganization[]; | ||
| }; | ||
This file contains hidden or 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,30 @@ | ||
| import {useMutation, useQueryClient} from '@tanstack/react-query'; | ||
| import {convert, ConvertUserRequest} from 'src/resources/UserResource'; | ||
|
|
||
| export function useConvertAccount({onSuccess, onError}) { | ||
| const queryClient = useQueryClient(); | ||
|
|
||
| const convertAccountMutator = useMutation( | ||
| async ({adminUser, adminPassword}: ConvertUserRequest) => { | ||
| return convert({adminUser, adminPassword}); | ||
| }, | ||
| { | ||
| onSuccess: () => { | ||
| onSuccess(); | ||
| queryClient.invalidateQueries(['user']); | ||
| queryClient.invalidateQueries(['organization']); | ||
| }, | ||
| onError: (err) => { | ||
| onError(err); | ||
| }, | ||
| }, | ||
| ); | ||
|
|
||
| return { | ||
| convert: async (convertUserRequest: ConvertUserRequest) => | ||
| convertAccountMutator.mutate(convertUserRequest), | ||
| loading: convertAccountMutator.isLoading, | ||
| error: convertAccountMutator.error, | ||
| clientKey: convertAccountMutator.data, | ||
| }; | ||
| } |
This file contains hidden or 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,30 @@ | ||
| import {useMutation, useQueryClient} from '@tanstack/react-query'; | ||
| import {createClientKey} from 'src/resources/UserResource'; | ||
|
|
||
| export function useCreateClientKey({onSuccess, onError}) { | ||
| const queryClient = useQueryClient(); | ||
|
|
||
| const createClientKeyMutator = useMutation( | ||
| async ({password}: {password: string}) => { | ||
| return createClientKey(password); | ||
| }, | ||
| { | ||
| onSuccess: () => { | ||
| onSuccess(); | ||
| queryClient.invalidateQueries(['user']); | ||
| queryClient.invalidateQueries(['organization']); | ||
| }, | ||
| onError: (err) => { | ||
| onError(err); | ||
| }, | ||
| }, | ||
| ); | ||
|
|
||
| return { | ||
| createClientKey: async (password: string) => | ||
| createClientKeyMutator.mutate({password}), | ||
| loading: createClientKeyMutator.isLoading, | ||
| error: createClientKeyMutator.error, | ||
| clientKey: createClientKeyMutator.data, | ||
| }; | ||
| } |
This file contains hidden or 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
This file contains hidden or 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,24 @@ | ||
| import {fetchPlan} from 'src/resources/PlanResource'; | ||
| import {useQuery} from '@tanstack/react-query'; | ||
| import {useOrganization} from './UseOrganization'; | ||
|
|
||
| export function usePlan(name: string) { | ||
| // Get usernames | ||
| const {isUserOrganization} = useOrganization(name); | ||
|
|
||
| // Get organization plan | ||
| const { | ||
| data: plan, | ||
| isLoading, | ||
| error, | ||
| isPlaceholderData, | ||
| } = useQuery(['organization', name, 'plan'], () => { | ||
| return fetchPlan(name, isUserOrganization); | ||
| }); | ||
|
|
||
| return { | ||
| error, | ||
| loading: isLoading || isPlaceholderData, | ||
| plan, | ||
| }; | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
The mock shows the org names to be clickable