Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add top menu to app #585

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
4 changes: 3 additions & 1 deletion client/components/Application/Dialogs/FileUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ export default function FileUploadDialog() {
store.closeDialog()
}

const [value, setValue] = React.useState(0)
const dialogTab = store.useStore((state) => state.dialogTab)

const [value, setValue] = React.useState(dialogTab ? dialogTab : 0)

const [remoteUrlValue, setRemoteUrlValue] = React.useState('')

Expand Down
52 changes: 48 additions & 4 deletions client/store/actions/app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as store from '../store'
import { togglePanel } from '@client/store'
import { undoTableChange, redoTableChange } from '@client/store'
import isEqual from 'fast-deep-equal'
import delay from 'delay'
import { openDialog } from './dialog'
Expand All @@ -10,7 +12,8 @@ import { loadFiles } from './file'

export async function onAppStart() {
// @ts-ignore
const sendFatalError = window?.opendataeditor?.sendFatalError
const bridge = window?.opendataeditor
const sendFatalError = bridge?.sendFatalError

let ready = false
let attempt = 0
Expand Down Expand Up @@ -38,6 +41,7 @@ export async function onAppStart() {
}

// Setup project sync polling

setInterval(async () => {
const result = await client.projectSync({})

Expand All @@ -58,8 +62,8 @@ export async function onAppStart() {

// Register on windows close event handler (only Desktop env)
// to prevent closing the app when there are unsaved changes
// @ts-ignore
if (window?.opendataeditor?.closeDesktopApp) {

if (bridge?.closeDesktopApp) {
window.onbeforeunload = (event) => {
const isUpdated = getIsFileOrResourceUpdated(store.getState())
if (isUpdated) {
Expand All @@ -68,9 +72,49 @@ export async function onAppStart() {
}
}
}

// Register menu events

bridge?.onMenuAddNewFile(() => {
openDialog('fileUpload', 0)
})

bridge?.onMenuAddExternalFile(() => {
openDialog('fileUpload', 1)
})

bridge?.onDeleteFile(() => {
openDialog('deleteFilesFolders')
})

bridge?.onPublishFile(() => {
openDialog('publish')
})

bridge?.onToggleMetadata(() => {
togglePanel('metadata')
})

bridge?.onToggleErrorsReport(() => {
togglePanel('report')
})

bridge?.onToggleSource(() => {
togglePanel('source')
})

bridge?.onUndo(() => {
undoTableChange()
})

bridge?.onRedo(() => {
redoTableChange()
})
}

export function closeDesktopApp() {
// @ts-ignore
window?.opendataeditor?.closeDesktopApp()
const bridge = window?.opendataeditor

bridge?.closeDesktopApp()
}
3 changes: 2 additions & 1 deletion client/store/actions/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ export function toggleDialog(dialog: IDialog) {
}
}

export function openDialog(dialog: IDialog) {
export function openDialog(dialog: IDialog, dialogTab?: number) {
store.setState('open-dialog', (state) => {
state.dialog = dialog
state.dialogTab = dialogTab
})
}

Expand Down
5 changes: 5 additions & 0 deletions client/store/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ export type IState = {
**/
dialog?: IDialog

/**
* Keeps track of the displayed dialog's tab
**/
dialogTab?: number

/**
* Will be opened when the main `dialog` is closed (for dialog chains)
**/
Expand Down
13 changes: 11 additions & 2 deletions desktop/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { app, dialog, BrowserWindow } from 'electron'
import { electronApp, optimizer } from '@electron-toolkit/utils'
import { electronApp, optimizer } from '@electron-toolkit/utils'
import { createWindow } from './window'
import { createBridge } from './bridge'
import { join } from 'path'
import log from 'electron-log'
import * as settings from './settings'
import { createMenu } from './menu'

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
Expand All @@ -15,7 +16,8 @@ app.whenReady().then(async () => {

log.info('## Start client')
createBridge()
await createWindow()
const mainWindow = await createWindow()
createMenu(mainWindow)
})

// Default open or close DevTools by F12 in development
Expand Down Expand Up @@ -53,5 +55,12 @@ process.on('unhandledRejection', async (error: any) => {
app.quit()
})

app.setAboutPanelOptions({
applicationName: 'Open Data Editor',
applicationVersion: '1.0.0',
website: 'https://opendataeditor.okfn.org/',
iconPath: './client/assets/ODE_sidebar_logo.svg'
})

// Configure logger to write to the app directory
log.transports.file.resolvePath = () => join(settings.APP_HOME, 'logger', 'main.log')
110 changes: 110 additions & 0 deletions desktop/menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { app, shell, Menu, BrowserWindow } from 'electron'

export function createMenu(mainWindow: BrowserWindow) {
Menu.setApplicationMenu(
Menu.buildFromTemplate([
{
label: app.name,
submenu: [{ role: 'about' }, { role: 'quit' }],
},
{
label: 'File',
submenu: [
{
label: 'Add',
submenu: [
{
label: 'New file',
click: async () => {
mainWindow.webContents.send('menuAddNewFile')
},
},
{
label: 'New folder',
click: async () => {
// Adding the same as Add New File, because it's the same dialog
mainWindow.webContents.send('menuAddNewFile')
},
},
{
label: 'External data',
click: async () => {
mainWindow.webContents.send('menuAddExternalFile')
},
},
],
},
{
label: 'Delete',
click: async () => {
mainWindow.webContents.send('menuDeleteFile')
},
},
{
label: 'Publish',
click: async () => {
mainWindow.webContents.send('menuPublishFile')
},
},
],
},
{
label: 'Edit',
submenu: [{
label: 'Undo',
click: async () => {
mainWindow.webContents.send('menuUndo')
},
}, {
label: 'Redo',
click: async () => {
mainWindow.webContents.send('menuRedo')
},
}],
},
{
label: 'View',
submenu: [
{
label: 'Toggle Metadata Panel',
click: async () => {
mainWindow.webContents.send('menuToggleMetadata')
},
},
{
label: 'Toggle Errors Panel',
click: async () => {
mainWindow.webContents.send('menuToggleErrorsReport')
},
},
{
label: 'Toggle Source Panel',
click: async () => {
mainWindow.webContents.send('menuToggleSource')
},
},
],
},
{
label: 'Help',
submenu: [
{
label: 'ODE User guide',
click: async () => {
await shell.openExternal(
'https://opendataeditor.okfn.org/documentation/getting-started/'
)
},
},
{
label: 'Report an issue',
click: async () => {
await shell.openExternal('https://github.com/okfn/opendataeditor/')
},
},
],
},
])
)
}

34 changes: 32 additions & 2 deletions desktop/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,39 @@ import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('opendataeditor', {
sendFatalError: (message: string) => ipcRenderer.invoke('sendFatalError', message),
openDirectoryDialog: () => ipcRenderer.invoke('openDirectoryDialog'),

ensureLogs: (callback: any) => ipcRenderer.on('ensureLogs', (_event, message: string) => callback(message)),
ensureLogs: (callback: any) =>
ipcRenderer.on('ensureLogs', (_event, message: string) => callback(message)),
openPathInExplorer: (path: string) => ipcRenderer.send('openPathInExplorer', path),
getAppPath: () => ipcRenderer.send('getAppPath'),
closeDesktopApp: () => ipcRenderer.invoke('closeDesktopApp'),

// Menu events

onMenuAddNewFile: (callback: () => void) => {
ipcRenderer.on('menuAddNewFile', callback)
},
onMenuAddExternalFile: (callback: () => void) => {
ipcRenderer.on('menuAddExternalFile', callback)
},
onDeleteFile: (callback: () => void) => {
ipcRenderer.on('menuDeleteFile', callback)
},
onPublishFile: (callback: () => void) => {
ipcRenderer.on('menuPublishFile', callback)
},
onToggleMetadata: (callback: () => void) => {
ipcRenderer.on('menuToggleMetadata', callback)
},
onToggleErrorsReport: (callback: () => void) => {
ipcRenderer.on('menuToggleErrorsReport', callback)
},
onToggleSource: (callback: () => void) => {
ipcRenderer.on('menuToggleSource', callback)
},
onUndo: (callback: () => void) => {
ipcRenderer.on('menuUndo', callback)
},
onRedo: (callback: () => void) => {
ipcRenderer.on('menuRedo', callback)
},
})
15 changes: 8 additions & 7 deletions desktop/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,22 @@ const loadingEvents = new EventEmitter()
import icon from './assets/icon.png?asset'

export async function createWindow() {

var loadingWindow = new BrowserWindow({
const loadingWindow = new BrowserWindow({
resizable: false,
autoHideMenuBar: true,
frame: false,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, 'preload', 'index.js'),
},
});
})

const mainWindow = new BrowserWindow({
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, 'preload', 'index.js'),
contextIsolation: true,
},
})

Expand All @@ -38,7 +37,7 @@ export async function createWindow() {
})

loadingEvents.on('finished', () => {
loadingWindow.close();
loadingWindow.close()
log.info('Opening index.html')
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
Expand All @@ -59,10 +58,12 @@ export async function createWindow() {

if (!is.dev) await server.runServer()

const serverStarted = await server.pollServer();
const serverStarted = await server.pollServer()
if (!serverStarted) {
throw new Error('Failed to start FastAPI server');
throw new Error('Failed to start FastAPI server')
}

loadingEvents.emit('finished')

return mainWindow
}
Loading