Skip to content

Commit 31d44e5

Browse files
authored
Merge pull request #4 from kungfux/feature/preferences
Add ability to update extension settings
2 parents ab8f488 + 08897a1 commit 31d44e5

File tree

11 files changed

+115
-15
lines changed

11 files changed

+115
-15
lines changed

.eslintrc.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
2+
"plugins": ["prettier"],
3+
"rules": {
4+
"prettier/prettier": "error"
5+
},
26
"overrides": [
37
{
48
"env": {

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
"eslint-config-prettier": "^8.8.0",
3838
"eslint-plugin-import": "^2.27.5",
3939
"eslint-plugin-n": "^15.7.0",
40+
"eslint-plugin-prettier": "^4.2.1",
4041
"eslint-plugin-promise": "^6.1.1",
42+
"html-webpack-plugin": "^5.5.1",
4143
"merge-jsons-webpack-plugin": "^2.0.1",
4244
"prettier": "^2.8.7",
4345
"ts-loader": "^9.4.2",

src/background/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
import { runtime } from 'webextension-polyfill';
12
import { Settings } from '../settings';
23
import { ServiceWorker } from './service-worker';
34

4-
const settings = new Settings().getSettings();
5-
const serviceWorker = new ServiceWorker(settings.urls);
5+
runtime.onInstalled.addListener((details) => {
6+
void runtime.openOptionsPage();
7+
});
8+
9+
const settings = new Settings();
10+
const s = await settings.getSettings();
11+
const serviceWorker = new ServiceWorker(s.urls);
612
serviceWorker.init();

src/manifest.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
"48": "icons/logo48.png",
88
"128": "icons/logo128.png"
99
},
10-
"permissions": ["tabs", "webNavigation", "scripting", "activeTab"],
10+
"options_ui": {
11+
"page": "options.html",
12+
"open_in_tab": true
13+
},
14+
"permissions": ["tabs", "webNavigation", "scripting", "activeTab", "storage"],
1115
"host_permissions": ["<all_urls>"]
1216
}

src/options/options.html

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!DOCTYPE html>
2+
3+
<html lang="en">
4+
<head>
5+
<meta charset="utf-8" />
6+
<title>Settings - IssueExpert for JIRA</title>
7+
</head>
8+
9+
<body>
10+
<form>
11+
<label for="urls" style="display: block">JIRA URLs:</label>
12+
<textarea
13+
id="urls"
14+
name="URL"
15+
rows="5"
16+
cols="33"
17+
placeholder="Specify JIRA URLs you want to enable IssueExpert for separated by semicolon e.g. https://*.atlassian.net/jira/.*;https://jira.issueexpert.com/.*"
18+
></textarea>
19+
<button type="submit" id="save" style="display: block">Save</button>
20+
</form>
21+
<script src="options.bundle.js"></script>
22+
</body>
23+
</html>

src/options/options.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Settings } from '../settings';
2+
3+
const settings = new Settings();
4+
const separatorChar = ';';
5+
const selectors = {
6+
url: '#urls',
7+
save: '#save',
8+
};
9+
10+
function saveOptions(): void {
11+
const urls: string | undefined =
12+
(document.querySelector(selectors.url) as HTMLTextAreaElement)?.value ??
13+
undefined;
14+
if (urls !== undefined) {
15+
void settings.setSettings({ urls: urls.split(separatorChar) });
16+
}
17+
}
18+
19+
function restoreOptions(): void {
20+
settings
21+
.getSettings()
22+
.then((settings) => {
23+
const urls = document.querySelector(selectors.url) as HTMLTextAreaElement;
24+
if (urls !== null && settings.urls.length > 0) {
25+
urls.value = settings.urls.join(separatorChar);
26+
}
27+
})
28+
.catch((error) => {
29+
console.error(error);
30+
});
31+
}
32+
33+
document.addEventListener('DOMContentLoaded', restoreOptions);
34+
document.querySelector(selectors.save)?.addEventListener('click', saveOptions);

src/settings.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1+
import { storage } from 'webextension-polyfill';
2+
13
export interface ISettings {
24
urls: string[];
35
}
46

57
export class Settings {
6-
getSettings(): ISettings {
8+
async getSettings(): Promise<ISettings> {
9+
const settings = (await storage.sync.get()) as ISettings;
710
return {
811
// TODO: RegExp is not user friendly
9-
urls: ['https://.*.atlassian.net/jira/software/projects'],
12+
urls: settings.urls ?? ['https://.*/jira/software/projects'],
1013
};
1114
}
15+
16+
async setSettings(settings: ISettings): Promise<void> {
17+
await storage.sync.set({
18+
urls: settings.urls,
19+
});
20+
}
1221
}

tsconfig.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
"outDir": "./dist/",
44
"sourceMap": true,
55
"noImplicitAny": true,
6-
"module": "es6",
7-
"target": "es5",
6+
"module": "es2022",
7+
"target": "es2017",
88
"moduleResolution": "node",
99
"strictNullChecks": true,
1010
"strict": true,
1111
"noImplicitThis": true,
1212
"alwaysStrict": true,
1313
"noUnusedLocals": true,
1414
"noImplicitReturns": true,
15-
"forceConsistentCasingInFileNames": true,
15+
"forceConsistentCasingInFileNames": true
1616
}
1717
}

webpack.common.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
const path = require('path');
22
const CopyPlugin = require('copy-webpack-plugin');
33
const MergeJsonWebpackPlugin = require('merge-jsons-webpack-plugin');
4+
const HtmlWebpackPlugin = require('html-webpack-plugin');
45

5-
module.exports = (env) => {
6+
module.exports = (env, argv) => {
67
const browser = env.BROWSER ?? 'chrome';
78
return {
8-
entry: { background: './src/background/index.ts', content: './src/content/index.ts' },
9+
entry: {
10+
background: './src/background/index.ts',
11+
content: './src/content/index.ts',
12+
options: './src/options/options.ts',
13+
},
914
output: {
1015
filename: '[name].bundle.js',
1116
path: path.resolve(__dirname, `dist/${browser}`),
@@ -23,11 +28,18 @@ module.exports = (env) => {
2328
resolve: {
2429
extensions: ['.tsx', '.ts', '.js'],
2530
},
31+
experiments: {
32+
topLevelAwait: true,
33+
},
2634
plugins: [
35+
new HtmlWebpackPlugin({
36+
filename: 'options.html',
37+
template: './src/options/options.html',
38+
chunks: [],
39+
minify: argv.mode === 'production',
40+
}),
2741
new CopyPlugin({
28-
patterns: [
29-
{ from: './src/icons', to: 'icons' },
30-
],
42+
patterns: [{ from: './src/icons', to: 'icons' }],
3143
}),
3244
new MergeJsonWebpackPlugin({
3345
space: 2,

webpack.dev.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ const { merge } = require('webpack-merge');
22
const common = require('./webpack.common.js');
33

44
module.exports = (env) => {
5-
return merge(common(env), {
5+
const argv = {
66
mode: 'development',
77
devtool: 'inline-source-map',
8+
};
9+
return merge(common(env, argv), {
10+
...argv,
811
});
912
};

0 commit comments

Comments
 (0)