Skip to content

Commit

Permalink
Merge pull request #600 from nexB/feature/closefile
Browse files Browse the repository at this point in the history
Close file option & cleanup before imports
  • Loading branch information
OmkarPh authored Oct 2, 2023
2 parents a3dd1b5 + f39c86a commit 8688efd
Show file tree
Hide file tree
Showing 14 changed files with 126 additions and 35 deletions.
38 changes: 20 additions & 18 deletions src/constants/IpcConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,35 @@ export interface ErrorInfo {
}

export const OPEN_DIALOG_CHANNEL = {
JSON: 'open-json-file',
SQLITE_PATH_FOR_JSON: 'choose-sqlite-path-for-json-file',
SQLITE: 'open-sqlite-file',
SAVE_SQLITE: 'save-sqlite-file',
}
JSON: "open-json-file",
SQLITE_PATH_FOR_JSON: "choose-sqlite-path-for-json-file",
SQLITE: "open-sqlite-file",
SAVE_SQLITE: "save-sqlite-file",
};

export const IMPORT_REPLY_CHANNEL = {
JSON: 'import-json-reply',
SQLITE: 'import-sqlite-reply',
}
JSON: "import-json-reply",
SQLITE: "import-sqlite-reply",
};

export const SAVE_REPLY_CHANNEL = {
SQLITE: 'save-sqlite-reply',
}
SQLITE: "save-sqlite-reply",
};

export const UTIL_CHANNEL = {
SET_CURRENT_FILE_TITLE: 'set-current-file-title',
}
SET_CURRENT_FILE_TITLE: "set-current-file-title",
RESET_FILE_TITLE: "reset-current-file-title",
CLOSE_FILE: "close-file",
};

export const NAVIGATION_CHANNEL = 'NAVIGATE_TO';
export const NAVIGATION_CHANNEL = "NAVIGATE_TO";
export type NAVIGATION_CHANNEL_MESSAGE = string;

export const GENERAL_ACTIONS = {
ZOOM_IN: 'zoom_in',
ZOOM_OUT: 'zoom_out',
ZOOM_RESET: 'zoom_reset',
}
ZOOM_IN: "zoom_in",
ZOOM_OUT: "zoom_out",
ZOOM_RESET: "zoom_reset",
};

export interface SQLITE_PATH_FOR_JSON_REQUEST_FORMAT {
jsonFilePath: string;
Expand All @@ -45,4 +47,4 @@ export interface SQLITE_IMPORT_REPLY_FORMAT {
}
export interface SQLITE_SAVE_REPLY_FORMAT {
sqliteFilePath: string;
}
}
2 changes: 2 additions & 0 deletions src/constants/general.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import packageJson from "../../package.json";

export const WORKBENCH_TITLE = "Scancode workbench";

export const WORKBENCH_VERSION = packageJson.version;
18 changes: 18 additions & 0 deletions src/contexts/dbContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface WorkbenchContextProperties extends BasicValueState {
processingQuery: boolean;
startImport: () => void;
abortImport: () => void;
closeFile: () => void;
startProcessing: () => void;
endProcessing: () => void;
sqliteParser: (sqliteFilePath: string, preventNavigation?: boolean) => void;
Expand Down Expand Up @@ -71,6 +72,7 @@ export const defaultWorkbenchContextValue: WorkbenchContextProperties = {
updateLoadingStatus: () => null,
startImport: () => null,
abortImport: () => null,
closeFile: () => null,
startProcessing: () => null,
endProcessing: () => null,
updateCurrentPath: () => null,
Expand Down Expand Up @@ -113,6 +115,7 @@ export const WorkbenchDBProvider = (

const startImport = () => {
updateLoadingStatus(0);
setProcessingQuery(false);
setValue({
db: null,
initialized: false,
Expand All @@ -123,6 +126,19 @@ export const WorkbenchDBProvider = (

const abortImport = () => updateLoadingStatus(null);

const closeFile = () => {
updateLoadingStatus(null);
setProcessingQuery(false);
setValue({
db: null,
initialized: false,
importedSqliteFilePath: null,
scanInfo: null,
});
navigate(ROUTES.HOME);
ipcRenderer.send(UTIL_CHANNEL.RESET_FILE_TITLE);
};

const updateWorkbenchDB = async (db: WorkbenchDB, sqliteFilePath: string) => {
updateLoadingStatus(100);
setValue({
Expand Down Expand Up @@ -440,6 +456,7 @@ export const WorkbenchDBProvider = (
}
}
);
ipcRenderer.on(UTIL_CHANNEL.CLOSE_FILE, closeFile);

// Remove all listeners on window unmount
return () => {
Expand All @@ -461,6 +478,7 @@ export const WorkbenchDBProvider = (
importJsonFile,
startImport,
abortImport,
closeFile,
startProcessing: () => setProcessingQuery(true),
endProcessing: () => setProcessingQuery(false),
updateCurrentPath,
Expand Down
3 changes: 2 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {

import getTemplate from "./mainMenu";
import { setUpGlobalIpcListeners, setUpWindowListeners } from "./mainActions";
import { WORKBENCH_TITLE } from "./constants/general";

// This allows TypeScript to pick up the magic constant that's auto-generated by Forge's Webpack
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
Expand Down Expand Up @@ -50,7 +51,7 @@ export const createWindow = (): void => {

// Create the browser window.
const mainWindow = new BrowserWindow({
title: "Scancode workbench",
title: WORKBENCH_TITLE,
width: 1200,
height: 800,
x,
Expand Down
10 changes: 9 additions & 1 deletion src/mainActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
UTIL_CHANNEL,
} from "./constants/IpcConnection";
import { figureOutDefaultSqliteFilePath } from "./utils/paths";
import { WORKBENCH_TITLE } from "./constants/general";

export function chooseSqlitePathForJsonImport(
mainWindow: BrowserWindow,
Expand Down Expand Up @@ -113,6 +114,10 @@ export function saveSqliteFile(mainWindow: BrowserWindow) {
});
}

export function closeFile(mainWindow: BrowserWindow) {
mainWindow.webContents.send(UTIL_CHANNEL.CLOSE_FILE);
}

export function showErrorDialog(err: ErrorInfo) {
console.log("Showing error to user:", err);
dialog.showErrorBox(err.title, err.message);
Expand All @@ -123,7 +128,7 @@ export function setCurrentFileTitle(mainWindow: BrowserWindow, title: string) {
console.log("Main window not found:", title, mainWindow);
return;
}
const titleString = "Scancode Workbench" + (title ? ` - ${title}` : "");
const titleString = WORKBENCH_TITLE + (title ? ` - ${title}` : "");
mainWindow.setTitle(titleString);
}

Expand All @@ -148,6 +153,9 @@ export function setUpGlobalIpcListeners() {
ipcMain.on(UTIL_CHANNEL.SET_CURRENT_FILE_TITLE, (e, title: string) =>
setCurrentFileTitle(getSenderWindow(e), title)
);
ipcMain.on(UTIL_CHANNEL.RESET_FILE_TITLE, (e) =>
setCurrentFileTitle(getSenderWindow(e), "")
);
ipcMain.on(OPEN_ERROR_DIALOG_CHANNEL, (_, err: ErrorInfo) =>
showErrorDialog(err)
);
Expand Down
13 changes: 12 additions & 1 deletion src/mainMenu.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { GENERAL_ACTIONS, NAVIGATION_CHANNEL } from "./constants/IpcConnection";
import { app, BrowserWindow, MenuItem, shell } from "electron";
import { importJsonFile, openSqliteFile, saveSqliteFile } from "./mainActions";
import {
closeFile,
importJsonFile,
openSqliteFile,
saveSqliteFile,
} from "./mainActions";
import { ROUTES } from "./constants/routes";
import { createWindow } from "./main";
import { WORKBENCH_VERSION } from "./constants/general";
Expand Down Expand Up @@ -46,6 +51,12 @@ function getTemplate() {
click: (_: MenuItem, currentWindow: BrowserWindow) =>
importJsonFile(currentWindow),
},
{
label: "Close File",
// accelerator: "CmdOrCtrl+",
click: (_: MenuItem, currentWindow: BrowserWindow) =>
closeFile(currentWindow),
},
// @TODO-discuss This is duplicated in App's menu tab, is it necessary under file tab also ??
// ...(
// isMac ? [
Expand Down
21 changes: 20 additions & 1 deletion src/pages/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import electron from "electron";
import * as electronFs from "fs";
import { toast } from "react-toastify";
import React, { useMemo, useState } from "react";
import { Button } from "react-bootstrap";
import {
faClose,
faCogs,
faDatabase,
faFileCode,
Expand Down Expand Up @@ -32,9 +34,11 @@ const Home = () => {
db,
loadingStatus,
initialized,
scanInfo,
importedSqliteFilePath,
jsonParser,
sqliteParser,
importedSqliteFilePath,
closeFile,
} = useWorkbenchDB();

const [historyRefreshToken, setRefreshToken] = useState(0);
Expand Down Expand Up @@ -114,6 +118,21 @@ const Home = () => {
OR Simply drop your json / sqlite file anywhere in the app !!
</h5>
</div>
{db && initialized && (
<div className="currentscan">
<h5>
Imported scan - {scanInfo.json_file_name}
<Button
variant="outline-danger"
className="mx-2"
size="sm"
onClick={closeFile}
>
<FontAwesomeIcon icon={faClose} /> Close
</Button>
</h5>
</div>
)}
<div className="history">
<br />
<h5>Recent files</h5>
Expand Down
13 changes: 11 additions & 2 deletions src/pages/Home/home.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,25 @@
.drop-instruction {
text-align: center;
width: 100%;
margin-top: 50px;
margin-top: 25px;
color: var(--lightTextColor);
}

.quicklinks,
.currentscan,
.history {
margin-top: 15px;
padding-left: 2rem;
}

.currentscan {
margin-top: 35px;
margin-bottom: 5px;
}

.quicklinks {
margin-top: 10px;
}

.history table {
min-width: 80%;
max-width: 95%;
Expand Down
2 changes: 2 additions & 0 deletions src/pages/ScanInfo/ScanInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const ScanInfo = () => {
{scanInfo ? (
<table border={1} className="overview-table">
<tbody>
<InfoEntry name="Scan">{scanInfo.json_file_name}</InfoEntry>

<InfoEntry name="Tool">{scanInfo.tool_name}</InfoEntry>

<InfoEntry name="Tool version">{scanInfo.tool_version}</InfoEntry>
Expand Down
1 change: 1 addition & 0 deletions src/services/importedJsonTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { JSON_Type } from "./models/databaseUtils";

export interface ParsedJsonHeader {
json_file_name: string;
tool_name: string;
tool_version: string;
notice: string;
Expand Down
2 changes: 2 additions & 0 deletions src/services/models/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { JSON_Type, jsonDataType } from "./databaseUtils";

export interface HeaderAttributes {
id: number;
json_file_name: string;
tool_name: string;
tool_version: string;
notice: string;
Expand Down Expand Up @@ -52,6 +53,7 @@ export default function headerModel(sequelize: Sequelize) {
primaryKey: true,
type: DataTypes.INTEGER,
},
json_file_name: DataTypes.STRING,
tool_name: DataTypes.STRING,
tool_version: DataTypes.STRING,
notice: DataTypes.STRING,
Expand Down
33 changes: 22 additions & 11 deletions src/services/workbenchDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const { version: workbenchVersion } = packageJson;
*
* The config will load an existing database or will create a new, empty
* database if none exists. For a new database, the data is loaded from a JSON
* file by calling addFromJson(jsonFileName).
* file by calling addFromJson(jsonFilePath).
*
* @param config
* @param config.dbName
Expand Down Expand Up @@ -271,16 +271,16 @@ export class WorkbenchDB {

// Add rows to the flattened files table from a ScanCode json object
addFromJson(
jsonFileName: string,
jsonFilePath: string,
onProgressUpdate: (progress: number) => void
): Promise<void> {
if (!jsonFileName) {
throw new Error("Invalid json file name: " + jsonFileName);
if (!jsonFilePath) {
throw new Error("Invalid json file name: " + jsonFilePath);
}

// console.log("Adding from json with params", { jsonFileName, workbenchVersion, onProgressUpdate });
// console.log("Adding from json with params", { jsonFilePath, workbenchVersion, onProgressUpdate });

const stream = fs.createReadStream(jsonFileName, { encoding: "utf8" });
const stream = fs.createReadStream(jsonFilePath, { encoding: "utf8" });
let files_count = 0;
let dirs_count = 0;
let index = 0;
Expand All @@ -303,7 +303,7 @@ export class WorkbenchDB {
let batchCount = 0;
let TopLevelData: TopLevelDataFormat = {
header: null,
parsedHeader: this._parseHeader(workbenchVersion, {}),
parsedHeader: this._parseHeader(jsonFilePath, workbenchVersion, {}),
packages: [],
dependencies: [],
license_clues: [],
Expand All @@ -318,7 +318,10 @@ export class WorkbenchDB {
stream
.pipe(JSONStream.parse("files.*")) // files field is piped to 'data' & rest to 'header' (Includes other top level fields)
.on("header", (rawTopLevelData: any) => {
TopLevelData = this._parseTopLevelFields(rawTopLevelData);
TopLevelData = this._parseTopLevelFields(
jsonFilePath,
rawTopLevelData
);

files_count = Number(TopLevelData.parsedHeader.files_count);
promiseChain = promiseChain
Expand Down Expand Up @@ -443,11 +446,18 @@ export class WorkbenchDB {
}

// Helper function for parsing Toplevel data
_parseTopLevelFields(rawTopLevelData: any): TopLevelDataFormat {
_parseTopLevelFields(
jsonFilePath: string,
rawTopLevelData: any
): TopLevelDataFormat {
const header = rawTopLevelData.headers
? rawTopLevelData.headers[0] || {}
: {};
const parsedHeader = this._parseHeader(workbenchVersion, header);
const parsedHeader = this._parseHeader(
jsonFilePath,
workbenchVersion,
header
);
const packages = rawTopLevelData.packages || [];
const dependencies = rawTopLevelData.dependencies || [];
const license_detections: TopLevelLicenseDetection[] = (
Expand Down Expand Up @@ -493,10 +503,11 @@ export class WorkbenchDB {
};
}

_parseHeader(workbenchVersion: string, header: any) {
_parseHeader(jsonFilePath: string, workbenchVersion: string, header: any) {
const input = header.options?.input || [];
delete header.options?.input;
const parsedHeader: ParsedJsonHeader = {
json_file_name: path.basename(jsonFilePath),
tool_name: header.tool_name,
tool_version: header.tool_version,
notice: header.notice,
Expand Down
Loading

0 comments on commit 8688efd

Please sign in to comment.