1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

reworks -- part 1

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2020-11-20 14:43:11 +02:00
parent f505dab282
commit 78dcd5d18d
3 changed files with 84 additions and 43 deletions

View File

@ -97,6 +97,11 @@ export class ExtensionManager {
} }
} }
getNpmPackageTarballUrl(packageName: string) {
const command = [this.npmPath, "view", packageName, "dist.tarball", "--silent"];
return child_process.execSync(command.join(" "), { encoding: "utf8" });
}
protected installPackages(): Promise<void> { protected installPackages(): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const child = child_process.fork(this.npmPath, ["install", "--silent", "--no-audit", "--only=prod", "--prefer-offline", "--no-package-lock"], { const child = child_process.fork(this.npmPath, ["install", "--silent", "--no-audit", "--only=prod", "--prefer-offline", "--no-package-lock"], {

View File

@ -24,8 +24,12 @@
} }
.install-extension { .install-extension {
.Clipboard:hover code { .Clipboard {
color: $textColorSecondary; font-size: $font-size-small;
&:hover {
color: $textColorSecondary;
}
} }
} }
} }

View File

@ -1,5 +1,7 @@
import "./extensions.scss"; import "./extensions.scss";
import { remote, shell } from "electron"; import { remote, shell } from "electron";
import path from "path";
import fse from "fs-extra";
import React from "react"; import React from "react";
import { computed, observable } from "mobx"; import { computed, observable } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
@ -13,10 +15,12 @@ import { PageLayout } from "../layout/page-layout";
import { Clipboard } from "../clipboard"; import { Clipboard } from "../clipboard";
import { extensionLoader } from "../../../extensions/extension-loader"; import { extensionLoader } from "../../../extensions/extension-loader";
import { extensionManager } from "../../../extensions/extension-manager"; import { extensionManager } from "../../../extensions/extension-manager";
import { Notifications } from "../notifications";
import request from "request";
import logger from "../../../main/logger";
@observer @observer
export class Extensions extends React.Component { export class Extensions extends React.Component {
@observable.ref input: Input;
@observable search = ""; @observable search = "";
@observable downloadUrl = ""; @observable downloadUrl = "";
@ -41,34 +45,75 @@ export class Extensions extends React.Component {
const { canceled, filePaths } = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), { const { canceled, filePaths } = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), {
defaultPath: app.getPath("downloads"), defaultPath: app.getPath("downloads"),
properties: ["openFile", "multiSelections"], properties: ["openFile", "multiSelections"],
message: _i18n._(t`Select extensions to install (supported: ${supportedFormats.join(", ")}), `), message: _i18n._(t`Select extensions to install (supported formats: ${supportedFormats.join(", ")}), `),
buttonLabel: _i18n._(t`Use configuration`), buttonLabel: _i18n._(t`Use configuration`),
filters: [ filters: [
{ name: "tarball", extensions: supportedFormats } { name: "tarball", extensions: supportedFormats }
] ]
}); });
if (!canceled && filePaths.length) { if (!canceled && filePaths.length) {
this.installFromLocalPath(filePaths); this.installFromSelectFileDialog(filePaths);
} }
} }
// todo // fixme: doesn't work
installFromUrl = () => { // todo: move to common/utils
if (!this.downloadUrl) { async downloadFile(url: string, fileName = path.basename(url)): Promise<File> {
this.input?.focus(); return new Promise((resolve, reject) => {
const downloadingReq = request(url, { gzip: true });
downloadingReq.on("complete", (res, body: Buffer) => {
resolve(new File([body], fileName));
});
downloadingReq.on("error", reject);
})
}
installFromUrl = async () => {
const { downloadUrl } = this;
if (!downloadUrl) {
return; return;
} }
console.log('Install from URL', this.downloadUrl); let tarballUrl: string;
if (InputValidators.isUrl.validate(downloadUrl)) {
tarballUrl = downloadUrl;
} else {
try {
tarballUrl = extensionManager.getNpmPackageTarballUrl(downloadUrl);
} catch (err) {
Notifications.error(`Error: npm package "${downloadUrl}" not found`);
return;
}
}
logger.info('Install from packed extension URL', { tarballUrl });
if (tarballUrl) {
try {
const file = await this.downloadFile(tarballUrl);
this.installExtensionFromFile([file]);
} catch (err) {
Notifications.error(`Installing extension from ${tarballUrl} has failed: ${String(err)}`);
}
}
} }
// todo installFromSelectFileDialog = async (filePaths: string[]) => {
installFromLocalPath = (filePaths: string[]) => { logger.info('Install from select dialog', { filePaths });
console.log('Install select from dialog', filePaths) const files: File[] = await Promise.all(
filePaths.map(filePath => {
const fileName = path.basename(filePath);
return fse.readFile(filePath).then(buffer => new File([buffer], fileName));
})
);
return this.installExtensionFromFile(files);
} }
// todo
installOnDrop = (files: File[]) => { installOnDrop = (files: File[]) => {
console.log('Install from D&D', files); logger.info('Install from D&D', { files });
return this.installExtensionFromFile(files);
}
// todo
async installExtensionFromFile(files: File[]) {
console.log(`Install files:`, files);
} }
renderInfo() { renderInfo() {
@ -80,31 +125,29 @@ export class Extensions extends React.Component {
features of Lens are built as extensions and use the same Extension API. features of Lens are built as extensions and use the same Extension API.
</div> </div>
<div> <div>
<p><em>All custom extensions located in:</em></p> <p><em>Extensions loaded from:</em></p>
<div className="extensions-path flex inline" onClick={() => shell.openPath(this.extensionsPath)}> <div className="extensions-path flex inline" onClick={() => shell.openPath(this.extensionsPath)}>
<Icon material="folder" tooltip={{ children: "Open folder", preferredPositions: "bottom" }}/> <Icon material="folder" tooltip={{ children: "Open folder", preferredPositions: "bottom" }}/>
<code>{this.extensionsPath}</code> <code>{this.extensionsPath}</code>
</div> </div>
</div> </div>
<div className="install-extension flex column gaps"> <div className="install-extension flex column gaps">
<p><em>Install extensions from local file-system or URL:</em></p> <p><em>Install extensions from archive (tarball.tgz):</em></p>
<div className="install-extension-by-url flex gaps align-center"> <div className="install-extension-by-url flex gaps align-center">
<Icon
material="get_app"
tooltip={{ children: "Download and Install", preferredPositions: "bottom" }}
interactive={this.downloadUrl.length > 0}
onClick={this.installFromUrl}
/>
<Input <Input
showErrorsAsTooltip={true} showErrorsAsTooltip={true}
className="box grow" className="box grow"
theme="round-black" theme="round-black"
placeholder="URL, e.g. https://registry.npmjs.org/%path-to-ext.tgz" placeholder="URL or NPM package name"
validators={InputValidators.isUrl} value={this.downloadUrl}
value={this.downloadUrl} // TODO: in addition we could support npm-package-name (if non-url value)?
onChange={v => this.downloadUrl = v} onChange={v => this.downloadUrl = v}
onSubmit={this.installFromUrl} onSubmit={this.installFromUrl}
ref={e => this.input = e} />
<Icon
material="get_app"
tooltip={{ children: "Install", preferredPositions: "bottom" }}
interactive={this.downloadUrl.length > 0}
onClick={this.installFromUrl}
/> />
</div> </div>
<Button <Button
@ -113,24 +156,13 @@ export class Extensions extends React.Component {
onClick={this.selectLocalExtensionsDialog} onClick={this.selectLocalExtensionsDialog}
/> />
<p className="hint"> <p className="hint">
<Trans><b>Pro-Tip 1</b>: you can download extension archive.tgz via NPM:</Trans> <Trans><b>Pro-Tip 1</b>: you can download NPM-package to local folder with</Trans>
<Clipboard showNotification>
<code>npm pack %package-name</code>
</Clipboard>
</p> </p>
<ul>
<Clipboard showNotification cssSelectorLimit="code">
<li>
<code>npm pack %name</code>
<em> (click to copy)</em>
</li>
</Clipboard>
<Clipboard showNotification cssSelectorLimit="code">
<li>
<code>npm view %name dist.tarball</code>
<em> (click to copy)</em>
</li>
</Clipboard>
</ul>
<p className="hint"> <p className="hint">
<Trans><b>Pro-Tip 2</b>: you also can drop archive from file-system to this window to request installation</Trans> <Trans><b>Pro-Tip 2</b>: you can drag & drop extension's tarball here to request installation</Trans>
</p> </p>
</div> </div>
<div className="more-info flex inline gaps align-center"> <div className="more-info flex inline gaps align-center">