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

Feature: Import model via URL #517

Merged
merged 33 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
16eeecc
Import modal initial template
idmarjr Dec 11, 2021
49891f0
Introduce import button to workspace
idmarjr Dec 11, 2021
901d5f6
Add name input to modal upload
idmarjr Dec 11, 2021
505d411
Add .note explanation to import model modal
idmarjr Dec 11, 2021
73f18fa
Merge branch 'development' into feature/import-model
idmarjr Dec 12, 2021
eeecd85
Remove conflict marks left by mistake
idmarjr Dec 12, 2021
5dd65bc
Merge branch 'development' into feature/import-model
idmarjr Dec 13, 2021
f01a36c
Merge branch 'master' into feature/import-model
idmarjr May 13, 2022
9e2fc28
Merge branch 'development' into feature/import-model
idmarjr May 13, 2022
3c81537
Merge branch 'development' into feature/import-model
idmarjr Jun 26, 2022
4e565a4
Merge branch 'main' into feature/import-model
idmarjr Sep 30, 2023
e4e442f
Merge branch 'main' into feature/import-model
idmarjr Apr 20, 2024
90059d5
Update Import modal
idmarjr Apr 20, 2024
ba2c671
Add placeholder to URL field
idmarjr Apr 20, 2024
5c8194f
merge main
miltonbsn Apr 24, 2024
aeaf2eb
Create import api endpoint
miltonbsn Apr 25, 2024
7894bc9
Create import modal basic function
miltonbsn Apr 25, 2024
2b0d6d3
Add import function to workspace
miltonbsn Apr 25, 2024
e58c1f4
Merge main
miltonbsn Apr 25, 2024
bff16bd
Validate url field
miltonbsn Apr 25, 2024
6a4b04a
Do not allow dismiss import modal on click outside area
miltonbsn Apr 25, 2024
93869ab
Change :placeholder color on input with error styes
idmarjr Apr 25, 2024
b4e3f91
Add Feedback message to import modal
idmarjr Apr 25, 2024
ee0f6bd
Create and manage allowImport config on sharing
miltonbsn Apr 25, 2024
abadf1a
Add allowImport config to export modal
miltonbsn Apr 25, 2024
7236b56
Improve import modal validation (Markup)
idmarjr Apr 25, 2024
fa391e8
Merge branch 'feature/import-model' of github.com:brmodeloweb/brmodel…
idmarjr Apr 25, 2024
ea2e414
Handle feedbacks on import model
miltonbsn Apr 25, 2024
18c5256
Fix add on list when import
miltonbsn Apr 25, 2024
fdbb270
Fix import messages
miltonbsn Apr 25, 2024
7a94d69
Update copies from Share model modal
idmarjr Apr 25, 2024
ce28138
Only enable import if share model option is true
idmarjr Apr 25, 2024
9067721
Remove consolle.log left overs
idmarjr Apr 25, 2024
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
42 changes: 42 additions & 0 deletions app/angular/components/importModelModal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<div class="modal-header">
<h3 class="modal-title">{{ 'Import model' | translate }}</h3>
<img
src="../../img/loading-dots.gif"
alt="Loading"
class="br-loader"
ng-class="{'loading': $ctrl.loading}"
/>
</div>

<div class="modal-body">
<aside class="feedback">
<div class="alert alert-danger" role="alert" data-ng-class="{'hide': !$ctrl.feedback.showing}">
<p>
{{ 'It was not possible to import this model. ' | translate}} <br/>
{{ 'The URL may not be correct or the model does not allow import.' | translate}}
</p>
</div>
</aside>
<form class="form-horizontal" role="form" name="modelForm">
<div class="form-group">
<label for="import-model" class="col-sm-3 control-label">{{ 'URL' | translate }}</label>
<div class="col-sm-7">
<input
class="form-control"
ng-class="{'error': (!$ctrl.valid && $ctrl.submitted)}"
type="text"
id="import-model"
autocomplete="off"
placeholder="https://app.brmodeloweb.com/#!/publicview/{hash}"
data-ng-model="$ctrl.url"
/>
<p class="note">{{ 'Please insert the URL to import' | translate }}</p>
</div>
</div>
</form>
</div>

<div class="modal-footer">
<button class="br-button yellow" type="button" ng-click="$ctrl.cancel()">{{ 'Cancel' | translate }}</button>
<button class="br-button" type="button" ng-click="$ctrl.save($ctrl.url)">{{ 'Import' | translate }}</button>
</div>
65 changes: 65 additions & 0 deletions app/angular/components/importModelModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import angular from "angular";
import template from "./ImportModelModal.html";

const app = angular.module("app.ImportModelModal", []);

const Controller = function (ModelAPI, AuthService, $timeout) {
const $ctrl = this;
const urlRegex = /^(https?:\/\/(?:[\w.-]+|\[::1\]|localhost)(?::\d{1,5})?\/#!\/publicview\/[\w.-]+)$/;;

const validateUrl = (url) => {
if(url == null || url == "") {
return false
}
return urlRegex.test(url);
}

$ctrl.$onInit = () => {
$ctrl.url = "";
$ctrl.submitted = false;
$ctrl.valid = false;
$ctrl.loading = false;
$ctrl.feedback = {
showing: false
}
};

$ctrl.cancel = () => {
$ctrl.dismiss({
reason: "cancel",
});
};

$ctrl.showErrorFeedback = () => {
$timeout(() => {
$ctrl.feedback.showing = true;
})
};

$ctrl.save = (url) => {
const parts = url.split("/");
const shareId = parts[parts.length-1];
$ctrl.submitted = true;
$ctrl.valid = validateUrl(url);
if($ctrl.valid) {
$ctrl.loading = true;
ModelAPI.importModel(shareId, AuthService.loggeduser).then(response => {
$ctrl.loading = false;
$ctrl.close({result: response.data});
}).catch(error => {
$ctrl.loading = false;
console.log(error);
$ctrl.showErrorFeedback();
});
}
};
};

export default app.component("importModelModal", {
template: template,
bindings: {
close: "&",
dismiss: "&"
},
controller: Controller,
}).name;
15 changes: 10 additions & 5 deletions app/angular/components/shareModelModal.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ <h3 class="modal-title">{{ 'Share model' | translate }}</h3>
</label>
</div>
</div>
<div class="col-sm-offset-3 col-sm-7">
<div class="checkbox">
<label for="share-import-config">
<input id="share-import-config" type="checkbox" ng-model="$ctrl.importAllowed" ng-disabled="!$ctrl.shared"/>
<span>{{ 'Enable import' | translate }}</span>
<p class="note">{{ 'Allow users to make copies using the public link' | translate }}</p>
</label>
</div>
</div>
</div>
<div class="form-group">
<label for="import-model" class="col-sm-3 control-label">{{ 'URL' | translate }}</label>
Expand All @@ -27,16 +36,12 @@ <h3 class="modal-title">{{ 'Share model' | translate }}</h3>
readonly
data-ng-model="$ctrl.url"
/>
<p class="note">{{ 'People will be able to see but not modify your model' | translate }}</p>
</div>
<div class="col-sm-3">
<button type="submit" class="btn btn-default" style="margin-left: -24px;" ng-click="$ctrl.copy()" ng-disabled="!$ctrl.url">{{ 'Copy' | translate }}</button>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-7">
<p class="note">{{ 'With this link, people will be able to see but not modify this model' | translate }}</p>
</div>
</div>
</form>
</div>

Expand Down
17 changes: 12 additions & 5 deletions app/angular/components/shareModelModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,29 @@ const Controller = function (ModelAPI) {
const shareConfig = response.data;
$ctrl.url = shareConfig.active ? shareConfig.url : "";
$ctrl.shared = shareConfig.active;
$ctrl.backupUrl = shareConfig.url;
$ctrl.backupShared = shareConfig.active;
$ctrl.importAllowed = shareConfig.importAllowed;
$ctrl.backupConfig = shareConfig;
});
};

const hasChanges = (newActive, newImportAllowed) => {
return $ctrl.backupConfig.active != newActive || $ctrl.backupConfig.importAllowed != newImportAllowed;
}

$ctrl.toggleShare = (shared) => {
$ctrl.url = shared? $ctrl.backupUrl : "";
$ctrl.url = shared? $ctrl.backupConfig.url : "";
if (!shared) {
$ctrl.importAllowed = false;
}
}

$ctrl.cancel = () => {
$ctrl.dismiss({reason: "cancel"});
};

$ctrl.save = () => {
if($ctrl.shared != $ctrl.backupShared) {
ModelAPI.toggleShare($ctrl.modelId, $ctrl.shared).then(() => {
if(hasChanges($ctrl.shared, $ctrl.importAllowed)) {
ModelAPI.toggleShare($ctrl.modelId, $ctrl.shared, $ctrl.importAllowed).then(() => {
$ctrl.close({reason: "model shared"});
}).catch(error => {
console.log(error);
Expand Down
13 changes: 11 additions & 2 deletions app/angular/service/modelAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ const authService = ($http) => {
});
};

const _toggleShare = function (modelId, active) {
const _toggleShare = function (modelId, active, importAllowed) {
return $http
.post(`/models/share`, {"modelId": modelId, "active": active})
.post(`/models/share`, {"modelId": modelId, "active": active, "importAllowed": importAllowed})
.then(function (resp) {
return resp;
});
Expand All @@ -75,6 +75,14 @@ const authService = ($http) => {
});
};

const _importModel = function (shareId, userId) {
return $http
.post(`/models/import`, {shareId, userId})
.then(function (resp) {
return resp;
});
};

const _duplicate= function (modelId, userId, newName) {
return $http
.post(`/models/${modelId}/duplicate`, {"userId": userId, "newName": newName})
Expand All @@ -93,6 +101,7 @@ const authService = ($http) => {
loadShareOptions: _loadShareOptions,
toggleShare: _toggleShare,
getSharedModel: _getSharedModel,
importModel: _importModel,
duplicate: _duplicate
};
};
Expand Down
1 change: 1 addition & 0 deletions app/angular/workspace/workspace.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<h2 class="h2 pull-left">{{ 'Models' | translate }}</h2>
<aside class="header-actions pull-right">
<a class="br-button" data-ng-click="$ctrl.newModel()"><i class="fa fa-plus-circle" aria-hidden="true"></i> {{ 'New model' | translate }}</a>
<a class="br-button" data-ng-click="$ctrl.importModel()"><i class="fa fa-upload" aria-hidden="true"></i> {{ 'Import model' | translate }}</a>
</aside>
</div><!-- End .page-header -->
</header><!-- End .container -->
Expand Down
17 changes: 17 additions & 0 deletions app/angular/workspace/workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import modelDuplicatorComponent from "../components/duplicateModelModal";
import modelDeleterComponent from "../components/deleteModelModal";
import modelRenameComponent from "../components/renameModelModal";
import bugReportButton from "../components/bugReportButton";
import modelImportComponent from "../components/importModelModal";
import githubSponsorBanner from "../components/githubSponsorBanner";
import shareModelModal from "../components/shareModelModal";
import iconConceptual from "../components/icons/conceptual";
Expand Down Expand Up @@ -105,6 +106,21 @@ const ListController = function (
});
};

ctrl.importModel = () => {
const modalInstance = $uibModal.open({
animation: true,
backdrop: 'static',
keyboard: false,
template: '<import-model-modal close="$close(result)" dismiss="$dismiss()"></import-model-modal>',
}).result;
modalInstance.then((importedModel) => {
ctrl.models.push(mapData(importedModel));
ctrl.showFeedback($filter('translate')("Your model was imported successfully!"), true, 'success');
}).catch((reason) => {
console.log("Modal dismissed with reason", reason);
});
};

ctrl.renameModel = (model) => {
const modalInstance = $uibModal.open({
animation: true,
Expand Down Expand Up @@ -205,6 +221,7 @@ export default angular
modelDeleterComponent,
modelRenameComponent,
bugReportButton,
modelImportComponent,
githubSponsorBanner,
shareModelModal,
iconConceptual,
Expand Down
14 changes: 9 additions & 5 deletions app/i18n/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,11 @@ export default {
'Request feature': 'Request feature',
'Report bug': 'Report bug',
'Import model': 'Import model',
'File': 'File',
'URL': 'URL',
'Import': 'Import',
'Please select a .BRT file': 'Please select a .BRT file',
'Please insert the URL to import': 'Please the URL to import',
'It was not possible to import this model. ': 'It was not possible to import this model. ',
'The URL may not be correct or the model does not allow import.': 'The URL may not be correct or the model is not allowed to be imported.',
'Last save:': 'Last save:',
'at': 'at',
'Equal to': 'Equal to',
Expand Down Expand Up @@ -167,9 +169,11 @@ export default {
'Go to Github Sponsors': 'Go to Github Sponsors',
'Share model':'Share model',
'Create public link':'Create public link',
'Make model public': 'Make model public',
'Enable import': 'Enable import',
'Allow users to make copies using the public link': 'Allow users to make copies using the public link',
'URL': 'URL',
'Copy': 'Copy',
'With this link, people will be able to see but not modify this model': 'With this link, people will be able to see but not modify this model',
"Sharing configuration has been updated successfully!": "Sharing configuration has been updated successfully!"
'People will be able to see but not modify your model': 'People will be able to see but not modify your model',
"Sharing configuration has been updated successfully!": "Sharing configuration has been updated successfully!",
"Your model was imported successfully!": "Your model was imported successfully!"
};
14 changes: 9 additions & 5 deletions app/i18n/languages/pt_BR.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,11 @@ export default {
'Request feature': 'Requisitar funcionalidade',
'Report bug': 'Reportar problema',
'Import model': 'Importar modelo',
'File': 'Arquivo',
'URL': 'URL',
'Import': 'Importar',
'Please select a .BRT file': 'Por favor selecione um arquivo .BRT',
'Please insert the URL to import': 'Por favor insira a URL para importar',
'It was not possible to import this model. ': 'Não foi possível importar esse modelo. ',
'The URL may not be correct or the model does not allow import.': 'A URL pode não estar correta ou o modelo não autoriza importação',
'Last save:': 'Salvo por último:',
'at': 'às',
'Equal to': 'Igual',
Expand Down Expand Up @@ -166,9 +168,11 @@ export default {
'Go to Github Sponsors': 'Ir para o Github Sponsors',
'Share model': 'Compartilhar modelo',
'Create public link': 'Criar link público',
'Make model public': 'Tornar modelo público',
'Enable import': 'Autorizar importação',
'Allow users to make copies using the public link': 'Permitir que os usuários façam cópias usando o link público',
'URL': 'URL',
'Copy': 'Copiar',
'With this link, people will be able to see but not modify this model': 'Com este link, as pessoas poderão ver, mas não modificar este modelo',
"Sharing configuration has been updated successfully!": "A configuração de compartilhamento foi atualizada com sucesso!"
'People will be able to see but not modify your model': 'As pessoas poderão ver, mas não modificar seu modelo',
"Sharing configuration has been updated successfully!": "A configuração de compartilhamento foi atualizada com sucesso!",
"Your model was imported successfully!": "Seu modelo foi importado com sucesso!"
};
10 changes: 10 additions & 0 deletions app/sass/form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ input[type="submit"]:focus {
border-bottom: 1px solid var(--border-default);
margin-bottom: 25px;
}
////////////////////////////////////////////////////////////////////////////////
// .form-group
////////////////////////////////////////////////////////////////////////////////
.form-group .note {
word-break: normal;
font-size: 0.9em;
font-style: italic;
margin: 2px 0 0 4px;
}

////////////////////////////////////////////////////////////////////////////////
// .columnsList
Expand Down Expand Up @@ -184,6 +193,7 @@ input[type="submit"]:focus {

.form-control.error::placeholder {
color: var(--danger-base);
opacity: 0.5;
}

textarea {
Expand Down
15 changes: 8 additions & 7 deletions app/sass/mainHeader.scss
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,19 @@
// Loading
////////////////////////////////////////////////////////////////////////////////
.br-loader {
display: none;
position: fixed;
top: 70px;
left: 50%;
margin-left: -20px;
display: none;
padding: 3px;;
border: 1px solid var(--border-light);
border-radius: 4px;
background-color: var(--white);
}

.br-loader.loading {display: block;}

///////////////////////////////////////////////////////////////////////////////
// .nav-icons dropdown-icon
///////////////////////////////////////////////////////////////////////////////
Expand All @@ -133,9 +139,4 @@

.nav-icons .dropdown-menu > li > a {
color: var(--gray-20);
}

///////////////////////////////////////////////////////////////////////////////
// .br-loader
///////////////////////////////////////////////////////////////////////////////
.br-loader.loading {display: block;}
}
Loading