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

Fix file associations on Windows + opening project bug #11030

Merged
merged 6 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- [Cloud file browser inserts `enso:` paths][11001]
- [Fixed issue where drag'n'dropped files were not uploaded in cloud
projects.][11014]
- [Fixed files associations not properly registered on Windows][11030]

[10774]: https://github.com/enso-org/enso/pull/10774
[10814]: https://github.com/enso-org/enso/pull/10814
Expand All @@ -26,6 +27,7 @@
[10979]: https://github.com/enso-org/enso/pull/10979
[11001]: https://github.com/enso-org/enso/pull/11001
[11014]: https://github.com/enso-org/enso/pull/11014
[11030]: https://github.com/enso-org/enso/pull/11030

#### Enso Standard Library

Expand Down
23 changes: 20 additions & 3 deletions app/dashboard/src/pages/dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,25 @@ export default function Dashboard(props: DashboardProps) {
)
}

/**
* Extract proper path from `file://` URL.
*/
function fileURLToPath(url: string): string | null {
if (URL.canParse(url)) {
const parsed = new URL(url)
if (parsed.protocol === 'file:') {
return detect.platform() === detect.Platform.windows ?
// On Windows, we must remove leading `/` from URL.
parsed.pathname.slice(1)
: parsed.pathname
} else {
return null
}
} else {
return null
}
}

/** The component that contains the entire UI. */
function DashboardInner(props: DashboardProps) {
const { appRunner, initialProjectName: initialProjectNameRaw, ydocUrl } = props
Expand All @@ -116,9 +135,7 @@ function DashboardInner(props: DashboardProps) {
const assetManagementApiRef = React.useRef<assetTable.AssetManagementApi | null>(null)

const initialLocalProjectPath =
initialProjectNameRaw != null && initialProjectNameRaw.startsWith('file://') ?
projectManager.Path(decodeURI(new URL(initialProjectNameRaw).pathname))
: null
initialProjectNameRaw != null ? fileURLToPath(initialProjectNameRaw) : null
const initialProjectName = initialLocalProjectPath != null ? null : initialProjectNameRaw

const [category, setCategory] = searchParamsState.useSearchParamsState<categoryModule.Category>(
Expand Down
4 changes: 2 additions & 2 deletions app/ide-desktop/client/electron-builder-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export const args: Arguments = await yargs(process.argv.slice(2))
/** File associations for the IDE. */
export const EXTENDED_FILE_ASSOCIATIONS = [
{
ext: fileAssociations.SOURCE_FILE_EXTENSION,
ext: `.${fileAssociations.SOURCE_FILE_EXTENSION}`,
name: `${common.PRODUCT_NAME} Source File`,
role: 'Editor',
// Note that MIME type is used on Windows by the enso-installer to register the file association.
Expand All @@ -118,7 +118,7 @@ export const EXTENDED_FILE_ASSOCIATIONS = [
progId: 'Enso.Source',
},
{
ext: fileAssociations.BUNDLED_PROJECT_EXTENSION,
ext: `.${fileAssociations.BUNDLED_PROJECT_EXTENSION}`,
name: `${common.PRODUCT_NAME} Project Bundle`,
role: 'Editor',
mimeType: 'application/gzip',
Expand Down
4 changes: 2 additions & 2 deletions app/ide-desktop/client/src/fileAssociations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export function onFileOpened(event: electron.Event, path: string): string | null

/** Set up the `open-file` event handler that might import a project and invoke the given callback,
* if this IDE instance should load the project. See {@link onFileOpened} for more details.
* @param setProjectToOpen - A function that will be called with the ID of the project to open. */
* @param setProjectToOpen - A function that will be called with the path of the project to open. */
export function setOpenFileEventHandler(setProjectToOpen: (path: string) => void) {
electron.app.on('open-file', (_event, path) => {
logger.log(`Opening file '${path}'.`)
Expand All @@ -137,7 +137,7 @@ export function setOpenFileEventHandler(setProjectToOpen: (path: string) => void
logger.log(`Got path '${path.toString()}' from second instance.`)
event.preventDefault()
const file = onFileOpened(event, path)
if (file) {
if (file != null) {
setProjectToOpen(file)
}
}
Expand Down
25 changes: 18 additions & 7 deletions app/ide-desktop/client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ import * as urlAssociations from '@/urlAssociations'

const logger = contentConfig.logger

/**
* Convert path to proper `file://` URL.
*/
function pathToURL(path: string): URL {
if (process.platform === 'win32') {
return new URL(encodeURI(`file:///${path.replaceAll('\\', '/')}`))
} else {
return new URL(encodeURI(`file://${path}`))
}
}

// ===========
// === App ===
// ===========
Expand All @@ -63,7 +74,7 @@ class App {
const project = fileAssociations.handleOpenFile(path)
this.window?.webContents.send(ipc.Channel.openProject, project)
} else {
this.setProjectToOpenOnStartup(path)
this.setProjectToOpenOnStartup(pathToURL(path))
}
})

Expand Down Expand Up @@ -149,17 +160,17 @@ class App {
* This method should be called before the application is ready, as it only
* modifies the startup options. If the application is already initialized,
* an error will be logged, and the method will have no effect.
* @param projectId - The ID of the project to be opened on startup. */
setProjectToOpenOnStartup(projectId: string) {
* @param projectUrl - The `file://` url of project to be opened on startup. */
setProjectToOpenOnStartup(projectUrl: URL) {
// Make sure that we are not initialized yet, as this method should be called before the
// application is ready.
if (!electron.app.isReady()) {
logger.log(`Setting the project to open on startup to '${projectId}'.`)
this.args.groups.startup.options.project.value = projectId
logger.log(`Setting the project to open on startup to '${projectUrl.toString()}'.`)
this.args.groups.startup.options.project.value = projectUrl.toString()
} else {
logger.error(
"Cannot set the project to open on startup to '" +
projectId +
projectUrl.toString() +
"', as the application is already initialized.",
)
}
Expand All @@ -173,7 +184,7 @@ class App {
if (fileToOpen != null) {
// The IDE must receive the project path, otherwise if the IDE has a custom root directory
// set then it is added to the (incorrect) default root directory.
this.setProjectToOpenOnStartup(`file://${encodeURI(fileToOpen)}`)
this.setProjectToOpenOnStartup(pathToURL(fileToOpen))
}

if (urlToOpen != null) {
Expand Down
Loading