127127 body
128128 {height : calc (100% - 40px );display : flex;flex-direction : column;gap : 10px ;margin : 20px }
129129
130+ [component ]
131+ {display : none}
132+
130133 input
131134 {font-size : 16px ;padding : 5px 10px }
132135 input [type = button ]
133136 {cursor : pointer}
137+ input [type = checkbox ]
138+ {width : 15px ;height : 15px ;margin : 0 }
134139
135140
136141
137142
143+ .value
144+ {white-space : pre-wrap;font-family : monospace;word-break : break-all;border : 1px solid lightgray;border-radius : 10px ;padding : 10px ;flex : 0 0 auto;}
145+
146+
147+
148+ # keyfile
149+ {height : 350px }
150+
151+
152+ # hldr
153+ {display : inline-block;width : 30px }
154+ # spinner
155+ {width : 20px ;height : 20px }
156+
157+ # scopes
158+ {border : 1px solid lightgray;padding : 10px ;border-radius : 10px }
159+ # scopes-hdr
160+ {margin-bottom : 10px }
161+ # scopes-list
162+ {display : flex;flex-direction : column;gap : 10px ;}
163+ .scopes-item
164+ {display : flex;gap : 20px ;align-items : center;padding : 5px 10px ;cursor : pointer;padding-left : 30px }
165+ .scopes-item : hover
166+ {background : lightyellow}
167+ .scopes-item # scope
168+ {flex : 1 }
169+ .scopes-item # desc
170+ {width : 400px }
171+
172+
138173 # output
139- {white-space : pre-wrap; font-family : monospace; word-break : break-all; border : 1 px solid lightgray; border-radius : 10 px ; padding : 10 px ;
140- height : 350 px ; flex : 0 0 auto; margin-bottom : 30 px ;
141- }
174+ {height : 350 px ; margin-bottom : 20 px }
175+
176+
142177
143178 web-editor
144179 {border : 1px solid lightgray;padding : 10px }
145180
146181 .visually-hidden
147182 {position : absolute;clip : rect (0 0 0 0 );width : 1px ;height : 1px ;overflow : hidden;}
183+
148184
149185 </ style >
150186
@@ -158,6 +194,7 @@ <h1 class=visually-hidden>generate access token from service account keyfile</h1
158194 < img class =title src ='images/generate-token-from-service-account-keyfile.png ' style ='top:5px;height:60px ' alt ='generate access token from service account keyfile '>
159195 < time slot =date datetime =2025-11-01 > 1 Nov 2025</ time >
160196 </ gcloud-hdr >
197+
161198
162199 < div >
163200 select service account keyfile
@@ -166,14 +203,38 @@ <h1 class=visually-hidden>generate access token from service account keyfile</h1
166203 < div >
167204 < input id =file type =file >
168205 </ div >
206+
207+
208+ < div id =keyfile class =value > </ div >
209+
210+
211+ < div id =scopes >
212+ < div id =scopes-hdr >
213+ scopes
214+ </ div >
215+ < div id =scopes-list >
216+ < div class =scopes-item style ='display:none '>
217+ < input type =checkbox checked >
218+ < span id =scope >
219+ https://www.googleapis.com/auth/devstorage.read_write
220+ </ span >
221+ < span id =desc >
222+ </ span >
223+ </ div >
224+ </ div >
225+ </ div >
226+
169227
170228 < div >
229+ < input value ='generate token ' type =button >
230+ < span id =hldr >
231+ < img src ='images/spinner.gif ' style ='display:none '>
232+ </ span >
171233 < input value =copy type =button >
172- < input value =new type =button >
173234 </ div >
235+
174236
175- < div id =output >
176- </ div >
237+ < div id =output class =value > </ div >
177238
178239
179240 < web-editor id =script component fullsize src ='generate.js '> </ web-editor >
@@ -189,26 +250,67 @@ <h1 class=visually-hidden>generate access token from service account keyfile</h1
189250
190251 var keyfile ;
191252 var token ;
253+ var spinner ;
192254
193- var scope = 'https://www.googleapis.com/auth/devstorage.read_write' ;
194-
195-
196- var btn = { } ;
255+ var def_scopes = [
256+ { scope :'https://www.googleapis.com/auth/devstorage.read_write' , chk :true , desc :'Read/write access to Cloud Storage' } ,
257+ { scope :'https://www.googleapis.com/auth/devstorage.full_control' , desc :'Full control Google Cloud Storage' } ,
258+ { scope :'https://www.googleapis.com/auth/cloud-platform' , desc :'Full access to all Google Cloud services' } ,
259+ { scope :'https://www.googleapis.com/auth/drive' , desc :'Full access to Google Drive' } ,
260+ ] ;
261+
262+ var ui = { } ;
197263
198-
264+
265+ var btn = { } ;
266+ var rd = { } ;
267+
268+
269+ //:
270+
271+
199272 function initdom ( ) {
200273
201274
202275 hdr . initdom ( ) ;
203276 script . initdom ( ) ;
204277 log . initdom ( ) ;
205278
206-
207- $ ( '[value=copy]' ) . onclick = btn . copy ;
208- $ ( '[value=new]' ) . onclick = btn . new ;
279+
280+ ui . list = $ ( '#scopes-list' ) ;
281+ ui . scope = $ ( '.scopes-item' ) ;
282+ ui . scope . remove ( ) ;
283+ ui . scope . style . display = '' ;
284+
285+ def_scopes . forEach ( item => {
286+
287+ var nscope = ui . scope . cloneNode ( true ) ;
288+ nscope . onclick = onclick ;
289+ $ ( nscope , '[type]' ) . checked = ! ! item . chk ;
290+ $ ( nscope , '#scope' ) . textContent = item . scope ;
291+ $ ( nscope , '#desc' ) . textContent = item . desc ;
292+ ui . list . append ( nscope ) ;
293+
294+ function onclick ( e ) {
295+
296+ var chk = $ ( nscope , '[type=checkbox]' ) ;
297+ if ( e . target === chk ) {
298+ return ;
299+ }
300+ chk . checked = ! chk . checked ;
301+
302+ } //onclick
303+
304+ } ) ;
305+ rd . scopes ( ) ;
306+
209307
308+ $ ( '[value="generate token"]' ) . onclick = btn . generate ;
309+ spinner = $ ( '#hldr img' ) ;
310+ $ ( '[value=copy]' ) . onclick = btn . copy ;
210311
211- file . onchange = onchange ;
312+
313+ file . onchange = onchange ;
212314
213315
214316
@@ -218,48 +320,62 @@ <h1 class=visually-hidden>generate access token from service account keyfile</h1
218320 //:
219321
220322
323+ btn . generate = async function ( ) {
324+
325+ if ( ! keyfile ) {
326+ log . red ( 'no service account file' ) ;
327+ return ;
328+ }
329+ create ( ) ;
330+
331+ } //generate
332+
333+
221334 btn . copy = function ( ) {
222335
223336 if ( ! token ) {
224- disp ( 'no token' ) ;
337+ log . red ( 'no token' ) ;
225338 return ;
226339 }
227340 navigator . clipboard . writeText ( token ) ;
228- disp ( 'token copied' ) ;
341+ log . green ( 'token copied' ) ;
229342
230343 } //copy
231344
232-
233- btn . new = async function ( ) {
234-
235- if ( ! keyfile ) {
236- disp ( 'no service account file' ) ;
237- return ;
238- }
239- create ( ) ;
240-
241- } //new
242-
243345
244346 async function onchange ( ) {
245347
246348 var blob = file . files [ 0 ] ;
247349 var txt = await blob . text ( ) ;
248350 keyfile = JSON . parse ( txt ) ;
249- create ( ) ;
250-
351+
352+ $ ( '#keyfile' ) . textContent = JSON . stringify ( keyfile , null , 4 ) ;
353+
251354 } //onchange
252355
253356
357+ rd . scopes = function ( ) {
358+
359+ var list = $ . all ( ui . list , '.scopes-item [type=checkbox]' ) ;
360+ list = list . filter ( chk => chk . checked ) ;
361+ list = list . map ( chk => $ ( chk . parentNode , '#scope' ) . textContent ) ;
362+ console . log ( list ) ;
363+ return list ;
364+
365+ } //scopes
366+
367+
254368 //:
255369
256370
257371 async function create ( ) {
258372
259373 output . replaceChildren ( ) ;
374+ $ . show ( spinner ) ;
375+
376+ var scope = rd . scopes ( ) ;
260377
261- gen ( ) ;
262-
378+ fn ( ) ;
263379 var { json, error} = await generate ( keyfile , scope ) ;
264380
265381 if ( error ) {
@@ -270,37 +386,35 @@ <h1 class=visually-hidden>generate access token from service account keyfile</h1
270386 token = json . access_token ;
271387
272388
273-
274- disp . json ( json ) ;
275-
276- disp ( ) ;
277-
278- disp ( 'token' ) ;
389+ navigator . clipboard . writeText ( token ) ;
390+ disp ( 'token, copied to clipboard' ) ;
279391 disp ( token ) ;
280392
281393 disp ( ) ;
282394
283- navigator . clipboard . writeText ( token ) ;
284- disp ( 'copied to clipboard' ) ;
395+ disp . json ( json ) ;
396+
397+ $ . hide ( spinner ) ;
285398
286399 } //create
287400
288401
289- function gen ( ) {
402+ function fn ( ) {
290403
291404 var txt = script . getvalue ( ) ;
292405 window . eval ( txt ) ;
293406
294407 } //gen
295408
296-
409+
297410 function disp ( ) {
298411
299412 console . log . apply ( console , arguments ) ;
300413
301- var str = [ ...arguments ] . join ( ' ' ) ;
302- var div = document . createElement ( 'div' ) ;
303- div . textContent = str ;
414+ var str = [ ...arguments ] . join ( ' ' ) ;
415+
416+ var div = document . createElement ( 'div' ) ;
417+ div . textContent = str || ' ' ;
304418 div . style . cssText = 'margin-bottom:10px' ;
305419 output . append ( div ) ;
306420
0 commit comments