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

Use vega-loader for validating links #47

Merged
merged 4 commits into from Apr 12, 2018
Merged

Use vega-loader for validating links #47

merged 4 commits into from Apr 12, 2018

Conversation

ydlamba
Copy link
Member

@ydlamba ydlamba commented Mar 10, 2018

Use vega-loader for validating links

  • It first checks whether the link is absolute or relative to the editor. If gets 404 then check whether it is relative to the caller and if still gets an error then throws it.

Fixes #30.

@ydlamba ydlamba changed the title Update Use vega-loader for validating links Mar 10, 2018
@ydlamba
Copy link
Member Author

ydlamba commented Mar 10, 2018

Currently, it is implemented for dataURL (like stocks.csv, etc). Should I implement the same for schema link?

@ydlamba ydlamba requested a review from domoritz March 10, 2018 08:55
@vega vega deleted a comment from ydlamba Mar 10, 2018
Copy link
Member

@domoritz domoritz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach won't work for nested specs. We need to create a custom loader and pass a baseUrl around. The loader would first try the baseUrl and if that returns a 404, try a link relative to the editor.

if (error.target.status === 404) {
// Relative to caller
this.loaderPromise({baseURL: evt.origin}, dataURL).then(() => {
parsed['data']['url'] = evt.origin + dataURL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work if we have a nested spec. Instead of this approach, we should set a baseUrl in the state and create a custom Vega loader. Here is some inspiration: https://github.com/domoritz/draco/blob/master/draco-tools/src/shared/js/components/Visualization.js#L50

const dataURL = parsed['data']['url'];

// Checking wheather link is absolute or relative to editor
this.loaderPromise({baseURL: 'https://vega.github.io/editor/'}, dataURL).then((data) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should first check whether the URL is absolute. In that case, we won't do anything.

Copy link
Member Author

@ydlamba ydlamba Mar 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vega-loader already checks whether it is absolute or not. If not then I am checking it with relative to the editor which means we aren't doing anything when URL is absolute. I tested it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, this will might change when we switch to a custom loader.

@domoritz
Copy link
Member

Currently, it is implemented for dataURL (like stocks.csv, etc). Should I implement the same for schema link?

This is irrelevant with the fix I am proposing above.

@ydlamba ydlamba changed the title Use vega-loader for validating links [WIP] Use vega-loader for validating links Mar 13, 2018
@domoritz
Copy link
Member

domoritz commented Apr 3, 2018

I'd love to get this in. Can I help with anything @ydlamba?

@ydlamba
Copy link
Member Author

ydlamba commented Apr 3, 2018

I understand your approach, working on it.

@ydlamba ydlamba force-pushed the ydl/vega-loader branch 3 times, most recently from f3a60a8 to 10d17c6 Compare April 3, 2018 12:27
console.info('[Vega-Editor] Received Message', evt.origin, data);
// send acknowledgement
const parsed = JSON.parse(data.spec);
let dataURL = parsed['data']['url'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's delete this. We shouldn't expect a spec to have a URL data source.

const editorURL = 'https://vega.github.io';
const loader = vega.loader();
const options = {
baseURL: this.props.baseURL
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of forcing the baseURL, try to check for every request whether it makes sense to change the baseURL. First, check whether there is data at the evt.origin that you grabbed above. If not, use the editor as the base.

Copy link
Member

@domoritz domoritz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't quite what I was hoping for. Can you override how the loader loads a single resource?

Copy link
Member

@domoritz domoritz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my proposal. Let me know what you think.

/**
* Async function that updates the baseURL (if gets 404)
*/
public async updateBaseUrl(url: string){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be deleted

console.info('[Vega-Editor] Received Message', evt.origin, data);
// send acknowledgement
const parsed = JSON.parse(data.spec);
if(parsed['data']['url']) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete this as well

@@ -134,6 +159,12 @@ class App extends React.Component<Props & {match: any, location: any}> {
}
}

function mapStateToProps(state: State, ownProps) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete this as well

@@ -160,4 +194,4 @@ const mapDispatchToProps = function(dispatch) {
};
};

export default withRouter(connect(null, mapDispatchToProps)(App));
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can undo this now

.logLevel(vega.Warn)
.initialize(Editor.chart);

Editor.view = new vega.View(runtime, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use something like this instead

const runtime = vega.parse(props.vegaSpec);

    const loader = vega.loader();
    const originalHttp = loader.http;
    loader.http = async(url, options) => {
      try {
		return await originalHttp(url, {options, ...{baseURL: this.props.baseURL}});
      } catch {
        return await originalHttp(url, options);
      }
    };

    Editor.view = new vega.View(runtime, {
      loader: loader,
      logLevel: vega.Warn,
    })
    .initialize(Editor.chart);

I haven't tested this but I think this communicates the idea.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is some problem with loader.http, its baseURL option is not working. Instead loader.load is working fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created the issue as well.

@ydlamba
Copy link
Member Author

ydlamba commented Apr 5, 2018

PR is now updated. I have tested this and working as expected (just with few minor changes). You can also have a look.

// Custom Loader
loader.load = async(url, options) => {
try {
return await originalLoad(url, {options, ...{baseURL: this.props.baseURL}});
Copy link
Member

@domoritz domoritz Apr 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. it should be ...options, right?
  2. what if options is undefined?
  3. shouldn't custom options override our baseurl? (this one os less important and you can ignore it)

Copy link
Member Author

@ydlamba ydlamba Apr 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you are thinking about options in options. Actually, we need to add baseURL directly in the options.

  1. ...options will append baseURL in options of options (nested object) while options will directly add baseURL in options. I tested it, working fine.
  2. We don't need to worry about options (not options in options) loader is taking care of it.
  3. Ignored for now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, if we go for loader.load(url, {options: {baseURL: this.props.baseURL}}) it won't work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. I thought the behavior of ...options and just options is flipped from how you describe it. I will test it when I'm.at a computer again.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I was right.

options = {foo:42, bar: 123}

$ {...options, ...{baseUrl: 'foo.bar'}}
{foo: 42, bar: 123, baseUrl: "foo.bar"}  // good

$ {options, ...{baseUrl: 'foo.bar'}}
{options: {foo: 42, bar: 123}, baseUrl: "foo.bar"} // not good

See https://github.com/vega/vega-loader#loader for documentation of the loader. We want all options at the top level.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. This is correct. I was thinking it the wrong way, nevermind. I've updated the PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question. Why override load and not http?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because loader.http method performs an HTTP request with a post-sanitization URL i.e we don't have baseURL option with this method. On the other hand, loader.load does all processing itself.
For more info check this vega/vega-loader#7.

@domoritz
Copy link
Member

domoritz commented Apr 6, 2018

Sweet, just one comment.

@ydlamba
Copy link
Member Author

ydlamba commented Apr 6, 2018

Changes are done, please let me know if I am missing something.

@domoritz domoritz merged commit dbaa0e5 into master Apr 12, 2018
@ydlamba ydlamba changed the title [WIP] Use vega-loader for validating links Use vega-loader for validating links Apr 12, 2018
@ydlamba ydlamba deleted the ydl/vega-loader branch April 12, 2018 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants