Compare commits
	
		
			3 Commits
		
	
	
		
			master
			...
			spencer/el
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					7e82930282 | ||
| 
						 | 
					3a6d3bb8c2 | ||
| 
						 | 
					7ddca00871 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -4,6 +4,7 @@
 | 
			
		||||
/dist
 | 
			
		||||
/tmp
 | 
			
		||||
/out-tsc
 | 
			
		||||
/out
 | 
			
		||||
# Only exists if Bazel was run
 | 
			
		||||
/bazel-out
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7860
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7860
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										57
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								package.json
									
									
									
									
									
								
							@ -1,6 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "cic-staff-client",
 | 
			
		||||
  "version": "0.0.0",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "author": "Spencer Ofwiti <maxspencer56@gmail.com>",
 | 
			
		||||
  "description": "A fully featured admin client for managing users and transactions in the CIC network.",
 | 
			
		||||
  "main": "dist/main.js",
 | 
			
		||||
  "license": "GPL-3.0-or-later",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "config:dev": "ts-node set-env.ts --environment=dev",
 | 
			
		||||
    "config:prod": "ts-node set-env.ts --environment=prod",
 | 
			
		||||
@ -18,7 +22,17 @@
 | 
			
		||||
    "e2e": "ng e2e",
 | 
			
		||||
    "precommit": "npm run format:fix && npm run lint",
 | 
			
		||||
    "postinstall": "node patch-webpack.js",
 | 
			
		||||
    "prepare": "husky install"
 | 
			
		||||
    "prepare": "husky install",
 | 
			
		||||
    "electron": "ng build --base-href ./ && electron .",
 | 
			
		||||
    "electron-tsc": "ng build --base-href ./ && tsc --p src-backend --outDir dist && electron .",
 | 
			
		||||
    "electron:build:dev": "ng build -c dev --base-href ./ && tsc --lib ES2018,DOM  --target ES5 src-backend/main.ts --outDir dist && electron .",
 | 
			
		||||
    "electron:package": "npx electron-forge import && npm run make",
 | 
			
		||||
    "start": "electron-forge start",
 | 
			
		||||
    "package": "electron-forge package",
 | 
			
		||||
    "make": "electron-forge make",
 | 
			
		||||
    "elec:package": "npm run build:dev && electron-packager . CICADA --out out --overwrite --asar --icon=dist/cic-staff-client/icons/manifest-icon-512.ico   --ignore=^e2e$ --ignore=^src$ --ignore=^src-backend$ --ignore=^.editorconfig$ --ignore=^.gitignore$ --ignore=^angular.json$ --ignore=^browserslist$ --ignore=^karma.conf.js$ --ignore=^package-lock.json$ --ignore=^README.md$ --ignore=^tslint --ignore=^tsconfig --all",
 | 
			
		||||
    "clean": "rimraf dist",
 | 
			
		||||
    "prebuild": "npm run clean"
 | 
			
		||||
  },
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
@ -38,6 +52,7 @@
 | 
			
		||||
    "bootstrap": "^4.5.3",
 | 
			
		||||
    "cic-client": "0.1.4",
 | 
			
		||||
    "cic-client-meta": "0.0.7-alpha.6",
 | 
			
		||||
    "electron-squirrel-startup": "^1.0.0",
 | 
			
		||||
    "ethers": "^5.0.31",
 | 
			
		||||
    "http-server": "^0.12.3",
 | 
			
		||||
    "jquery": "^3.5.1",
 | 
			
		||||
@ -53,13 +68,21 @@
 | 
			
		||||
    "@angular-devkit/build-angular": "~0.1002.0",
 | 
			
		||||
    "@angular/cli": "~10.2.0",
 | 
			
		||||
    "@angular/compiler-cli": "~10.2.0",
 | 
			
		||||
    "@electron-forge/cli": "^6.0.0-beta.55",
 | 
			
		||||
    "@electron-forge/maker-deb": "^6.0.0-beta.55",
 | 
			
		||||
    "@electron-forge/maker-rpm": "^6.0.0-beta.55",
 | 
			
		||||
    "@electron-forge/maker-squirrel": "^6.0.0-beta.55",
 | 
			
		||||
    "@electron-forge/maker-zip": "^6.0.0-beta.55",
 | 
			
		||||
    "@types/datatables.net": "^1.10.19",
 | 
			
		||||
    "@types/electron": "^1.6.10",
 | 
			
		||||
    "@types/jasmine": "~3.5.0",
 | 
			
		||||
    "@types/jasminewd2": "~2.0.3",
 | 
			
		||||
    "@types/jquery": "^3.5.4",
 | 
			
		||||
    "@types/node": "^12.20.6",
 | 
			
		||||
    "@types/node": "^15.6.1",
 | 
			
		||||
    "codelyzer": "^6.0.0",
 | 
			
		||||
    "dotenv": "^8.2.0",
 | 
			
		||||
    "electron": "^12.0.9",
 | 
			
		||||
    "electron-packager": "^15.2.0",
 | 
			
		||||
    "husky": "^6.0.0",
 | 
			
		||||
    "jasmine-core": "~3.6.0",
 | 
			
		||||
    "jasmine-spec-reporter": "~5.0.0",
 | 
			
		||||
@ -72,6 +95,7 @@
 | 
			
		||||
    "prettier": "^2.3.0",
 | 
			
		||||
    "pretty-quick": "^3.1.0",
 | 
			
		||||
    "protractor": "~7.0.0",
 | 
			
		||||
    "rimraf": "^3.0.2",
 | 
			
		||||
    "secp256k1": "^4.0.2",
 | 
			
		||||
    "ts-node": "~8.3.0",
 | 
			
		||||
    "tslint": "~6.1.0",
 | 
			
		||||
@ -85,5 +109,32 @@
 | 
			
		||||
    "hooks": {
 | 
			
		||||
      "pre-commit": "pretty-quick --staged & ng lint"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "config": {
 | 
			
		||||
    "forge": {
 | 
			
		||||
      "packagerConfig": {},
 | 
			
		||||
      "makers": [
 | 
			
		||||
        {
 | 
			
		||||
          "name": "@electron-forge/maker-squirrel",
 | 
			
		||||
          "config": {
 | 
			
		||||
            "name": "cic_staff_client"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "name": "@electron-forge/maker-zip",
 | 
			
		||||
          "platforms": [
 | 
			
		||||
            "darwin"
 | 
			
		||||
          ]
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "name": "@electron-forge/maker-deb",
 | 
			
		||||
          "config": {}
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "name": "@electron-forge/maker-rpm",
 | 
			
		||||
          "config": {}
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										139
									
								
								src-backend/main.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src-backend/main.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
			
		||||
import { BrowserWindow, Menu, Tray, app, ipcMain } from 'electron';
 | 
			
		||||
import * as path from 'path';
 | 
			
		||||
import * as url from 'url';
 | 
			
		||||
import * as fs from 'fs';
 | 
			
		||||
 | 
			
		||||
let mainWindow: BrowserWindow;
 | 
			
		||||
 | 
			
		||||
async function createWindow(): Promise<void> {
 | 
			
		||||
  // Create the browser window.
 | 
			
		||||
  mainWindow = new BrowserWindow({
 | 
			
		||||
    fullscreen: false,
 | 
			
		||||
    width: 1000,
 | 
			
		||||
    height: 800,
 | 
			
		||||
    icon: path.join(__dirname, '/cic-staff-client/assets/icons/manifest-icon-512.png'),
 | 
			
		||||
    // Allows IPC and other APIs
 | 
			
		||||
    webPreferences: {
 | 
			
		||||
      nodeIntegration: true,
 | 
			
		||||
      enableRemoteModule: true,
 | 
			
		||||
      nodeIntegrationInWorker: true,
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  // load the dist folder from Angular
 | 
			
		||||
  await mainWindow.loadURL(
 | 
			
		||||
    url.format({
 | 
			
		||||
      pathname: path.join(__dirname, '/cic-staff-client/index.html'),
 | 
			
		||||
      protocol: 'file',
 | 
			
		||||
      slashes: true
 | 
			
		||||
    })
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  // Open the DevTools.
 | 
			
		||||
  // mainWindow.webContents.openDevTools();
 | 
			
		||||
 | 
			
		||||
  mainWindow.on('closed', () => {
 | 
			
		||||
    mainWindow = null;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function openModal(): Promise<void> {
 | 
			
		||||
  const modal = new BrowserWindow({
 | 
			
		||||
    parent: mainWindow,
 | 
			
		||||
    modal: true,
 | 
			
		||||
    show: false,
 | 
			
		||||
  });
 | 
			
		||||
  await modal.loadURL('https://dashboard.sarafu.network/');
 | 
			
		||||
  modal.once('ready-to-show', () => {
 | 
			
		||||
    modal.show();
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isRoot(): boolean {
 | 
			
		||||
  return path.parse(process.cwd()).root === process.cwd();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getImages(): void {
 | 
			
		||||
  const cwd = process.cwd();
 | 
			
		||||
  fs.readdir('.', { withFileTypes: true }, ((err, files) => {
 | 
			
		||||
    if (!err) {
 | 
			
		||||
      const re = /(?:\.([^.]+))?$/;
 | 
			
		||||
      const images = files.filter(file => file.isFile() && ['jpg', 'png'].includes(re.exec(file.name)[1])).map(file => `file://${cwd}/${file.name}`);
 | 
			
		||||
      mainWindow.webContents.send('getImagesResponse', images);
 | 
			
		||||
    }
 | 
			
		||||
  }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getDirectory(): void {
 | 
			
		||||
  fs.readdir('.', { withFileTypes: true }, (err, files) => {
 | 
			
		||||
    if (!err) {
 | 
			
		||||
      const directories = files.filter(file =>  file.isDirectory()).map(file => file.name);
 | 
			
		||||
      if (!isRoot()) {
 | 
			
		||||
        directories.unshift('..');
 | 
			
		||||
      }
 | 
			
		||||
      mainWindow.webContents.send('getDirectoryResponse', directories);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This method will be called when Electron has finished
 | 
			
		||||
// initialization and is ready to create browser windows.
 | 
			
		||||
// Some APIs can only be used after this event occurs.
 | 
			
		||||
app.on('ready', async () => {
 | 
			
		||||
  let tray = null;
 | 
			
		||||
  tray = new Tray(path.join(__dirname, '/cic-staff-client/assets/icons/manifest-icon-512.png'));
 | 
			
		||||
  const contextMenu = Menu.buildFromTemplate([
 | 
			
		||||
    { label: 'Item1', type: 'radio' },
 | 
			
		||||
    { label: 'Item2', type: 'radio' },
 | 
			
		||||
    { label: 'Item3', type: 'radio', checked: true },
 | 
			
		||||
    { label: 'Exit', type: 'normal', click: () => { app.quit(); } },
 | 
			
		||||
  ]);
 | 
			
		||||
  tray.setToolTip('CIC Administration Dashboard.');
 | 
			
		||||
  // Overrides 'right-click' event.
 | 
			
		||||
  tray.setContextMenu(contextMenu);
 | 
			
		||||
  tray.on('click', (event, arg) => {
 | 
			
		||||
    console.log('Systray was left-clicked.', event, arg);
 | 
			
		||||
  });
 | 
			
		||||
  tray.on('double-click', (event, arg) => {
 | 
			
		||||
    console.log('Systray was double-clicked.', event, arg);
 | 
			
		||||
  });
 | 
			
		||||
  await createWindow();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
app.on('activate', async () => {
 | 
			
		||||
  // On macOS it's common to re-create a window in the app when the
 | 
			
		||||
  // dock icon is clicked and there are no other windows open.
 | 
			
		||||
  if (BrowserWindow.getAllWindows().length === 0) {
 | 
			
		||||
    await createWindow();
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Quit when all windows are closed, except on macOS. There, it's common
 | 
			
		||||
// for applications and their menu bar to stay active until the user quits
 | 
			
		||||
// explicitly with Cmd + Q.
 | 
			
		||||
app.on('window-all-closed', () => {
 | 
			
		||||
  if (process.platform !== 'darwin') {
 | 
			
		||||
    app.quit();
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
ipcMain.on('my-custom-signal', (event, arg) => {
 | 
			
		||||
  console.log('Print to the main process terminal (STDOUT) when signal received from renderer process.');
 | 
			
		||||
  console.log(event);
 | 
			
		||||
  console.log(arg);
 | 
			
		||||
  mainWindow.webContents.send('other-custom-signal', 'message from the backend process');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
ipcMain.on('navigateDirectory', (event, arg) => {
 | 
			
		||||
  process.chdir(arg);
 | 
			
		||||
  getImages();
 | 
			
		||||
  getDirectory();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
ipcMain.on('getFiles', (event, arg) => {
 | 
			
		||||
  const files = fs.readdirSync(__dirname);
 | 
			
		||||
  mainWindow.webContents.send('getFilesResponse', files);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
ipcMain.on('openModal', async (event, arg) => {
 | 
			
		||||
  await openModal();
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										9
									
								
								src-backend/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src-backend/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
 | 
			
		||||
{
 | 
			
		||||
  "extends": "../tsconfig.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "outDir": "../dist",
 | 
			
		||||
    "module": "commonjs",
 | 
			
		||||
    "skipLibCheck": true
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/app/_services/electron.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/app/_services/electron.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
import { TestBed } from '@angular/core/testing';
 | 
			
		||||
 | 
			
		||||
import { ElectronService } from './electron.service';
 | 
			
		||||
 | 
			
		||||
describe('ElectronService', () => {
 | 
			
		||||
  let service: ElectronService;
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    TestBed.configureTestingModule({});
 | 
			
		||||
    service = TestBed.inject(ElectronService);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should be created', () => {
 | 
			
		||||
    expect(service).toBeTruthy();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										65
									
								
								src/app/_services/electron.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/app/_services/electron.service.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { IpcRenderer } from 'electron';
 | 
			
		||||
import {BehaviorSubject} from 'rxjs';
 | 
			
		||||
 | 
			
		||||
@Injectable({
 | 
			
		||||
  providedIn: 'root'
 | 
			
		||||
})
 | 
			
		||||
export class ElectronService {
 | 
			
		||||
  private ipc: IpcRenderer;
 | 
			
		||||
  images = new BehaviorSubject<string[]>([]);
 | 
			
		||||
  directory = new BehaviorSubject<string[]>([]);
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    if ((window as any).require) {
 | 
			
		||||
      console.log('Pass');
 | 
			
		||||
      try {
 | 
			
		||||
        console.log('supported');
 | 
			
		||||
        this.ipc = (window as any).require('electron').ipcRenderer;
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        throw error;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      console.warn('Could not load electron ipc');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  testIpc(): void {
 | 
			
		||||
    this.ipc.on('my-custom-signal', (event, arg) => {
 | 
			
		||||
      console.log('Received acknowledged from backend about receipt of our signal.');
 | 
			
		||||
      console.log(event);
 | 
			
		||||
      console.log(arg);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.ipc.on('getImageResponse', (event, images) => {
 | 
			
		||||
      this.images.next(images);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.ipc.on('getDirectoryResponse', (event, directory) => {
 | 
			
		||||
      this.directory.next(directory);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    console.log('Sending message to backend.');
 | 
			
		||||
    this.ipc.send('my-custom-signal', 'hello, are you there?');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  navigateDirectory(path): any {
 | 
			
		||||
    this.ipc.send('navigateDirectory', path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getFiles(): Promise<string[]> {
 | 
			
		||||
    console.log('Starting');
 | 
			
		||||
    return new Promise<string[]>((resolve, reject) => {
 | 
			
		||||
      this.ipc.once('getFilesResponse', (event, arg) => {
 | 
			
		||||
        resolve(arg);
 | 
			
		||||
      });
 | 
			
		||||
      this.ipc.send('getFiles');
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  openModal(): void {
 | 
			
		||||
    console.log('Open a modal.');
 | 
			
		||||
    this.ipc.send('openModal');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/manifest-icon-512.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/icons/manifest-icon-512.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.1 KiB  | 
@ -3,10 +3,11 @@
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="utf-8">
 | 
			
		||||
  <title>CICADA</title>
 | 
			
		||||
  <base href="/">
 | 
			
		||||
  <base href="./">
 | 
			
		||||
  <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
  <meta content="A fully featured admin client for managing users and transactions in the CIC network." name="description"/>
 | 
			
		||||
  <meta content="Spencer Ofwiti" name="author"/>
 | 
			
		||||
  <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
 | 
			
		||||
  <link rel="icon" type="image/x-icon" href="assets/icons/manifest-icon-512.png">
 | 
			
		||||
  <link rel="apple-touch-icon" href="assets/icons/apple-icon-180.png">
 | 
			
		||||
  <meta name="apple-mobile-web-app-capable" content="yes">
 | 
			
		||||
 | 
			
		||||
@ -14,9 +14,11 @@
 | 
			
		||||
    "downlevelIteration": true,
 | 
			
		||||
    "experimentalDecorators": true,
 | 
			
		||||
    "moduleResolution": "node",
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "importHelpers": true,
 | 
			
		||||
    "target": "es2015",
 | 
			
		||||
    "target": "es5",
 | 
			
		||||
    "module": "es2020",
 | 
			
		||||
    "typeRoots": ["node_modules/@types"],
 | 
			
		||||
    "lib": [
 | 
			
		||||
      "es2018",
 | 
			
		||||
      "dom"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user