Skip to content

Commit

Permalink
Merge branch 'main' into user-testing-1
Browse files Browse the repository at this point in the history
  • Loading branch information
CodyCBakerPhD authored Sep 25, 2023
2 parents e79a7b3 + f86da5d commit 1f85f8e
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 103 deletions.
17 changes: 3 additions & 14 deletions .github/workflows/Build-and-deploy-mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,14 @@ jobs:

- uses: apple-actions/import-codesign-certs@v1
with:
# https://developer.apple.com/account/resources/certificates/add
# Sign up for an Apple Developer account (annual fee)
# Create a new certificate for Mac development at website above (max 1 certificate)
# Create a Certificate Signing Request (CSR) on your Mac --
# see https://developer.apple.com/help/account/create-certificates/create-a-certificate-signing-request
# Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority...
# Enter email address, common name
# Download the new certificate (.cer file)
# Double click the .cer file to install in Keychain Access
# Use Keychain Access to export the certificate as a .p12
# base64 -i cent.p12 -o base64.txt
# Open base64.txt and copy the contents to the nwb-guide repository secret for MACOS_CERTIFICATE
# Currently this is set up to use Ryan's account and certificate
# Currently this is set to Ryan's Developer ID certificate
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }}
p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }}

- name: Build and deploy on MAC
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
appleId: ${{ secrets.APPLE_ID }} # currently this is set to Ryan's Apple ID and password
# Currently this is set to Ryan's Apple ID and app-specific password
appleId: ${{ secrets.APPLE_ID }}
appleIdPassword: ${{ secrets.APPLE_PASSWORD }}
run: npm run deploy:mac
29 changes: 9 additions & 20 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ concurrency: # Cancel previous workflows on the same pull request
cancel-in-progress: true

env:
CACHE_NUMBER: 1 # increase to reset cache manually
CACHE_NUMBER: 2 # increase to reset cache manually

jobs:
testing:
Expand All @@ -24,20 +24,14 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- python-version: "3.9"
os: ubuntu-latest
- os: ubuntu-latest
label: environments/environment-Linux.yml
prefix: /usr/share/miniconda3/envs/env-electron-python

- python-version: "3.10"
os: macos-latest
- os: macos-latest
label: environments/environment-Mac.yml
prefix: /Users/runner/miniconda3/envs/env-electron-python

- python-version: "3.9"
os: windows-latest
- os: windows-latest
label: environments/environment-Windows.yml
prefix: C:\Miniconda3\envs\env-electron-python


steps:
Expand All @@ -50,7 +44,7 @@ jobs:
with:
miniforge-variant: Mambaforge
miniforge-version: latest
activate-environment: env-electron-python
activate-environment: nwb-guide
use-mamba: true

- name: Set cache date
Expand All @@ -62,17 +56,12 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ env.CONDA }}/envs
key:
conda-${{ runner.os }}-${{ runner.arch }}-${{steps.get-date.outputs.today }}-${{ hashFiles(matrix.label) }}-${{ env.CACHE_NUMBER }}
env:
# Increase this value to reset cache if environment file has not changed
CACHE_NUMBER: 0
key: conda-${{ runner.os }}-${{ runner.arch }}-${{steps.get-date.outputs.today }}-${{ hashFiles(matrix.label) }}-${{ env.CACHE_NUMBER }}
id: cache

- name: Update environment
run:
mamba env update -n env-electron-python -f ${{ matrix.label }}
if: steps.cache.outputs.cache-hit != 'true'
- if: steps.cache.outputs.cache-hit != 'true'
name: Create and activate environment
run: mamba env update -n nwb-guide -f ${{ matrix.label }}

- name: Use Node.js 18
uses: actions/setup-node@v3
Expand Down
46 changes: 46 additions & 0 deletions docs/developer_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,49 @@ Pre-Commit
We use an automated pre-commit bot to enforce these on the main repo, but contributions from external forks would either have to grant bot permissions on their own fork (via :pre-commit-bot:`the pre-commit bot website <>`) or run pre-commit manually.

For instructions to install pre-commit, as well as some other minor coding styles we follow, refer to the :neuroconv-coding-style:`NeuroConv style guide <>`.

Code signing on Mac OS
---------------------------

1. Sign up for an Apple Developer account (99 USD annual fee).

2. Follow steps in https://developer.apple.com/help/account/create-certificates/create-developer-id-certificates/
a. Browse current Certificates at https://developer.apple.com/account/resources/certificates/list.
b. Click Certificates in the sidebar. On the top left, click the add button (+).
c. Under Software, select Developer ID Application.
d. Select Profile Type: G2 Sub-CA (Xcode 11.4.1 or later).
e. Create a certificate signing request (CSR) by following the steps in https://developer.apple.com/help/account/create-certificates/create-a-certificate-signing-request
i. Open Keychain Access.
ii. Choose Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.
iii. In the Certificate Assistant dialog, enter an email address in the User Email Address field.
iv. In the Common Name field, enter a name for the key (for example, John Doe Dev Key). Ryan entered "Ryan Ly".
v. Leave the CA Email Address field empty.
vi. Choose “Saved to disk”, and click Continue.
vii. Save the certificate request file to disk.
f. Select the certificate request file (a file with a .certSigningRequest file extension), then click Choose.
g. Click Continue, click Download - The certificate file (.cer file) appears in your Downloads folder.
h. To install the certificate in your keychain, double-click the downloaded certificate file.
i. The certificate appears in the My Certificates category in Keychain Access, but may not be trusted.
j. For local development, download the appropriate Apple Intermediate Certificate.
k. from https://www.apple.com/certificateauthority/ to make certificate trusted/valid.
l. For this, it is Developer ID - G2 (Expiring 09/17/2031 00:00:00 UTC).
m. Double-click the downloaded file.
n. Confirm that the certificate now shows up as trusted in Keychain Access.

3. Provide a p12 file for notarizing via GitHub Action.
a. Open Keychain Access.
b. Select the Developer ID Application certificate.
c. Choose Keychain Access > Export Items...
d. Export the certificate to a file with a password.
e. Get a base64 version of the certificate by running: base64 -i Certificate.p12 -o base64.txt
f. Open base64.txt and copy the contents to the nwb-guide repository secret MACOS_CERTIFICATE.
g. Set the password for the certificate in the nwb-guide repository secret MACOS_CERTIFICATE_PASSWORD.

4. Create an app-specific password for building locally and via the GitHub Action.
a. Go to https://appleid.apple.com/account/manage.
b. Follow the steps to create an App-Specific Password.
c. Use that for local building and in the secrets.APPLE_PASSWORD repository secret.

5. Review and agree to any pending agreements.
a. Go to https://appstoreconnect.apple.com/agreements/#/ and agree to pending agreements for Free Apps.
b. Review and agree to the Apple Developer Program License Agreement, which updates periodically.
16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,20 @@
"mac": {
"asar": true,
"target": [
"dmg",
"zip"
{
"target": "dmg",
"arch": [
"x64",
"arm64"
]
},
{
"target": "zip",
"arch": [
"x64",
"arm64"
]
}
],
"icon": "src/renderer/assets/img/logo-guide-draft.png",
"darkModeSupport": false,
Expand Down
8 changes: 5 additions & 3 deletions prepare_pyinstaller_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
lines[data_line_index] = "datas = [('./paths.config.json', '.'), ('./package.json', '.')]\n"

# Another platform specific difference is the app.py location
app_py_line_index = next(index for index, line in enumerate(lines) if "app.py" in line)
app_py_line = " [f\"{Path('pyflask') / 'app.py'}\"],\n"
lines[app_py_line_index] = app_py_line
app_py_line_index, app_py_line = next((index, line) for index, line in enumerate(lines) if "app.py" in line)
pyflask_start = app_py_line.find("pyflask") # Can change on certain systems
injected_app_py_line_base = app_py_line[: (pyflask_start - 1)]
injected_app_py_line = injected_app_py_line_base + "f\"{Path('pyflask') / 'app.py'}\"],\n"
lines[app_py_line_index] = injected_app_py_line

with open(file=Path(__file__).parent / "nwb-guide.spec", mode="w") as io:
io.writelines(lines)
Expand Down
72 changes: 40 additions & 32 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ const pythonIsClosed = (err = globals.python.latestError) => {
* @returns {boolean} True if the app is packaged, false if it is running from a dev version.
*/
const getPackagedPath = () => {
const scriptPath = isWindows ? path.join(__dirname, PY_FLASK_DIST_FOLDER, PYFLASK_BUILD_SUBFOLDER_NAME, `${PYINSTALLER_NAME}.exe`) : path.join(process.resourcesPath, PYFLASK_BUILD_SUBFOLDER_NAME, PYINSTALLER_NAME)
const scriptPath = isWindows ? path.join(__dirname, PY_FLASK_DIST_FOLDER, PYINSTALLER_NAME, `${PYINSTALLER_NAME}.exe`) : path.join(process.resourcesPath, PYFLASK_BUILD_SUBFOLDER_NAME, PYINSTALLER_NAME)
if (fs.existsSync(scriptPath)) return scriptPath;
};

Expand Down Expand Up @@ -190,7 +190,7 @@ const exitPyProc = async () => {
"/t",
]) // Windows does not properly shut off the python server process. This ensures it is killed.

else pyflaskProcess.kill()
pyflaskProcess.kill() // Try killing twice on Windows

pyflaskProcess = null;
};
Expand Down Expand Up @@ -223,6 +223,8 @@ let hasBeenOpened = false;

function initialize() {

if (globals.mainWindow) return // Do not re-initialize if the main window is already declared

makeSingleInstance();

function createWindow() {
Expand Down Expand Up @@ -254,42 +256,39 @@ function initialize() {
})
.then((responseObject) => {
let { response } = responseObject;
if (response === 0) quit_app()
if (response === 0) app.quit();
else globals.mainWindowReady = true
});
}
} else {
await exitPyProc();
app.exit();
app.quit();
}
});
}

const quit_app = () => {
globals.mainWindow.close();
if (!globals.mainWindow.closed) globals.mainWindow.destroy()
};

function onAppReady () {

const promise = createPyProc();

// Listen after first load
promise.then(() => {
const chokidar = require('chokidar');
chokidar.watch(path.join(__dirname, "../../pyflask"), {
ignored: ['**/__pycache__/**']
}).on('all', async (event: string) => {
if (event === 'change' && !globals.python.restart) {
globals.python.restart = true
await exitPyProc();
setTimeout(async () => {
await createPyProc();
globals.python.restart = false
}, 1000)
}
});
})
// Only create one python process
if (!pyflaskProcess) {
const promise = createPyProc();

// Listen after first load
promise.then(() => {
const chokidar = require('chokidar');
chokidar.watch(path.join(__dirname, "../../pyflask"), {
ignored: ['**/__pycache__/**']
}).on('all', async (event: string) => {
if (event === 'change' && !globals.python.restart) {
globals.python.restart = true
await exitPyProc();
setTimeout(async () => {
await createPyProc();
globals.python.restart = false
}, 1000)
}
});
})
}

const windowOptions = {
minWidth: 1121,
Expand Down Expand Up @@ -394,13 +393,22 @@ app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) initialize()
})

app.on("window-all-closed", async () => {
if (process.platform != 'darwin') {
await exitPyProc();
app.quit();
app.on('will-quit', async () => {
try {
await exitPyProc()
if (globals.mainWindow) {
globals.mainWindow.close();
if (!globals.mainWindow.closed) globals.mainWindow.destroy()
}
} catch (err) {
console.error(err);
}
});

app.on("window-all-closed", async () => {
if (process.platform != 'darwin') app.quit();
});

// app.on("will-quit", () => app.quit());

app.on("open-file", onFileOpened)
Expand Down
21 changes: 3 additions & 18 deletions src/renderer/src/progress/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { merge } from "../stories/pages/utils.js";
import { updateAppProgress, updateFile } from "./update.js";
import { updateURLParams } from "../../utils/url.js";

import * as operations from "./operations";

export * from "./update";

class GlobalAppConfig {
Expand Down Expand Up @@ -122,24 +124,7 @@ export const remove = async (name) => {
focusCancel: true,
});

if (result.isConfirmed) {
//Get the path of the progress file to delete
const progressFilePathToDelete = joinPath(guidedProgressFilePath, name + ".json");

//delete the progress file
if (fs) fs.unlinkSync(progressFilePathToDelete);
else localStorage.removeItem(progressFilePathToDelete);

if (fs) {
// delete default stub location
fs.rmSync(joinPath(stubSaveFolderPath, name), { recursive: true, force: true });

// delete default conversion location
fs.rmSync(joinPath(conversionSaveFolderPath, name), { recursive: true, force: true });
}

return true;
}
if (result.isConfirmed) return operations.remove(name);

return false;
};
Expand Down
22 changes: 22 additions & 0 deletions src/renderer/src/progress/operations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { joinPath } from "../globals";
import { conversionSaveFolderPath, guidedProgressFilePath, stubSaveFolderPath } from "../dependencies/simple";
import { fs } from "../electron";

export const remove = (name) => {
//Get the path of the progress file to delete
const progressFilePathToDelete = joinPath(guidedProgressFilePath, name + ".json");

//delete the progress file
if (fs) fs.unlinkSync(progressFilePathToDelete);
else localStorage.removeItem(progressFilePathToDelete);

if (fs) {
// delete default stub location
fs.rmSync(joinPath(stubSaveFolderPath, name), { recursive: true, force: true });

// delete default conversion location
fs.rmSync(joinPath(conversionSaveFolderPath, name), { recursive: true, force: true });
}

return true;
};
15 changes: 7 additions & 8 deletions src/renderer/src/progress/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { updateURLParams } from "../../utils/url.js";
import { guidedProgressFilePath } from "../dependencies/simple.js";
import { fs } from "../electron/index.js";
import { joinPath } from "../globals.js";
import { get } from "./index.js";
import { get, hasEntry } from "./index.js";

export const update = (newDatasetName, previousDatasetName) => {
//If updataing the dataset, update the old banner image path with a new one
export const rename = (newDatasetName, previousDatasetName) => {
//If updating the dataset, update the old banner image path with a new one
if (previousDatasetName) {
if (previousDatasetName === newDatasetName) return "No changes made to dataset name";
if (previousDatasetName === newDatasetName) return;

if (hasEntry(newDatasetName))
throw new Error("An existing progress file already exists with that name. Please choose a different name.");
throw new Error("An existing project already exists with that name. Please choose a different name.");

// update old progress file with new dataset name
const oldProgressFilePath = `${guidedProgressFilePath}/${previousDatasetName}.json`;
Expand All @@ -20,10 +20,9 @@ export const update = (newDatasetName, previousDatasetName) => {
localStorage.setItem(newProgressFilePath, localStorage.getItem(oldProgressFilePath));
localStorage.removeItem(oldProgressFilePath);
}

return "Dataset name updated";
} else throw new Error("No previous dataset name provided");
} else throw new Error("No previous project name provided");
};

export const updateAppProgress = (
pageId,
dataOrProjectName = {},
Expand Down
Loading

0 comments on commit 1f85f8e

Please sign in to comment.