Skip to content

Commit

Permalink
Several improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
willson556 committed Jan 15, 2024
1 parent bb26797 commit bf97ec0
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 63 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
.DS_Store
.AppleDouble
.LSOverride
xcode/

# Icon must end with two \r
Icon
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
},
"scripts": {
"start": "node --loader ts-node/esm scripts/build.ts --dev",
"build": "node --loader ts-node/esm scripts/build.ts"
"build": "node --loader ts-node/esm scripts/build.ts",
"build-safari": "rm -rf dist/safari-xcode && xcrun safari-web-extension-converter --swift --force --project-location xcode --app-name \"Jira Minute7 Autocomplete\" --bundle-identifier \"com.staflsystems.jira-minute7-autocomplete\" --no-open dist/safari/"
},
"type": "module",
"dependencies": {
Expand Down
Binary file modified public/icon-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/icon-34.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icon-full.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 19 additions & 33 deletions src/lib/jira.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export class JiraIssue {
key!: string;
summary!: string;
assignee!: string;
iconUrl!: string;
}

export class JiraIssueRetriever {
Expand All @@ -21,19 +22,12 @@ export class JiraIssueRetriever {
}
}

async searchIssues(jql: string, startAt: number) : Promise<{issues: JiraIssue[], total: number}> {
async get(endpoint: string, params: any): Promise<any> {
if (!this.Credentials) {
throw new Error('Not initialized');
}

const params = {
'jql': jql,
'fields': 'summary,description,assignee',
'startAt': startAt.toString(),
'maxResults': '100',
}

var url = new URL(this.Credentials.instanceUrl + '/rest/api/3/search');
var url = new URL(this.Credentials.instanceUrl + endpoint);
url.search = new URLSearchParams(params).toString();

const response = await fetch(url.toString(), {
Expand All @@ -45,40 +39,32 @@ export class JiraIssueRetriever {
});

if (!response.ok) {
throw new Error(`Failed to fetch issues: ${response.statusText}`);
throw new Error(`Failed to fetch ${url.toString()}: ${response.statusText}`);
}

const rawIssueResponse = await response.json();

console.log(rawIssueResponse);

const rawIssues = rawIssueResponse.issues;
const issues = rawIssues.map((rawIssue: any) => {
return new JiraIssue({
key: rawIssue.key,
summary: rawIssue.fields.summary,
assignee: rawIssue.fields.assignee?.displayName || '',
});
});

return { issues: issues, total: rawIssueResponse.total };
return await response.json();
}

async getRecentlyUpdatedIssues(): Promise<JiraIssue[]> {
async getSuggestions(query: string): Promise<JiraIssue[]> {
if (!this.Credentials) {
throw new Error('Not initialized');
}

const query = 'updated >= -30d order by updated DESC';
const params = {
'query': query,
};

const initialResults = await this.searchIssues(query, 0);
const total = initialResults.total;
var issues = initialResults.issues;
const response = await this.get('/rest/api/3/issue/picker', params);

while (issues.length < total) {
const nextResults = await this.searchIssues(query, issues.length);
issues = issues.concat(nextResults.issues);
}
console.log(response);
const issues = response.sections[0].issues.map((rawIssue: any) => {
return new JiraIssue({
key: rawIssue.key,
summary: rawIssue.summary,
assignee: '',
iconUrl: this.Credentials?.instanceUrl + rawIssue.img,
});
});

return issues;
}
Expand Down
4 changes: 3 additions & 1 deletion src/manifest/v2.mts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const manifest: ManifestTypeV2 = {
"128": "public/icon-128.png",
},
web_accessible_resources: ["public/*", "assets/*"],
permissions: ["storage", "https://*.atlassian.net/*"],
};

function getManifestV2(pageDirMap: { [x: string]: any }): ManifestTypeV2 {
Expand All @@ -31,6 +32,7 @@ function getManifestV2(pageDirMap: { [x: string]: any }): ManifestTypeV2 {
if (pages.indexOf("background") > -1) {
manifest.background = {
scripts: [pageDirMap["background"]],
persistent: false,
};
}

Expand All @@ -44,7 +46,7 @@ function getManifestV2(pageDirMap: { [x: string]: any }): ManifestTypeV2 {
if (pages.indexOf("content") > -1) {
manifest.content_scripts = [
{
matches: ["http://*/*", "https://*/*", "<all_urls>"],
matches: ["https://frontend.minute7.com/*"],
js: [pageDirMap["content"]],
css: pageDirMap["content-css"],
run_at: "document_start",
Expand Down
4 changes: 2 additions & 2 deletions src/manifest/v3.mts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const manifest: ManifestTypeV3 = {
matches: ["<all_urls>"],
},
],
permissions:[ "storage", "webRequest" ],
permissions:[ "storage" ],
host_permissions: [
"https://*.atlassian.net/*",
]
Expand Down Expand Up @@ -72,7 +72,7 @@ function getManifestV3(pageDirMap: { [x: string]: any }): ManifestTypeV3 {
if (pages.indexOf("content") > -1) {
manifest.content_scripts = [
{
matches: ["http://*/*", "https://*/*", "<all_urls>"],
matches: ["https://frontend.minute7.com/*"],
js: [pageDirMap["content"]],
css: pageDirMap["content-css"],
run_at: "document_start",
Expand Down
5 changes: 3 additions & 2 deletions src/pages/background/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ browser.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.type === "jiraSuggestions") {
const jiraIssueRetriever = new JiraIssueRetriever();
jiraIssueRetriever.init().then(async () => {
const issues = await jiraIssueRetriever.getRecentlyUpdatedIssues();
const issues = await jiraIssueRetriever.getSuggestions(message.text);
console.log(issues);
sendResponse(issues);
});

return true;
}
}
});

console.log("listener added");
57 changes: 33 additions & 24 deletions src/pages/content/index.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,68 @@
import React from "react";
import { createRoot } from "react-dom/client";
import { JiraIssue } from "@src/lib/jira";
import browser from 'webextension-polyfill';
import autocomplete, { AutocompleteItem } from "autocompleter";

import "./style.css";

async function init() {
console.log(document.URL)

if (!document.URL.startsWith("https://frontend.minute7.com")) {
return;
async function getDescriptionField(): Promise<HTMLTextAreaElement>
{
var te: HTMLTextAreaElement | null = null;
while (te == null) {
te = document.getElementsByTagName("textarea")[0];
await new Promise(r => setTimeout(r, 100));
}

const issues: JiraIssue[] = await browser.runtime.sendMessage({ type: "jiraSuggestions" });

console.log(issues);
type MyItem = JiraIssue & AutocompleteItem;
const te = document.getElementsByTagName("textarea")[0];
return te;
}

async function init() {
if (!document.URL.startsWith("https://frontend.minute7.com")) {
return;
}

const autocompleteContainer = document.createElement("div");
autocompleteContainer.classList.add("autocomplete");
autocompleteContainer.role = "listbox";
autocompleteContainer.style.backgroundColor = "white";
autocompleteContainer.style.zIndex = "1";
document.body.appendChild(autocompleteContainer);


const textArea = await getDescriptionField();
type MyItem = JiraIssue & AutocompleteItem;
autocomplete<MyItem>({
input: te,
input: textArea,
emptyMsg: "No issues found",
fetch: (text: string, update: (items: JiraIssue[]) => void) => {
text = text.toLowerCase();
const suggestions = issues.filter(n => n.summary.toLowerCase().includes(text));
update(suggestions);
browser.runtime.sendMessage({ type: "jiraSuggestions", text: text }).then(
(response: JiraIssue[]) => {
update(response);
}
);
},
onSelect: (item: JiraIssue) => {
te.value = `${item.key} - ${item.summary}`;
textArea.value = `${item.key} - ${item.summary.replaceAll('<b>', '').replaceAll('</b>', '')}`;
},
render: (item: JiraIssue, currentValue: string) => {
const div = document.createElement("div");
div.classList.add("autocomplete-entry");
div.textContent = `${item.key} - ${item.summary}`;

const img = document.createElement("img");
img.src = item.iconUrl;
div.appendChild(img);

const p = document.createElement("div");

p.innerHTML = `${item.key} - ${item.summary}`;
if (item.assignee) {
div.textContent += ` (${item.assignee})`;
p.innerHTML += ` (${item.assignee})`;
}

div.appendChild(p);

return div;
},
click: e => e.fetch(),
container: autocompleteContainer,
});



}

document.addEventListener("DOMContentLoaded", init);
18 changes: 18 additions & 0 deletions src/pages/content/style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
.autocomplete {
background-color: #FFFFFF;
z-index: 1;
border: rgba(38,46,58,.1) solid 1px;
border-radius: 5px;
}

.autocomplete-entry {
background-color: #FFFFFF;
padding: 5px;
Expand All @@ -9,4 +16,15 @@

.autocomplete-entry:hover {
background-color: #cbd1d3;
}

.autocomplete-entry>img {
display: inline;
}

.autocomplete-entry>div {
display: inline;
line-height: 22px;
vertical-align: top;
margin-left: 5px;
}

0 comments on commit bf97ec0

Please sign in to comment.