diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..943ff82
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,14 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Launch Program",
+ "program": "${workspaceFolder}\\serve"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/addon/adapters/sequence.js b/addon/adapters/sequence.js
new file mode 100644
index 0000000..41c783a
--- /dev/null
+++ b/addon/adapters/sequence.js
@@ -0,0 +1,54 @@
+import JSONAPIAdapter from 'ember-data/adapters/json-api';
+import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
+import ENV from 'explorviz-frontend/config/environment';
+
+export default JSONAPIAdapter.extend(DataAdapterMixin,{
+
+ host: ENV.APP.API_ROOT,
+
+ init() {
+
+ this.set('headers', {
+ "Accept": "application/vnd.api+json"
+ });
+
+ },
+
+ urlForUpdateRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/sequences/${id}`;
+ },
+
+ urlForDeleteRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/sequences/${id}`;
+ },
+
+ urlForFindAll() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/sequences/`;
+ },
+ // @Override
+ urlForQueryRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/sequences/`;
+ },
+ urlForFindRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/sequences/${id}`;
+ },
+
+ // @Override
+ // Overrides URL for model.save()
+ urlForCreateRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/sequences/`;
+ },
+
+
+ authorize(xhr) {
+ let { access_token } = this.get('session.data.authenticated');
+ xhr.setRequestHeader('Authorization', `Bearer ${access_token}`);
+ }
+
+});
diff --git a/addon/adapters/step.js b/addon/adapters/step.js
new file mode 100644
index 0000000..0f75576
--- /dev/null
+++ b/addon/adapters/step.js
@@ -0,0 +1,54 @@
+import JSONAPIAdapter from 'ember-data/adapters/json-api';
+import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
+import ENV from 'explorviz-frontend/config/environment';
+
+export default JSONAPIAdapter.extend(DataAdapterMixin,{
+
+ host: ENV.APP.API_ROOT,
+
+ init() {
+
+ this.set('headers', {
+ "Accept": "application/vnd.api+json"
+ });
+
+ },
+
+ urlForUpdateRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/steps/${id}`;
+ },
+
+ urlForDeleteRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/steps/${id}`;
+ },
+
+ urlForFindAll() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/steps/`;
+ },
+ // @Override
+ urlForQueryRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/steps`;
+ },
+ urlForFindRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/steps/${id}`;
+ },
+
+ // @Override
+ // Overrides URL for model.save()
+ urlForCreateRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/steps/`;
+ },
+
+
+ authorize(xhr) {
+ let { access_token } = this.get('session.data.authenticated');
+ xhr.setRequestHeader('Authorization', `Bearer ${access_token}`);
+ }
+
+});
diff --git a/addon/adapters/tutorial.js b/addon/adapters/tutorial.js
new file mode 100644
index 0000000..e4b6a55
--- /dev/null
+++ b/addon/adapters/tutorial.js
@@ -0,0 +1,54 @@
+import JSONAPIAdapter from 'ember-data/adapters/json-api';
+import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
+import ENV from 'explorviz-frontend/config/environment';
+
+export default JSONAPIAdapter.extend(DataAdapterMixin,{
+
+ host: ENV.APP.API_ROOT,
+
+ init() {
+
+ this.set('headers', {
+ "Accept": "application/vnd.api+json"
+ });
+
+ },
+
+ urlForUpdateRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/${id}`;
+ },
+
+ urlForDeleteRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/${id}`;
+ },
+
+ urlForFindAll() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/`;
+ },
+ // @Override
+ urlForQueryRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials`;
+ },
+ urlForFindRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/${id}`;
+ },
+
+ // @Override
+ // Overrides URL for model.save()
+ urlForCreateRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/`;
+ },
+
+
+ authorize(xhr) {
+ let { access_token } = this.get('session.data.authenticated');
+ xhr.setRequestHeader('Authorization', `Bearer ${access_token}`);
+ }
+
+});
diff --git a/addon/adapters/tutoriallandscape.js b/addon/adapters/tutoriallandscape.js
new file mode 100644
index 0000000..5579174
--- /dev/null
+++ b/addon/adapters/tutoriallandscape.js
@@ -0,0 +1,53 @@
+import JSONAPIAdapter from 'ember-data/adapters/json-api';
+import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
+import ENV from 'explorviz-frontend/config/environment';
+
+export default JSONAPIAdapter.extend(DataAdapterMixin,{
+
+ host: ENV.APP.API_ROOT,
+
+ init() {
+
+ this.set('headers', {
+ "Accept": "application/vnd.api+json"
+ });
+
+ },
+
+ urlForUpdateRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/landscapes/${id}`;
+ },
+
+ urlForDeleteRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/landscapes/${id}`;
+ },
+ urlForFindAll() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/landscapes/all`;
+ },
+ // @Override
+ urlForQueryRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/landscapes/by-timestamp`;
+ },
+ urlForFindRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/landscapes/${id}`;
+ },
+
+ // @Override
+ // Overrides URL for model.save()
+ urlForCreateRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/landscapes/import`;
+ },
+
+
+ authorize(xhr) {
+ let { access_token } = this.get('session.data.authenticated');
+ xhr.setRequestHeader('Authorization', `Bearer ${access_token}`);
+ }
+
+});
diff --git a/addon/adapters/tutorialtimestamp.js b/addon/adapters/tutorialtimestamp.js
new file mode 100644
index 0000000..de5106f
--- /dev/null
+++ b/addon/adapters/tutorialtimestamp.js
@@ -0,0 +1,53 @@
+import JSONAPIAdapter from 'ember-data/adapters/json-api';
+import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
+import ENV from 'explorviz-frontend/config/environment';
+
+export default JSONAPIAdapter.extend(DataAdapterMixin,{
+
+ host: ENV.APP.API_ROOT,
+
+ init() {
+
+ this.set('headers', {
+ "Accept": "application/vnd.api+json"
+ });
+
+ },
+
+ urlForUpdateRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/timestamps/${id}`;
+ },
+
+ urlForDeleteRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/timestamps/${id}`;
+ },
+ urlForFindAll() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/timestamps/`;
+ },
+ // @Override
+ urlForQueryRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/timestamps/`;
+ },
+ urlForFindRecord(id) {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/timestamps/${id}`;
+ },
+
+ // @Override
+ // Overrides URL for model.save()
+ urlForCreateRecord() {
+ const baseUrl = this.buildURL();
+ return `${baseUrl}/v1/tutorials/timestamps/import`;
+ },
+
+
+ authorize(xhr) {
+ let { access_token } = this.get('session.data.authenticated');
+ xhr.setRequestHeader('Authorization', `Bearer ${access_token}`);
+ }
+
+});
diff --git a/addon/components/application-interaction.js b/addon/components/application-interaction.js
new file mode 100644
index 0000000..0368cf2
--- /dev/null
+++ b/addon/components/application-interaction.js
@@ -0,0 +1,9 @@
+import Interaction from 'explorviz-frontend/utils/application-rendering/interaction'
+import { inject as service } from "@ember/service";
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+
+export default Interaction.extend(AlertifyHandler,{
+ landscapeService: service(),
+ tutorialService: service(),
+ store: service()
+});
diff --git a/addon/components/application-visualization.js b/addon/components/application-visualization.js
new file mode 100644
index 0000000..0dca032
--- /dev/null
+++ b/addon/components/application-visualization.js
@@ -0,0 +1,92 @@
+import layout from '../templates/components/application-visualization';
+import ApplicationRendering from 'explorviz-frontend/components/visualization/rendering/application-rendering';
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+import { inject as service } from '@ember/service';
+export default ApplicationRendering.extend(AlertifyHandler,{
+ layout,
+ renderingService: service(),
+ tutorialService: service(),
+ landscapeService: service(),
+ interactionModel:null,
+ initInteraction(){
+ this._super(...arguments);
+ const self = this;
+ if(this.get('runmode')){
+ this.set('interaction.model',this.get('tutorialService.activeStep'));
+ }else{
+ this.set('interaction.model',this.get('interactionModel'));
+ }
+ this.set('interaction.completed',this.get('completed'));
+ this.set('interaction.runmode',this.get('runmode'));
+ this.get('interaction').on('singleClick', this.get('clickListenerSingle'));
+ this.get('interaction').on('doubleClick', this.get('clickListenerDouble'));
+ },
+ cleanup(){
+ this._super(...arguments);
+ this.get('interaction').off('singleClick',this, this.clickListenerSingle);
+ this.get('interaction').off('doubleClick',this, this.clickListenerDouble);
+ },
+ willDestroyElement(){
+ this._super(...arguments);
+ this.get('interaction').off('singleClick',this, this.clickListenerSingle);
+ this.get('interaction').off('doubleClick',this, this.clickListenerDouble);
+ },
+ clickListenerSingle(emberModel){
+ if(emberModel!=undefined){
+ if(this.get('selectTarget')){
+ this.set("model.targetType",emberModel.get('constructor.modelName'));
+ this.set("model.targetId",emberModel.get("id"));
+ this.set("model.actionType","singleClick");
+ this.set('selectTarget',false);
+ this.showAlertifyMessage(`Target selected 'single click' on '`+emberModel.get('constructor.modelName')+"' with name '"+emberModel.get('name')+"'");
+ }else{
+ if(this.get("model.targetType")==emberModel.get('constructor.modelName') && this.get("model.targetId")==emberModel.get("id")&& this.get('model.actionType')=="singleClick"){
+ if(this.get("runmode")){
+ this.completed(this.get('model'));
+ }
+ }
+ }
+ }
+ },
+ clickListenerDouble(emberModel){
+ if(emberModel!=undefined){
+ if(this.get('selectTarget')){
+ this.set("model.targetType",emberModel.get('constructor.modelName'));
+ this.set("model.targetId",emberModel.get("id"));
+ this.set("model.actionType","doubleClick");
+ this.set('selectTarget',false);
+ this.showAlertifyMessage(`Target selected 'double click' on '`+emberModel.get('constructor.modelName')+"'");
+ }else{
+ if(this.get("model.targetType")==emberModel.get('constructor.modelName') && this.get("model.targetId")==emberModel.get("id")&& this.get('model.actionType')=="doubleClick"){
+ if(this.get("runmode")){
+ this.completed(this.get('model'));
+ }
+ }
+ }
+ }
+ },
+ completed(laststep){
+ if(this.get('runmode')){
+ var step = this.get('tutorialService').getNextStep(laststep);
+ if(step){
+ this.get('tutorialService').getSequence(step).then((sequence)=>{
+ if(sequence.get('landscapeTimestamp')!=undefined){
+ this.get('landscapeService').loadLandscape(sequence);
+ }else{
+ this.get('tutorialService').getTutorial(sequence).then((tutorial)=>{
+ if(tutorial.get('landscapeTimestamp')!=undefined){
+ this.get('landscapeService').loadLandscape(tutorial);
+ }else{
+ console.log("no landscape defined");
+ }
+ });
+ }
+ });
+ this.get('tutorialService').set('activeStep',step);
+ this.set('model',step);
+ }else{
+ this.showAlertifyMessage(`Last step completed.`);
+ }
+ }
+ }
+});
diff --git a/addon/components/landscape-interaction.js b/addon/components/landscape-interaction.js
new file mode 100644
index 0000000..789de05
--- /dev/null
+++ b/addon/components/landscape-interaction.js
@@ -0,0 +1,9 @@
+import Interaction from 'explorviz-frontend/utils/landscape-rendering/interaction'
+import { inject as service } from "@ember/service";
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+
+export default Interaction.extend(AlertifyHandler,{
+ landscapeService: service(),
+ tutorialService: service(),
+ store: service(),
+});
diff --git a/addon/components/landscape-select/landscapelist.js b/addon/components/landscape-select/landscapelist.js
new file mode 100644
index 0000000..0bad192
--- /dev/null
+++ b/addon/components/landscape-select/landscapelist.js
@@ -0,0 +1,24 @@
+import Component from '@ember/component';
+import layout from '../../templates/components/landscape-select/landscapelist';
+import {inject as service} from '@ember/service';
+
+export default Component.extend({
+ layout,
+ store: service(),
+ landscapeListener: service(),
+ landscapeService: service(),
+ tutorialService: service(),
+ actions:{
+ setTimestamp(model,timestamp){
+ model.set('landscapeTimestamp',timestamp);
+ },
+ showLiveLandscapes(){
+ this.set("landscapeService.livelandscapes",true);
+ this.get('landscapeListener').set('pauseVisualizationReload',false);
+ },
+ hideLiveLandscapes(){
+ this.set("landscapeService.livelandscapes",false);
+ this.get('landscapeListener').set('pauseVisualizationReload',true);
+ },
+ },
+});
diff --git a/addon/components/landscape-select/navbar/toggle-live-landscape.js b/addon/components/landscape-select/navbar/toggle-live-landscape.js
new file mode 100644
index 0000000..e893fd0
--- /dev/null
+++ b/addon/components/landscape-select/navbar/toggle-live-landscape.js
@@ -0,0 +1,28 @@
+import Component from '@ember/component';
+import layout from '../../../templates/components/landscape-select/navbar/toggle-live-landscape';
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+import {inject as service} from '@ember/service';
+
+export default Component.extend(AlertifyHandler,{
+ layout,
+ tagName:'li',
+ landscapeListener: service(),
+ landscapeService: service(),
+ actions:{
+ toggleVisualizationReload() {
+ this.get('landscapeListener').toggleVisualizationReload();
+ if(this.get('landscapeListener,pauseVisualizationReload')){
+ this.get('landscapeService').set('selected',null);
+ }
+ this.handleMessageForUser(this.get('landscapeListener.pauseVisualizationReload'));
+ }
+ },
+ handleMessageForUser(pauseReload) {
+ if(pauseReload){
+ this.showAlertifyMessage("Visualization paused! Tutorial landscapes are shown.");
+ }
+ else {
+ this.showAlertifyMessage("Visualization resumed! Live landscapes will be shown and can be selected.");
+ }
+ }
+});
diff --git a/addon/components/landscape-visualization.js b/addon/components/landscape-visualization.js
new file mode 100644
index 0000000..3bed31e
--- /dev/null
+++ b/addon/components/landscape-visualization.js
@@ -0,0 +1,111 @@
+import layout from '../templates/components/landscape-visualization';
+import LandscapeRendering from 'explorviz-frontend/components/visualization/rendering/landscape-rendering'
+import { inject as service } from '@ember/service';
+import { getOwner } from '@ember/application';
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+
+
+export default LandscapeRendering.extend(AlertifyHandler,{
+ layout,
+ landscapeService:service(),
+ tutorialService:service(),
+ interactionModel: null,
+ setSelectTarget(value){
+ this.set('interaction,selectTarget',value);
+ },
+ initInteraction(){
+ this._super(...arguments);
+ //const self = this;
+
+ if(this.get('runmode')){
+ this.set('interaction.model',this.get('tutorialService.activeStep'));
+ }else{
+ this.set('interaction.model',this.get('interactionModel'));
+ }
+ this.set('interaction.completed',this.get('completed'));
+ this.set('interaction.runmode',this.get('runmode'));
+
+ this.get('interaction').on('showApplication', function (emberModel) {
+ this.set('landscapeService.application', emberModel);
+ // this.trigger('doubleClick', emberModel);
+ });
+
+ this.get('interaction').on('singleClick', this.clickListenerSingle);
+ this.get('interaction').on('doubleClick', this.clickListenerDouble);
+ },
+ cleanup(){
+ this._super(...arguments);
+ this.get('interaction').off('singleClick',this, this.clickListenerSingle);
+ this.get('interaction').off('doubleClick',this, this.clickListenerDouble);
+ },
+ willDestroyElement(){
+ this._super(...arguments);
+ this.get('interaction').off('singleClick',this, this.clickListenerSingle);
+ this.get('interaction').off('doubleClick',this, this.clickListenerDouble);
+ },
+ clickListenerSingle(emberModel){
+ if(emberModel!=undefined){
+ if(this.get('selectTarget')){
+ this.set("model.targetType",emberModel.get('constructor.modelName'));
+ this.set("model.targetId",emberModel.get("id"));
+ this.set("model.actionType","singleClick");
+ this.set('selectTarget',false);
+ this.showAlertifyMessage(`Target selected 'single click' on '`+emberModel.get('constructor.modelName')+"' with name '"+emberModel.get('name')+"'");
+ }else{
+ if(this.get("model.targetType")==emberModel.get('constructor.modelName') && this.get("model.targetId")==emberModel.get("id")&& this.get('model.actionType')=="singleClick"){
+ if(this.get("runmode")){
+ this.completed(this.get('model'));
+ }
+ }
+ }
+ }
+ },
+ clickListenerDouble(emberModel){
+ if(emberModel!=undefined){
+ if(this.get('selectTarget')){
+ this.set("model.targetType",emberModel.get('constructor.modelName'));
+ this.set("model.targetId",emberModel.get("id"));
+ this.set("model.actionType","doubleClick");
+ this.set('selectTarget',false);
+ this.showAlertifyMessage(`Target selected 'double click' on '`+emberModel.get('constructor.modelName')+"'");
+ }else{
+ if(this.get("model.targetType")==emberModel.get('constructor.modelName') && this.get("model.targetId")==emberModel.get("id")&& this.get('model.actionType')=="doubleClick"){
+ if(this.get("runmode")){
+ this.completed(this.get('model'));
+ }
+ }
+ }
+ }
+ },
+ getLandscape(){
+ if(this.get('landscapeService.livelandscapes')){
+ return this.get('landscapeRepo.latestLandscape');
+ }else{
+ return this.get('landscapeService.landscape');
+ }
+ },
+ completed(laststep){
+ if(this.get('runmode')){
+ var step = this.get('tutorialService').getNextStep(laststep);
+ if(step){
+ this.get('tutorialService').getSequence(step).then((sequence)=>{
+ if(sequence.get('landscapeTimestamp')!=undefined){
+ this.get('landscapeService').loadLandscape(sequence);
+ }else{
+ this.get('tutorialService').getTutorial(sequence).then((tutorial)=>{
+ if(tutorial.get('landscapeTimestamp')!=undefined){
+ this.get('landscapeService').loadLandscape(tutorial);
+ }else{
+ console.log("no landscape defined");
+ }
+ });
+ }
+ });
+ this.get('tutorialService').set('activeStep',step);
+ this.set('model',step);
+ }else{
+ this.showAlertifyMessage(`Last step completed.`);
+ }
+ }
+ }
+});
diff --git a/addon/components/sequence-form.js b/addon/components/sequence-form.js
new file mode 100644
index 0000000..cd3527c
--- /dev/null
+++ b/addon/components/sequence-form.js
@@ -0,0 +1,34 @@
+import Component from '@ember/component';
+import layout from '../templates/components/sequence-form';
+import { inject as service } from "@ember/service";
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+
+export default Component.extend(AlertifyHandler,{
+ layout,
+ tutorialService: service(),
+ landscapeService: service(),
+ tagName: "",
+ actions:{
+ toggleSetLandscape(){
+ this.set('landscapeService.selectLandscape',!this.get('landscapeService.selectLandscape'));
+ },
+ saveSequenceChanges(sequence) {
+ if(sequence) {
+ // check for valid input
+ if(!sequence.get('title') || sequence.get('title').length === 0) {
+ this.showAlertifyMessage('Title cannot be empty.');
+ return;
+ }
+ sequence.save()
+ .then(()=> {
+ const message = `Sequence updated.`;
+ this.showAlertifyMessage(message);
+ }, (reason) => {
+ this.showReasonErrorAlert(reason);
+ });
+ } else {
+ this.showAlertifyMessage(`Sequence not found.`);
+ }
+ },
+ }
+});
diff --git a/addon/components/side-form-layout.js b/addon/components/side-form-layout.js
new file mode 100644
index 0000000..4d92fa0
--- /dev/null
+++ b/addon/components/side-form-layout.js
@@ -0,0 +1,84 @@
+import Component from '@ember/component';
+import layout from '../templates/components/side-form-layout';
+import { inject as service } from "@ember/service";
+import { computed } from '@ember/object';
+
+export default Component.extend({
+ layout,
+ tagName: "",
+ store: service(),
+ tutorialService: service(),
+ landscapeService: service(),
+ renderingService: service(),
+ landscapeRepo: service("repos/landscape-repository"),
+ landscapeListener: service(),
+ currentUser: service(),
+ showLandscape: computed('landscapeService.application', function() {
+ return !this.get('landscapeService.application');
+ }),
+ selectMode: computed('landscapeService.selectLandscape',function(){
+ if(this.get('model.constructor.modelName')=="tutorial" || this.get('model.constructor.modelName')=="sequence"){
+ return this.get('landscapeService.selectLandscape') ;
+ }
+ return false;
+ }),
+ liveMode: computed('landscapeService.livelandscapes','selectMode', function() {
+ if(this.get('model.constructor.modelName')=="tutorial" || this.get('model.constructor.modelName')=="sequence"){
+ return this.get('selectMode') && this.get('landscapeService.livelandscapes');
+ }
+ return false;
+ }),
+ actions: {
+
+ resetView() {
+ this.get('renderingService').reSetupScene();
+ },
+ openLandscapeView() {
+ this.set('landscapeService.application', null);
+ },
+ toggleTimeline() {
+ this.get('renderingService').toggleTimeline();
+ },
+ showLiveLandscapes(){
+ this.set("landscapeService.livelandscapes",true);
+ this.get('landscapeListener').set('pauseVisualizationReload',false);
+ },
+ hideLiveLandscapes(){
+ this.set('landscapeService.livelandscapes',false);
+ this.get('landscapeListener').set('pauseVisualizationReload',true);
+ },
+ toggleSelectTarget(interaction,model){
+ interaction.set('model',model);
+ interaction.set('selectTarget',!interaction.get('selectTarget'));
+ }
+ },
+ init(){
+ this._super(...arguments);
+ this.get('landscapeService').updateLandscapeList(true);
+ this.get('landscapeListener').initSSE();
+ this.get('landscapeListener').set('pauseVisualizationReload',true);
+ },
+ showTimeline() {
+ this.set('renderingService.showTimeline', true);
+ },
+
+ hideVersionbar(){
+ this.set('renderingService.showVersionbar', false);
+ },
+
+ initRendering() {
+ this.get('landscapeListener').initSSE();
+ this.get('additionalData').on('showWindow', this, this.onShowWindow);
+ },
+
+ onShowWindow() {
+ this.get('renderingService').resizeCanvas();
+ },
+
+ // @Override
+ cleanup() {
+ this._super(...arguments);
+ this.get('additionalData').off('showWindow', this, this.onShowWindow);
+ },
+
+});
diff --git a/addon/components/step-form.js b/addon/components/step-form.js
new file mode 100644
index 0000000..1161ba4
--- /dev/null
+++ b/addon/components/step-form.js
@@ -0,0 +1,85 @@
+import Component from '@ember/component';
+import layout from '../templates/components/step-form';
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+import { inject as service } from "@ember/service";
+import { computed } from '@ember/object';
+
+export default Component.extend(AlertifyHandler,{
+ layout,
+ tagName: "",
+ tutorialService: service(),
+ landscapeService: service(),
+ store: service(),
+ nextStepAvailable: computed("model",function(){
+ return this.get('tutorialService').getNextStep(this.get('model'));
+ }),
+ targetName: computed("model.targetId","model.targetType",function(){
+ if(this.get("model.targetType")==undefined ||this.get("model.targetId")==undefined){
+ return "";
+ }
+ let object = this.get('store').peekRecord(this.get("model.targetType"),this.get("model.targetId"));
+ if(object!=undefined){
+ return object.get('name');
+ }
+ return "";
+ }),
+ actions:{
+ skipStep(){
+ var step = this.get('tutorialService').getNextStep(this.get('model'));
+ if(step){
+ this.get('tutorialService').getSequence(step).then((sequence)=>{
+ if(sequence.get('landscapeTimestamp')!=undefined){
+ this.get('landscapeService').loadLandscape(sequence);
+ }else{
+ this.get('tutorialService').getTutorial(sequence).then((tutorial)=>{
+ if(tutorial.get('landscapeTimestamp')!=undefined){
+ this.get('landscapeService').loadLandscape(tutorial);
+ }else{
+ console.log("no landscape defined");
+ }
+ });
+ }
+ });
+ this.get('tutorialService').set('activeStep',step);
+ this.get('landscapeService').setInteractionModel(step);
+ }else{
+ this.showAlertifyMessage(`Last step completed.`);
+ }
+ },
+ saveStepChanges(step) {
+ if(step) {
+ // check for valid input
+ if(!step.get('title') || step.get('title').length === 0) {
+ this.showAlertifyMessage('Title cannot be empty.');
+ return;
+ }
+ step.save()
+ .then(()=> {
+ const message = `Step updated.`;
+ this.showAlertifyMessage(message);
+ }, (reason) => {
+ this.showReasonErrorAlert(reason);
+ });
+ } else {
+ this.showAlertifyMessage(`Step not found.`);
+ }
+ },
+ toggleSelectTarget(){
+ if(this.get('landscapeService.application')){
+ this.set('landscapeService.applicationinteraction.selectTarget',!this.get('landscapeService.applicationinteraction.selectTarget'));
+ this.set('')
+ }else{
+ this.set('landscapeService.landscapeinteraction.selectTarget',!this.get('landscapeService.landscapeinteraction.selectTarget'));
+ }
+ },
+ removeTarget(){
+ this.set('model.targetType',"");
+ this.set('model.targetId',"");
+ this.set('model.actionType',"");
+ }
+},
+showReasonErrorAlert(reason) {
+ const {title, detail} = reason.errors[0];
+ this.showAlertifyMessage(`${title}: ${detail}`);
+},
+});
diff --git a/addon/components/timeline.js b/addon/components/timeline.js
new file mode 100644
index 0000000..cb2abb9
--- /dev/null
+++ b/addon/components/timeline.js
@@ -0,0 +1,38 @@
+import Timeline from 'explorviz-frontend/components/visualization/page-setup/timeline/timeline';
+//import layout from 'explorviz-frontend/templates/components/visualization/page-setup/timeline/timeline'
+
+import layout from '../templates/components/timeline'
+
+import {inject as service} from '@ember/service';
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+
+export default Timeline.extend(AlertifyHandler,{
+ layout,
+ landscapeService: service(),
+ landscapeListener: service(),
+ chartClickHandler(evt) {
+ this._super(...arguments);
+ if(this.get('timelineChart').getElementAtEvent(evt)[0]){
+ this.set('importLandscape',true);
+ this.set('tutorialActivePoint',this.get('timelineChart').getElementAtEvent(evt)[0]);
+ }
+ },
+ actions:{
+ submit(){
+ if ( this.get('tutorialActivePoint')) {
+ this.get('landscapeListener').set('pauseVisualizationReload',true);
+ this.get('landscapeService').importLandscape(this.get('tutorialActivePoint')._chart.data.datasets[this.get('tutorialActivePoint')._datasetIndex].data[this.get('tutorialActivePoint')._index].x,this.get('landscapeName'));
+ this.set('model.landscapeTimestamp',this.get('tutorialActivePoint')._chart.data.datasets[this.get('tutorialActivePoint')._datasetIndex].data[this.get('tutorialActivePoint')._index].x);
+ this.get('landscapeService').set('livelandscapes',false);
+ if(this.get('landscapeService.mockBackend')){
+ this.get('landscapeService').set('selectLandscape',false);
+ this.showAlertifyMessage("Mock landscape is active. Saved landscapes cannot be selected.");
+ this.showAlertifyMessage("Please click 'Save it' to persist the selected Lanscape.");
+ }
+ }
+ },
+ close(){
+ this.get('landscapeListener').set('pauseVisualizationReload',false);
+ }
+ }
+});
diff --git a/addon/components/tutorial-form.js b/addon/components/tutorial-form.js
new file mode 100644
index 0000000..5311969
--- /dev/null
+++ b/addon/components/tutorial-form.js
@@ -0,0 +1,22 @@
+import Component from '@ember/component';
+import layout from '../templates/components/tutorial-form';
+import { inject as service } from "@ember/service";
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+
+export default Component.extend(AlertifyHandler,{
+ layout,
+ tutorialService: service(),
+ landscapeService: service(),
+ tagName: "",
+ actions:{
+ saveTutorialChanges(tutorial){
+ this.get('tutorialService').saveTutorialChanges(tutorial);
+ this.set('landscapeService.livelandscapes',false);
+ this.set('landscapeService.selectLandscape',false);
+ },
+ toggleSetLandscape(){
+ this.set('landscapeService.selectLandscape',!this.get('landscapeService.selectLandscape'));
+ },
+
+ }
+});
diff --git a/addon/controllers/tutorial.js b/addon/controllers/tutorial.js
index 30289de..f7d3838 100644
--- a/addon/controllers/tutorial.js
+++ b/addon/controllers/tutorial.js
@@ -1,17 +1,17 @@
import Controller from '@ember/controller';
+import { inject as service } from "@ember/service";
export default Controller.extend({
+ store: service(),
+ renderingService: service("rendering-service"),
+ setupController(controller, model) {
+ this._super(controller, model);
+ controller.initRendering();
-
-actions: {
- // body
- selectedSingleFile(){
-
-
- },
- addTutorial(){
-
+ },
+ actions: {
+ resetRoute() {
+ //const routeName = this.get('tutorial');
+ }
}
-}
-
});
diff --git a/addon/controllers/tutorial/list.js b/addon/controllers/tutorial/list.js
new file mode 100644
index 0000000..bf7e02d
--- /dev/null
+++ b/addon/controllers/tutorial/list.js
@@ -0,0 +1,54 @@
+import Controller from '@ember/controller';
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+import { inject as service } from "@ember/service";
+
+export default Controller.extend(AlertifyHandler,{
+ tutorialService: service(),
+ currentUser: service(),
+
+ actions: {
+ toggleTutorial(tutorial){
+ tutorial.set('expanded',!tutorial.get('expanded'));
+ //this.get('tutorialService').expandTutorial(tutorial);
+ },
+ toggleSequence(sequence){
+ sequence.set('expanded',!sequence.get('expanded'));
+ //this.get('tutorialService').expandTutorial(tutorial);
+ },
+ addNewTutorial(){
+ let newTutorial = this.get('store').createRecord("tutorial",{
+ title: "new tutorial"
+ })
+ newTutorial.save();
+ },
+ addNewSequence(tutorial){
+ let newSequence = this.get('store').createRecord("sequence",{
+ title: "new sequence"
+ })
+ tutorial.set('expanded',true);
+ tutorial.get('sequences').pushObject(newSequence);
+ newSequence.save().then(function () {
+ tutorial.save();
+ });
+ },
+ addNewStep(sequence){
+ let newStep = this.get('store').createRecord("step",{
+ title: "new step"
+ })
+ sequence.set('expanded',true);
+ sequence.get('steps').pushObject(newStep);
+ newStep.save().then(function () {
+ sequence.save();
+ });
+ },
+ deleteStep(step){
+ step.destroyRecord();
+ },
+ deleteSequence(sequence){
+ sequence.destroyRecord();
+ },
+ deleteTutorial(tutorial){
+ tutorial.destroyRecord();
+ }
+ }
+});
diff --git a/addon/controllers/tutorial/run.js b/addon/controllers/tutorial/run.js
new file mode 100644
index 0000000..e229e23
--- /dev/null
+++ b/addon/controllers/tutorial/run.js
@@ -0,0 +1,10 @@
+import Controller from '@ember/controller';
+import { inject as service } from "@ember/service";
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+
+
+export default Controller.extend(AlertifyHandler,{
+ tutorialService:service(),
+ landscapeService:service(),
+ currentUser: service()
+});
diff --git a/addon/controllers/tutorial/sequence.js b/addon/controllers/tutorial/sequence.js
new file mode 100644
index 0000000..a82a9b9
--- /dev/null
+++ b/addon/controllers/tutorial/sequence.js
@@ -0,0 +1,33 @@
+import Controller from '@ember/controller';
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+import { inject as service } from "@ember/service";
+
+export default Controller.extend(AlertifyHandler,{
+ tutorialService:service(),
+ landscapeService:service(),
+ actions:{
+ saveSequenceChanges(sequence) {
+ if(sequence) {
+ // check for valid input
+ if(!sequence.get('title') || sequence.get('title').length === 0) {
+ this.showAlertifyMessage('Title cannot be empty.');
+ return;
+ }
+
+ sequence.save()
+ .then(()=> {
+ const message = `Sequence updated.`;
+ this.showAlertifyMessage(message);
+ }, (reason) => {
+ this.showReasonErrorAlert(reason);
+ });
+ } else {
+ this.showAlertifyMessage(`Sequence not found.`);
+ }
+ },
+ },
+ showReasonErrorAlert(reason) {
+ const {title, detail} = reason.errors[0];
+ this.showAlertifyMessage(`${title}: ${detail}`);
+ },
+});
diff --git a/addon/controllers/tutorial/step.js b/addon/controllers/tutorial/step.js
new file mode 100644
index 0000000..632c314
--- /dev/null
+++ b/addon/controllers/tutorial/step.js
@@ -0,0 +1,33 @@
+import Controller from '@ember/controller';
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+import { inject as service } from "@ember/service";
+
+export default Controller.extend(AlertifyHandler,{
+ tutorialService:service(),
+ landscapeService:service(),
+ actions:{
+ saveStepChanges(step) {
+ if(step) {
+ // check for valid input
+ if(!step.get('title') || step.get('title').length === 0) {
+ this.showAlertifyMessage('Title cannot be empty.');
+ return;
+ }
+
+ step.save()
+ .then(()=> {
+ const message = `Step updated.`;
+ this.showAlertifyMessage(message);
+ }, (reason) => {
+ this.showReasonErrorAlert(reason);
+ });
+ } else {
+ this.showAlertifyMessage(`Step not found.`);
+ }
+ },
+},
+showReasonErrorAlert(reason) {
+ const {title, detail} = reason.errors[0];
+ this.showAlertifyMessage(`${title}: ${detail}`);
+},
+});
diff --git a/addon/controllers/tutorial/tutorial.js b/addon/controllers/tutorial/tutorial.js
new file mode 100644
index 0000000..86f41a8
--- /dev/null
+++ b/addon/controllers/tutorial/tutorial.js
@@ -0,0 +1,8 @@
+import Controller from '@ember/controller';
+import { inject as service } from "@ember/service";
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+
+export default Controller.extend(AlertifyHandler,{
+ tutorialService:service(),
+ landscapeService:service(),
+});
diff --git a/addon/instance-initializers/explorviz-frontend-extension-tutorial.js b/addon/instance-initializers/explorviz-frontend-extension-tutorial.js
index 1c64bbc..636068e 100644
--- a/addon/instance-initializers/explorviz-frontend-extension-tutorial.js
+++ b/addon/instance-initializers/explorviz-frontend-extension-tutorial.js
@@ -9,11 +9,17 @@ export function initialize(appInstance) {
}
Router.map(function() {
- this.route("tutorial");
+ this.route("tutorial", function(){
+ this.route("list", { path: '/list' });
+ this.route('tutorial', { path: '/:tutorial_id' });
+ this.route('sequence', { path: '/sequence/:sequence_id' });
+ this.route('step', { path: '/step/:step_id' });
+ this.route('run', { path: '/run/:tutorial_id' });
+ });
});
}
export default {
name: 'explorviz-frontend-extension-tutorial',
- initialize
+ initialize: initialize
};
diff --git a/addon/models/sequence.js b/addon/models/sequence.js
new file mode 100644
index 0000000..6ce81d3
--- /dev/null
+++ b/addon/models/sequence.js
@@ -0,0 +1,11 @@
+import DS from 'ember-data';
+
+export default DS.Model.extend({
+ title: DS.attr('string'),
+ text: DS.attr('string'),
+ landscapeTimestamp: DS.attr('string'),
+ steps: DS.hasMany('step',{async:false}),
+ containsSteps: function() {
+ return this.get('steps.length')>0;
+ }.property('steps')
+});
diff --git a/addon/models/step.js b/addon/models/step.js
new file mode 100644
index 0000000..293f5b5
--- /dev/null
+++ b/addon/models/step.js
@@ -0,0 +1,9 @@
+import DS from 'ember-data';
+
+export default DS.Model.extend({
+ title: DS.attr('string'),
+ text: DS.attr('string'),
+ targetId: DS.attr('string'),
+ targetType: DS.attr('string'),
+ actionType: DS.attr('string'),
+});
diff --git a/addon/models/tutorial.js b/addon/models/tutorial.js
index 99ec896..fd88709 100644
--- a/addon/models/tutorial.js
+++ b/addon/models/tutorial.js
@@ -2,8 +2,9 @@ import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
- sequences: hasMany('tutorialSequence', {
- inverse: 'parentTutorial'
- }),
-
+ landscapeTimestamp: DS.attr('string'),
+ sequences: DS.hasMany('sequence',{async:false}),
+ containsSequences: function() {
+ return this.get('sequences.length')>0;
+ }.property('sequences')
});
diff --git a/addon/models/tutorialSequence.js b/addon/models/tutorialSequence.js
deleted file mode 100644
index 499600b..0000000
--- a/addon/models/tutorialSequence.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import DS from 'ember-data';
-
-export default DS.Model.extend({
- title: DS.attr('string'),
- text: DS.attr('string'),
-
- action: DS.attr('string'),
- target: DS.attr('string'),
-
- landscape: belongsTo('landscape'),
- parentTutorial: belongsTo('tutorial'),
- steps: hasMany('tutorialStep', {
- inverse: 'parentSequence'
- }),
-});
diff --git a/addon/models/tutorialStep.js b/addon/models/tutorialStep.js
deleted file mode 100644
index b1a6034..0000000
--- a/addon/models/tutorialStep.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import DS from 'ember-data';
-
-export default DS.Model.extend({
- title: DS.attr('string'),
- text: DS.attr('string'),
- action: DS.attr('string'),
- target: DS.attr('string'),
-
- parentSequence: belongsTo('tutorialSequence'),
-});
diff --git a/addon/models/tutoriallandscape.js b/addon/models/tutoriallandscape.js
new file mode 100644
index 0000000..5a53c86
--- /dev/null
+++ b/addon/models/tutoriallandscape.js
@@ -0,0 +1,23 @@
+import DS from 'ember-data';
+import Landscape from "explorviz-frontend/models/landscape"
+const { belongsTo, hasMany } = DS;
+
+export default Landscape.extend({
+ timestamp: belongsTo('tutorialtimestamp'),
+
+ events: hasMany('event', {
+ inverse: null,
+ async: false
+ }),
+
+ systems: hasMany('system', {
+ inverse: 'parent',
+ async: false
+ }),
+
+ // list of applicationCommunication for rendering purposes
+ totalApplicationCommunications: hasMany('applicationcommunication', {
+ inverse: null,
+ async: false
+ }),
+});
diff --git a/addon/models/tutorialtimestamp.js b/addon/models/tutorialtimestamp.js
new file mode 100644
index 0000000..9f30ee5
--- /dev/null
+++ b/addon/models/tutorialtimestamp.js
@@ -0,0 +1,7 @@
+import Timestamp from "explorviz-frontend/models/timestamp"
+import DS from 'ember-data';
+
+export default Timestamp.extend({
+ name: DS.attr('String'),
+ timestamp: DS.attr('String')
+});
diff --git a/addon/routes/tutorial.js b/addon/routes/tutorial.js
index 79f4fed..0db5cc4 100644
--- a/addon/routes/tutorial.js
+++ b/addon/routes/tutorial.js
@@ -1,20 +1,10 @@
import BaseRoute from 'explorviz-frontend/routes/base-route';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-import { getOwner } from '@ember/application';
-import { inject as service } from "@ember/service";
export default BaseRoute.extend(AuthenticatedRouteMixin, {
- setupController(controller, model) {
- // Call _super for default behavior
-
-
- },
- actions: {
- // @Override BaseRoute
- resetRoute() {
- const routeName = this.get('tutorial');
- },
-
- }
-
+ actions: {
+ resetRoute() {
+ //const routeName = this.get('tutorial');
+ },
+ }
});
diff --git a/addon/routes/tutorial/index.js b/addon/routes/tutorial/index.js
new file mode 100644
index 0000000..1d24f43
--- /dev/null
+++ b/addon/routes/tutorial/index.js
@@ -0,0 +1,12 @@
+import BaseRoute from 'explorviz-frontend/routes/base-route';
+
+export default BaseRoute.extend({
+ beforeModel: function() {
+ this.transitionTo("tutorial.list");
+ },
+ actions: {
+ resetRoute() {
+ //const routeName = this.get('tutorial');
+ },
+ }
+});
diff --git a/addon/routes/tutorial/list.js b/addon/routes/tutorial/list.js
new file mode 100644
index 0000000..961cdf3
--- /dev/null
+++ b/addon/routes/tutorial/list.js
@@ -0,0 +1,16 @@
+import BaseRoute from 'explorviz-frontend/routes/base-route';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+import RSVP from 'rsvp';
+
+export default BaseRoute.extend(AuthenticatedRouteMixin, {
+ model() {
+ return RSVP.hash({
+ tutorials: this.get('store').findAll('tutorial')
+ });
+ },
+ actions: {
+ resetRoute() {
+ //const routeName = this.get('tutorial');
+ },
+ }
+});
diff --git a/addon/routes/tutorial/run.js b/addon/routes/tutorial/run.js
new file mode 100644
index 0000000..deeead6
--- /dev/null
+++ b/addon/routes/tutorial/run.js
@@ -0,0 +1,36 @@
+import BaseRoute from 'explorviz-frontend/routes/base-route';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default BaseRoute.extend(AuthenticatedRouteMixin, {
+ model(params) {
+ var val = this.get('store').findRecord('tutorial', params.tutorial_id);
+ return val;
+ },
+ setupController(controller, model) {
+ this._super(...arguments);
+ controller.get('tutorialService').initService(model);
+ controller.get('landscapeService').updateLandscapeList(true);
+ controller.set('landscapeService.liveMode',false);
+
+ var step = controller.get('tutorialService').getNextStep();
+ controller.set('tutorialService.activeStep',step);
+
+ controller.set('landscapeService.landscape',null);
+ controller.set('landscapeService.application', null);
+
+ controller.get('tutorialService').getSequence(step).then((sequence)=>{
+ if(sequence!=undefined && sequence.get('landscapeTimestamp')!=undefined){
+ controller.get('landscapeService').loadLandscape(sequence);
+ }else{
+ controller.get('landscapeService').loadLandscape(model);
+ }
+ });
+
+ },
+ actions: {
+ // @Override BaseRoute
+ resetRoute() {
+ //const routeName = this.get('tutorial');
+ },
+ }
+});
diff --git a/addon/routes/tutorial/sequence.js b/addon/routes/tutorial/sequence.js
new file mode 100644
index 0000000..e15df58
--- /dev/null
+++ b/addon/routes/tutorial/sequence.js
@@ -0,0 +1,35 @@
+import BaseRoute from 'explorviz-frontend/routes/base-route';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default BaseRoute.extend(AuthenticatedRouteMixin, {
+ model(params) {
+ return this.get('store').findRecord('sequence', params.sequence_id);
+ },
+ setupController(controller, model) {
+ this._super(...arguments);
+ controller.set('landscapeService.liveMode',false);
+ controller.get('landscapeService').updateLandscapeList(true);
+
+ controller.set('landscapeService.landscape',null);
+ controller.set('landscapeService.application', null);
+
+ if(controller.get('currentUser.user.isAdmin')){
+ controller.set('runmode',false);
+ }
+ if(model.get('landscapeTimestamp')!=undefined){
+ controller.get('landscapeService').loadLandscape(model);
+ }else{
+ controller.get('tutorialService').getTutorial(model).then((tutorial)=>{
+ controller.get('landscapeService').loadLandscape(tutorial);
+ });
+ }
+ //controller.get('landscapeService').loadLandscape(model.get('tutorial'));
+ },
+ actions: {
+ // @Override BaseRoute
+ resetRoute() {
+ //const routeName = this.get('tutorial');
+ },
+ }
+
+});
diff --git a/addon/routes/tutorial/step.js b/addon/routes/tutorial/step.js
new file mode 100644
index 0000000..731c022
--- /dev/null
+++ b/addon/routes/tutorial/step.js
@@ -0,0 +1,38 @@
+import BaseRoute from 'explorviz-frontend/routes/base-route';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default BaseRoute.extend(AuthenticatedRouteMixin, {
+ model(params) {
+ return this.get('store').findRecord('step',params.step_id);
+ },
+ setupController(controller, model) {
+ controller.set('landscapeService.liveMode',false);
+ controller.get('landscapeService').updateLandscapeList(true);
+
+ controller.set('landscapeService.landscape',null);
+ controller.set('landscapeService.application', null);
+
+ controller.get('tutorialService').getSequence(model).then((sequence)=>{
+ if(sequence.get('landscapeTimestamp')!=undefined){
+ controller.get('landscapeService').loadLandscape(sequence);
+ }else{
+ controller.get('tutorialService').getTutorial(sequence).then((tutorial)=>{
+ controller.get('landscapeService').loadLandscape(tutorial);
+ });
+ }
+ });
+
+ if(controller.get('currentUser.user.isAdmin')){
+ controller.set('runmode',false);
+ }
+ this._super(...arguments);
+
+ },
+ actions: {
+ // @Override BaseRoute
+ resetRoute() {
+ //const routeName = this.get('tutorial');
+ },
+ }
+
+});
diff --git a/addon/routes/tutorial/tutorial.js b/addon/routes/tutorial/tutorial.js
new file mode 100644
index 0000000..6abe5c9
--- /dev/null
+++ b/addon/routes/tutorial/tutorial.js
@@ -0,0 +1,27 @@
+import BaseRoute from 'explorviz-frontend/routes/base-route';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default BaseRoute.extend(AuthenticatedRouteMixin, {
+ model(params) {
+ return this.get('store').findRecord('tutorial', params.tutorial_id);
+ },
+ setupController(controller, model) {
+ this._super(...arguments);
+ controller.get('landscapeService').updateLandscapeList(true);
+ controller.set('landscapeService.landscape',null);
+ controller.set('landscapeService.application', null);
+
+ controller.get('landscapeService').loadLandscape(model);
+ controller.set('landscapeService.liveMode',false);
+ if(controller.get('currentUser.user.isAdmin')){
+ controller.set('runmode',false);
+ }
+ },
+ actions: {
+ // @Override BaseRoute
+ resetRoute() {
+ //const routeName = this.get('tutorial');
+ },
+ }
+
+});
diff --git a/addon/serializers/tutoriallandscape.js b/addon/serializers/tutoriallandscape.js
new file mode 100644
index 0000000..c7ae62a
--- /dev/null
+++ b/addon/serializers/tutoriallandscape.js
@@ -0,0 +1,131 @@
+import LandscapeSerializer from "explorviz-frontend/serializers/landscape"
+import SaveRelationshipsMixin from 'ember-data-save-relationships';
+
+
+
+
+export default LandscapeSerializer.extend(SaveRelationshipsMixin,{
+ attrs: {
+ systems:{serialize:true},
+ totalApplicationCommunications:{serialize:true}
+ },
+ payloadKeyFromModelName(model){
+ return model;
+ },
+ serializeRecordForIncluded(key,relationship){
+ if (relationship.kind === 'belongsTo') {
+ var nextSnapshot = this.belongsTo(key);
+ nextSnapshot.serializedTypes=this.serializedTypes;
+ nextSnapshot.included=this.included;
+ if(nextSnapshot.record.threeJSModel!=undefined){
+ nextSnapshot.record.set('threeJSModel', null);
+ }
+ if(this.serializedTypes.indexOf(nextSnapshot.get('id'))==-1){
+ this.serializedTypes.push(nextSnapshot.get('id'));
+ nextSnapshot.serializeRecordForIncluded=this.serializeRecordForIncluded;
+ if(nextSnapshot.record.get('id')!=undefined){
+ this.included.push(nextSnapshot.record.serialize({includeId:true}).data);
+ }
+ nextSnapshot.eachRelationship(this.serializeRecordForIncluded,nextSnapshot)
+ this.included.concat(nextSnapshot.included);
+ }
+ }else if (relationship.kind === 'hasMany') {
+ var self=this;
+ var nkey=key;
+ var hasmany=this.hasMany(nkey);
+ hasmany.forEach(function(v){
+ if(v.record.threeJSModel!=undefined){
+ v.record.set('threeJSModel', null);
+ }
+ if(self.included==undefined){
+ self.included=[];
+ }
+ if(v.record.get('id')!=undefined){
+ self.included.push(v.record.serialize({includeId:true}).data);
+ hasmany.forEach(function(value){
+ value.serializedTypes=self.serializedTypes;
+ value.included=self.included;
+ if(self.serializedTypes.indexOf(nkey)==-1){
+ self.serializedTypes.push(nextSnapshot.get('id'));
+ }
+ value.serializeRecordForIncluded=self.serializeRecordForIncluded;
+ value.eachRelationship(self.serializeRecordForIncluded,value);
+ self.included.concat(value.included);
+ });
+ }
+ });
+ }
+ },
+ serialize(snapshot) {
+ let json = this._super(...arguments);
+
+ snapshot.serializeRecordForIncluded=this.serializeRecordForIncluded;
+ snapshot.serializedTypes=[];
+ snapshot.included=[];
+ snapshot.eachRelationship(this.serializeRecordForIncluded,snapshot);
+
+ snapshot.hasMany('systems').forEach(function(v,k){
+ delete json.data.relationships.systems.data[k].attributes.threeJSModel;
+ });
+
+ snapshot.hasMany('totalApplicationCommunications').forEach(function(v,k){
+ delete json.data.relationships.totalApplicationCommunications.data[k].attributes.threeJSModel;
+ });
+
+json.included=snapshot.included;
+ var newjson={
+ data:{
+ id: snapshot.record.get('id'),
+ type: "tutoriallandscape",
+ attributes:{
+ landscape:JSON.stringify(json),
+ },
+ relationships:{
+ timestamp:{
+ data:{
+ type:'tutorialtimestamp',
+ id:snapshot.record.get('timestamp').get('id')
+ }
+ }
+ }
+ },
+ included:[
+ {id: snapshot.record.get('timestamp').get('id'),
+ type: "tutorialtimestamp",
+ attributes:{
+ timestamp:snapshot.record.get('timestamp').get('timestamp'),
+ name:snapshot.record.get('timestamp').get('name')
+ }
+ }
+ ]
+ };
+ return newjson;
+ },
+ normalizeResponse(store, primaryModelClass, payload, id, requestType) {
+ var json = {};
+ if(Array.isArray(payload.data) ){
+ json = {data:[]};
+ payload.data.forEach(function(v,k){
+ json.data[k]=JSON.parse(v.attributes.landscape).data;
+ json.data[k].relationships.timestamp=v.relationships.timestamp;
+ });
+ }else{
+ json = JSON.parse(payload.data.attributes.landscape);
+ json.data.relationships.timestamp=payload.data.relationships.timestamp;
+ }
+ if(Array.isArray(json.included)){
+ if(Array.isArray(payload.included)){
+ json.included=json.included.concat(payload.included);
+ }
+ }else{
+ if(payload.included!=undefined){
+ json.included=payload.included;
+ }
+ }
+ // if(requestType=="queryRecord"){
+ // json.data=json.data[0];
+ // return this._super(store, primaryModelClass, json, id, requestType);
+ // }
+ return this._super(store, primaryModelClass, json, id, requestType);
+ }
+});
diff --git a/addon/services/landscape-service.js b/addon/services/landscape-service.js
new file mode 100644
index 0000000..2f18db7
--- /dev/null
+++ b/addon/services/landscape-service.js
@@ -0,0 +1,110 @@
+import Service from '@ember/service';
+import Evented from '@ember/object/evented';
+import debugLogger from 'ember-debug-logger';
+import { inject as service } from "@ember/service";
+//import LandscapeInteraction from 'explorviz-frontend/utils/landscape-rendering/interaction'
+import LandscapeInteraction from '../components/landscape-interaction';
+import ApplicationInteraction from '../components/application-interaction';
+
+import { getOwner } from '@ember/application';
+
+export default Service.extend(Evented, {
+ mockBackend: true,
+ debug: debugLogger(),
+ store: service(),
+ renderingService: service(),
+ landscape: null,
+ selectLandscape: false,
+ application: null,
+ livelandscapes: false,
+ landscapeList: null,
+
+ landscapeinteraction:null,
+ applicationinteraction:null,
+ init() {
+ this._super(...arguments);
+ const landscapeInteraction = LandscapeInteraction.create(getOwner(this).ownerInjection());
+ const applicationInteraction = ApplicationInteraction.create(getOwner(this).ownerInjection());
+ this.set('landscapeinteraction',landscapeInteraction);
+ this.set('applicationinteraction',applicationInteraction);
+ },
+ setInteractionModel(model){
+ this.set('landscapeinteraction.model',model);
+ this.set('applicationinteraction.model',model);
+ },
+ updateLandscapeList(reload) {
+ if(this.get('mockBackend')){
+ this.set('landscapeList', []);
+ this.set('landscapeList', this.get('store').peekAll('tutoriallandscape'));
+ }else{
+ this.set('landscapeList', []);
+ this.get('store').findAll('tutoriallandscape', { reload })
+ .then(landscapes => {
+ let landscapeList = landscapes.toArray();
+ // sort by id
+ landscapeList.sort((landscape1, landscape2) => parseInt(landscape1.id) < parseInt(landscape2.id) ? -1 : 1);
+ this.set('landscapeList', landscapeList);
+ });
+ }
+ },
+ loadLandscape(model) {
+ if (this.get('landscape') !== null) {
+ if(!this.get('mockBackend')){
+ this.get('store').queryRecord('tutoriallandscape',{ timestamp: model.get('landscapeTimestamp') }).then((landscape)=>{
+ if (this.get('landscape.id')!= landscape.get('id')){
+ this.get('store').unloadRecord(this.get('landscape'));
+ }else{
+ return;
+ }
+ });
+ }
+ }
+ if(model.get('landscapeTimestamp')!=undefined && model.get('landscapeTimestamp')!=""){
+ if(model.get('landscapeTimestamp')!=this.get('landscape.timestamp.timestamp')){
+ this.importLandscape(model.get('landscapeTimestamp'),"");
+ }
+ }
+
+ },
+ importLandscape(landscapeTimestamp,name){
+ if(this.get('mockBackend')){
+ this.get('store').queryRecord('landscape', { timestamp: landscapeTimestamp }).then((landscape) => {
+ this.set('landscape',landscape);
+ this.get('renderingService').reSetupScene();
+ });
+ }else{
+ this.get('store').queryRecord('tutoriallandscape', { timestamp: landscapeTimestamp }).then((tutlandscape) => {
+ this.set('landscape',tutlandscape);
+ this.get('renderingService').reSetupScene();
+ }, () => {
+ this.get('store').queryRecord('landscape', { timestamp: landscapeTimestamp }).then((landscape) => {
+ if(!this.get('store').hasRecordForId('tutoriallandscape',landscape.get('id'))){
+ if(name=="" ||name == undefined){
+ name="new landscape";
+ }
+ var timestamprecord=this.get('store').createRecord("tutorialtimestamp",{
+ id:landscape.get('timestamp.id'),
+ timestamp:landscape.get('timestamp.timestamp'),
+ totalRequests:landscape.get('timestamp.totalRequests'),
+ name:name,
+ });
+ var landscaperecord = this.get('store').createRecord("tutoriallandscape",{
+ id:landscape.get('id'),
+ systems:landscape.get('systems'),
+ events:landscape.get('events'),
+ totalApplicationCommunications:landscape.get('totalApplicationCommunications'),
+ timestamp:timestamprecord
+ });
+ timestamprecord.save();
+ landscaperecord.save();
+ this.set('landscape',landscaperecord);
+ this.get('renderingService').reSetupScene();
+ }else{
+ this.set('landscape',landscape);
+ this.get('renderingService').reSetupScene();
+ }
+ });
+ });
+ }
+ },
+})
diff --git a/addon/services/tutorial-service.js b/addon/services/tutorial-service.js
new file mode 100644
index 0000000..0bf6ce4
--- /dev/null
+++ b/addon/services/tutorial-service.js
@@ -0,0 +1,114 @@
+import Service from '@ember/service';
+import Evented from '@ember/object/evented';
+import debugLogger from 'ember-debug-logger';
+import { inject as service } from "@ember/service";
+import AlertifyHandler from 'explorviz-frontend/mixins/alertify-handler';
+import { Promise } from 'rsvp';
+import { computed } from '@ember/object';
+export default Service.extend(Evented,AlertifyHandler, {
+ debug: debugLogger(),
+ store: service(),
+ landscapeService:service(),
+ tutorialList: null,
+ activeStep:null,
+ steps:null,
+ sequences:null,
+ skipButton: computed('activeStep', function() {
+ if(this.get('activeStep.targetId')!=="" && this.get('activeStep.targetType')!=="" && this.get('activeStep.actionType')!==""){
+ return false;
+ }
+ return true;
+ }),
+ initService(model){
+ this.set('sequences',[]);
+ this.set('steps',[]);
+ this.set('sequences',model.get('sequences'));
+ this.get('sequences').forEach((k)=>{
+ k.get('steps').forEach((s)=>{
+ this.get('steps').push(s);
+ });
+ });
+ },
+ getNextStep(prevstep){
+ if(prevstep==undefined){
+ return this.get('steps')[0];
+ }
+ var nextStep=false;
+ var step;
+ this.get('steps').forEach(function(s){
+ if(nextStep==true){
+ step=s;
+ nextStep=false;
+ }
+ if(s.get('id')==prevstep.get('id')){
+ nextStep=true;
+ }
+ });
+ if(step==undefined && nextStep==true){
+ return false;
+ }
+ return step;
+ },
+ getSequence(step){
+ return this.get('store').findAll('tutorial').then((tutorials)=>{
+ var returnSequence;
+ tutorials.forEach(function(tutorial){
+ tutorial.get('sequences').forEach(function(sequence){
+ sequence.get('steps').forEach(function(stepcompare){
+ if(stepcompare.get('id')==step.get('id')){
+ returnSequence=sequence;
+ }
+ });
+ });
+ });
+ return returnSequence;
+ });
+},
+ getTutorial(sequence){
+ return this.get('store').findAll('tutorial').then((tutorials)=>{
+ var returnTutorial;
+ tutorials.forEach(function(tutorial){
+ tutorial.get('sequences').forEach(function(sequencecompare){
+ if(sequencecompare.get('id')==sequence.get('id')){
+ returnTutorial=tutorial;
+ }
+ });
+ });
+ return returnTutorial;
+ });
+
+ },
+ updateTutorialList(reload) {
+ this.set('tutorialList', []);
+ this.get('store').findAll('tutorial', { reload })
+ .then(tutorials => {
+ let tutorialList = tutorials.toArray();
+ // sort by id
+ tutorialList.sort((tutorial1, tutorial2) => parseInt(tutorial1.id) < parseInt(tutorial2.id) ? -1 : 1);
+ this.set('tutorialList', tutorialList);
+ });
+ },
+ saveTutorialChanges(tutorial) {
+ if(tutorial) {
+ // check for valid input
+ if(!tutorial.get('title') || tutorial.get('title').length === 0) {
+ this.showAlertifyMessage('Title cannot be empty.');
+ return;
+ }
+ tutorial.save()
+ .then((tutorial)=> {
+ const message = `Tutorial updated.`;
+ this.get('landscapeService').loadLandscape(tutorial);
+ this.showAlertifyMessage(message);
+ }, (reason) => {
+ this.showReasonErrorAlert(reason);
+ });
+ } else {
+ this.showAlertifyMessage(`Tutorial not found.`);
+ }
+ },
+ showReasonErrorAlert(reason) {
+ const {title, detail} = reason.errors[0];
+ this.showAlertifyMessage(`${title}: ${detail}`);
+ },
+});
diff --git a/addon/templates/components/application-interaction.hbs b/addon/templates/components/application-interaction.hbs
new file mode 100644
index 0000000..fb5c4b1
--- /dev/null
+++ b/addon/templates/components/application-interaction.hbs
@@ -0,0 +1 @@
+{{yield}}
\ No newline at end of file
diff --git a/addon/templates/components/application-visualization.hbs b/addon/templates/components/application-visualization.hbs
new file mode 100644
index 0000000..1c2b5e4
--- /dev/null
+++ b/addon/templates/components/application-visualization.hbs
@@ -0,0 +1,2 @@
+
diff --git a/addon/templates/components/landscape-interaction.hbs b/addon/templates/components/landscape-interaction.hbs
new file mode 100644
index 0000000..fb5c4b1
--- /dev/null
+++ b/addon/templates/components/landscape-interaction.hbs
@@ -0,0 +1 @@
+{{yield}}
\ No newline at end of file
diff --git a/addon/templates/components/landscape-select/landscapelist.hbs b/addon/templates/components/landscape-select/landscapelist.hbs
new file mode 100644
index 0000000..3459ada
--- /dev/null
+++ b/addon/templates/components/landscape-select/landscapelist.hbs
@@ -0,0 +1,17 @@
+{{#if landscapeService.selectLandscape}}
+ {{landscapeService.landscapeList.length}} possible landscapes:
+
+{{/if}}
diff --git a/addon/templates/components/landscape-select/navbar/toggle-live-landscape.hbs b/addon/templates/components/landscape-select/navbar/toggle-live-landscape.hbs
new file mode 100644
index 0000000..364d5fb
--- /dev/null
+++ b/addon/templates/components/landscape-select/navbar/toggle-live-landscape.hbs
@@ -0,0 +1,9 @@
+{{#if landscapeListener.pauseVisualizationReload}}
+
+ {{svg-jar "history" class="octicon align-middle navbar-highlight"}}
+
+{{else}}
+
+ {{svg-jar "history" class="octicon align-middle"}}
+
+{{/if}}
diff --git a/addon/templates/components/landscape-visualization.hbs b/addon/templates/components/landscape-visualization.hbs
new file mode 100644
index 0000000..1c2b5e4
--- /dev/null
+++ b/addon/templates/components/landscape-visualization.hbs
@@ -0,0 +1,2 @@
+
diff --git a/addon/templates/components/sequence-form.hbs b/addon/templates/components/sequence-form.hbs
new file mode 100644
index 0000000..f7f7d0e
--- /dev/null
+++ b/addon/templates/components/sequence-form.hbs
@@ -0,0 +1,34 @@
+{{#link-to "tutorial.list"}}{{svg-jar "reply" class="octicon align-middle"}} Back{{/link-to}}
+{{#bs-form model=model onSubmit=(action "saveSequenceChanges" model) as |form|}}
+ {{form.element controlType="text" label="Title" placeholder="Enter New Sequence Title" property="title"}}
+{{bs-button defaultText="Save" type="primary" buttonType="submit"}}
+{{/bs-form}}
+{{#if model.isDirty}}
+ there are unsaved changes
+{{/if}}
+{{#bs-dropdown as |dd|}}
+ {{#dd.button class="removecaret d-flex-center" size="sm" title="Options"}}
+ {{svg-jar "kebab-vertical" class="octicon"}}
+ {{/dd.button}}
+ {{#dd.menu as |ddm|}}
+ {{#ddm.item title="set landscape"}}
+
+ {{svg-jar "globe" class="octicon" id="change-landscape"}}
+ {{#unless landscapeService.selectLandscape}}
+ {{#if model.landscapeTimestamp}}
+ change landscape
+ {{else}}
+ select landscape
+ {{/if}}
+ {{else}}
+ {{#if model.landscapeTimestamp}}
+ stop changing landscape
+ {{else}}
+ stop selecting landscape
+ {{/if}}
+ {{/unless}}
+
+ {{/ddm.item}}
+ {{/dd.menu}}
+{{/bs-dropdown}}
diff --git a/addon/templates/components/side-form-layout.hbs b/addon/templates/components/side-form-layout.hbs
new file mode 100644
index 0000000..518a6e7
--- /dev/null
+++ b/addon/templates/components/side-form-layout.hbs
@@ -0,0 +1,101 @@
+
+
+ {{#if selectMode}}
+ {{#unless liveMode}}
+ {{#bs-button
+ onClick=(action "showLiveLandscapes")
+ type="secondary"
+ outline=true
+ class="btn-timeline"
+ title="show live landscapes"
+ }}
+ show live landscapes
+ {{/bs-button}}
+ {{landscape-select/landscapelist model=model}}
+ {{else}}
+ {{#bs-button
+ onClick=(action "hideLiveLandscapes")
+ type="secondary"
+ outline=true
+ class="btn-timeline"
+ title="hide live landscapes"
+ }}
+ hide live landscapes
+ {{/bs-button}}
+ {{#if showLandscape}}
+ {{#if landscapeService.latestLandscape.systems}}
+
+ {{landscape-visualization interaction=landscapeService.landscapeinteraction interactionModel=model runmode=runmode }}
+
+ {{visualization/rendering/popups/popup-coordinator
+ popupData=additionalData.popupContent}}
+
+ {{else}}
+
+
+
No Landscape Found!
+
A new landscape will be fetched every 10 seconds.
+
+
+ {{ember-spinner}}
+
+
+ {{/if}}
+ {{else}}
+
+
+ {{#bs-button onClick=(action "openLandscapeView") type="secondary" outline=true title="Back to Landscape"}}
+ {{svg-jar "reply" class="octicon align-middle"}}
+ {{/bs-button}}
+
+ {{application-visualization latestApplication=landscapeRepo.latestApplication interaction=landscapeService.applicationinteraction interactionModel=model runmode=runmode }}
+ {{visualization/rendering/popups/popup-coordinator
+ popupData=additionalData.popupContent}}
+
+ {{/if}}
+
+
+ {{#bs-button
+ onClick=(action "toggleTimeline")
+ type="secondary"
+ outline=true
+ class="btn-timeline"
+ title=(if renderingService.showTimeline "Hide Timeline" "Show Timeline")
+ }}
+ {{#unless renderingService.showTimeline}}
Show Timeline{{/unless}}
+ {{svg-jar "chevron-up" id="hidetimeline-icon" class=(if renderingService.showTimeline "octicon align-middle hidetimeline-icon-down" "octicon align-middle")}}
+ {{/bs-button}}
+
+ {{component "timeline" model=model}}
+
+
+ {{/unless}}
+ {{else}}
+ {{#if showLandscape}}
+
+ {{landscape-visualization interaction=landscapeService.landscapeinteraction interactionModel=model runmode=runmode }}
+
+ {{else}}
+
+
+ {{#bs-button onClick=(action "openLandscapeView") type="secondary" outline=true title="Back to Landscape"}}
+ {{svg-jar "reply" class="octicon align-middle"}}
+ {{/bs-button}}
+
+ {{application-visualization latestApplication=landscapeService.application interaction=landscapeService.applicationinteraction interactionModel=model runmode=runmode }}
+
+ {{/if}}
+ {{/if}}
+
+
+ {{#unless runmode}}
+ {{#if this.currentUser.user.isAdmin}}
+ {{component form model=model runmode=runmode}}
+ {{else}}
+ {{component "step-form" model=tutorialService.activeStep runmode=true}}
+ {{/if}}
+ {{else}}
+ {{component "step-form" model=tutorialService.activeStep runmode=true}}
+ {{/unless}}
+
+
diff --git a/addon/templates/components/step-form.hbs b/addon/templates/components/step-form.hbs
new file mode 100644
index 0000000..aa9f0b7
--- /dev/null
+++ b/addon/templates/components/step-form.hbs
@@ -0,0 +1,82 @@
+{{#unless runmode}}
+ {{#link-to "tutorial.list"}}{{svg-jar "reply" class="octicon align-middle"}} Back{{/link-to}}
+ {{#bs-form model=model onSubmit=(action "saveStepChanges" model) as |form|}}
+ {{form.element controlType="text" label="Title" placeholder="Enter New Step Title" property="title"}}
+ {{form.element controlType="textarea" label="Text" rows=18 placeholder="Text" property="text"}}
+ {{bs-button defaultText="Save" type="primary" buttonType="submit"}}
+ {{/bs-form}}
+ {{#if model.isDirty}}
+ there are unsaved changes
+ {{/if}}
+ {{#bs-dropdown as |dd|}}
+ {{#dd.button class="removecaret d-flex-center" size="sm" title="Options"}}
+ {{svg-jar "kebab-vertical" class="octicon"}}
+ {{/dd.button}}
+ {{#dd.menu as |ddm|}}
+ {{#ddm.item title="Run"}}
+
+ {{svg-jar "play" class="octicon" id="run-button"}}
+ {{#if landscapeService.application}}
+ {{if landscapeService.applicationinteraction.selectTarget "Selecting target" "Select target" }}
+ {{else}}
+ {{if landscapeService.landscapeinteraction.selectTarget "Selecting target" "Select target"}}
+ {{/if}}
+
+
+ {{/ddm.item}}
+ {{#ddm.item title="Run"}}
+
+ {{svg-jar "trashcan" class="octicon" id="run-button"}}Remove target
+
+ {{/ddm.item}}
+ {{/dd.menu}}
+ {{/bs-dropdown}}
+ {{#unless model.targetType}}
+ {{#unless model.actionType}}
+ {{#unless model.targetId}}
+ no target selected
+ {{/unless}}
+ {{/unless}}
+ {{/unless}}
+
+ {{#if model.targetType}}
+ {{#if model.actionType}}
+ {{#if model.targetId}}
+ {{#if landscapeService.landscape.systems}}
+ Target: {{model.actionType}} on {{targetName}}
+ {{else}}
+ Target: {{model.actionType}} on {{help-tooltip title=model.targetId}}
+
+
+
+ {{/if}}
+ {{/if}}
+ {{/if}}
+ {{/if}}
+
+{{else}}
+ {{model.title}}
+ {{model.text}}
+ {{#unless model.targetType}}
+ {{#unless model.actionType}}
+ {{#unless model.targetId}}
+ {{#if nextStepAvailable}}
+ {{#bs-button
+ onClick=(action "skipStep")
+ type="secondary"
+ outline=true
+ disabled=(not landscapeService.landscape.systems)
+ title="next step" as |button|
+ }}
+ next
+ {{/bs-button}}
+ {{/if}}
+ {{/unless}}
+ {{/unless}}
+ {{/unless}}
+ {{#if model.actionType }}
+ {{#let (concat model.actionType " on " targetName) as |text| }}
+ {{help-tooltip title=text}}
+ {{/let}}
+ {{/if}}
+{{/unless}}
diff --git a/addon/templates/components/timeline.hbs b/addon/templates/components/timeline.hbs
new file mode 100644
index 0000000..4a1d52a
--- /dev/null
+++ b/addon/templates/components/timeline.hbs
@@ -0,0 +1,19 @@
+
+{{#bs-modal
+ open=importLandscape
+ title="import landscape"
+ closeTitle="closeTitle"
+ submitTitle="submitTitle"
+ closeButton="closeButton"
+ onSubmit=(action "submit" )
+ onHidden=(action (mut importLandscape) false)
+ renderInPlace=true as |modal|}}
+ {{#modal.body}}
+ Import landscape
+ {{input type="text" value=landscapeName placehoder="new landscape"}}
+ {{/modal.body}}
+ {{#modal.footer}}
+ {{#bs-button onClick=(action modal.close)}}Cancel{{/bs-button}}
+ {{#bs-button type="success" onClick=(action modal.submit)}}Save{{/bs-button}}
+ {{/modal.footer}}
+{{/bs-modal}}
diff --git a/addon/templates/components/tutorial-form.hbs b/addon/templates/components/tutorial-form.hbs
new file mode 100644
index 0000000..d0eb0ff
--- /dev/null
+++ b/addon/templates/components/tutorial-form.hbs
@@ -0,0 +1,41 @@
+{{#link-to "tutorial.list"}}{{svg-jar "reply" class="octicon align-middle"}} Back{{/link-to}}
+{{#bs-form model=model onSubmit=(action "saveTutorialChanges" model) as |form|}}
+ {{form.element controlType="text" label="Title" placeholder="Enter new tutorial title" property="title"}}
+{{bs-button defaultText="Save it" type="primary" buttonType="submit"}}
+{{/bs-form}}
+{{#if model.isDirty}}
+ there are unsaved changes
+{{/if}}
+{{#bs-dropdown as |dd|}}
+ {{#dd.button class="removecaret d-flex-center" size="sm" title="Options"}}
+ {{svg-jar "kebab-vertical" class="octicon"}}
+ {{/dd.button}}
+ {{#dd.menu as |ddm|}}
+ {{#ddm.item title="Run"}}
+
+ {{#link-to "tutorial.run" model}}
+ {{svg-jar "play" class="octicon" id="run-button"}}Run
+ {{/link-to}}
+
+ {{/ddm.item}}
+ {{#ddm.item title="set landscape"}}
+
+ {{svg-jar "globe" class="octicon" id="change-landscape"}}
+ {{#unless landscapeService.selectLandscape}}
+ {{#if model.landscapeTimestamp}}
+ change landscape
+ {{else}}
+ select landscape
+ {{/if}}
+ {{else}}
+ {{#if model.landscapeTimestamp}}
+ stop changing landscape
+ {{else}}
+ stop selecting landscape
+ {{/if}}
+ {{/unless}}
+
+ {{/ddm.item}}
+ {{/dd.menu}}
+ {{/bs-dropdown}}
diff --git a/addon/templates/tutorial.hbs b/addon/templates/tutorial.hbs
index 591173b..c24cd68 100644
--- a/addon/templates/tutorial.hbs
+++ b/addon/templates/tutorial.hbs
@@ -1,29 +1 @@
-
-
-
- {{#bs-button-group
- value=page
- type="radio"
- class="mt-3"
- onChange=(action (mut page)) as |bg|}}
- {{#bg.button value="importTutorial"}}Tutorial importieren{{/bg.button}}
- {{#bg.button value="createNewSequence"}}Neue Sequenz erstellen{{/bg.button}}
- {{/bs-button-group}}
- {{#if (eq page "createNewSequence")}}
-
Add tutorial
- {{#bs-form formLayout=formLayout model=this as |form|}}
- {{form.element controlType="text" label="Title" placeholder="Title" property="Title" required=true}}
- {{bs-button defaultText="Create Tutorial" value="createTutorial" type="primary" buttonType="submit"}}
- {{/bs-form}}
- {{else if (eq page "importTutorial")}}
- Tutorial importieren
-
- {{/if}}
-
-
-
+{{outlet}}
diff --git a/addon/templates/tutorial/list.hbs b/addon/templates/tutorial/list.hbs
new file mode 100644
index 0000000..927ff42
--- /dev/null
+++ b/addon/templates/tutorial/list.hbs
@@ -0,0 +1,165 @@
+
+
Tutorials
+ {{#if this.currentUser.user.isAdmin}}
+
+
+ {{#bs-button type="default" onClick=(action "addNewTutorial")}}{{svg-jar "plus-small"}} New tutorial{{/bs-button}}
+
+
+ {{/if}}
+
+
+
+
+ {{#if this.currentUser.user.isAdmin}}
+ |
+ |
+ {{/if}}
+ Type |
+ Title |
+ Children |
+ {{#if this.currentUser.user.isAdmin}}
+ |
+ {{/if}}
+
+
+
+ {{#each model.tutorials as |tutorial|}}
+
+ {{#if this.currentUser.user.isAdmin}}| {{#if tutorial.containsSequences}}{{#bs-button type="default" onClick=(action "toggleTutorial" tutorial)}}{{svg-jar (if tutorial.expanded 'chevron-down' 'chevron-right') color=white}}{{/bs-button}}{{/if}} | {{/if}}
+ |
+ tutorial |
+ {{#link-to "tutorial.tutorial" tutorial}}{{tutorial.title}}{{/link-to}} |
+
+ {{tutorial.sequences.length}} sequences
+ |
+ {{#if this.currentUser.user.isAdmin}}
+
+ {{#bs-dropdown as |dd|}}
+ {{#dd.button class="removecaret d-flex-center" size="sm" title="Options"}}
+ {{svg-jar "kebab-vertical" class="octicon"}}
+ {{/dd.button}}
+ {{#dd.menu as |ddm|}}
+ {{#ddm.item title="Run"}}
+ {{#link-to "tutorial.run" tutorial}}
+
+ {{svg-jar "play" class="octicon" id="run-button"}}Run
+
+ {{/link-to}}
+ {{/ddm.item}}
+ {{#ddm.item title="Edit"}}
+ {{#link-to "tutorial.tutorial" tutorial}}
+
+ {{svg-jar "pencil" class="octicon" id="edit-button"}}Edit
+
+ {{/link-to}}
+ {{/ddm.item}}
+ {{#ddm.item title="new sequence"}}
+
+ {{svg-jar "plus" class="octicon" id="new-sequence"}}New sequence
+
+ {{/ddm.item}}
+ {{#ddm.item}}
+
+ {{/ddm.item}}
+ {{#ddm.item title="delete tutorial"}}
+
+ {{svg-jar "trashcan" class="octicon" id="delete-tutorial"}}Delete Tutorial
+
+ {{/ddm.item}}
+ {{/dd.menu}}
+ {{/bs-dropdown}}
+ |
+ {{/if}}
+
+ {{#if this.currentUser.user.isAdmin}}
+ {{#if tutorial.expanded}}
+ {{#each tutorial.sequences as |sequence|}}
+
+ |
+ {{#if sequence.containsSteps}}{{#bs-button type="default" onClick=(action "toggleSequence" sequence)}}{{svg-jar (if sequence.expanded 'chevron-down' 'chevron-right')}}{{/bs-button}}{{/if}} |
+ sequence |
+ {{#link-to "tutorial.sequence" sequence}}{{sequence.title}}{{/link-to}} |
+
+ {{sequence.steps.length}} steps
+ |
+
+ {{#bs-dropdown as |dd|}}
+ {{#dd.button class="removecaret d-flex-center" size="sm" title="Options"}}
+ {{svg-jar "kebab-vertical" class="octicon"}}
+ {{/dd.button}}
+ {{#dd.menu as |ddm|}}
+ {{#ddm.item title="Edit"}}
+ {{#link-to "tutorial.sequence" sequence}}
+
+ {{svg-jar "pencil" class="octicon" id="edit-button"}}Edit
+
+ {{/link-to}}
+ {{/ddm.item}}
+ {{#ddm.item title="new sequence"}}
+
+ {{svg-jar "plus" class="octicon" id="new-step"}}New step
+
+ {{/ddm.item}}
+ {{#ddm.item}}
+
+ {{/ddm.item}}
+ {{#ddm.item title="delete sequence"}}
+
+ {{svg-jar "trashcan" class="octicon" id="delete-sequence"}}Delete sequence
+
+ {{/ddm.item}}
+ {{/dd.menu}}
+ {{/bs-dropdown}}
+ |
+
+ {{#if sequence.expanded}}
+ {{#each sequence.steps as |step|}}
+
+ |
+ |
+ step |
+ {{#link-to "tutorial.step" step}}{{step.title}}{{/link-to}} |
+
+ |
+
+ {{#bs-dropdown as |dd|}}
+ {{#dd.button class="removecaret d-flex-center" size="sm" title="Options"}}
+ {{svg-jar "kebab-vertical" class="octicon"}}
+ {{/dd.button}}
+ {{#dd.menu as |ddm|}}
+ {{#ddm.item title="Edit"}}
+ {{#link-to "tutorial.step" step}}
+
+ {{svg-jar "pencil" class="octicon" id="edit-button"}}Edit
+
+ {{/link-to}}
+ {{/ddm.item}}
+ {{#ddm.item}}
+
+ {{/ddm.item}}
+ {{#ddm.item title="delete step"}}
+
+ {{svg-jar "trashcan" class="octicon" id="delete-step"}}Delete step
+
+ {{/ddm.item}}
+ {{/dd.menu}}
+ {{/bs-dropdown}}
+ |
+
+ {{/each}}
+ {{/if}}
+ {{/each}}
+ {{/if}}
+ {{/if}}
+ {{/each}}
+
+
+
+
+
diff --git a/addon/templates/tutorial/run.hbs b/addon/templates/tutorial/run.hbs
new file mode 100644
index 0000000..d4317fb
--- /dev/null
+++ b/addon/templates/tutorial/run.hbs
@@ -0,0 +1 @@
+{{side-form-layout form="tutorial-form" model=model tutorial=model runmode=true }}
diff --git a/addon/templates/tutorial/sequence.hbs b/addon/templates/tutorial/sequence.hbs
new file mode 100644
index 0000000..a04cbc4
--- /dev/null
+++ b/addon/templates/tutorial/sequence.hbs
@@ -0,0 +1 @@
+{{side-form-layout form="sequence-form" model=model tutorial=model.tutorial runmode=false}}
diff --git a/addon/templates/tutorial/step.hbs b/addon/templates/tutorial/step.hbs
new file mode 100644
index 0000000..8d8eb81
--- /dev/null
+++ b/addon/templates/tutorial/step.hbs
@@ -0,0 +1 @@
+{{side-form-layout form="step-form" model=model tutorial=model.sequence.tutorial runmode=false}}
diff --git a/addon/templates/tutorial/tutorial.hbs b/addon/templates/tutorial/tutorial.hbs
new file mode 100644
index 0000000..6c416b5
--- /dev/null
+++ b/addon/templates/tutorial/tutorial.hbs
@@ -0,0 +1 @@
+{{side-form-layout form="tutorial-form" model=model tutorial=model runmode=false}}
diff --git a/app/adapters/sequence.js b/app/adapters/sequence.js
new file mode 100644
index 0000000..23c599c
--- /dev/null
+++ b/app/adapters/sequence.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/adapters/sequence';
diff --git a/app/adapters/step.js b/app/adapters/step.js
new file mode 100644
index 0000000..8cefc7d
--- /dev/null
+++ b/app/adapters/step.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/adapters/step';
diff --git a/app/adapters/tutorial.js b/app/adapters/tutorial.js
new file mode 100644
index 0000000..0379553
--- /dev/null
+++ b/app/adapters/tutorial.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/adapters/tutorial';
diff --git a/app/adapters/tutoriallandscape.js b/app/adapters/tutoriallandscape.js
new file mode 100644
index 0000000..b974551
--- /dev/null
+++ b/app/adapters/tutoriallandscape.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/adapters/tutoriallandscape';
diff --git a/app/adapters/tutorialtimestamp.js b/app/adapters/tutorialtimestamp.js
new file mode 100644
index 0000000..f724475
--- /dev/null
+++ b/app/adapters/tutorialtimestamp.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/adapters/tutorialtimestamp';
diff --git a/app/components/application-interaction.js b/app/components/application-interaction.js
new file mode 100644
index 0000000..0afe532
--- /dev/null
+++ b/app/components/application-interaction.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/landscape-interaction';
\ No newline at end of file
diff --git a/app/components/application-visualization.js b/app/components/application-visualization.js
new file mode 100644
index 0000000..49b90a3
--- /dev/null
+++ b/app/components/application-visualization.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/application-visualization';
diff --git a/app/components/landscape-interaction.js b/app/components/landscape-interaction.js
new file mode 100644
index 0000000..0afe532
--- /dev/null
+++ b/app/components/landscape-interaction.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/landscape-interaction';
\ No newline at end of file
diff --git a/app/components/landscape-select/landscapelist.js b/app/components/landscape-select/landscapelist.js
new file mode 100644
index 0000000..3fff765
--- /dev/null
+++ b/app/components/landscape-select/landscapelist.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/landscape-select/landscapelist';
\ No newline at end of file
diff --git a/app/components/landscape-select/navbar/toggle-live-landscape.js b/app/components/landscape-select/navbar/toggle-live-landscape.js
new file mode 100644
index 0000000..8489a25
--- /dev/null
+++ b/app/components/landscape-select/navbar/toggle-live-landscape.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/landscape-select/navbar/toggle-live-landscape';
\ No newline at end of file
diff --git a/app/components/landscape-visualization.js b/app/components/landscape-visualization.js
new file mode 100644
index 0000000..a506142
--- /dev/null
+++ b/app/components/landscape-visualization.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/landscape-visualization';
\ No newline at end of file
diff --git a/app/components/sequence-form.js b/app/components/sequence-form.js
new file mode 100644
index 0000000..aa0afd9
--- /dev/null
+++ b/app/components/sequence-form.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/sequence-form';
\ No newline at end of file
diff --git a/app/components/side-form-layout.js b/app/components/side-form-layout.js
new file mode 100644
index 0000000..ebe092b
--- /dev/null
+++ b/app/components/side-form-layout.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/side-form-layout';
diff --git a/app/components/step-form.js b/app/components/step-form.js
new file mode 100644
index 0000000..1c247f4
--- /dev/null
+++ b/app/components/step-form.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/step-form';
\ No newline at end of file
diff --git a/app/components/timeline.js b/app/components/timeline.js
new file mode 100644
index 0000000..004baa7
--- /dev/null
+++ b/app/components/timeline.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/timeline';
\ No newline at end of file
diff --git a/app/components/tutorial-form.js b/app/components/tutorial-form.js
new file mode 100644
index 0000000..89ebc6e
--- /dev/null
+++ b/app/components/tutorial-form.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/tutorial-form';
\ No newline at end of file
diff --git a/app/components/tutorial-hierarchie.js b/app/components/tutorial-hierarchie.js
new file mode 100644
index 0000000..e0a0f3d
--- /dev/null
+++ b/app/components/tutorial-hierarchie.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/tutorial-hierarchie';
\ No newline at end of file
diff --git a/app/components/tutorial-management.js b/app/components/tutorial-management.js
new file mode 100644
index 0000000..ff5a6dd
--- /dev/null
+++ b/app/components/tutorial-management.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/components/tutorial-management';
\ No newline at end of file
diff --git a/app/controllers/tutorial/list.js b/app/controllers/tutorial/list.js
new file mode 100644
index 0000000..0181aba
--- /dev/null
+++ b/app/controllers/tutorial/list.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/controllers/tutorial/list';
diff --git a/app/controllers/tutorial/run.js b/app/controllers/tutorial/run.js
new file mode 100644
index 0000000..9a66c98
--- /dev/null
+++ b/app/controllers/tutorial/run.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/controllers/tutorial/run';
diff --git a/app/controllers/tutorial/sequence.js b/app/controllers/tutorial/sequence.js
new file mode 100644
index 0000000..8970acb
--- /dev/null
+++ b/app/controllers/tutorial/sequence.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/controllers/tutorial/sequence';
diff --git a/app/controllers/tutorial/step.js b/app/controllers/tutorial/step.js
new file mode 100644
index 0000000..0d7de59
--- /dev/null
+++ b/app/controllers/tutorial/step.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/controllers/tutorial/step';
diff --git a/app/controllers/tutorial/tutorial.js b/app/controllers/tutorial/tutorial.js
new file mode 100644
index 0000000..8379892
--- /dev/null
+++ b/app/controllers/tutorial/tutorial.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/controllers/tutorial/tutorial';
diff --git a/app/models/sequence.js b/app/models/sequence.js
new file mode 100644
index 0000000..8c71bf0
--- /dev/null
+++ b/app/models/sequence.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/models/sequence';
diff --git a/app/models/step.js b/app/models/step.js
new file mode 100644
index 0000000..7d4a058
--- /dev/null
+++ b/app/models/step.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/models/step';
diff --git a/app/models/tutorial.js b/app/models/tutorial.js
new file mode 100644
index 0000000..7baeb59
--- /dev/null
+++ b/app/models/tutorial.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/models/tutorial';
diff --git a/app/models/tutoriallandscape.js b/app/models/tutoriallandscape.js
new file mode 100644
index 0000000..b8942df
--- /dev/null
+++ b/app/models/tutoriallandscape.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/models/tutoriallandscape';
diff --git a/app/models/tutorialtimestamp.js b/app/models/tutorialtimestamp.js
new file mode 100644
index 0000000..0ef2d37
--- /dev/null
+++ b/app/models/tutorialtimestamp.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/models/tutorialtimestamp';
diff --git a/app/routes/tutorial/index.js b/app/routes/tutorial/index.js
new file mode 100644
index 0000000..7ef5c24
--- /dev/null
+++ b/app/routes/tutorial/index.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/routes/tutorial/index';
diff --git a/app/routes/tutorial/list.js b/app/routes/tutorial/list.js
new file mode 100644
index 0000000..3091ef1
--- /dev/null
+++ b/app/routes/tutorial/list.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/routes/tutorial/list';
diff --git a/app/routes/tutorial/run.js b/app/routes/tutorial/run.js
new file mode 100644
index 0000000..567e49e
--- /dev/null
+++ b/app/routes/tutorial/run.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/routes/tutorial/run';
diff --git a/app/routes/tutorial/sequence.js b/app/routes/tutorial/sequence.js
new file mode 100644
index 0000000..69e78be
--- /dev/null
+++ b/app/routes/tutorial/sequence.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/routes/tutorial/sequence';
diff --git a/app/routes/tutorial/step.js b/app/routes/tutorial/step.js
new file mode 100644
index 0000000..66c6a0a
--- /dev/null
+++ b/app/routes/tutorial/step.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/routes/tutorial/step';
diff --git a/app/routes/tutorial/tutorial.js b/app/routes/tutorial/tutorial.js
new file mode 100644
index 0000000..a62dfc4
--- /dev/null
+++ b/app/routes/tutorial/tutorial.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/routes/tutorial/tutorial';
diff --git a/app/serializers/tutoriallandscape.js b/app/serializers/tutoriallandscape.js
new file mode 100644
index 0000000..f13ae16
--- /dev/null
+++ b/app/serializers/tutoriallandscape.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/serializers/tutoriallandscape';
diff --git a/app/services/landscape-service.js b/app/services/landscape-service.js
new file mode 100644
index 0000000..cf57266
--- /dev/null
+++ b/app/services/landscape-service.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/services/landscape-service';
diff --git a/app/services/tutorial-service.js b/app/services/tutorial-service.js
new file mode 100644
index 0000000..1832f4d
--- /dev/null
+++ b/app/services/tutorial-service.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/services/tutorial-service';
diff --git a/app/templates/tutorial/index.js b/app/templates/tutorial/index.js
new file mode 100644
index 0000000..0e0687b
--- /dev/null
+++ b/app/templates/tutorial/index.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/tutorial';
diff --git a/app/templates/tutorial/list.js b/app/templates/tutorial/list.js
new file mode 100644
index 0000000..5ca3011
--- /dev/null
+++ b/app/templates/tutorial/list.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/templates/tutorial/list';
diff --git a/app/templates/tutorial/run.js b/app/templates/tutorial/run.js
new file mode 100644
index 0000000..7826608
--- /dev/null
+++ b/app/templates/tutorial/run.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/templates/tutorial/run';
diff --git a/app/templates/tutorial/sequence.js b/app/templates/tutorial/sequence.js
new file mode 100644
index 0000000..c0159ee
--- /dev/null
+++ b/app/templates/tutorial/sequence.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/templates/tutorial/sequence';
diff --git a/app/templates/tutorial/step.js b/app/templates/tutorial/step.js
new file mode 100644
index 0000000..441c123
--- /dev/null
+++ b/app/templates/tutorial/step.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/templates/tutorial/step';
diff --git a/app/templates/tutorial/tutorial.js b/app/templates/tutorial/tutorial.js
new file mode 100644
index 0000000..2e3718d
--- /dev/null
+++ b/app/templates/tutorial/tutorial.js
@@ -0,0 +1 @@
+export { default } from 'explorviz-frontend-extension-tutorial/templates/tutorial/tutorial';
diff --git a/index.js b/index.js
index 2e1d1d8..4d70aae 100644
--- a/index.js
+++ b/index.js
@@ -1,5 +1,8 @@
'use strict';
module.exports = {
- name: require('./package').name
+ name: require('./package').name,
+ isDevelopingAddon() {
+ return true;
+ }
};
diff --git a/package-lock.json b/package-lock.json
index ccac8b7..ded9cef 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1203,7 +1203,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
- "dev": true,
"requires": {
"chalk": "^1.1.3",
"esutils": "^2.0.2",
@@ -1213,20 +1212,17 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
@@ -1238,14 +1234,12 @@
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
- "dev": true
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -1253,8 +1247,7 @@
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
}
}
},
@@ -1262,7 +1255,6 @@
"version": "6.26.3",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
"integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
- "dev": true,
"requires": {
"babel-code-frame": "^6.26.0",
"babel-generator": "^6.26.0",
@@ -1289,7 +1281,6 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -1297,14 +1288,12 @@
"json5": {
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
- "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
- "dev": true
+ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
@@ -1312,7 +1301,6 @@
"version": "6.26.1",
"resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
"integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
- "dev": true,
"requires": {
"babel-messages": "^6.23.0",
"babel-runtime": "^6.26.0",
@@ -1327,8 +1315,7 @@
"jsesc": {
"version": "1.3.0",
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
- "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
- "dev": true
+ "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s="
}
}
},
@@ -1336,7 +1323,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
"integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=",
- "dev": true,
"requires": {
"babel-helper-explode-assignable-expression": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1347,7 +1333,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
"integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
- "dev": true,
"requires": {
"babel-helper-hoist-variables": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1359,7 +1344,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
"integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
- "dev": true,
"requires": {
"babel-helper-function-name": "^6.24.1",
"babel-runtime": "^6.26.0",
@@ -1371,7 +1355,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
"integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-traverse": "^6.24.1",
@@ -1382,7 +1365,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
"integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
- "dev": true,
"requires": {
"babel-helper-get-function-arity": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1395,7 +1377,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
"integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-types": "^6.24.1"
@@ -1405,7 +1386,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
"integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-types": "^6.24.1"
@@ -1415,7 +1395,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
"integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-types": "^6.24.1"
@@ -1425,7 +1404,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
"integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
- "dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"babel-types": "^6.26.0",
@@ -1436,7 +1414,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
"integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
- "dev": true,
"requires": {
"babel-helper-function-name": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1449,7 +1426,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
"integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
- "dev": true,
"requires": {
"babel-helper-optimise-call-expression": "^6.24.1",
"babel-messages": "^6.23.0",
@@ -1463,7 +1439,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
"integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-template": "^6.24.1"
@@ -1473,7 +1448,6 @@
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
"integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1482,7 +1456,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
"integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1524,26 +1497,22 @@
"babel-plugin-syntax-async-functions": {
"version": "6.13.0",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
- "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
- "dev": true
+ "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU="
},
"babel-plugin-syntax-exponentiation-operator": {
"version": "6.13.0",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
- "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=",
- "dev": true
+ "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4="
},
"babel-plugin-syntax-trailing-function-commas": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
- "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=",
- "dev": true
+ "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM="
},
"babel-plugin-transform-async-to-generator": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
"integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
- "dev": true,
"requires": {
"babel-helper-remap-async-to-generator": "^6.24.1",
"babel-plugin-syntax-async-functions": "^6.8.0",
@@ -1554,7 +1523,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
"integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1563,7 +1531,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
"integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1572,7 +1539,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
"integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
- "dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"babel-template": "^6.26.0",
@@ -1585,7 +1551,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
"integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
- "dev": true,
"requires": {
"babel-helper-define-map": "^6.24.1",
"babel-helper-function-name": "^6.24.1",
@@ -1602,7 +1567,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
"integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-template": "^6.24.1"
@@ -1612,7 +1576,6 @@
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
"integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1621,7 +1584,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
"integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-types": "^6.24.1"
@@ -1631,7 +1593,6 @@
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
"integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1640,7 +1601,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
"integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
- "dev": true,
"requires": {
"babel-helper-function-name": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1651,7 +1611,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
"integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1660,7 +1619,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
"integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
- "dev": true,
"requires": {
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1671,7 +1629,6 @@
"version": "6.26.2",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz",
"integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==",
- "dev": true,
"requires": {
"babel-plugin-transform-strict-mode": "^6.24.1",
"babel-runtime": "^6.26.0",
@@ -1683,7 +1640,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
"integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
- "dev": true,
"requires": {
"babel-helper-hoist-variables": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1694,7 +1650,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
"integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
- "dev": true,
"requires": {
"babel-plugin-transform-es2015-modules-amd": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1705,7 +1660,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
"integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
- "dev": true,
"requires": {
"babel-helper-replace-supers": "^6.24.1",
"babel-runtime": "^6.22.0"
@@ -1715,7 +1669,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
"integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
- "dev": true,
"requires": {
"babel-helper-call-delegate": "^6.24.1",
"babel-helper-get-function-arity": "^6.24.1",
@@ -1729,7 +1682,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
"integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-types": "^6.24.1"
@@ -1739,7 +1691,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
"integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1748,7 +1699,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
"integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
- "dev": true,
"requires": {
"babel-helper-regex": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1759,7 +1709,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
"integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1768,7 +1717,6 @@
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
"integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -1777,7 +1725,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
"integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
- "dev": true,
"requires": {
"babel-helper-regex": "^6.24.1",
"babel-runtime": "^6.22.0",
@@ -1787,14 +1734,12 @@
"jsesc": {
"version": "0.5.0",
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
- "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
- "dev": true
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0="
},
"regexpu-core": {
"version": "2.0.0",
"resolved": "http://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
"integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
- "dev": true,
"requires": {
"regenerate": "^1.2.1",
"regjsgen": "^0.2.0",
@@ -1804,14 +1749,12 @@
"regjsgen": {
"version": "0.2.0",
"resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
- "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
- "dev": true
+ "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc="
},
"regjsparser": {
"version": "0.1.5",
"resolved": "http://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
"integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
- "dev": true,
"requires": {
"jsesc": "~0.5.0"
}
@@ -1822,7 +1765,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
"integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=",
- "dev": true,
"requires": {
"babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1",
"babel-plugin-syntax-exponentiation-operator": "^6.8.0",
@@ -1833,7 +1775,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
"integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
- "dev": true,
"requires": {
"regenerator-transform": "^0.10.0"
},
@@ -1842,7 +1783,6 @@
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
"integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
- "dev": true,
"requires": {
"babel-runtime": "^6.18.0",
"babel-types": "^6.19.0",
@@ -1855,7 +1795,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
"integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-types": "^6.24.1"
@@ -1865,7 +1804,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
"integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
- "dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"core-js": "^2.5.0",
@@ -1875,8 +1813,7 @@
"regenerator-runtime": {
"version": "0.10.5",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
- "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
- "dev": true
+ "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
}
}
},
@@ -1884,7 +1821,6 @@
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz",
"integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==",
- "dev": true,
"requires": {
"babel-plugin-check-es2015-constants": "^6.22.0",
"babel-plugin-syntax-trailing-function-commas": "^6.22.0",
@@ -1922,7 +1858,6 @@
"version": "3.2.8",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz",
"integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==",
- "dev": true,
"requires": {
"caniuse-lite": "^1.0.30000844",
"electron-to-chromium": "^1.3.47"
@@ -1934,7 +1869,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
"integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
- "dev": true,
"requires": {
"babel-core": "^6.26.0",
"babel-runtime": "^6.26.0",
@@ -1949,7 +1883,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
@@ -1959,7 +1892,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
"integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
- "dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"babel-traverse": "^6.26.0",
@@ -1972,7 +1904,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
"integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
- "dev": true,
"requires": {
"babel-code-frame": "^6.26.0",
"babel-messages": "^6.23.0",
@@ -1989,7 +1920,6 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -1997,14 +1927,12 @@
"globals": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
- "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
- "dev": true
+ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
@@ -2012,7 +1940,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
"integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
- "dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"esutils": "^2.0.2",
@@ -2023,16 +1950,14 @@
"to-fast-properties": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
- "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
- "dev": true
+ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
}
}
},
"babylon": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
- "dev": true
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
},
"backbone": {
"version": "1.3.3",
@@ -3989,7 +3914,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
"integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
- "dev": true,
"requires": {
"repeating": "^2.0.0"
}
@@ -4442,7 +4366,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-3.0.1.tgz",
"integrity": "sha512-pyyB2s52vKTXDC5svU3IjU7GRLg2+5O81o9Ui0ZSiBS14US/bZl46H2dwcdSJAK+T+Za36ZkQM9eh1rNwOxfoA==",
- "dev": true,
"requires": {
"broccoli-persistent-filter": "^1.4.3",
"hash-for-dep": "^1.2.3",
@@ -4453,8 +4376,7 @@
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
- "dev": true
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
}
}
},
@@ -4731,6 +4653,83 @@
"semver": "^5.3.0"
}
},
+ "ember-data-save-relationships": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/ember-data-save-relationships/-/ember-data-save-relationships-0.0.10.tgz",
+ "integrity": "sha1-vXigw+p2J8KjHumlAzIp+jZt8Sc=",
+ "requires": {
+ "ember-cli-babel": "^6.12.0"
+ },
+ "dependencies": {
+ "amd-name-resolver": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz",
+ "integrity": "sha512-hlSTWGS1t6/xq5YCed7YALg7tKZL3rkl7UwEZ/eCIkn8JxmM6fU6Qs/1hwtjQqfuYxlffuUcgYEm0f5xP4YKaA==",
+ "requires": {
+ "ensure-posix-path": "^1.0.1"
+ }
+ },
+ "broccoli-babel-transpiler": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.1.tgz",
+ "integrity": "sha512-w6GcnkxvHcNCte5FcLGEG1hUdQvlfvSN/6PtGWU/otg69Ugk8rUk51h41R0Ugoc+TNxyeFG1opRt2RlA87XzNw==",
+ "requires": {
+ "babel-core": "^6.26.0",
+ "broccoli-funnel": "^2.0.1",
+ "broccoli-merge-trees": "^2.0.0",
+ "broccoli-persistent-filter": "^1.4.3",
+ "clone": "^2.0.0",
+ "hash-for-dep": "^1.2.3",
+ "heimdalljs-logger": "^0.1.7",
+ "json-stable-stringify": "^1.0.0",
+ "rsvp": "^4.8.2",
+ "workerpool": "^2.3.0"
+ }
+ },
+ "broccoli-merge-trees": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.1.tgz",
+ "integrity": "sha512-WjaexJ+I8BxP5V5RNn6um/qDRSmKoiBC/QkRi79FT9ClHfldxRyCDs9mcV7mmoaPlsshmmPaUz5jdtcKA6DClQ==",
+ "requires": {
+ "broccoli-plugin": "^1.3.0",
+ "merge-trees": "^1.0.1"
+ }
+ },
+ "ember-cli-babel": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz",
+ "integrity": "sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA==",
+ "requires": {
+ "amd-name-resolver": "1.2.0",
+ "babel-plugin-debug-macros": "^0.2.0-beta.6",
+ "babel-plugin-ember-modules-api-polyfill": "^2.6.0",
+ "babel-plugin-transform-es2015-modules-amd": "^6.24.0",
+ "babel-polyfill": "^6.26.0",
+ "babel-preset-env": "^1.7.0",
+ "broccoli-babel-transpiler": "^6.5.0",
+ "broccoli-debug": "^0.6.4",
+ "broccoli-funnel": "^2.0.0",
+ "broccoli-source": "^1.1.0",
+ "clone": "^2.0.0",
+ "ember-cli-version-checker": "^2.1.2",
+ "semver": "^5.5.0"
+ }
+ },
+ "merge-trees": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-trees/-/merge-trees-1.0.1.tgz",
+ "integrity": "sha1-zL5nRWl4f53vF/1G5lJfVwC70j4=",
+ "requires": {
+ "can-symlink": "^1.0.0",
+ "fs-tree-diff": "^0.5.4",
+ "heimdalljs": "^0.2.1",
+ "heimdalljs-logger": "^0.1.7",
+ "rimraf": "^2.4.3",
+ "symlink-or-copy": "^1.0.0"
+ }
+ }
+ }
+ },
"ember-disable-prototype-extensions": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz",
@@ -7471,7 +7470,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "dev": true,
"requires": {
"ansi-regex": "^2.0.0"
},
@@ -7479,8 +7477,7 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
}
}
},
@@ -7641,7 +7638,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
"integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
- "dev": true,
"requires": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.1"
@@ -7976,7 +7972,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
"integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
- "dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -9401,8 +9396,7 @@
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"object-assign": {
"version": "4.1.1",
@@ -9574,8 +9568,7 @@
"os-homedir": {
"version": "1.0.2",
"resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
- "dev": true
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
},
"os-shim": {
"version": "0.1.3",
@@ -10369,7 +10362,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
"integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
- "dev": true,
"requires": {
"is-finite": "^1.0.0"
}
@@ -10704,8 +10696,7 @@
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
- "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
- "dev": true
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
},
"slice-ansi": {
"version": "1.0.0",
@@ -10995,7 +10986,6 @@
"version": "0.4.18",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
"integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
- "dev": true,
"requires": {
"source-map": "^0.5.6"
}
diff --git a/package.json b/package.json
index 77d0bce..52ca7ef 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,8 @@
},
"dependencies": {
"ember-cli-babel": "^7.1.2",
- "ember-cli-htmlbars": "^3.0.0"
+ "ember-cli-htmlbars": "^3.0.0",
+ "ember-data-save-relationships": "0.0.10"
},
"devDependencies": {
"@ember/optional-features": "^0.6.3",
@@ -35,6 +36,7 @@
"ember-cli-sri": "^2.1.1",
"ember-cli-template-lint": "^1.0.0-beta.1",
"ember-cli-uglify": "^2.1.0",
+ "ember-data-save-relationships": "0.0.10",
"ember-disable-prototype-extensions": "^1.1.3",
"ember-export-application-global": "^2.0.0",
"ember-load-initializers": "^1.1.0",
diff --git a/tests/integration/components/create-form-test.js b/tests/integration/components/create-form-test.js
new file mode 100644
index 0000000..ffa3bae
--- /dev/null
+++ b/tests/integration/components/create-form-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | create-form', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{create-form}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#create-form}}
+ template block text
+ {{/create-form}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/edit-for-list-test.js b/tests/integration/components/edit-for-list-test.js
new file mode 100644
index 0000000..e89fc19
--- /dev/null
+++ b/tests/integration/components/edit-for-list-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | edit-for-list', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{edit-for-list}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#edit-for-list}}
+ template block text
+ {{/edit-for-list}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/edit-page-test.js b/tests/integration/components/edit-page-test.js
new file mode 100644
index 0000000..4234aa6
--- /dev/null
+++ b/tests/integration/components/edit-page-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | edit-page', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{edit-page}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#edit-page}}
+ template block text
+ {{/edit-page}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/edit-tutorial-test.js b/tests/integration/components/edit-tutorial-test.js
new file mode 100644
index 0000000..7c87428
--- /dev/null
+++ b/tests/integration/components/edit-tutorial-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | edit-tutorial', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{edit-tutorial}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#edit-tutorial}}
+ template block text
+ {{/edit-tutorial}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/landscape-interaction-test.js b/tests/integration/components/landscape-interaction-test.js
new file mode 100644
index 0000000..92902b0
--- /dev/null
+++ b/tests/integration/components/landscape-interaction-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | landscape-interaction', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{landscape-interaction}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#landscape-interaction}}
+ template block text
+ {{/landscape-interaction}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/landscape-select/landscapelist-test.js b/tests/integration/components/landscape-select/landscapelist-test.js
new file mode 100644
index 0000000..db4fc46
--- /dev/null
+++ b/tests/integration/components/landscape-select/landscapelist-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | landscape-select/landscapelist', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{landscape-select/landscapelist}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#landscape-select/landscapelist}}
+ template block text
+ {{/landscape-select/landscapelist}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/landscape-select/navbar/return-to-saved-test.js b/tests/integration/components/landscape-select/navbar/return-to-saved-test.js
new file mode 100644
index 0000000..86cc467
--- /dev/null
+++ b/tests/integration/components/landscape-select/navbar/return-to-saved-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | landscape-select/navbar/return-to-saved', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{landscape-select/navbar/return-to-saved}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#landscape-select/navbar/return-to-saved}}
+ template block text
+ {{/landscape-select/navbar/return-to-saved}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/landscape-select/navbar/save-landscape-test.js b/tests/integration/components/landscape-select/navbar/save-landscape-test.js
new file mode 100644
index 0000000..a633b51
--- /dev/null
+++ b/tests/integration/components/landscape-select/navbar/save-landscape-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | landscape-select/navbar/save-landscape', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{landscape-select/navbar/save-landscape}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#landscape-select/navbar/save-landscape}}
+ template block text
+ {{/landscape-select/navbar/save-landscape}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/landscape-select/navbar/toggle-live-landscape-test.js b/tests/integration/components/landscape-select/navbar/toggle-live-landscape-test.js
new file mode 100644
index 0000000..f1feca7
--- /dev/null
+++ b/tests/integration/components/landscape-select/navbar/toggle-live-landscape-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | landscape-select/navbar/toggle-live-landscape', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{landscape-select/navbar/toggle-live-landscape}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#landscape-select/navbar/toggle-live-landscape}}
+ template block text
+ {{/landscape-select/navbar/toggle-live-landscape}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/landscape-select/timeline-test.js b/tests/integration/components/landscape-select/timeline-test.js
new file mode 100644
index 0000000..9e009cd
--- /dev/null
+++ b/tests/integration/components/landscape-select/timeline-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | landscape-select/timeline', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{landscape-select/timeline}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#landscape-select/timeline}}
+ template block text
+ {{/landscape-select/timeline}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/landscape-visualization-test.js b/tests/integration/components/landscape-visualization-test.js
new file mode 100644
index 0000000..024d818
--- /dev/null
+++ b/tests/integration/components/landscape-visualization-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | landscape-visualization', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{landscape-visualization}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#landscape-visualization}}
+ template block text
+ {{/landscape-visualization}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/sequence-form-test.js b/tests/integration/components/sequence-form-test.js
new file mode 100644
index 0000000..4fc20cb
--- /dev/null
+++ b/tests/integration/components/sequence-form-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | sequence-form', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{sequence-form}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#sequence-form}}
+ template block text
+ {{/sequence-form}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/side-form-test.js b/tests/integration/components/side-form-test.js
new file mode 100644
index 0000000..ce56371
--- /dev/null
+++ b/tests/integration/components/side-form-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | side-form', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{side-form}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#side-form}}
+ template block text
+ {{/side-form}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/step-form-test.js b/tests/integration/components/step-form-test.js
new file mode 100644
index 0000000..15a9865
--- /dev/null
+++ b/tests/integration/components/step-form-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | step-form', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{step-form}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#step-form}}
+ template block text
+ {{/step-form}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/tutorial-editor-test.js b/tests/integration/components/tutorial-editor-test.js
new file mode 100644
index 0000000..3834be0
--- /dev/null
+++ b/tests/integration/components/tutorial-editor-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | tutorial-editor', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{tutorial-editor}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#tutorial-editor}}
+ template block text
+ {{/tutorial-editor}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/tutorial-form-test.js b/tests/integration/components/tutorial-form-test.js
new file mode 100644
index 0000000..2998130
--- /dev/null
+++ b/tests/integration/components/tutorial-form-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | tutorial-form', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{tutorial-form}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#tutorial-form}}
+ template block text
+ {{/tutorial-form}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/tutorial-hierarchie-test.js b/tests/integration/components/tutorial-hierarchie-test.js
new file mode 100644
index 0000000..f74557e
--- /dev/null
+++ b/tests/integration/components/tutorial-hierarchie-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | tutorial-hierarchie', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{tutorial-hierarchie}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#tutorial-hierarchie}}
+ template block text
+ {{/tutorial-hierarchie}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/integration/components/tutorial-management-test.js b/tests/integration/components/tutorial-management-test.js
new file mode 100644
index 0000000..fe30c35
--- /dev/null
+++ b/tests/integration/components/tutorial-management-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | tutorial-management', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs`{{tutorial-management}}`);
+
+ assert.equal(this.element.textContent.trim(), '');
+
+ // Template block usage:
+ await render(hbs`
+ {{#tutorial-management}}
+ template block text
+ {{/tutorial-management}}
+ `);
+
+ assert.equal(this.element.textContent.trim(), 'template block text');
+ });
+});
diff --git a/tests/unit/controllers/tutorial-management-test.js b/tests/unit/controllers/tutorial-management-test.js
new file mode 100644
index 0000000..1e4a5ac
--- /dev/null
+++ b/tests/unit/controllers/tutorial-management-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial-management', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial-management');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/edit/sequence-test.js b/tests/unit/controllers/tutorial/edit/sequence-test.js
new file mode 100644
index 0000000..0cff886
--- /dev/null
+++ b/tests/unit/controllers/tutorial/edit/sequence-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/edit/sequence', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/edit/sequence');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/edit/step-test.js b/tests/unit/controllers/tutorial/edit/step-test.js
new file mode 100644
index 0000000..060a65e
--- /dev/null
+++ b/tests/unit/controllers/tutorial/edit/step-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/edit/step', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/edit/step');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/edit/step/target-test.js b/tests/unit/controllers/tutorial/edit/step/target-test.js
new file mode 100644
index 0000000..0d868a4
--- /dev/null
+++ b/tests/unit/controllers/tutorial/edit/step/target-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/edit/step/target', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/edit/step/target');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/edit/tutorial-test.js b/tests/unit/controllers/tutorial/edit/tutorial-test.js
new file mode 100644
index 0000000..4d15b74
--- /dev/null
+++ b/tests/unit/controllers/tutorial/edit/tutorial-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/edit/tutorial', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/edit/tutorial');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/edit/tutorial/landscape-test.js b/tests/unit/controllers/tutorial/edit/tutorial/landscape-test.js
new file mode 100644
index 0000000..2ef9f04
--- /dev/null
+++ b/tests/unit/controllers/tutorial/edit/tutorial/landscape-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/edit/tutorial/landscape', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/edit/tutorial/landscape');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/edit/tutorial/target-test.js b/tests/unit/controllers/tutorial/edit/tutorial/target-test.js
new file mode 100644
index 0000000..117b970
--- /dev/null
+++ b/tests/unit/controllers/tutorial/edit/tutorial/target-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/edit/tutorial/target', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/edit/tutorial/target');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/list-test.js b/tests/unit/controllers/tutorial/list-test.js
new file mode 100644
index 0000000..9eb0651
--- /dev/null
+++ b/tests/unit/controllers/tutorial/list-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/list', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/list');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/list/landscape-test.js b/tests/unit/controllers/tutorial/list/landscape-test.js
new file mode 100644
index 0000000..2910eb2
--- /dev/null
+++ b/tests/unit/controllers/tutorial/list/landscape-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/list/landscape', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/list/landscape');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/run-test.js b/tests/unit/controllers/tutorial/run-test.js
new file mode 100644
index 0000000..1613479
--- /dev/null
+++ b/tests/unit/controllers/tutorial/run-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/run', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/run');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/sequence-test.js b/tests/unit/controllers/tutorial/sequence-test.js
new file mode 100644
index 0000000..99072e8
--- /dev/null
+++ b/tests/unit/controllers/tutorial/sequence-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/sequence', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/sequence');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/step-test.js b/tests/unit/controllers/tutorial/step-test.js
new file mode 100644
index 0000000..c95444f
--- /dev/null
+++ b/tests/unit/controllers/tutorial/step-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/step', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/step');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/tutorial/tutorial-test.js b/tests/unit/controllers/tutorial/tutorial-test.js
new file mode 100644
index 0000000..f32f7c2
--- /dev/null
+++ b/tests/unit/controllers/tutorial/tutorial-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | tutorial/tutorial', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:tutorial/tutorial');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/routes/tutorial/edit/sequence-test.js b/tests/unit/routes/tutorial/edit/sequence-test.js
new file mode 100644
index 0000000..5fa9624
--- /dev/null
+++ b/tests/unit/routes/tutorial/edit/sequence-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/edit/sequence', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/edit/sequence');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/edit/step-test.js b/tests/unit/routes/tutorial/edit/step-test.js
new file mode 100644
index 0000000..0228b01
--- /dev/null
+++ b/tests/unit/routes/tutorial/edit/step-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/edit/step', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/edit/step');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/edit/step/target-test.js b/tests/unit/routes/tutorial/edit/step/target-test.js
new file mode 100644
index 0000000..ae8a493
--- /dev/null
+++ b/tests/unit/routes/tutorial/edit/step/target-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/edit/step/target', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/edit/step/target');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/edit/tutorial-test.js b/tests/unit/routes/tutorial/edit/tutorial-test.js
new file mode 100644
index 0000000..c1231cb
--- /dev/null
+++ b/tests/unit/routes/tutorial/edit/tutorial-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/edit/tutorial', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/edit/tutorial');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/edit/tutorial/landscape-test.js b/tests/unit/routes/tutorial/edit/tutorial/landscape-test.js
new file mode 100644
index 0000000..e21e4db
--- /dev/null
+++ b/tests/unit/routes/tutorial/edit/tutorial/landscape-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/edit/tutorial/landscape', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/edit/tutorial/landscape');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/edit/tutorial/target-test.js b/tests/unit/routes/tutorial/edit/tutorial/target-test.js
new file mode 100644
index 0000000..be47d81
--- /dev/null
+++ b/tests/unit/routes/tutorial/edit/tutorial/target-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/edit/tutorial/target', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/edit/tutorial/target');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/list-test.js b/tests/unit/routes/tutorial/list-test.js
new file mode 100644
index 0000000..3873296
--- /dev/null
+++ b/tests/unit/routes/tutorial/list-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/list', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/list');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/list/sequence-test.js b/tests/unit/routes/tutorial/list/sequence-test.js
new file mode 100644
index 0000000..cbfc509
--- /dev/null
+++ b/tests/unit/routes/tutorial/list/sequence-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/list/sequence', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/list/sequence');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/list/step-test.js b/tests/unit/routes/tutorial/list/step-test.js
new file mode 100644
index 0000000..c4201f9
--- /dev/null
+++ b/tests/unit/routes/tutorial/list/step-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/list/step', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/list/step');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/list/tutorial-test.js b/tests/unit/routes/tutorial/list/tutorial-test.js
new file mode 100644
index 0000000..ae9e1a6
--- /dev/null
+++ b/tests/unit/routes/tutorial/list/tutorial-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/list/tutorial', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/list/tutorial');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/run-test.js b/tests/unit/routes/tutorial/run-test.js
new file mode 100644
index 0000000..9fe3a92
--- /dev/null
+++ b/tests/unit/routes/tutorial/run-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/run', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/run');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/sequence-test.js b/tests/unit/routes/tutorial/sequence-test.js
new file mode 100644
index 0000000..b9764d2
--- /dev/null
+++ b/tests/unit/routes/tutorial/sequence-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/sequence', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/sequence');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/step-test.js b/tests/unit/routes/tutorial/step-test.js
new file mode 100644
index 0000000..a7b6f64
--- /dev/null
+++ b/tests/unit/routes/tutorial/step-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/step', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/step');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/tutorial/tutorial-test.js b/tests/unit/routes/tutorial/tutorial-test.js
new file mode 100644
index 0000000..b804424
--- /dev/null
+++ b/tests/unit/routes/tutorial/tutorial-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | tutorial/tutorial', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:tutorial/tutorial');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/services/landscape-test.js b/tests/unit/services/landscape-test.js
new file mode 100644
index 0000000..597f24e
--- /dev/null
+++ b/tests/unit/services/landscape-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Service | landscape', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let service = this.owner.lookup('service:landscape');
+ assert.ok(service);
+ });
+});
diff --git a/tests/unit/services/tutorial-landscape-test.js b/tests/unit/services/tutorial-landscape-test.js
new file mode 100644
index 0000000..01659dd
--- /dev/null
+++ b/tests/unit/services/tutorial-landscape-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Service | tutorial-landscape', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let service = this.owner.lookup('service:tutorial-landscape');
+ assert.ok(service);
+ });
+});