Skip to content

Commit

Permalink
feat(datasets): user can import datasets though the UI
Browse files Browse the repository at this point in the history
  • Loading branch information
vfried committed Mar 12, 2020
1 parent cad115f commit edda85d
Show file tree
Hide file tree
Showing 13 changed files with 383 additions and 45 deletions.
58 changes: 52 additions & 6 deletions src/api-client/dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ export default function addDatasetMethods(client) {
if (controller) queryParams.signal = controller.signal;

return fetch(`${client.baseUrl}/renku/cache.files_upload?override_existing=true`, queryParams)
.then(response => {
if (controller !== undefined)
.then(response => {
if (controller !== undefined)
response.controller = controller;
return response;
});
});
};

client.addFilesToDataset = (projectUrl, datasetName, filesList, signal) => {
client.addFilesToDataset = (projectUrl, datasetName, filesList) => {
let headers = client.getBasicHeaders();
headers.append("Content-Type", "application/json");
headers.append("X-Requested-With", "XMLHttpRequest");
Expand All @@ -54,7 +54,7 @@ export default function addDatasetMethods(client) {
};

return client.clientFetch(`${client.baseUrl}/renku/cache.project_clone`,
queryParams
queryParams
).then(response => {
if (response.data.error) { return response; }
else
Expand Down Expand Up @@ -91,6 +91,7 @@ export default function addDatasetMethods(client) {
return response;

project_id = response.data.result.project_id;

return client.clientFetch(`${client.baseUrl}/renku/datasets.create`, {
method: "POST",
headers: headers,
Expand All @@ -100,7 +101,6 @@ export default function addDatasetMethods(client) {
"project_id": project_id
})
});

})
.then(response => {
if (response.data.error) { return response; }
Expand All @@ -118,4 +118,50 @@ export default function addDatasetMethods(client) {
} return response;
});
};

client.datasetImport = (projectUrl, renkuDataset) => {
let headers = client.getBasicHeaders();
headers.append("Content-Type", "application/json");
headers.append("X-Requested-With", "XMLHttpRequest");

let project_id;

return client.clientFetch(`${client.baseUrl}/renku/cache.project_clone`, {
method: "POST",
headers: headers,
body: JSON.stringify({
depth: 1,
git_url: projectUrl
})
}).then(response => {
if (response.data.error !== undefined)
return response;

project_id = response.data.result.project_id;

return client.clientFetch(`${client.baseUrl}/renku/datasets.import`, {
method: "POST",
headers: headers,
body: JSON.stringify({
"dataset_uri": renkuDataset.uri,
"project_id": project_id
})
});

});
};


client.getJobStatus = (job_id) => {
let headers = client.getBasicHeaders();
headers.append("Content-Type", "application/json");
headers.append("X-Requested-With", "XMLHttpRequest");

return client.clientFetch(`${client.baseUrl}/renku/jobs/${job_id}`, {
method: "GET",
headers: headers
}).then(response => {
return response.data.result;
});
};
}
22 changes: 10 additions & 12 deletions src/dataset/Dataset.present.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,13 @@ export default function DatasetView(props) {
}).catch(error => {
if (fetchError === null) {
if (!unmounted && error.case === API_ERRORS.notFoundError) {
setFetchError(
"Error 404: The dataset that was selected does not exist or could not be accessed." +
"If you just created the dataset try reloading the page."
);
}
setFetchError("Error 404: The dataset that was selected does" +
" not exist or could not be accessed. If you just created or" +
" imported the dataset try reloading the page.");
}
else if (!unmounted && error.case === API_ERRORS.internalServerError) {
setFetchError("Error 500: The dataset that was selected couldn't be fetched.");
}
}
}
});
}
Expand All @@ -156,10 +155,8 @@ export default function DatasetView(props) {
}).catch(error => {
if (fetchError === null) {
if (!unmounted && error.case === API_ERRORS.notFoundError) {
setFetchError(
"Error 404: The dataset that was selected does not exist or could not be accessed." +
"If you just created the dataset try reloading the page."
);
setFetchError("Error 404: The dataset that was selected does not exist or" +
" could not be accessed. If you just created or imported the dataset try reloading the page.");
}
else if (!unmounted && error.case === API_ERRORS.internalServerError) {
setFetchError("Error 500: The dataset that was selected couldn't be fetched.");
Expand Down Expand Up @@ -200,13 +197,14 @@ export default function DatasetView(props) {
if (dataset === null) {
return (
<Alert color="danger">
The dataset that was selected does not exist or could not
be accessed.<br /> <br /> If you just created the dataset
The dataset that was selected does not exist or could notbe accessed.<br /> <br />
If you just created or imported the dataset
try <Button color="danger" size="sm" onClick={
() => window.location.reload()
}>reloading</Button> the page.</Alert>
);
}

return <Col>
<Row>
<Col md={8} sm={12}>
Expand Down
22 changes: 21 additions & 1 deletion src/model/RenkuModels.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,26 @@ const issueFormSchema = new Schema({
}
});

const datasetImportFormSchema = new Schema({
uri: {
initial: "",
name: "uri",
label: "URI/DOI",
edit: false,
help: "This will import the dataset with the DOI (Digital Object Identifier) 10.5281/zenodo.3352150" +
" and make it locally available. Dataverse and Zenodo are supported, with DOIs (e.g. 10.5281/zenodo.3352150" +
" or doi:10.5281/zenodo.3352150) and full URLs (e.g. http://zenodo.org/record/3352150). A tag with the" +
" remote version of the dataset is automatically created.",
type: FormGenerator.FieldTypes.TEXT,
// parseFun: expression => FormGenerator.Parsers.slugFromTitle(expression),
validators: [{
id: "uri-length",
isValidFun: expression => FormGenerator.Validators.isNotEmpty(expression),
alert: "URI is too short"
}]
}
});


export { userSchema, metaSchema, displaySchema, newProjectSchema, projectSchema, forkProjectSchema };
export { notebooksSchema, projectsSchema, datasetFormSchema, issueFormSchema };
export { notebooksSchema, projectsSchema, datasetFormSchema, issueFormSchema, datasetImportFormSchema };
20 changes: 20 additions & 0 deletions src/project/Project.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import Fork from "./fork";
import ShowDataset from "../dataset/Dataset.container";
import NewDataset from "./datasets/new/index";
import EditDataset from "./datasets/edit/index";
import ImportDataset from "./datasets/import/index";


const subRoutes = {
Expand Down Expand Up @@ -293,6 +294,7 @@ class View extends Component {
overviewDatasetsUrl: `${baseUrl}/overview/datasets`,
datasetsUrl: `${datasetsUrl}`,
newDatasetUrl: `${datasetsUrl}/new`,
importDatasetUrl: `${datasetsUrl}/import`,
datasetUrl: `${datasetsUrl}/:datasetId`,
editDatasetUrl: `${datasetsUrl}/:datasetId/modify`,
issueNewUrl: `${collaborationUrl}/issues/issue_new`,
Expand Down Expand Up @@ -466,6 +468,24 @@ class View extends Component {
httpProjectUrl={httpProjectUrl}
/>,

importDataset: (p) => <ImportDataset
key="datasetnew" {...subProps}
progress={graphProgress}
maintainer={maintainer}
accessLevel={accessLevel}
forked={forked}
insideProject={true}
datasets={datasets}
reFetchProject={this.fetchAll.bind(this)}
lineagesUrl={subUrls.lineagesUrl}
fileContentUrl={subUrls.fileContentUrl}
projectsUrl={subUrls.projectsUrl}
selectedDataset={p.match.params.datasetId}
client={this.props.client}
history={this.props.history}
httpProjectUrl={httpProjectUrl}
/>,

mrList: <ConnectedMergeRequestList key="mrList" store={this.projectState.reduxStore}
mergeRequestsOverviewUrl={subUrls.mergeRequestsOverviewUrl} />,

Expand Down
14 changes: 9 additions & 5 deletions src/project/Project.present.js
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ class ProjectDatasetsNav extends Component {
datasets={this.props.core.datasets}
datasetsUrl={this.props.datasetsUrl}
newDatasetUrl={this.props.newDatasetUrl}
importDatasetUrl={this.props.importDatasetUrl}
visibility={this.props.visibility}
/>;
}
Expand All @@ -565,9 +566,11 @@ class ProjectViewDatasets extends Component {
render() {
return <Switch>
<Route exact path={this.props.newDatasetUrl}
render={p => this.props.newDataset(p)} />
render={p => this.props.newDataset(p)} />
<Route exact path={this.props.importDatasetUrl}
render={p => this.props.importDataset(p)} />
<Route path={this.props.editDatasetUrl}
render={p => this.props.editDataset(p)} />
render={p => this.props.editDataset(p)} />
<Route path={this.props.datasetsUrl} render={props =>
<ProjectViewDatasetsList {...this.props} {...props} />} />
</Switch>;
Expand Down Expand Up @@ -598,10 +601,11 @@ class ProjectViewDatasetsList extends Component {
return <Col sm={12} md={8} lg={10}>
<Alert timeout={0} color="primary">
No datasets found for this project. <br /><br />
<FontAwesomeIcon icon={faInfoCircle} /> If you recently activated the knowledge graph or
<FontAwesomeIcon icon={faInfoCircle} /> If you recently activated the knowledge graph or
added the datasets try refreshing the page. <br /><br />
You can also click on the button to create
a <Link className="btn btn-primary btn-sm" to={this.props.newDatasetUrl}>New Dataset</Link>
You can also click on the button to create a
<Link className="btn btn-primary btn-sm" to={this.props.newDatasetUrl}>New Dataset</Link>
or <Link className="btn btn-primary btn-sm" to={this.props.importDatasetUrl}>Import Dataset</Link>
</Alert>
</Col>;
}
Expand Down
4 changes: 2 additions & 2 deletions src/project/Project.state.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ class ProjectModel extends StateModel {
}

fetchProjectDatasets(client) { //from KG
if (this.get("transient.requests.datasets") === SpecialPropVal.UPDATING) return;
this.setUpdating({ transient: { requests: { datasets: true } } });
if (this.get("core.datasets") === SpecialPropVal.UPDATING) return;
this.setUpdating({ core: { datasets: true } });
return client.getProjectDatasetsFromKG(this.get("core.path_with_namespace"))
.then(datasets => {
const updatedState = { datasets: datasets, transient: { requests: { datasets: false } } };
Expand Down
34 changes: 20 additions & 14 deletions src/project/datasets/DatasetsListView.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,22 @@ function DatasetListRow(props) {

function CreateDatasetButton(props) {
if (props.visibility.accessLevel >= ACCESS_LEVELS.MAINTAINER) {
return <span className="float-right throw-right-in-flex">
<UncontrolledButtonDropdown size="sm">
<DropdownToggle color="primary" className="alternateToggleStyle" caret>
<FontAwesomeIcon icon={faPlus} style={{ color: "white", backgroundColor: "#5561A6" }} />
</DropdownToggle>
<DropdownMenu right={false}>
<DropdownItem>
<Link to={props.newDatasetUrl}>New Dataset</Link>
</DropdownItem>
</DropdownMenu>
</UncontrolledButtonDropdown>
</span>;
}
return <span className="float-right throw-right-in-flex">
<UncontrolledButtonDropdown size="sm">
<DropdownToggle color="primary" className="alternateToggleStyle" caret>
<FontAwesomeIcon icon={faPlus} style={{ color: "white", backgroundColor: "#5561A6" }} />
</DropdownToggle>
<DropdownMenu right={false}>
<DropdownItem>
<Link to={props.newDatasetUrl}>New Dataset</Link>
</DropdownItem>
<DropdownItem>
<Link to={props.importDatasetUrl}>Import Dataset</Link>
</DropdownItem>
</DropdownMenu>
</UncontrolledButtonDropdown>
</span>;
}
return null;
}

Expand All @@ -53,7 +56,10 @@ export default function DatasetsListView(props) {
<span className="tree-header-title text-truncate">
Datasets List
</span>
<CreateDatasetButton visibility={props.visibility} newDatasetUrl={props.newDatasetUrl}/>
<CreateDatasetButton
visibility={props.visibility}
newDatasetUrl={props.newDatasetUrl}
importDatasetUrl={props.importDatasetUrl}/>
</div>
<nav>
{
Expand Down
2 changes: 1 addition & 1 deletion src/project/datasets/edit/DatasetEdit.present.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function DatasetEdit(props) {
return null;

if (props.accessLevel < ACCESS_LEVELS.MAINTAINER) {
return <Col sm={12} md={8} lg={10}>
return <Col sm={12} md={10} lg={8}>
<Alert timeout={0} color="primary">
Acces Denied. You don&apos;t have rights to edit datasets for this project.<br /><br />
<FontAwesomeIcon icon={faInfoCircle} /> If you were recently given access to this project,
Expand Down
Loading

0 comments on commit edda85d

Please sign in to comment.