Skip to content

Commit

Permalink
feat: add electron based desktop application (#428)
Browse files Browse the repository at this point in the history
  • Loading branch information
LinuxSuRen authored May 15, 2024
1 parent ea033d9 commit f7fdbac
Show file tree
Hide file tree
Showing 12 changed files with 6,952 additions and 1 deletion.
26 changes: 25 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
# run: cd operator && make docker-build

BuildEmbedUI:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- uses: ./tools/github-actions/setup-deps
Expand All @@ -123,3 +123,27 @@ jobs:
sudo atest service restart
- name: Test
run: make test-ui

BuildDesktop:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- uses: ./tools/github-actions/setup-deps
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18.x
# for fixing Error: Cannot find module 'appdmg'
- name: Install Python 3.11.4
uses: actions/setup-python@v4
with:
python-version: '3.11.4'
- name: Build Desktop
run: |
cd console/atest-desktop
npm i
npm run package
npm run make
41 changes: 41 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,47 @@ jobs:
fi
make helm-pkg helm-push
BuildDesktop:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- uses: ./tools/github-actions/setup-deps
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18.x
# for fixing Error: Cannot find module 'appdmg'
- name: Install Python 3.11.4
uses: actions/setup-python@v4
with:
python-version: '3.11.4'
- name: Build Desktop
run: |
cd console/atest-desktop
npm i
npm run package
npm run make
tree out/make
- name: Upload to Draft
env:
GITHUB_TOKEN: ${{ secrets.GH_PUBLISH_SECRETS }}
if: github.ref == 'refs/heads/master'
run: |
export TAG=$(gh release list -L 1 | awk '{print $4}')
jq '.version = env.TAG' package.json > package.json.new && mv package.json.new package.json
npm run publish
- name: Upload
env:
GITHUB_TOKEN: ${{ secrets.GH_PUBLISH_SECRETS }}
if: github.ref != 'refs/heads/master'
run: |
export TAG=$(git describe --tags --abbrev=0)
jq '.version = env.TAG' package.json > package.json.new && mv package.json.new package.json
npm run publish
# image-operator:
# runs-on: ubuntu-20.04
# steps:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ helm/*.tgz
helm/api-testing/*.tgz
oryxBuildBinary
/helm/api-testing/charts/
console/atest-desktop/out
console/atest-desktop/node_modules
31 changes: 31 additions & 0 deletions console/atest-desktop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
```shell
npx electron-forge import
```

```shell
npm config set registry https://registry.npmmirror.com
```

## Package

```shell
npm run package -- --platform=darwin
npm run package -- --platform=win32
npm run package -- --platform=linux
```

## For Linux

You need to install tools if you want to package Windows on Linux:
```shell
apt install wine64 zip -y
```

## Publish

export GITHUB_TOKEN=your-token

```shell
npm run publish -- --platform=darwin
npm run publish -- --platform=linux
```
16 changes: 16 additions & 0 deletions console/atest-desktop/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
exports.control = function(okCallback, errorCallback) {
fetch('http://localhost:' + getPort() + '/healthz').
then(okCallback).catch(errorCallback)
}

function getPort() {
// TODO support set this value
return 7788
}

function getHomePage() {
return 'http://localhost:' + getPort()
}

exports.getPort = getPort
exports.getHomePage = getHomePage
68 changes: 68 additions & 0 deletions console/atest-desktop/forge.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const { FusesPlugin } = require('@electron-forge/plugin-fuses');
const { FuseV1Options, FuseVersion } = require('@electron/fuses');

module.exports = {
packagerConfig: {
asar: true,
},
rebuildConfig: {},
makers: [
{
name: '@electron-forge/maker-squirrel',
config: {},
},
{
name: '@electron-forge/maker-zip',
},
{
name: '@electron-forge/maker-deb',
config: {},
},
{
name: '@electron-forge/maker-rpm',
config: {},
},
{
name: '@electron-forge/maker-dmg',
config: {
format: 'ULFO'
}
},
{
name: '@electron-forge/maker-wix',
config: {
language: 1033,
manufacturer: 'API Testing Authors'
},
}
],
plugins: [
{
name: '@electron-forge/plugin-auto-unpack-natives',
config: {},
},
// Fuses are used to enable/disable various Electron functionality
// at package time, before code signing the application
new FusesPlugin({
version: FuseVersion.V1,
[FuseV1Options.RunAsNode]: false,
[FuseV1Options.EnableCookieEncryption]: true,
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
[FuseV1Options.EnableNodeCliInspectArguments]: false,
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
[FuseV1Options.OnlyLoadAppFromAsar]: true,
}),
],
publishers: [
{
name: '@electron-forge/publisher-github',
config: {
repository: {
owner: 'linuxsuren',
name: 'api-testing'
},
prerelease: true
}
}
]
};
42 changes: 42 additions & 0 deletions console/atest-desktop/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src * self blob: data: gap:; style-src * self 'unsafe-inline' blob: data: gap:; script-src * 'self' 'unsafe-eval' 'unsafe-inline' blob: data: gap:; object-src * 'self' blob: data: gap:; img-src * self 'unsafe-inline' blob: data: gap:; connect-src self * 'unsafe-inline' blob: data: gap:; frame-src * self blob: data: gap:;">
<title>API Testing</title>
</head>
<body>

<button type="button" id="action">Start</button>
<div>
Log output
</div>
<button type="button" id="open-server-page">Open Server Page</button>

<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
<script>
const actionBut = document.getElementById('action');
actionBut.addEventListener('click', (e) => {
const action = actionBut.innerHTML;
switch (action) {
case 'Stop':
stop();
actionBut.innerHTML = 'Start';
break;
case 'Start':
start();
actionBut.innerHTML= 'Stop';
break;
}
})

const openServerBut = document.getElementById('open-server-page');
openServerBut.addEventListener('click', (e) => {
window.location = 'http://localhost:8080'
})
</script>
</body>
</html>
105 changes: 105 additions & 0 deletions console/atest-desktop/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// main.js

// Modules to control application life and create native browser window
const { app, BrowserWindow, Menu, MenuItem } = require('electron')
const path = require('node:path')
const server = require('./api')
const spawn = require("child_process").spawn;

const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1000,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
}
})

server.control(() => {
mainWindow.loadURL(server.getHomePage())
}, () => {
// and load the index.html of the app.
mainWindow.loadFile('index.html')
})
}

const menu = new Menu()
menu.append(new MenuItem({
label: 'Window',
submenu: [{
label: 'Console',
accelerator: process.platform === 'darwin' ? 'Alt+Cmd+C' : 'Alt+Shift+C',
click: () => {
BrowserWindow.getFocusedWindow().loadFile('index.html');
}
}, {
label: 'Server',
accelerator: process.platform === 'darwin' ? 'Alt+Cmd+S' : 'Alt+Shift+S',
click: () => {
BrowserWindow.getFocusedWindow().loadURL(server.getHomePage());
}
}, {
label: 'Reload',
accelerator: process.platform === 'darwin' ? 'Cmd+R' : 'F5',
click: () => {
BrowserWindow.getFocusedWindow().reload()
}
}, {
label: 'Developer Mode',
accelerator: process.platform === 'darwin' ? 'Alt+Cmd+D' : 'F12',
click: () => {
BrowserWindow.getFocusedWindow().webContents.openDevTools();
}
}, {
label: 'Quit',
accelerator: process.platform === 'darwin' ? 'Cmd+Q' : 'Alt+Shift+Q',
click: () => {
app.quit()
}
}]
}))

Menu.setApplicationMenu(menu)

let serverProcess;
// 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.whenReady().then(() => {
// const homedir = require('os').homedir();

serverProcess = spawn("atest", [
"server",
"--http-port", server.getPort(),
// TODO below setting is not working
// "--local-storage", path.join(homedir, ".atest", "data", "*.yaml")
]);

createWindow()

app.on('activate', () => {
// 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) 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()

if (serverProcess) {
serverProcess.kill();
}
}
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
Loading

0 comments on commit f7fdbac

Please sign in to comment.