Skip to content

Commit

Permalink
#206: Closes #852. Added open schema as url (TODO: as file).
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew Mulholland committed Jun 28, 2019
1 parent b704928 commit fba593e
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 37 deletions.
11 changes: 4 additions & 7 deletions src/main/menu.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { openFile, saveFileAs, saveFile, importDataPackage } from './file.js'
import { showUrlDialog } from './url.js'
import { showUrlDialogForPackage, showUrlDialogForResourceSchema } from './url.js'
import { createWindowTab, focusMainWindow } from './windows.js'
import { importExcel } from './excel.js'
import { showKeyboardHelp } from './help.js'
Expand Down Expand Up @@ -59,8 +59,7 @@ class AppMenu {
label: 'Import Column Properties',
accelerator: 'Shift+CmdOrCtrl+I',
click () {
webContents().send('importColumnProperties')
webContents().send('toggleLockColumnProperties')
showUrlDialogForResourceSchema()
}
}, {
type: 'separator'
Expand Down Expand Up @@ -343,8 +342,7 @@ class AppMenu {
label: 'zip from URL...',
enabled: true,
click () {
// downloadDataPackageJson()
showUrlDialog()
showUrlDialogForPackage()
}
}, {
label: 'zip from file...',
Expand All @@ -356,8 +354,7 @@ class AppMenu {
label: 'json from URL...',
enabled: true,
click () {
// downloadDataPackageJson()
showUrlDialog()
showUrlDialogForPackage()
}
}]
}
Expand Down
99 changes: 73 additions & 26 deletions src/main/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@ import { ipcMain as ipc, dialog } from 'electron'
import { focusOrNewSecondaryWindow, focusMainWindow, closeWindowSafely } from './windows'
import { disableOpenFileItems, enableOpenFileItems } from './menuUtils.js'
import { Package } from 'datapackage'
import { Schema } from 'tableschema'
import tmp from 'tmp'
import _ from 'lodash'
import { dataResourceToFormat } from '../renderer/file-formats.js'

// auto cleanup
tmp.setGracefulCleanup()

export function showUrlDialogForResourceSchema() {
showUrlDialogForCallback(handleJsonForResourceSchema)
}

// TODO: handle errors by rejecting promises and throwing back up stack
export function showUrlDialog() {
// let labels = ['zip from URL....', 'zip from file...', 'json from URL...']
export function showUrlDialogForPackage() {
showUrlDialogForCallback(handleZipOrJsonForPackage)
}

export function showUrlDialogForCallback(callback, errorMessage='There was a problem loading package or resource(s)') {
disableOpenFileItems()
let browserWindow = focusOrNewSecondaryWindow('urldialog', { width: 300, height: 150, modal: true, alwaysOnTop: true })
browserWindow.on('closed', () => {
Expand All @@ -27,23 +35,31 @@ export function showUrlDialog() {
ipc.once('urlSubmitted', (e, urlText) => {
closeWindowSafely(browserWindow)
try {
handleZipOrJson(urlText)
callback(urlText)
} catch (error) {
console.error(`There was a problem loading package or resource(s)`, error)
console.error(errorMessage, error)
const mainWindow = focusMainWindow()
mainWindow.webContents.send('closeLoadingScreen')
}
})
})
}

function handleZipOrJson(urlText) {
function handleZipOrJsonForPackage(urlText) {
if (_.endsWith(urlText, '.json')) {
loadPackageFromJsonUrl(urlText)
} else if (_.endsWith(urlText, '.zip')) {
importDataPackageZipFromUrl(urlText)
} else {
showUrlPathNotSupportedMessage()
showUrlPathNotSupportedMessage(urlText, '".json" or ".zip"')
}
}

function handleJsonForResourceSchema(urlText) {
if (_.endsWith(urlText, '.json')) {
loadResourceSchemaFromJsonUrl(urlText)
} else {
showUrlPathNotSupportedMessage(urlText, '".json"')
}
}

Expand Down Expand Up @@ -95,48 +111,69 @@ function handleDownloadedZip(zipPath, mainWindow) {

async function loadPackageFromJsonUrl(urlText) {
const mainWindow = focusMainWindow()
mainWindow.webContents.send('closeAndshowLoadingScreen', 'Loading package URL..')
const dataPackageJson = await loadPackageJson(urlText, mainWindow)
if (!dataPackageJson) {
const dataPackageJson = await loadGenericFrictionlessFromJsonUrl(urlText, loadPackageJson, 'Data Package')
try {
await loadResources(dataPackageJson, mainWindow)
} catch (error) {
console.error('There was a problem loading package from json', error)
}
}

async function loadResourceSchemaFromJsonUrl(urlText) {
try {
const resourceSchema = await loadGenericFrictionlessFromJsonUrl(urlText, loadTableResourceSchemaJson, 'Table Resource Schema')
const mainWindow = focusMainWindow()
mainWindow.webContents.send('closeLoadingScreen')
if (resourceSchema && resourceSchema.descriptor) {
const mainWindow = focusMainWindow()
mainWindow.webContents.send('addSchemaToTabAndLock', resourceSchema.descriptor)
}
} catch (error) {
console.error('There was a problem loading resource schema from json', error)
}
}

// atm, 'types' are only : Data Package or Resource Schema
async function loadGenericFrictionlessFromJsonUrl(urlText, callback, frictionlessType) {
const mainWindow = focusMainWindow()
mainWindow.webContents.send('closeAndshowLoadingScreen', `Loading ${frictionlessType} URL..`)
const frictionlessTypeJson = await callback(urlText, mainWindow)
if (!frictionlessTypeJson) {
dialog.showMessageBox(mainWindow, {
type: 'warning',
title: `Unable to load Data Package`,
title: `Unable to load ${frictionlessType}`,
message:
`The data package, ${urlText}, could not be loaded.
If the data package is a URL, please check that the URL exists.`
`The ${frictionlessType}, ${urlText}, could not be loaded.
If the ${frictionlessType} is a URL, please check that the URL exists.`
})
mainWindow.webContents.send('closeLoadingScreen')
return
}
if (!dataPackageJson.valid) {
showInvalidMessage(urlText, mainWindow)
if (!frictionlessTypeJson.valid) {
showInvalidMessage(urlText, mainWindow, frictionlessType)
mainWindow.webContents.send('closeLoadingScreen')
return
}
try {
await loadResources(dataPackageJson, mainWindow)
} catch (error) {
console.error('There was a problem loading package from json', error)
}
return frictionlessTypeJson
}

function showInvalidMessage(urlText, mainWindow) {
function showInvalidMessage(urlText, mainWindow, frictionlessType) {
dialog.showMessageBox(mainWindow, {
type: 'warning',
title: `Invalid Data Package`,
title: `Invalid ${frictionlessType}`,
message:
`The data package, at ${urlText}, is not valid. Please refer to
`The ${frictionlessType}, at ${urlText}, is not valid. Please refer to
https://frictionlessdata.io/specs/
for more information.`
})
}

function showUrlPathNotSupportedMessage(urlText, mainWindow) {
dialog.showMessageBox(mainWindow, {
function showUrlPathNotSupportedMessage(urlText, supportedFileExtensions) {
dialog.showMessageBox(focusMainWindow(), {
type: 'warning',
title: `Unsupported URL Path extension`,
message:
`Data Curator, does not support downloading ${urlText}, as the path does not end in ".zip" or ".json"`
`Data Curator, does not support downloading ${urlText}, as the path does not end in ${supportedFileExtensions}`
})
}

Expand All @@ -150,7 +187,8 @@ export async function loadPackageJson(json) {
}
}

async function loadResources(dataPackageJson, mainWindow) {
async function loadResources(dataPackageJson) {
const mainWindow = focusMainWindow()
let packageProperties = _.assign({}, dataPackageJson.descriptor)
_.unset(packageProperties, 'resources')
mainWindow.webContents.send('resetPackagePropertiesToObject', packageProperties)
Expand All @@ -166,6 +204,15 @@ async function loadResources(dataPackageJson, mainWindow) {
}
}

async function loadTableResourceSchemaJson(json) {
try {
const resourceSchema = await Schema.load(json)
return resourceSchema
} catch (error) {
console.error(`There was a problem loading the table resource schema: ${json}`, error)
}
}

export async function loadResourceDataFromPackageUrl(url, resourceName) {
const dataPackage = await loadPackageJson(url)
const rowOfObjects = []
Expand Down
30 changes: 30 additions & 0 deletions src/renderer/components/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,9 @@ export default {
ipc.on('addTabWithFormattedDataAndDescriptor', function(e, data, format, descriptor) {
self.addTab(data, format, descriptor)
})
ipc.on('addSchemaToTabAndLock', function(e, schema) {
self.safeInitHotColumnPropertiesFromSchema(schema)
})
ipc.on('addTabWithFormattedDataFile', function(e, data, format, filename) {
self.addTabWithFilename(data, format, filename)
})
Expand Down Expand Up @@ -912,6 +915,33 @@ export default {
tableHotIdProperties[hotId] = tableProperties
this.resetTablePropertiesToObject(tableHotIdProperties)
},
safeInitHotColumnPropertiesFromSchema: function(schema) {
try {
const schemaFieldsCount = _.get(schema, 'fields', 0).length
const columnCount = getColumnCount()
if (this.currentHotId && schemaFieldsCount === columnCount) {
this.initHotColumnPropertiesFromSchema(this.currentHotId, schema)
// hot rendering problem when tabs opened quickly - https://github.com/ODIQueensland/data-curator/issues/803- workaround as selecting table re-renders
getCurrentColumnIndexOrMin()
updateHotDimensions$.next()
LockProperties.toggleLockColumnProperties()
this.addImportDataPropertiesError('Import Column properties success', `${schemaFieldsCount} schema fields were imported.`)
} else {
const errorMessage = `Unable to import ${schemaFieldsCount} schema fields to a ${columnCount}-column table`
this.addImportDataPropertiesError('Validation Error', errorMessage)
}
} catch (error) {
console.error('ERROR: Import Column Properties: ', error)
this.addImportDataPropertiesError('Import Column properties error', 'The column properties could not be imported.')
}
},
addImportDataPropertiesError: function(title, message) {
this.messagesTitle = title
this.messages = message
// as there's only 1 message, simpler to send as feedback (without rows/cols for error)
this.messagesType = 'feedback'
},
initHotColumnPropertiesFromSchema: function(hotId, schema) {
// TODO : move this to similar logic in importDataPackage to tidy up
if (!_.isEmpty(schema)) {
Expand Down
4 changes: 0 additions & 4 deletions src/renderer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,6 @@ ipc.on('toggleCaseSensitiveHeader', function() {
ipc.send('hasCaseSensitiveHeader', toggledCase)
})

ipc.on('importColumnProperties', function() {
console.log('arrived')
})

export function closeSecondaryWindow(windowName) {
ipc.sendSync('closeSecondaryWindow', windowName)
}
Expand Down

0 comments on commit fba593e

Please sign in to comment.