Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple account interface in options #117

Merged
merged 1 commit into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
);
};
Loading