Use .vscode folder for settings and such
This commit is contained in:
parent
a122e5e47e
commit
420303bffa
12
README.md
12
README.md
@ -4,7 +4,13 @@ Issuetracker for Gitea
|
|||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
To setup a gitea issue tracked project you need to first select the issues tab at the activitiy bar. After that open the command palette in order to type in the command `Initialize Gitea-Issue Tracker` and enter your crendentials:
|
Go to your settings, and find the `Gitea` section, and fill out the details.
|
||||||
|
|
||||||
|
Please make sure to not to make your authtoken public, as it can be used to act on your behalf.
|
||||||
|
You can store it in the user settings, whilst leaving the rest in the workspace settings.
|
||||||
|
|
||||||
|
### The following details are needed
|
||||||
|
|
||||||
- Authtoken
|
- Authtoken
|
||||||
- Domain in format: "example.com"
|
- Domain in format: "example.com"
|
||||||
- Repository Owner (may be an organisation): "TestOrganisation"
|
- Repository Owner (may be an organisation): "TestOrganisation"
|
||||||
@ -16,8 +22,10 @@ When you've finished you can press the refresh button in the open issues section
|
|||||||
|
|
||||||
![Issues with multiple colors](./media/gitea-issues.png)
|
![Issues with multiple colors](./media/gitea-issues.png)
|
||||||
|
|
||||||
In order to get nice looking issue icons in multiple colors (of your choice) you just need to assign a label to your issue. The color is being fetched automatically. If you change the color of the label however, you need to delete the `.gitea/{issuename}.svg` file in the given folder. If you skip this step, the file is not going to get updated. In most cases you need to restart visual studio code to apply the icons in the issues tab.
|
In order to get nice looking issue icons in multiple colors (of your choice) you just need to assign a label to your issue. The color is being fetched automatically. In most cases you need to restart visual studio code to apply the icons in the issues tab if you've changed them though.
|
||||||
|
|
||||||
## Future
|
## Future
|
||||||
|
|
||||||
- Implement a `Close Issue` Button
|
- Implement a `Close Issue` Button
|
||||||
- Create Issues via Webview
|
- Create Issues via Webview
|
||||||
- `Comment` Issues
|
- `Comment` Issues
|
12
package-lock.json
generated
12
package-lock.json
generated
@ -251,14 +251,6 @@
|
|||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"configparser": {
|
|
||||||
"version": "0.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/configparser/-/configparser-0.3.6.tgz",
|
|
||||||
"integrity": "sha512-qCYjKDEK69qRtm3n+RYM55b8XiH2uKfnI6qOKg+ZLrKSG5vY59RBcZhLxxVd18+B5C5Zc7Jy8KpFsB5YOAD+hw==",
|
|
||||||
"requires": {
|
|
||||||
"mkdirp": "^0.5.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
@ -606,12 +598,14 @@
|
|||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
|
217
package.json
217
package.json
@ -1,93 +1,128 @@
|
|||||||
{
|
{
|
||||||
"name": "gitea-vscode",
|
"name": "gitea-vscode",
|
||||||
"displayName": "Gitea-VSCode",
|
"displayName": "Gitea-VSCode",
|
||||||
"description": "Gitea Issue Tracker for vs-code",
|
"description": "Gitea Issue Tracker for vs-code",
|
||||||
"publisher": "IJustDev",
|
"publisher": "IJustDev",
|
||||||
"version": "0.0.6",
|
"version": "0.0.7",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.32.0"
|
"vscode": "^1.32.0"
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"Other"
|
"Other"
|
||||||
],
|
],
|
||||||
"activationEvents": [
|
"activationEvents": [
|
||||||
"onView:open-issues",
|
"onView:open-issues",
|
||||||
"onCommand:giteaIssues.initRepo",
|
"onCommand:giteaIssues.initRepo",
|
||||||
"onCommand:giteaIssues.refreshIssues"
|
"onCommand:giteaIssues.refreshIssues"
|
||||||
],
|
],
|
||||||
"main": "./out/extension.js",
|
"main": "./out/extension.js",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"viewsContainers": {
|
"viewsContainers": {
|
||||||
"activitybar": [
|
"activitybar": [
|
||||||
{
|
{
|
||||||
"id": "issue-explorer",
|
"id": "issue-explorer",
|
||||||
"title": "Gitea-Issues",
|
"title": "Gitea-Issues",
|
||||||
"icon": "media/issue.svg"
|
"icon": "media/issue.svg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"views": {
|
"views": {
|
||||||
"issue-explorer": [
|
"issue-explorer": [
|
||||||
{
|
{
|
||||||
"id": "open-issues",
|
"id": "open-issues",
|
||||||
"name": "Open Issues"
|
"name": "Open Issues"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "closed-issues",
|
"id": "closed-issues",
|
||||||
"name": "Closed Issues"
|
"name": "Closed Issues"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"command": "giteaIssues.openIssue",
|
"command": "giteaIssues.openIssue",
|
||||||
"title": "Show"
|
"title": "Show"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "giteaIssues.refreshIssues",
|
"command": "giteaIssues.refreshIssues",
|
||||||
"title": "Refresh",
|
"title": "Refresh",
|
||||||
"icon": {
|
"icon": {
|
||||||
"dark": "resources/dark/refresh.svg",
|
"dark": "resources/dark/refresh.svg",
|
||||||
"light": "resources/light/refresh.svg"
|
"light": "resources/light/refresh.svg"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "giteaIssues.initRepo",
|
"command": "giteaIssues.initRepo",
|
||||||
"title": "Initialize Gitea-Issue Tracker"
|
"title": "Initialize Gitea-Issue Tracker"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
"view/title": [
|
"view/title": [
|
||||||
{
|
{
|
||||||
"command": "giteaIssues.refreshIssues",
|
"command": "giteaIssues.refreshIssues",
|
||||||
"group": "navigation",
|
"group": "navigation",
|
||||||
"when": "view == open-issues"
|
"when": "view == open-issues"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
},
|
"configuration": {
|
||||||
"scripts": {
|
"title": "Gitea",
|
||||||
"vscode:prepublish": "npm run compile",
|
"properties": {
|
||||||
"compile": "tsc -p ./",
|
"gitea.token": {
|
||||||
"watch": "tsc -watch -p ./",
|
"scope": "application",
|
||||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
"type": "string",
|
||||||
"test": "npm run compile && node ./node_modules/vscode/bin/test"
|
"default": "",
|
||||||
},
|
"description": "The token for the gitea server."
|
||||||
"devDependencies": {
|
},
|
||||||
"@types/axios": "^0.14.0",
|
"gitea.domain": {
|
||||||
"@types/mocha": "^2.2.42",
|
"scope": "resource",
|
||||||
"@types/node": "^10.12.21",
|
"type": "string",
|
||||||
"tslint": "^5.12.1",
|
"default": "",
|
||||||
"typescript": "^3.3.1",
|
"description": "The remote gitea instance's domain."
|
||||||
"vscode": "^1.1.28"
|
},
|
||||||
},
|
"gitea.owner": {
|
||||||
"dependencies": {
|
"scope": "resource",
|
||||||
"axios": "^0.18.1",
|
"type": "string",
|
||||||
"configparser": "^0.3.6",
|
"default": "",
|
||||||
"marked": "^0.6.2"
|
"description": "The username for the repository."
|
||||||
},
|
},
|
||||||
"repository": {
|
"gitea.repo": {
|
||||||
"type": "github",
|
"scope": "resource",
|
||||||
"url": "https://github.com/IJustdev/Gitea-VSCode.git"
|
"type": "string",
|
||||||
}
|
"default": "",
|
||||||
|
"description": "The repository name."
|
||||||
|
},
|
||||||
|
"gitea.ssl": {
|
||||||
|
"scope": "resource",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "If https should be used or not."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"vscode:prepublish": "npm run compile",
|
||||||
|
"compile": "tsc -p ./",
|
||||||
|
"watch": "tsc -watch -p ./",
|
||||||
|
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||||
|
"test": "npm run compile && node ./node_modules/vscode/bin/test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/axios": "^0.14.0",
|
||||||
|
"@types/mocha": "^2.2.42",
|
||||||
|
"@types/node": "^10.12.21",
|
||||||
|
"tslint": "^5.12.1",
|
||||||
|
"typescript": "^3.3.1",
|
||||||
|
"vscode": "^1.1.28"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.18.1",
|
||||||
|
"marked": "^0.6.2"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/IJustdev/Gitea-VSCode.git"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
82
src/Config.ts
Normal file
82
src/Config.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { workspace, window } from 'vscode';
|
||||||
|
|
||||||
|
interface ConfigStorage {
|
||||||
|
token: string;
|
||||||
|
domain: string;
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
ssl: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConfigTypes extends ConfigStorage {
|
||||||
|
readonly repoApiUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Config implements ConfigTypes {
|
||||||
|
private get storage() {
|
||||||
|
return workspace.getConfiguration('gitea', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadConfigValue<T extends keyof ConfigStorage>(configKey: T, type: 'string' | 'boolean' | 'number', acceptDetault = false): ConfigStorage[T] {
|
||||||
|
if (!acceptDetault && !this.storage.has(configKey)) {
|
||||||
|
window.showErrorMessage("Gitea-VSCode didn't find a required configuration value: " + configKey);
|
||||||
|
throw new Error(`Failed to load configuration: "${configKey}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = this.storage.has(configKey)
|
||||||
|
? (this.storage.get(configKey) as ConfigStorage[T])
|
||||||
|
: (this.storage.inspect(configKey) as { defaultValue: ConfigStorage[T]; key: string }).defaultValue;
|
||||||
|
|
||||||
|
if (typeof value === type && (type !== 'string' || (value as string).length > 0)) {
|
||||||
|
return value as ConfigStorage[T];
|
||||||
|
}
|
||||||
|
|
||||||
|
window.showErrorMessage('Gitea-VSCode failed to load a configuration value that is needed: ' + configKey);
|
||||||
|
throw new Error(`Failed to load configuration: "gitea.${configKey}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get token() {
|
||||||
|
return this.loadConfigValue('token', 'string');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set token(value) {
|
||||||
|
this.storage.update('token', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get domain() {
|
||||||
|
return this.loadConfigValue('domain', 'string');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set domain(value) {
|
||||||
|
this.storage.update('domain', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get owner() {
|
||||||
|
return this.loadConfigValue('owner', 'string');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set owner(value) {
|
||||||
|
this.storage.update('owner', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get repo() {
|
||||||
|
return this.loadConfigValue('repo', 'string');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set repo(value) {
|
||||||
|
this.storage.update('repo', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get ssl() {
|
||||||
|
return this.loadConfigValue('ssl', 'boolean', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set ssl(value) {
|
||||||
|
this.storage.update('ssl', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get repoApiUrl() {
|
||||||
|
const prefix = this.ssl ? 'https' : 'http';
|
||||||
|
return prefix + '://' + this.domain + '/api/v1/repos/' + this.owner + '/' + this.repo + '/issues';
|
||||||
|
}
|
||||||
|
}
|
@ -1,32 +0,0 @@
|
|||||||
const ConfigParser = require("configparser");
|
|
||||||
const path = require("path");
|
|
||||||
|
|
||||||
export class RepositoryInformationManager {
|
|
||||||
public token(rootPath: string | undefined) {
|
|
||||||
const config = new ConfigParser();
|
|
||||||
config.read(path.join(rootPath as string, "/.gitea/config.ini"));
|
|
||||||
return config.get("PRIVATE", "token");
|
|
||||||
}
|
|
||||||
public repoApiUrl(rootPath: string | undefined) {
|
|
||||||
const config = new ConfigParser();
|
|
||||||
config.read(rootPath + "/.gitea/config.ini");
|
|
||||||
const domain = config.get("REPO", "domain");
|
|
||||||
const repo_owner = config.get("REPO", "repo_owner");
|
|
||||||
const repo_name = config.get("REPO", "repo_name");
|
|
||||||
const ssl = config.get("REPO", "ssl");
|
|
||||||
const prefix = ssl ? "https" : "http";
|
|
||||||
return prefix + "://" + domain + "/api/v1/repos/" + repo_owner + "/" + repo_name + "/issues";
|
|
||||||
}
|
|
||||||
public saveRepoInformation(rootPath: string | undefined, repoInformations: any) {
|
|
||||||
const file_path = path.join(rootPath as string, ".gitea/config.ini");
|
|
||||||
const config = new ConfigParser();
|
|
||||||
config.addSection("PRIVATE");
|
|
||||||
config.addSection("REPO");
|
|
||||||
config.set("PRIVATE", "token", repoInformations.token);
|
|
||||||
config.set("REPO", "domain", repoInformations.domain);
|
|
||||||
config.set("REPO", "repo_owner", repoInformations.repo_owner);
|
|
||||||
config.set("REPO", "repo_name", repoInformations.repo_name);
|
|
||||||
config.set("REPO", "ssl", true);
|
|
||||||
config.write(file_path, true);
|
|
||||||
}
|
|
||||||
}
|
|
113
src/extension.ts
113
src/extension.ts
@ -1,90 +1,47 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
import { showIssueHTML } from './template.html';
|
import { showIssueHTML } from './template.html';
|
||||||
import { Issue } from "./issue";
|
import { Issue } from './issue';
|
||||||
import { RepositoryInformationManager } from './configurationProvider';
|
|
||||||
import { OpenIssuesProvider, ClosedIssuesProvider } from './issueProvider';
|
import { OpenIssuesProvider, ClosedIssuesProvider } from './issueProvider';
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
let disposable = vscode.commands.registerCommand('giteaIssues.initRepo', () => {
|
let openIssues: Array<Issue> = [];
|
||||||
initializeIssueTracker();
|
const openIssuesProvider = new OpenIssuesProvider();
|
||||||
});
|
const closedIssuesProvider = new ClosedIssuesProvider();
|
||||||
context.subscriptions.push(disposable);
|
|
||||||
let openIssues: Array<Issue> = [];
|
|
||||||
const openIssuesProvider = new OpenIssuesProvider();
|
|
||||||
const closedIssuesProvider = new ClosedIssuesProvider();
|
|
||||||
|
|
||||||
vscode.window.registerTreeDataProvider('open-issues', openIssuesProvider);
|
vscode.window.registerTreeDataProvider('open-issues', openIssuesProvider);
|
||||||
vscode.window.registerTreeDataProvider('closed-issues', closedIssuesProvider);
|
vscode.window.registerTreeDataProvider('closed-issues', closedIssuesProvider);
|
||||||
|
|
||||||
// TODO: Implement in next version.
|
// TODO: Implement in next version.
|
||||||
// vscode.commands.registerCommand('giteaIssues.createIssue', async () => {
|
// vscode.commands.registerCommand('giteaIssues.createIssue', async () => {
|
||||||
// const panel = vscode.window.createWebviewPanel('createIssue', 'Create an new Issue', vscode.ViewColumn.Active, {});
|
// const panel = vscode.window.createWebviewPanel('createIssue', 'Create an new Issue', vscode.ViewColumn.Active, {});
|
||||||
// panel.webview.html = "";
|
// panel.webview.html = "";
|
||||||
// });
|
// });
|
||||||
|
|
||||||
vscode.commands.registerCommand('giteaIssues.openIssue', (issue: Issue) => {
|
vscode.commands.registerCommand('giteaIssues.openIssue', (issue: Issue) => {
|
||||||
for (let i = 0; i !== openIssues.length; i++) {
|
for (let i = 0; i !== openIssues.length; i++) {
|
||||||
let openIssue = openIssues[i];
|
let openIssue = openIssues[i];
|
||||||
if (openIssue.issueId === issue.issueId) {
|
if (openIssue.issueId === issue.issueId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
const panel = vscode.window.createWebviewPanel('issue', issue.label,
|
|
||||||
vscode.ViewColumn.Active,
|
|
||||||
{});
|
|
||||||
panel.webview.html = showIssueHTML(issue);
|
|
||||||
openIssues.push(issue);
|
|
||||||
panel.onDidDispose(event => {
|
|
||||||
for (let i = 0; i !== openIssues.length; i++) {
|
|
||||||
let openIssue = openIssues[i];
|
|
||||||
if (openIssue.issueId === issue.issueId) {
|
|
||||||
openIssues.splice(openIssues.indexOf(issue), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
vscode.commands.registerCommand('giteaIssues.refreshIssues', () => {
|
|
||||||
openIssuesProvider.refresh();
|
|
||||||
closedIssuesProvider.refresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deactivate() { }
|
|
||||||
|
|
||||||
export async function initializeIssueTracker() {
|
|
||||||
if (vscode.workspace.rootPath === undefined) {
|
|
||||||
return vscode.window.showErrorMessage("No project opened!");
|
|
||||||
}
|
}
|
||||||
let Token, Domain, Owner, Name;
|
const panel = vscode.window.createWebviewPanel('issue', issue.label, vscode.ViewColumn.Active, {});
|
||||||
await vscode.window.showInputBox({
|
panel.webview.html = showIssueHTML(issue);
|
||||||
placeHolder: "Enter your gitea token here",
|
openIssues.push(issue);
|
||||||
}).then(token => {
|
panel.onDidDispose((event) => {
|
||||||
Token = token === undefined ? "" : token;
|
for (let i = 0; i !== openIssues.length; i++) {
|
||||||
|
let openIssue = openIssues[i];
|
||||||
|
if (openIssue.issueId === issue.issueId) {
|
||||||
|
openIssues.splice(openIssues.indexOf(issue), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
await vscode.window.showInputBox({
|
});
|
||||||
placeHolder: "Domain from your gitea server without 'https://'",
|
|
||||||
}).then(domain => {
|
vscode.commands.registerCommand('giteaIssues.refreshIssues', () => {
|
||||||
Domain = domain === undefined ? "" : domain;
|
openIssuesProvider.refresh();
|
||||||
});
|
closedIssuesProvider.refresh();
|
||||||
await vscode.window.showInputBox({
|
});
|
||||||
placeHolder: "Repository Owner",
|
|
||||||
}).then(owner => {
|
|
||||||
Owner = owner === undefined ? "" : owner;
|
|
||||||
});
|
|
||||||
await vscode.window.showInputBox({
|
|
||||||
placeHolder: "Repository Name",
|
|
||||||
}).then(name => {
|
|
||||||
Name = name === undefined ? "" : name;
|
|
||||||
});
|
|
||||||
const repoInfo = {
|
|
||||||
token: Token,
|
|
||||||
domain: Domain,
|
|
||||||
repo_owner: Owner,
|
|
||||||
repo_name: Name,
|
|
||||||
};
|
|
||||||
const rpim = new RepositoryInformationManager();
|
|
||||||
rpim.saveRepoInformation(vscode.workspace.rootPath, repoInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deactivate() {}
|
||||||
|
105
src/issue.ts
105
src/issue.ts
@ -1,59 +1,54 @@
|
|||||||
import * as vscode from "vscode";
|
import { Uri, TreeItem, TreeItemCollapsibleState, Command } from 'vscode';
|
||||||
import * as path from "path";
|
|
||||||
import * as fs from "fs";
|
|
||||||
|
|
||||||
export class Issue extends vscode.TreeItem {
|
interface Label {
|
||||||
|
color: string;
|
||||||
constructor(public readonly label: string,
|
id: number;
|
||||||
public issueId: number,
|
name: string;
|
||||||
public body: string,
|
url: string;
|
||||||
public issueState: string,
|
|
||||||
public assignee: string,
|
|
||||||
public creator: string,
|
|
||||||
public labels: any[],
|
|
||||||
public collapsibleState: vscode.TreeItemCollapsibleState,
|
|
||||||
public readonly command?: vscode.Command) {
|
|
||||||
super(label, collapsibleState);
|
|
||||||
try {
|
|
||||||
for (const issueLabel of labels) {
|
|
||||||
const folderPath = path.join(vscode.workspace.rootPath as string, '.gitea', 'label_pictures');
|
|
||||||
if (!fs.existsSync(path.join(folderPath, issueLabel.name + ".svg"))) {
|
|
||||||
if (!fs.existsSync(folderPath)) {
|
|
||||||
fs.mkdirSync(folderPath);
|
|
||||||
}
|
|
||||||
fs.writeFileSync(path.join(folderPath, issueLabel.name + ".svg"), createIconWithColor(issueLabel.color));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get tooltip() {
|
|
||||||
return this.label + " - " + this.assignee;
|
|
||||||
}
|
|
||||||
|
|
||||||
labelDependentIcon(dark: boolean = false): string {
|
|
||||||
if (this.labels.length === 0) {
|
|
||||||
return path.join(__filename, '..', '..', 'media', 'issue.svg');
|
|
||||||
} else {
|
|
||||||
return path.join(vscode.workspace.rootPath as string, '.gitea', 'label_pictures', this.labels[0].name + ".svg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iconPath = {
|
|
||||||
light: this.labelDependentIcon(),
|
|
||||||
dark: this.labelDependentIcon(true)
|
|
||||||
};
|
|
||||||
|
|
||||||
contextValue = 'issue';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createIconWithColor(color: string) {
|
export class Issue extends TreeItem {
|
||||||
return `<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
constructor(
|
||||||
<path d="M16 31.5C24.5604 31.5 31.5 24.5604 31.5 16C31.5 7.43959 24.5604 0.5 16 0.5C7.43959 0.5 0.5 7.43959 0.5 16C0.5 24.5604 7.43959 31.5 16 31.5Z" stroke="{{color}}"/>
|
public readonly label: string,
|
||||||
<path d="M19 6C19 4.34315 17.6569 3 16 3C14.3431 3 13 4.34315 13 6V20C13 21.6569 14.3431 23 16 23C17.6569 23 19 21.6569 19 20V6Z" fill="{{color}}"/>
|
public issueId: number,
|
||||||
<path d="M16.5 24H15.5C14.1193 24 13 25.1193 13 26.5C13 27.8807 14.1193 29 15.5 29H16.5C17.8807 29 19 27.8807 19 26.5C19 25.1193 17.8807 24 16.5 24Z" fill="{{color}}"/>
|
public body: string,
|
||||||
</svg>
|
public issueState: string,
|
||||||
`.replace(new RegExp("{{color}}", 'g'), "#" + color);
|
public assignee: string,
|
||||||
|
public creator: string,
|
||||||
|
public labels: Label[],
|
||||||
|
public collapsibleState: TreeItemCollapsibleState,
|
||||||
|
public readonly command?: Command
|
||||||
|
) {
|
||||||
|
super(label, collapsibleState);
|
||||||
|
}
|
||||||
|
|
||||||
|
get tooltip() {
|
||||||
|
return this.label + ' - ' + this.assignee;
|
||||||
|
}
|
||||||
|
|
||||||
|
labelDependentIcon(dark: boolean = false): Uri {
|
||||||
|
if (this.labels.length === 0) {
|
||||||
|
return createIconWithColor('#868686');
|
||||||
|
} else {
|
||||||
|
return createIconWithColor(this.labels[0].color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iconPath = {
|
||||||
|
light: this.labelDependentIcon(),
|
||||||
|
dark: this.labelDependentIcon(true),
|
||||||
|
};
|
||||||
|
|
||||||
|
contextValue = 'issue';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createIconWithColor(color: string): Uri {
|
||||||
|
const icon = `<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M16 31.5C24.5604 31.5 31.5 24.5604 31.5 16C31.5 7.43959 24.5604 0.5 16 0.5C7.43959 0.5 0.5 7.43959 0.5 16C0.5 24.5604 7.43959 31.5 16 31.5Z" stroke="{{color}}"/>
|
||||||
|
<path d="M19 6C19 4.34315 17.6569 3 16 3C14.3431 3 13 4.34315 13 6V20C13 21.6569 14.3431 23 16 23C17.6569 23 19 21.6569 19 20V6Z" fill="{{color}}"/>
|
||||||
|
<path d="M16.5 24H15.5C14.1193 24 13 25.1193 13 26.5C13 27.8807 14.1193 29 15.5 29H16.5C17.8807 29 19 27.8807 19 26.5C19 25.1193 17.8807 24 16.5 24Z" fill="{{color}}"/>
|
||||||
|
</svg>
|
||||||
|
`.replace(new RegExp('{{color}}', 'g'), '#' + color);
|
||||||
|
|
||||||
|
return Uri.parse('data:image/svg+xml;base64,' + Buffer.from(icon).toString('base64'));
|
||||||
}
|
}
|
@ -1,159 +1,170 @@
|
|||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import * as vscode from "vscode";
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
const marked = require("marked");
|
const marked = require('marked');
|
||||||
import { Issue } from "./issue";
|
import { Issue } from './issue';
|
||||||
import { RepositoryInformationManager } from "./configurationProvider";
|
import { Config } from './Config';
|
||||||
|
|
||||||
export class OpenIssuesProvider implements vscode.TreeDataProvider<Issue> {
|
export class OpenIssuesProvider implements vscode.TreeDataProvider<Issue> {
|
||||||
|
private _onDidChangeTreeData: vscode.EventEmitter<Issue | undefined> = new vscode.EventEmitter<Issue | undefined>();
|
||||||
|
readonly onDidChangeTreeData: vscode.Event<Issue | undefined> = this._onDidChangeTreeData.event;
|
||||||
|
|
||||||
private _onDidChangeTreeData: vscode.EventEmitter<Issue | undefined> = new vscode.EventEmitter<Issue | undefined>();
|
issueList: Issue[] = [];
|
||||||
readonly onDidChangeTreeData: vscode.Event<Issue | undefined> = this._onDidChangeTreeData.event;
|
|
||||||
|
|
||||||
issueList: Issue[] = [];
|
async refresh() {
|
||||||
|
await this.getChildrenAsync();
|
||||||
|
this._onDidChangeTreeData.fire();
|
||||||
|
}
|
||||||
|
|
||||||
async refresh() {
|
constructor() {
|
||||||
await this.getChildrenAsync();
|
// Auto update the issuelist after 10 minutes
|
||||||
this._onDidChangeTreeData.fire();
|
setInterval(() => {
|
||||||
|
this.refresh();
|
||||||
|
}, 10 * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTreeItem(element: Issue): vscode.TreeItem | Thenable<vscode.TreeItem> {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all open issues;
|
||||||
|
*/
|
||||||
|
async getChildrenAsync() {
|
||||||
|
this.issueList = [];
|
||||||
|
const config = new Config();
|
||||||
|
const repoUri = config.repoApiUrl;
|
||||||
|
const token = config.token;
|
||||||
|
let stop = false;
|
||||||
|
for (let i = 0; i !== 10; i++) {
|
||||||
|
await axios
|
||||||
|
.get(repoUri + '?page=' + i, { headers: { Authorization: 'token ' + token } })
|
||||||
|
.then((res) => {
|
||||||
|
console.log(res.data);
|
||||||
|
if (res.data.length === 0) {
|
||||||
|
stop = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parseToIssues(res, this.issueList);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
stop = true;
|
||||||
|
vscode.window.showErrorMessage("Can't fetch issues; HTTP Error!");
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
if (stop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
constructor() {
|
getChildren(element?: Issue): vscode.ProviderResult<any[]> {
|
||||||
// Auto update the issuelist after 10 minutes
|
return getChildren(element, this.issueList);
|
||||||
setInterval(() => {
|
}
|
||||||
this.refresh();
|
|
||||||
}, 10 * 60 * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTreeItem(element: Issue): vscode.TreeItem | Thenable<vscode.TreeItem> {
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of all open issues;
|
|
||||||
*/
|
|
||||||
async getChildrenAsync() {
|
|
||||||
this.issueList = [];
|
|
||||||
const repoMng = new RepositoryInformationManager();
|
|
||||||
const repoUri = repoMng.repoApiUrl(vscode.workspace.rootPath);
|
|
||||||
const token = repoMng.token(vscode.workspace.rootPath);
|
|
||||||
let stop = false;
|
|
||||||
for (let i = 0; i !== 10; i++) {
|
|
||||||
await axios.get(repoUri + "?page=" + i, { headers: { Authorization: "token " + token } }).then(res => {
|
|
||||||
console.log(res.data);
|
|
||||||
if (res.data.length === 0) {
|
|
||||||
stop = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parseToIssues(res, this.issueList);
|
|
||||||
}).catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
stop = true;
|
|
||||||
vscode.window.showErrorMessage("Can't fetch issues; HTTP Error!");
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
if (stop) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getChildren(element?: Issue): vscode.ProviderResult<any[]> {
|
|
||||||
return getChildren(element, this.issueList);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClosedIssuesProvider implements vscode.TreeDataProvider<Issue> {
|
export class ClosedIssuesProvider implements vscode.TreeDataProvider<Issue> {
|
||||||
|
private _onDidChangeTreeData: vscode.EventEmitter<Issue | undefined> = new vscode.EventEmitter<Issue | undefined>();
|
||||||
|
readonly onDidChangeTreeData: vscode.Event<Issue | undefined> = this._onDidChangeTreeData.event;
|
||||||
|
|
||||||
private _onDidChangeTreeData: vscode.EventEmitter<Issue | undefined> = new vscode.EventEmitter<Issue | undefined>();
|
issueList: Issue[] = [];
|
||||||
readonly onDidChangeTreeData: vscode.Event<Issue | undefined> = this._onDidChangeTreeData.event;
|
|
||||||
|
|
||||||
issueList: Issue[] = [];
|
async refresh() {
|
||||||
|
await this.getChildrenAsync();
|
||||||
|
this._onDidChangeTreeData.fire();
|
||||||
|
}
|
||||||
|
|
||||||
async refresh() {
|
constructor() {
|
||||||
await this.getChildrenAsync();
|
setInterval(() => {
|
||||||
this._onDidChangeTreeData.fire();
|
this.refresh();
|
||||||
}
|
}, 10 * 60 * 1000);
|
||||||
|
}
|
||||||
constructor() {
|
|
||||||
setInterval(() => {
|
getTreeItem(element: Issue): vscode.TreeItem | Thenable<vscode.TreeItem> {
|
||||||
this.refresh();
|
return element;
|
||||||
}, 10 * 60 * 1000);
|
}
|
||||||
}
|
|
||||||
|
async getChildrenAsync() {
|
||||||
getTreeItem(element: Issue): vscode.TreeItem | Thenable<vscode.TreeItem> {
|
this.issueList = [];
|
||||||
return element;
|
const config = new Config();
|
||||||
}
|
const repoUri = config.repoApiUrl;
|
||||||
|
const token = config.token;
|
||||||
async getChildrenAsync() {
|
let stop = false;
|
||||||
this.issueList = [];
|
for (let i = 0; i !== 10; i++) {
|
||||||
const repoMng = new RepositoryInformationManager();
|
await axios
|
||||||
const repoUri = repoMng.repoApiUrl(vscode.workspace.rootPath);
|
.get(repoUri + '?state=closed&page=' + i, { headers: { Authorization: 'token ' + token } })
|
||||||
const token = repoMng.token(vscode.workspace.rootPath);
|
.then((res) => {
|
||||||
let stop = false;
|
console.log(res.data);
|
||||||
for (let i = 0; i !== 10; i++) {
|
if (res.data.length === 0) {
|
||||||
await axios.get(repoUri + "?state=closed&page=" + i, { headers: { Authorization: "token " + token } }).then(res => {
|
stop = true;
|
||||||
console.log(res.data);
|
return;
|
||||||
if (res.data.length === 0) {
|
}
|
||||||
stop = true;
|
parseToIssues(res, this.issueList);
|
||||||
return;
|
})
|
||||||
}
|
.catch(() => {
|
||||||
parseToIssues(res, this.issueList);
|
stop = true;
|
||||||
}).catch(() => {
|
vscode.window.showErrorMessage("Can't fetch issues; HTTP Error!");
|
||||||
stop = true; vscode.window.showErrorMessage("Can't fetch issues; HTTP Error!");
|
return;
|
||||||
return;
|
});
|
||||||
});
|
if (stop) {
|
||||||
if (stop) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getChildren(element?: Issue): vscode.ProviderResult<any[]> {
|
|
||||||
return getChildren(element, this.issueList);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
getChildren(element?: Issue): vscode.ProviderResult<any[]> {
|
||||||
|
return getChildren(element, this.issueList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getChildren(element: Issue | undefined, issueList: Issue[]) {
|
export function getChildren(element: Issue | undefined, issueList: Issue[]) {
|
||||||
for (const issue of issueList) {
|
for (const issue of issueList) {
|
||||||
if (element === issue) {
|
if (element === issue) {
|
||||||
let childItems: vscode.TreeItem[] = [
|
let childItems: vscode.TreeItem[] = [
|
||||||
new vscode.TreeItem("Assignee - " + element.assignee, vscode.TreeItemCollapsibleState.None),
|
new vscode.TreeItem('Assignee - ' + element.assignee, vscode.TreeItemCollapsibleState.None),
|
||||||
new vscode.TreeItem("State - " + element.issueState, vscode.TreeItemCollapsibleState.None),
|
new vscode.TreeItem('State - ' + element.issueState, vscode.TreeItemCollapsibleState.None),
|
||||||
new vscode.TreeItem("ID - " + element.issueId, vscode.TreeItemCollapsibleState.None),
|
new vscode.TreeItem('ID - ' + element.issueId, vscode.TreeItemCollapsibleState.None),
|
||||||
new vscode.TreeItem("From - " + element.creator, vscode.TreeItemCollapsibleState.None)
|
new vscode.TreeItem('From - ' + element.creator, vscode.TreeItemCollapsibleState.None),
|
||||||
];
|
];
|
||||||
return Promise.resolve(childItems);
|
return Promise.resolve(childItems);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return issueList;
|
}
|
||||||
|
return issueList;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseToIssues(res: any, issueList: any[], collapsibleState: vscode.TreeItemCollapsibleState = vscode.TreeItemCollapsibleState.Collapsed) {
|
export function parseToIssues(res: any, issueList: Issue[], collapsibleState: vscode.TreeItemCollapsibleState = vscode.TreeItemCollapsibleState.Collapsed) {
|
||||||
for (const issue of res.data) {
|
for (const issue of res.data) {
|
||||||
const id = issue["number"];
|
const id = issue['number'];
|
||||||
let isAlreadyInList = false;
|
let isAlreadyInList = false;
|
||||||
issueList.forEach((issueOfList) => {
|
issueList.forEach((issueOfList) => {
|
||||||
if (id === issueOfList.issueId) {
|
if (id === issueOfList.issueId) {
|
||||||
isAlreadyInList = true;
|
isAlreadyInList = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (isAlreadyInList) {
|
if (isAlreadyInList) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
const title = issue["title"];
|
|
||||||
const body = marked(issue["body"]);
|
|
||||||
const state = issue["state"];
|
|
||||||
const assignee = issue["assignee"] === null ? "None" : issue["assignee"]["username"];
|
|
||||||
const labels = issue["labels"];
|
|
||||||
const creator = issue["user"]["username"];
|
|
||||||
const tmpIssue = new Issue("#" + id + " - " + title, id, body, state, assignee, creator, labels, collapsibleState);
|
|
||||||
const issueForList = new Issue(tmpIssue.label, tmpIssue.issueId, tmpIssue.body, tmpIssue.issueState,
|
|
||||||
tmpIssue.assignee, tmpIssue.creator, tmpIssue.labels, tmpIssue.collapsibleState, {
|
|
||||||
command: 'giteaIssues.openIssue',
|
|
||||||
title: '',
|
|
||||||
arguments: [tmpIssue],
|
|
||||||
});
|
|
||||||
issueList.push(issueForList);
|
|
||||||
}
|
}
|
||||||
|
const title = issue['title'];
|
||||||
|
const body = marked(issue['body']);
|
||||||
|
const state = issue['state'];
|
||||||
|
const assignee = issue['assignee'] === null ? 'None' : issue['assignee']['username'];
|
||||||
|
const labels = issue['labels'];
|
||||||
|
const creator = issue['user']['username'];
|
||||||
|
const tmpIssue = new Issue('#' + id + ' - ' + title, id, body, state, assignee, creator, labels, collapsibleState);
|
||||||
|
const issueForList = new Issue(
|
||||||
|
tmpIssue.label,
|
||||||
|
tmpIssue.issueId,
|
||||||
|
tmpIssue.body,
|
||||||
|
tmpIssue.issueState,
|
||||||
|
tmpIssue.assignee,
|
||||||
|
tmpIssue.creator,
|
||||||
|
tmpIssue.labels,
|
||||||
|
tmpIssue.collapsibleState,
|
||||||
|
{
|
||||||
|
command: 'giteaIssues.openIssue',
|
||||||
|
title: '',
|
||||||
|
arguments: [tmpIssue],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
issueList.push(issueForList);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user