Skip to content

Commit

Permalink
Package detail file browser #31 (#32)
Browse files Browse the repository at this point in the history
* fix console error on loading package list

* Update vuetify from 1.0.19 to 1.3.4

* Make server read package fileList

* PackageDetail.vue: add tree view for fileList

* PackageDetail.vue: beautify file tree icons

* format code

* cli: correct server and ui logs properties

* PackageDetail.vue: file tree: add open animation

* PackageDetail.vue: add video icons

* backend: add file content service

* BackendApi: fix tslint error

* file content service: add version as param

* BackendApi: add new fetFileContent method

* vscode tasks: never scan output

* tasks: format

* Server: add path to file tree

* BackendApi: fix promise type and xhr param

* DataStore: Add getFileContent method and format code

* types/Package: add property `fileList`

* (WIP) PackageDetail.vue: Make code selectable in file tree

* fileLister: cleanup code: fix warnings

* cleanup code: typedef

* format code

* update vuetify to 1.3.5

* Add type TreeItem

* backendApi: fix filepath concat

* DataStore: cache fileContent Promise

* PackageDetail.vue: open code on click and add loadingspinner

* cleanup: remove function

* EventBus: Add timeout error

* improve error handling

* PackageDetail fileContent: add timeout, error handling, find subdirfiles

* remove console.log

* PackageDetail: tree view: fix timeout

* improve error message style

* PackgeDetail tree view: get clicked label correctly

* PackageDetail tree view: encode filepath to send correct request

* packagedetail tree view: try to get smooth transition

* format code

* PackageDetail: improve treeview loading animation

* DataStore: fix promise cache

* DataStore: add fileContentCache

* cleanup code
  • Loading branch information
dmstern authored Nov 3, 2018
1 parent b3c97a4 commit 9eed49f
Show file tree
Hide file tree
Showing 18 changed files with 525 additions and 173 deletions.
17 changes: 16 additions & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "compile:watch",
"problemMatcher": []
},
{
"type": "npm",
"script": "webui",
"problemMatcher": []
},
{
"type": "npm",
"script": "server",
"problemMatcher": []
}
]
}
}
9 changes: 2 additions & 7 deletions bin/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,8 @@ import * as path from 'path';
const pm2Config = require('../pm2.config');
const port = pm2Config.serveUIStatic.env.PM2_SERVE_PORT;
const logFiles = {
ui: path.join(__dirname, '..', pm2Config.runServer.cwd || '', pm2Config.runServer.log),
server: path.join(
__dirname,
'..',
pm2Config.serveUIStatic.cwd || '',
pm2Config.serveUIStatic.log,
),
ui: path.join(__dirname, '..', pm2Config.serveUIStatic.cwd || '', pm2Config.serveUIStatic.log),
server: path.join(__dirname, '..', pm2Config.runServer.cwd || '', pm2Config.runServer.log),
};
const startCommand = 'run prod';
const programm = 'npmfrog';
Expand Down
36 changes: 11 additions & 25 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
}
},
"dependencies": {
"@babel/polyfill": "^7.0.0",
"@fortawesome/fontawesome-free": "^5.3.0",
"@mdi/font": "^2.8.94",
"axios": "^0.18.0",
"body-parser": "^1.18.3",
"cors": "^2.8.4",
Expand All @@ -47,10 +50,7 @@
"vue-router": "^3.0.1",
"vue-simple-svg": "^1.3.1",
"vue-timeago": "^5.0.0",
"vuetify": "^1.0.19",
"@fortawesome/fontawesome-free": "^5.3.0",
"@babel/polyfill": "^7.0.0",
"@mdi/font": "^2.8.94"
"vuetify": "^1.3.5"
},
"devDependencies": {
"@types/body-parser": "^1.17.0",
Expand Down
36 changes: 32 additions & 4 deletions server/artifactory-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as showdown from 'showdown';
import * as emoji from 'node-emoji';
import { PackagesResponse } from '../types/PackageResponse';
import PackageId from '../types/PackageId';
import getFiles from './fileLister';

import config from './config-service.js';
const repoKey = config.artifactory.repoKey;
Expand All @@ -20,6 +21,7 @@ axios.defaults.headers.common.Authorization = config.artifactory.apiKey;
interface AdditionalCode {
readme: string;
mainCode: string | undefined;
fileList;
}

function name2url({ scope, packageName }: PackageId): string {
Expand Down Expand Up @@ -110,14 +112,17 @@ async function getPackageDetail({
resolve({
readme: data,
mainCode: readMainCode(path.join(__dirname, '..', '..')),
fileList: [],
});
})
: await new Promise<AdditionalCode>(async (resolve, reject) => {
const packageDetail = packageDetailResponse.data;
const downloadUrl = packageDetail.versions[currentVersion].dist.tarball;
const storageDir = path.join(tmpDir, scope || '', packageName, currentVersion);
const storageDir = path.join(tmpDir, scope, packageName, currentVersion);
if (fs.existsSync(storageDir)) {
resolve(readAdditionalCode(storageDir));
readAdditionalCode(storageDir).then(response => {
resolve(response);
});
} else {
axios
// Request package:
Expand Down Expand Up @@ -145,7 +150,9 @@ async function getPackageDetail({
return tar.x({ file, cwd }).then(() => cwd);
})
.then(dir => {
resolve(readAdditionalCode(dir));
readAdditionalCode(dir).then(response => {
resolve(response);
});
});
}
});
Expand All @@ -158,9 +165,10 @@ async function getPackageDetail({
});
}

function readAdditionalCode(storageDir: string): AdditionalCode {
async function readAdditionalCode(storageDir: string): Promise<AdditionalCode> {
let readme;
let mainCode;
let fileList;
try {
readme = readme2Html(path.join(storageDir, 'package', 'README.md'));
} catch (error) {
Expand All @@ -171,9 +179,15 @@ function readAdditionalCode(storageDir: string): AdditionalCode {
} catch (error) {
mainCode = undefined;
}
try {
fileList = await getFiles(storageDir, 'package', false);
} catch {
fileList = [];
}
return {
readme,
mainCode,
fileList,
};
}

Expand All @@ -189,9 +203,23 @@ function getDistTags({ scope, packageName }: PackageId): AxiosPromise<any> {
: axios.get(`/-/package/${name2url({ scope, packageName })}/dist-tags`);
}

async function getFileContent(packageId: PackageId, filepath: string): Promise<string> {
const versionResponse = await getDistTags(packageId);
const absPath = path.join(
tmpDir,
packageId.scope,
packageId.packageName,
packageId.version,
'package',
filepath,
);
return fs.readFileSync(absPath).toString();
}

export default {
fetchPackages,
getDistTags,
getPackageDetail,
baseURL: axios.defaults.baseURL,
getFileContent,
};
40 changes: 40 additions & 0 deletions server/fileLister.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { promisify } from 'util';
import { resolve } from 'path';
import * as fs from 'fs';

const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);

function generateId(): string {
return (
'_' +
Math.random()
.toString(36)
.substr(2, 30)
);
}

export default async function getFiles(
basedir: string,
sub: string,
recursive: boolean,
): Promise<any> {
const dir = resolve(basedir, sub);
const subdirs = await readdir(dir);
return await Promise.all(
subdirs.map(async subdir => {
const res = resolve(dir, subdir);
return (await stat(res)).isDirectory()
? {
id: generateId(),
name: subdir,
children: await getFiles(basedir, `${sub}/${subdir}`, true),
}
: {
id: generateId(),
name: subdir,
path: recursive ? sub.substring(sub.indexOf('/') + 1, sub.length) : '',
};
}),
);
}
Loading

0 comments on commit 9eed49f

Please sign in to comment.