88 <b-tab title =" Apps" >
99 <template v-slot :title >
1010 Apps
11- <span style = " opacity : 0.6 ; font-size : 80 % " >{{resource.config.services.length}}</span >
11+ <span class = " resouce-apps-count__span " >{{resource.config.services.length}}</span >
1212 </template >
1313 </b-tab >
1414 </b-tabs >
1515 </b-container >
1616 </div >
17- <b-form class = " page-content " >
18- <b-container >
19- <br >
20-
21- < div v-if = " tab == 0 " >
22- < div style = " padding-bottom : 10 px " >
23- < b-form-checkbox v-model = " resource.active " >Active</ b-form-checkbox >
24- < p >
25- <small >Uncheck this to temporarily disable this resource.</ small >
26- </p >
27- </div >
17+ <b-form >
18+ <div v-if = " tab == 0 " class = " page-content " >
19+ <b-container >
20+ < b-row >
21+ < b-col cols = " 12 " >
22+ < b-form-checkbox v-model = " resource.active " >Active</ b-form-checkbox >
23+ < p >
24+ < small >Uncheck this to temporarily disable this resource.</ small >
25+ </ p >
26+ </b-col >
27+ </b-row >
2828
2929 <b-row >
3030 <b-col cols =" 3" >
3131 <span class =" form-header" >Name *</span >
3232 </b-col >
3333 <b-col cols =" 9" >
3434 <b-input type =" text" v-model =" resource.name" placeholder =" Resource Name" />
35- <br >
3635 </b-col >
3736 </b-row >
3837
4342 <b-col cols =" 9" >
4443 <p >
4544 <contact :id =" resource.user_id" />
46- <br >
4745 <small >Users who registered this resource and administer this resource.</small >
4846 </p >
4947 </b-col >
9290 <small >Please select projects that you'd like enable this resource. Any jobs submitted by any member of specified project will be executed on this resource. You have to be listed as administrator of the project to be able to select it.</small >
9391 </p >
9492 </b-col >
95- <br >
96- <br >
9793 </b-row >
9894
9995 <b-row >
10298 </b-col >
10399 <b-col cols =" 9" >
104100 <b-input type =" text" v-model.trim =" resource.avatar" placeholder =" Avatar URL" />
105- <br >
106101 </b-col >
107102 </b-row >
108103
169164 </b-col >
170165 <b-col cols =" 9" >
171166 <p >
172- <b >Public Key</b >
173- <br >
167+ <b >Public Key</b ><br />
174168 <small >The following ssh public key should be stored in ~/.ssh/authorized_keys on this resource.</small >
175169 <b-form-textarea :rows =" 6" v-model =" resource.config.ssh_public" />
176170 </p >
177171 <p >
178- <b >Private Key</b >
179- <br >
172+ <b >Private Key</b ><br />
180173 <small >Brainlife will use the following private key to access this resource (You should not have to copy/paste this out of here).</small >
181174 <b-form-checkbox v-if =" resource.config.enc_ssh_private === true" v-model =" resource.config.enc_ssh_private" >Use the current private key</b-form-checkbox >
182175 <b-form-textarea v-if =" resource.config.enc_ssh_private !== true" :rows =" 3" v-model =" resource.config.enc_ssh_private" />
183176 </p >
184177 <p >
185- <b-btn @click =" reset_sshkey" size =" sm" >Issue New Keypair</b-btn >
178+ <b-btn @click =" reset_sshkey" size =" sm" :disabled = " resetting_sshkey " >Issue New Keypair</b-btn >
186179 </p >
187180
188181 </b-col >
189182 </b-row >
183+ </b-container >
184+ </div >
190185
191- </div ><!-- end of detail tab-->
192-
193- <div v-if =" tab == 1" >
186+ <div v-if =" tab == 1" class =" page-content" >
187+ <b-container >
194188 <p >
195189 <b-input-group prepend =" Max Jobs" >
196190 <b-input type =" text" v-model =" resource.config.maxtask" />
201195 <p >
202196 <small >The following Apps are allowed to run on this resource.</small >
203197 </p >
204- <div v-for =" (service, idx) in resource.config.services" :key =" idx" style =" margin-bottom : 5px ;" >
205- <b-button @click =" remove_service(service)" size =" sm" text =" Button" variant =" danger" style =" float : right ;" ><icon name =" trash" /></b-button >
206- <div style =" padding-right : 50px ;" >
207- <b-input-group prepend =" Name" >
208- <b-form-input v-model =" service.name" list =" service_names" trim ></b-form-input >
209- <datalist id =" service_names" >
210- <option v-for =" service in service_names" >{{service}}</option >
211- </datalist >
212- <b-input-group-prepend is-text >Score</b-input-group-prepend >
213- <b-form-input v-model =" service.score" ></b-form-input >
214- </b-input-group >
215- </div >
198+ <div v-for =" (service, idx) in resource.config.services" :key =" idx" class =" resource-apps-detail__div" >
199+ <b-row >
200+ <b-col >
201+ <b-input-group >
202+ <b-input-group-prepend is-text >Name</b-input-group-prepend >
203+ <b-form-input v-model =" service.name" list =" service_names" trim ></b-form-input >
204+ <datalist id =" service_names" >
205+ <option v-for =" service in service_names" >{{service}}</option >
206+ </datalist >
207+ <b-input-group-prepend is-text >Score</b-input-group-prepend >
208+ <b-form-input v-model =" service.score" ></b-form-input >
209+ </b-input-group >
210+ </b-col >
211+ <b-col cols =" auto" >
212+ <b-button @click =" remove_service(service)" size =" sm" text =" Button" variant =" danger" ><icon name =" trash" /></b-button >
213+ </b-col >
214+ </b-row >
216215 </div >
217216 <p >
218217 <b-btn @click =" add_service" variant =" success" size =" sm" >Add App</b-btn >
219218 </p >
220- </div >
221- < div class = " page-footer " >
222- < b-container >
223- <b-button variant = " danger " @click = " remove " v-if = " this.resource._id " style = " float : left ; " >< icon name = " trash " /> Remove</ b-button >
224- <b-button variant = " secondary " @click = " cancel " >Cancel</ b-button >
225- <b-button variant = " primary " @click = " submit " :disabled = " submitting " >< icon v-if = " submitting " name = " cog " spin /> Submit</ b-button >
226- </ b-container >
227- </ div >
228-
229- < br >
230- < br >
231- < br >
232- < br >
233- <br >
234- </b-container >
219+ </b-container >
220+ </ div >
221+ < div class = " page-footer " >
222+ <b-container >
223+ <b-row no-gutters >
224+ <b-col cols = " auto " >
225+ < b-button variant = " danger " @click = " remove " v-if = " this.resource._id " >< icon name = " trash " /> Remove</ b-button >
226+ </ b-col >
227+ < b-col >
228+ < b-button variant = " secondary " @click = " cancel " >Cancel</ b-button >
229+ < b-button variant = " primary " @click = " submit " :disabled = " submitting " >< icon v-if = " submitting " name = " cog " spin /> Submit</ b-button >
230+ </ b-col >
231+ </ b-row >
232+ </ b-container >
233+ </div >
235234 <!--
236235 <div v-if="config.debug">
237236 <pre>{{JSON.stringify(resource, null, 4)}}</pre>
@@ -249,8 +248,8 @@ import contactlist from '@/components/contactlist'
249248import contact from ' @/components/contact'
250249import tageditor from ' @/components/tageditor'
251250
252- // let's lazy fetch node-forge (it's pretty big..)
253- const getForge = ()=> import (' node-forge' )
251+ // Lazy import, given the module is big
252+ const getForge = () => import (' node-forge' )
254253
255254export default {
256255 components: {
@@ -262,38 +261,31 @@ export default {
262261 data () {
263262 return {
264263 resource: null ,
265-
266264 projects: null ,
267-
268265 tab: 0 ,
269-
270266 envs_: " " ,
271- // global: false,
272- // archive_access: false,
273-
274- service_names: [], // all services that user can choose from
275-
267+ service_names: [], // All services that user can choose from
276268 submitting: false ,
277-
269+ resetting_sshkey : false ,
278270 config: Vue .config ,
279271 }
280272 },
281273
282274 mounted : function () {
283275
284- // load all apps service names
276+ // Load all apps service names
285277 this .$http .get (" app" , {params: {
286278 select: " github" ,
287279 limit: 1000 ,
288280 }}).then (res => {
289- this .service_names = res .data .apps .map (app => app .github );
290- this .service_names = [... new Set (this .service_names )]; // debupe
291- this .service_names = this .service_names .filter (name => name && name .includes (" /" )); // remove odd looking service names
281+ this .service_names = res .data .apps .map (app => app .github );
282+ this .service_names = [... new Set (this .service_names )]; // remove duplicates
283+ this .service_names = this .service_names .filter (name => name && name .includes (" /" )); // remove odd looking service names
292284 this .service_names .sort ();
293285 });
294286
295287 if (this .$route .params .id !== ' _' ) {
296- // TODO use resource_cache mixin?
288+ // TODO use resource_cache mixin?
297289 this .$http .get (Vue .config .amaretti_api + ' /resource' , {params: {
298290 find: JSON .stringify ({_id: this .$route .params .id })
299291 }}).then (res => {
@@ -318,12 +310,11 @@ export default {
318310 this .reset_sshkey ();
319311 this .loadProjects ();
320312 }
321-
322313 },
323314
324315 methods: {
325316 loadProjects () {
326- // load project that user can share this resource with
317+ // Load projects that user can share this resource with
327318 this .$http .get (' project' , {params: {
328319 find: JSON .stringify ({
329320 removed: false ,
@@ -353,7 +344,7 @@ export default {
353344 });
354345 }
355346
356- // add private groups that user doesn't have access to.. so the value won't disappear
347+ // Add groups that user doesn't have access to, so the selection will not disappear
357348 this .resource .gids .forEach (gid => {
358349 const project = this .projects .find (p => p .group_id == gid);
359350 if (! project) {
@@ -387,26 +378,33 @@ export default {
387378 },
388379
389380 reset_sshkey () {
390- delete this .resource .config .enc_ssh_private ;
391- getForge ().then (forge => {
392- // publicKeyToOpenSSH only works for rsa.. not forge.pki.ed25519
393- forge .pki .rsa .generateKeyPair ({bits: 2048 , workers: 2 /* e: 0x10001*/ }, (err , keypair )=> {
394- if (err) {
395- this .$notify ({type: ' error' , text: err});
396- return ;
397- }
398- Vue .set (this .resource .config , ' ssh_public' , forge .ssh .publicKeyToOpenSSH (keypair .publicKey ));// , "pubkey comment");
399- Vue .set (this .resource .config , ' enc_ssh_private' , forge .ssh .privateKeyToOpenSSH (keypair .privateKey ));
400- });
401- });
381+ if (this .resetting_sshkey ) return ;
382+ this .resetting_sshkey = true ;
383+ getForge ()
384+ .then (forge => {
385+ forge .pki .rsa .generateKeyPair ({bits: 2048 , workers: 2 }, (err , keypair ) => {
386+ if (err) {
387+ this .$notify ({type: ' error' , text: err});
388+ this .resetting_sshkey = false ;
389+ return ;
390+ }
391+ delete this .resource .config .enc_ssh_private ;
392+ Vue .set (this .resource .config , ' ssh_public' , forge .ssh .publicKeyToOpenSSH (keypair .publicKey ));
393+ Vue .set (this .resource .config , ' enc_ssh_private' , forge .ssh .privateKeyToOpenSSH (keypair .privateKey ));
394+ this .resetting_sshkey = false ;
395+ });
396+ })
397+ .catch (err => {
398+ this .$notify ({type: ' error' , text: err});
399+ this .resetting_sshkey = false ;
400+ })
402401 },
403402
404- submit (evt ) {
405- evt .preventDefault (); // TODO do I need this?
406- if (this .submitting ) return ; // prevent double submission..
403+ submit () {
404+ if (this .submitting ) return ; // Prevent double submission
407405 this .submitting = true ;
408- // validate things
409- if (this .envs_ && this .envs_ .trim ()) {
406+
407+ if (this .envs_ && this .envs_ .trim ()) {
410408 try {
411409 this .resource .envs = JSON .parse (this .envs_ );
412410 } catch (err) {
@@ -415,25 +413,22 @@ export default {
415413 return ;
416414 }
417415 }
418- if (! this .resource .gids .length ) {
416+ if (! this .resource .gids .length ) {
419417 this .$notify ({type: ' error' , text: " Please specify at least 1 project to use this resource" });
420418 this .submitting = false ;
421419 return ;
422420 }
423421
424- if (this .resource ._id ) {
425- // update
422+ if (this .resource ._id ) { // Update resource
426423 this .$http .put (Vue .config .amaretti_api + ' /resource/' + this .resource ._id , this .resource ).then (res => {
427- // this.$router.push('/resource/'+this.resource._id);
428424 this .$router .go (- 1 );
429425 this .submitting = false ;
430426 }).catch (err => {
431427 this .$notify ({text: err .response .data .message , type: ' error' });
432428 console .error (err);
433429 this .submitting = false ;
434430 });
435- } else {
436- // create
431+ } else { // Create resource
437432 delete this .resource ._id ;
438433 this .$http .post (Vue .config .amaretti_api + ' /resource' , this .resource ).then (res => {
439434 this .$router .replace (' /resource/' + res .data ._id );
@@ -473,10 +468,24 @@ export default {
473468}
474469.page-content {
475470 margin-top : 40px ;
471+ padding-bottom : 60px ;
472+ }
473+ .page-content .container {
474+ margin-top : 2em ;
475+ }
476+ .page-content .container .row {
477+ margin-bottom : 1em ;
476478}
477479small {
478480 opacity : 0.5 ;
479481}
482+ .resource-apps-detail__div {
483+ margin-bottom : 1em ;
484+ }
485+ .resouce-apps-count__span {
486+ opacity : 0.6 ;
487+ font-size : 80% ;
488+ }
480489.resource-projects-all_admin-message {
481490 color : #C00 ;
482491}
0 commit comments