Skip to content

Commit

Permalink
Multiple account interface in options (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikescops authored Jun 17, 2024
1 parent 6e6b395 commit 529371f
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 99 deletions.
10 changes: 9 additions & 1 deletion src/common/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as browser from 'webextension-polyfill';
import { Configuration, TabId } from '../common/types';
import { Account, Configuration, TabId } from '../common/types';
import { config } from '../config/config';

export const updateConfiguration = async (objectToStore: Record<string, any>): Promise<void> => {
Expand Down Expand Up @@ -50,3 +50,11 @@ export const readConfiguration = async <T>(keys: string[]): Promise<T> => {
return settings as T;
});
};

export const defaultEmptyAccount: Account = {
token: '',
address: '',
gitlabCE: false,
draftInToReviewTab: false,
projectDirectoryPrefix: ''
};
185 changes: 109 additions & 76 deletions src/options/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as browser from 'webextension-polyfill';
import { useState, useEffect } from 'react';
import { Box, TextInput, Tooltip, Octicon, FormControl, Select, ThemeProvider } from '@primer/react';
import { CheckIcon, InfoIcon, ClockIcon } from '@primer/octicons-react';
import { Box, Button, TextInput, Tooltip, Octicon, FormControl, Select, ThemeProvider } from '@primer/react';
import { InfoIcon, ClockIcon } from '@primer/octicons-react';
import './style.css';
import { updateConfiguration, readConfiguration } from '../common/configuration';
import { updateConfiguration, readConfiguration, defaultEmptyAccount } from '../common/configuration';
import { Account, Configuration, TabId } from '../common/types';
import { AccountConfiguration } from './components/Account';

Expand Down Expand Up @@ -38,83 +38,116 @@ export const App = () => {
}
};

const addNewAccount = () =>
updateConfigurationInMemory({
accounts: [...(configuration?.accounts || []), defaultEmptyAccount]
});

const removeAccount = (index: number) => {
const accounts = configuration?.accounts || [];
accounts.splice(index, 1);
updateConfigurationInMemory({ accounts });
};

return (
<ThemeProvider colorMode="auto">
<Box display="grid" gridGap={3} sx={{ width: 500, p: 2, pl: 4, pr: 6, bg: 'canvas.default' }}>
<FormControl>
<FormControl.Label>
Refresh rate in seconds{' '}
<Tooltip aria-label="It is not recommended to go below 30 seconds.">
<Octicon icon={InfoIcon} size={15} color="blue.5" />
</Tooltip>
</FormControl.Label>
<TextInput
leadingVisual={ClockIcon}
trailingVisual={configuration?.refreshRate ? CheckIcon : undefined}
block
type="number"
name="refreshRate"
min="20"
value={configuration?.refreshRate}
placeholder="0"
onChange={(e) => updateConfigurationInMemory({ refreshRate: parseInt(e.target.value) })}
/>
</FormControl>
<FormControl>
<FormControl.Label>Default tab</FormControl.Label>
<Select
name="default-tab"
onChange={(e) => updateConfigurationInMemory({ defaultTab: e.target.value as TabId })}
>
<Select.Option selected={configuration?.defaultTab === 'to_review'} value="to_review">
To Review
</Select.Option>
<Select.Option selected={configuration?.defaultTab === 'under_review'} value="under_review">
Under Review
</Select.Option>
<Select.Option selected={configuration?.defaultTab === 'drafts'} value="drafts">
Drafts
</Select.Option>
<Select.Option selected={configuration?.defaultTab === 'issues'} value="issues">
Issues
</Select.Option>
<Select.Option selected={configuration?.defaultTab === 'todo_list'} value="todo_list">
To-Do List
</Select.Option>
</Select>
</FormControl>
<FormControl>
<FormControl.Label>
Alert badge counters{' '}
<Tooltip aria-label="You can select multiple counters but display might be too small.">
<Octicon icon={InfoIcon} size={15} color="blue.5" />
</Tooltip>
</FormControl.Label>
<select
name="alert-badge-counters"
multiple
onChange={(event) => {
const options = [...event.target.selectedOptions].map((option) => parseInt(option.value));
updateConfigurationInMemory({ alertBadgeCounters: options });
}}
>
<option selected={configuration?.alertBadgeCounters.includes(0)} value="0">
To Review
</option>
<option selected={configuration?.alertBadgeCounters.includes(1)} value="1">
Reviewed by others
</option>
<option selected={configuration?.alertBadgeCounters.includes(2)} value="2">
Issues
</option>
<option selected={configuration?.alertBadgeCounters.includes(3)} value="3">
To-Do List
</option>
</select>
</FormControl>
<Box display="grid" sx={{ width: 500, p: 2, pl: 4, pr: 6, bg: 'canvas.default', gap: 1 }}>
<h2>Main Settings</h2>
<Box
display="grid"
sx={{
borderWidth: 1,
borderStyle: 'solid',
borderColor: 'border.default',
p: 3,
borderRadius: 2,
gap: 3
}}
>
<FormControl>
<FormControl.Label>
Refresh rate in seconds{' '}
<Tooltip aria-label="It is not recommended to go below 30 seconds.">
<Octicon icon={InfoIcon} size={15} color="blue.5" />
</Tooltip>
</FormControl.Label>
<TextInput
leadingVisual={ClockIcon}
block
type="number"
name="refreshRate"
min="20"
value={configuration?.refreshRate}
placeholder="0"
onChange={(e) => updateConfigurationInMemory({ refreshRate: parseInt(e.target.value) })}
sx={{ boxSizing: 'border-box' }}
/>
</FormControl>
<FormControl>
<FormControl.Label>Default tab on opening</FormControl.Label>
<Select
name="default-tab"
onChange={(e) => updateConfigurationInMemory({ defaultTab: e.target.value as TabId })}
>
<Select.Option selected={configuration?.defaultTab === 'to_review'} value="to_review">
To Review
</Select.Option>
<Select.Option selected={configuration?.defaultTab === 'under_review'} value="under_review">
Under Review
</Select.Option>
<Select.Option selected={configuration?.defaultTab === 'drafts'} value="drafts">
Drafts
</Select.Option>
<Select.Option selected={configuration?.defaultTab === 'issues'} value="issues">
Issues
</Select.Option>
<Select.Option selected={configuration?.defaultTab === 'todo_list'} value="todo_list">
To-Do List
</Select.Option>
</Select>
</FormControl>
<FormControl>
<FormControl.Label>
Alert badge counters{' '}
<Tooltip aria-label="You can select multiple counters but display might be too small.">
<Octicon icon={InfoIcon} size={15} color="blue.5" />
</Tooltip>
</FormControl.Label>
<select
name="alert-badge-counters"
multiple
onChange={(event) => {
const options = [...event.target.selectedOptions].map((option) =>
parseInt(option.value)
);
updateConfigurationInMemory({ alertBadgeCounters: options });
}}
>
<option selected={configuration?.alertBadgeCounters.includes(0)} value="0">
To Review
</option>
<option selected={configuration?.alertBadgeCounters.includes(1)} value="1">
Reviewed by others
</option>
<option selected={configuration?.alertBadgeCounters.includes(2)} value="2">
Issues
</option>
<option selected={configuration?.alertBadgeCounters.includes(3)} value="3">
To-Do List
</option>
</select>
</FormControl>
</Box>
<h2>Accounts</h2>
{configuration?.accounts.map((account, index) => (
<AccountConfiguration key={index} accountIndex={index} account={account} />
<AccountConfiguration
key={index}
accountIndex={index}
account={account}
removeAccount={() => removeAccount(index)}
/>
))}
<Button onClick={addNewAccount}>Add account</Button>
</Box>
</ThemeProvider>
);
Expand Down
53 changes: 31 additions & 22 deletions src/options/components/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ import { useCallback, useState } from 'react';
import {
InfoIcon,
KeyIcon,
CheckIcon,
ServerIcon,
FileDirectoryIcon,
PackageDependenciesIcon
PackageDependenciesIcon,
TrashIcon
} from '@primer/octicons-react';
import { Button, Checkbox, FormControl, Link, Octicon, TextInput, Tooltip, Text } from '@primer/react';
import { Box, Button, Checkbox, Flash, FormControl, Link, Octicon, TextInput, Tooltip } from '@primer/react';
import { Account } from '../../common/types';
import { updateAccountConfiguration } from '../../common/configuration';

interface Props {
accountIndex: number;
account: Account;
removeAccount: () => void;
}

export const AccountConfiguration = (props: Props) => {
Expand All @@ -32,7 +33,17 @@ export const AccountConfiguration = (props: Props) => {
}, []);

return (
<>
<Box
display="grid"
sx={{
borderWidth: 1,
borderStyle: 'solid',
borderColor: 'border.default',
p: 3,
borderRadius: 2,
gap: 3
}}
>
<FormControl>
<FormControl.Label>Using GitLab Community Edition</FormControl.Label>
<Checkbox
Expand Down Expand Up @@ -60,13 +71,13 @@ export const AccountConfiguration = (props: Props) => {
<TextInput
type="password"
leadingVisual={KeyIcon}
trailingVisual={account.token ? CheckIcon : undefined}
block
name="gitlab-token"
value={account.token}
placeholder="<your_token_here>"
onChange={(e) => setAccountConfiguration({ token: e.target.value })}
aria-label="gitlab-token"
sx={{ boxSizing: 'border-box' }}
/>
</FormControl>
<FormControl>
Expand All @@ -78,13 +89,13 @@ export const AccountConfiguration = (props: Props) => {
</FormControl.Label>
<TextInput
leadingVisual={ServerIcon}
trailingVisual={account.address ? CheckIcon : undefined}
block
name="gitlab-address"
value={account.address}
placeholder="<host_address_here>"
onChange={(e) => setAccountConfiguration({ address: e.target.value })}
aria-label="gitlab-address"
sx={{ boxSizing: 'border-box' }}
/>
</FormControl>
<FormControl>
Expand Down Expand Up @@ -116,28 +127,26 @@ export const AccountConfiguration = (props: Props) => {
block
name="project-directory-prefix"
value={account.projectDirectoryPrefix}
trailingVisual={account.projectDirectoryPrefix ? CheckIcon : undefined}
placeholder="teams/code/projects/"
onChange={(e) => setAccountConfiguration({ projectDirectoryPrefix: e.target.value })}
aria-label="project-directory-prefix"
sx={{ boxSizing: 'border-box' }}
/>
</FormControl>

<>
<Button onClick={testConnection} block variant="default">
<PackageDependenciesIcon /> Test my settings
<Box display="flex" sx={{ columnGap: 2 }}>
<Button onClick={testConnection} variant="default" leadingVisual={PackageDependenciesIcon}>
Test connection
</Button>
<Text
opacity={testSuccess === null ? 0 : 100}
sx={{
color: testSuccess === true ? 'success.fg' : 'danger.fg',
fontSize: 18,
textAlign: 'center'
}}
>
{testSuccess === true ? 'Success' : 'Could not connect'}
</Text>
</>
</>
<Button onClick={props.removeAccount} variant="danger" leadingVisual={TrashIcon}>
Remove this account
</Button>
</Box>
{testSuccess !== null && (
<Flash variant={testSuccess === true ? 'success' : 'danger'}>
{testSuccess === true ? 'Connection successful' : 'Could not connect'}
</Flash>
)}
</Box>
);
};

0 comments on commit 529371f

Please sign in to comment.