chore: implement options component
This commit is contained in:
@@ -152,7 +152,7 @@ var Options = reactCreateClass({
|
|||||||
handleChange={that._updateWhitelistState}
|
handleChange={that._updateWhitelistState}
|
||||||
label="Whitelist"
|
label="Whitelist"
|
||||||
sites={that.state.whitelist}
|
sites={that.state.whitelist}
|
||||||
placeholder="http://google.com http://myproject.com@@MyProject"
|
placeholder="http://google.com http://myproject.com/MyProject"
|
||||||
helpText="Sites that you want to show in your reports. You can assign URL to project by adding @@YourProject at the end of line."
|
helpText="Sites that you want to show in your reports. You can assign URL to project by adding @@YourProject at the end of line."
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
227
src/components/Options.tsx
Normal file
227
src/components/Options.tsx
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
import React, { useRef, useState, useEffect } from 'react';
|
||||||
|
import config, { SuccessOrFailType } from '../config/config';
|
||||||
|
import Alert from './Alert';
|
||||||
|
import SitesList from './SitesList';
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
alertText: string;
|
||||||
|
alertType: SuccessOrFailType;
|
||||||
|
blacklist: string;
|
||||||
|
displayAlert: boolean;
|
||||||
|
loading: boolean;
|
||||||
|
loggingStyle: string;
|
||||||
|
loggingType: string;
|
||||||
|
theme: string;
|
||||||
|
whitelist: string;
|
||||||
|
}
|
||||||
|
export default function Options(): JSX.Element {
|
||||||
|
const [state, setState] = useState<State>({
|
||||||
|
alertText: config.alert.success.text,
|
||||||
|
alertType: config.alert.success.type,
|
||||||
|
blacklist: '',
|
||||||
|
displayAlert: false,
|
||||||
|
loading: false,
|
||||||
|
loggingStyle: config.loggingStyle,
|
||||||
|
loggingType: config.loggingType,
|
||||||
|
theme: config.theme,
|
||||||
|
whitelist: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const loggingStyleRef = useRef(null);
|
||||||
|
|
||||||
|
const restoreSettings = async (): Promise<void> => {
|
||||||
|
const items = await browser.storage.sync.get({
|
||||||
|
blacklist: '',
|
||||||
|
loggingStyle: config.loggingStyle,
|
||||||
|
loggingType: config.loggingType,
|
||||||
|
theme: config.theme,
|
||||||
|
whitelist: '',
|
||||||
|
});
|
||||||
|
setState({
|
||||||
|
...state,
|
||||||
|
blacklist: items.blacklist,
|
||||||
|
loggingStyle: items.loggingStyle,
|
||||||
|
loggingType: items.loggingType,
|
||||||
|
theme: items.theme,
|
||||||
|
whitelist: items.whitelist,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
void restoreSettings();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (state.displayAlert) {
|
||||||
|
setTimeout(function () {
|
||||||
|
setState({ ...state, displayAlert: false, loading: false });
|
||||||
|
}, 2500);
|
||||||
|
}
|
||||||
|
}, [state.displayAlert]);
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (state.loading) return;
|
||||||
|
setState({ ...state, loading: true });
|
||||||
|
|
||||||
|
const theme = state.theme;
|
||||||
|
const loggingType = state.loggingType;
|
||||||
|
const loggingStyle = state.loggingStyle;
|
||||||
|
// Trimming blacklist and whitelist removes blank lines and spaces.
|
||||||
|
const blacklist = state.blacklist.trim();
|
||||||
|
const whitelist = state.whitelist.trim();
|
||||||
|
|
||||||
|
// Sync options with google storage.
|
||||||
|
await browser.storage.sync.set({
|
||||||
|
blacklist: blacklist,
|
||||||
|
loggingStyle: loggingStyle,
|
||||||
|
loggingType: loggingType,
|
||||||
|
theme: theme,
|
||||||
|
whitelist: whitelist,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set state to be newly entered values.
|
||||||
|
setState({
|
||||||
|
...state,
|
||||||
|
blacklist: blacklist,
|
||||||
|
displayAlert: true,
|
||||||
|
loggingStyle: loggingStyle,
|
||||||
|
loggingType: loggingType,
|
||||||
|
theme: theme,
|
||||||
|
whitelist: whitelist,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateBlacklistState = (sites: string) => {
|
||||||
|
setState({
|
||||||
|
...state,
|
||||||
|
blacklist: sites,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateWhitelistState = (sites: string) => {
|
||||||
|
setState({
|
||||||
|
...state,
|
||||||
|
whitelist: sites,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const loggingStyle = function () {
|
||||||
|
if (state.loggingStyle == 'blacklist') {
|
||||||
|
return (
|
||||||
|
<SitesList
|
||||||
|
handleChange={updateBlacklistState}
|
||||||
|
label="Blacklist"
|
||||||
|
sites={state.blacklist}
|
||||||
|
helpText="Sites that you don't want to show in your reports."
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SitesList
|
||||||
|
handleChange={updateWhitelistState}
|
||||||
|
label="Whitelist"
|
||||||
|
sites={state.whitelist}
|
||||||
|
placeholder="http://google.com http://myproject.com/MyProject"
|
||||||
|
helpText="Sites that you want to show in your reports. You can assign URL to project by adding @@YourProject at the end of line."
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const alert = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: state.displayAlert ? 55 : 0,
|
||||||
|
opacity: state.displayAlert ? 1 : 0,
|
||||||
|
transition: 'opacity 500ms, height 1000ms',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Alert key={state.alertText} type={state.alertType} text={state.alertText} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="container"
|
||||||
|
style={{
|
||||||
|
height: 515,
|
||||||
|
overflow: 'hidden',
|
||||||
|
overflowY: 'scroll',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12">
|
||||||
|
{alert()}
|
||||||
|
|
||||||
|
<form className="form-horizontal">
|
||||||
|
<div className="form-group">
|
||||||
|
<label className="col-lg-2 control-label">Logging style!</label>
|
||||||
|
|
||||||
|
<div className="col-lg-10">
|
||||||
|
<select
|
||||||
|
ref={loggingStyleRef}
|
||||||
|
className="form-control"
|
||||||
|
value={state.loggingStyle}
|
||||||
|
onChange={(e) => setState({ ...state, loggingStyle: e.target.value })}
|
||||||
|
>
|
||||||
|
<option value="blacklist">All except blacklisted sites</option>
|
||||||
|
<option value="whitelist">Only whitelisted sites</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{loggingStyle()}
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label className="col-lg-2 control-label">Logging type</label>
|
||||||
|
|
||||||
|
<div className="col-lg-10">
|
||||||
|
<select
|
||||||
|
className="form-control"
|
||||||
|
value={state.loggingType}
|
||||||
|
onChange={(e) => setState({ ...state, loggingType: e.target.value })}
|
||||||
|
>
|
||||||
|
<option value="domain">Only the domain</option>
|
||||||
|
<option value="url">Entire URL</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="theme" className="col-lg-2 control-label">
|
||||||
|
Theme
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className="col-lg-10">
|
||||||
|
<select
|
||||||
|
className="form-control"
|
||||||
|
value={state.theme}
|
||||||
|
onChange={(e) => setState({ ...state, theme: e.target.value })}
|
||||||
|
>
|
||||||
|
<option value="light">Light</option>
|
||||||
|
<option value="dark">Dark</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<div className="col-lg-10 col-lg-offset-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`btn btn-primary ${state.loading ? 'disabled' : ''}`}
|
||||||
|
disabled={state.loading}
|
||||||
|
data-loading-text="Loading..."
|
||||||
|
onClick={handleSubmit}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
44
src/components/SitesList.tsx
Normal file
44
src/components/SitesList.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
handleChange: (sites: string) => void;
|
||||||
|
helpText: string;
|
||||||
|
label: string;
|
||||||
|
placeholder?: string;
|
||||||
|
sites: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function SitesList({
|
||||||
|
handleChange,
|
||||||
|
label,
|
||||||
|
placeholder,
|
||||||
|
sites,
|
||||||
|
helpText,
|
||||||
|
}: Props): JSX.Element {
|
||||||
|
const textareaChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
|
handleChange(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="sites" className="col-lg-2 control-label">
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className="col-lg-10">
|
||||||
|
<textarea
|
||||||
|
className="form-control"
|
||||||
|
rows={3}
|
||||||
|
onChange={textareaChange}
|
||||||
|
placeholder={placeholder ?? 'http://google.com'}
|
||||||
|
value={sites}
|
||||||
|
></textarea>
|
||||||
|
<span className="help-block">
|
||||||
|
{helpText}
|
||||||
|
<br />
|
||||||
|
One line per site.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import Options from './components/Options';
|
||||||
|
|
||||||
|
/* This is a fix for Bootstrap requiring jQuery */
|
||||||
|
global.jQuery = require('jquery');
|
||||||
|
require('bootstrap');
|
||||||
|
|
||||||
const container = document.getElementById('wakatime-options');
|
const container = document.getElementById('wakatime-options');
|
||||||
|
const root = createRoot(container!);
|
||||||
|
|
||||||
ReactDOM.render(<h1>OPTIONS GO HERE</h1>, container);
|
root.render(<Options />);
|
||||||
|
|||||||
Reference in New Issue
Block a user