@@ -7,18 +7,8 @@ import {
77const status = document . querySelector ( "[data-toolbox-votes-status]" ) ;
88const dragStatus = document . querySelector ( "[data-toolbox-votes-drag-status]" ) ;
99const body = document . querySelector ( "[data-toolbox-votes-body]" ) ;
10- const selectedOrder = document . querySelector ( "[data-toolbox-votes-selected-order]" ) ;
11- const selectedGroup = document . querySelector ( "[data-toolbox-votes-selected-group]" ) ;
12- const selectedPath = document . querySelector ( "[data-toolbox-votes-selected-path]" ) ;
1310const sortButtons = Array . from ( document . querySelectorAll ( "[data-toolbox-votes-sort]" ) ) ;
1411const sortHeaders = Array . from ( document . querySelectorAll ( "[data-toolbox-votes-sort-header]" ) ) ;
15- const widthLayout = document . querySelector ( "[data-toolbox-votes-layout]" ) ;
16- const widthToggle = document . querySelector ( "[data-toolbox-votes-width-toggle]" ) ;
17- const widthStatus = document . querySelector ( "[data-toolbox-votes-width-status]" ) ;
18- const groupEdit = document . querySelector ( "[data-toolbox-votes-group-edit]" ) ;
19- const pathEdit = document . querySelector ( "[data-toolbox-votes-path-edit]" ) ;
20- const statusEdit = document . querySelector ( "[data-toolbox-votes-status-edit]" ) ;
21- const metadataSave = document . querySelector ( "[data-toolbox-votes-metadata-save]" ) ;
2212const sortButtonLabels = new Map ( sortButtons . map ( ( button ) => [
2313 button . dataset . toolboxVotesSort ,
2414 button . textContent . trim ( ) ,
@@ -30,6 +20,7 @@ const RELEASE_CHANNEL_OPTIONS = Object.freeze([
3020 [ "beta" , "Beta" ] ,
3121 [ "complete" , "Complete" ] ,
3222] ) ;
23+ const RELEASE_CHANNEL_LABELS = new Map ( RELEASE_CHANNEL_OPTIONS ) ;
3324
3425const SORT_TYPES = Object . freeze ( {
3526 down : "number" ,
@@ -97,6 +88,53 @@ function orderCell(voteRow) {
9788 return cell ;
9889}
9990
91+ function releaseChannelLabel ( value ) {
92+ return RELEASE_CHANNEL_LABELS . get ( value ) || RELEASE_CHANNEL_LABELS . get ( "planned" ) ;
93+ }
94+
95+ function stateCell ( voteRow ) {
96+ const cell = document . createElement ( "td" ) ;
97+ const select = document . createElement ( "select" ) ;
98+ const currentState = RELEASE_CHANNEL_LABELS . has ( voteRow . releaseChannel ) ? voteRow . releaseChannel : "planned" ;
99+ select . dataset . toolboxVotesState = voteRow . toolId ;
100+ select . setAttribute ( "aria-label" , `State for ${ voteRow . toolName } ` ) ;
101+ RELEASE_CHANNEL_OPTIONS . forEach ( ( [ value , label ] ) => {
102+ const option = document . createElement ( "option" ) ;
103+ option . value = value ;
104+ option . textContent = label ;
105+ select . append ( option ) ;
106+ } ) ;
107+ select . value = currentState ;
108+ select . addEventListener ( "click" , ( event ) => {
109+ event . stopPropagation ( ) ;
110+ } ) ;
111+ select . addEventListener ( "change" , ( ) => {
112+ handleStateChange ( voteRow , select ) ;
113+ } ) ;
114+ cell . append ( select ) ;
115+ return cell ;
116+ }
117+
118+ function handleStateChange ( voteRow , select ) {
119+ const nextState = select . value ;
120+ if ( nextState === voteRow . releaseChannel ) {
121+ return ;
122+ }
123+ try {
124+ const snapshot = updateToolboxVoteMetadata ( voteRow . toolId , {
125+ group : voteRow . group ,
126+ path : voteRow . path ,
127+ releaseChannel : nextState ,
128+ } ) ;
129+ renderSnapshot ( snapshot , `${ voteRow . toolName } state updated to ${ releaseChannelLabel ( nextState ) } . Toolbox Build Path uses the same metadata.` ) ;
130+ selectRow ( voteRow . toolId ) ;
131+ } catch ( error ) {
132+ select . value = RELEASE_CHANNEL_LABELS . has ( voteRow . releaseChannel ) ? voteRow . releaseChannel : "planned" ;
133+ const message = error instanceof Error ? error . message : String ( error || "Toolbox state update unavailable." ) ;
134+ setStatus ( `${ voteRow . toolName } state could not be updated. ${ message } ` ) ;
135+ }
136+ }
137+
100138function sortValue ( voteRow , key ) {
101139 if ( key === "currentUserVote" ) {
102140 return voteRow . currentUserVote || "None" ;
@@ -145,74 +183,8 @@ function updateDragStatus() {
145183 dragStatus . textContent = `Drag/drop row ordering is disabled while sorted by ${ sortLabel ( sortState . key ) } . Sort by Order to reorder.` ;
146184}
147185
148- function setSelectedDetails ( voteRow ) {
149- if ( selectedOrder ) {
150- selectedOrder . textContent = voteRow ? String ( wholeNumberOrder ( voteRow . order ) ) : "None" ;
151- }
152- if ( selectedGroup ) {
153- selectedGroup . textContent = voteRow ?. group || "None" ;
154- }
155- if ( selectedPath ) {
156- selectedPath . textContent = voteRow ?. path || "None" ;
157- }
158- setMetadataEditor ( voteRow ) ;
159- }
160-
161- function option ( value , label = value ) {
162- const node = document . createElement ( "option" ) ;
163- node . value = value ;
164- node . textContent = label ;
165- return node ;
166- }
167-
168- function populateGroupOptions ( rows ) {
169- if ( ! groupEdit ) {
170- return ;
171- }
172- const selectedValue = groupEdit . value ;
173- const groups = [ ...new Set ( rows . map ( ( row ) => row . group ) . filter ( Boolean ) ) ] . sort ( ( left , right ) => left . localeCompare ( right ) ) ;
174- groupEdit . replaceChildren ( ...groups . map ( ( group ) => option ( group ) ) ) ;
175- if ( groups . includes ( selectedValue ) ) {
176- groupEdit . value = selectedValue ;
177- }
178- }
179-
180- function populateStatusOptions ( ) {
181- if ( ! statusEdit || statusEdit . childElementCount ) {
182- return ;
183- }
184- statusEdit . replaceChildren ( ...RELEASE_CHANNEL_OPTIONS . map ( ( [ value , label ] ) => option ( value , label ) ) ) ;
185- }
186-
187- function setMetadataEditor ( voteRow ) {
188- populateStatusOptions ( ) ;
189- const disabled = ! voteRow ;
190- [ groupEdit , pathEdit , statusEdit , metadataSave ] . forEach ( ( control ) => {
191- if ( control ) {
192- control . disabled = disabled ;
193- }
194- } ) ;
195- if ( ! voteRow ) {
196- if ( groupEdit ) groupEdit . value = "" ;
197- if ( pathEdit ) pathEdit . value = "" ;
198- if ( statusEdit ) statusEdit . value = "planned" ;
199- return ;
200- }
201- if ( groupEdit ) {
202- groupEdit . value = voteRow . group || "" ;
203- }
204- if ( pathEdit ) {
205- pathEdit . value = voteRow . path || "" ;
206- }
207- if ( statusEdit ) {
208- statusEdit . value = voteRow . releaseChannel || "planned" ;
209- }
210- }
211-
212186function selectRow ( toolId ) {
213187 selectedToolId = String ( toolId || "" ) ;
214- const selectedRow = snapshotRows . find ( ( row ) => row . toolId === selectedToolId ) ;
215- setSelectedDetails ( selectedRow ) ;
216188 body ?. querySelectorAll ( "tr[data-toolbox-votes-tool-id]" ) . forEach ( ( row ) => {
217189 row . setAttribute ( "aria-selected" , String ( row . dataset . toolboxVotesToolId === selectedToolId ) ) ;
218190 } ) ;
@@ -280,7 +252,6 @@ function renderRows(rows) {
280252 return ;
281253 }
282254 snapshotRows = rows ;
283- populateGroupOptions ( snapshotRows ) ;
284255 updateSortHeaders ( ) ;
285256 updateDragStatus ( ) ;
286257 const displayRows = sortedRows ( ) ;
@@ -291,7 +262,7 @@ function renderRows(rows) {
291262 cell . textContent = "No Toolbox vote rows are available." ;
292263 row . append ( cell ) ;
293264 body . replaceChildren ( row ) ;
294- setSelectedDetails ( null ) ;
265+ selectedToolId = "" ;
295266 return ;
296267 }
297268
@@ -320,7 +291,7 @@ function renderRows(rows) {
320291 orderCell ( voteRow ) ,
321292 tableCell ( voteRow . group ) ,
322293 tableCell ( voteRow . path ) ,
323- tableCell ( voteRow . releaseChannelLabel ) ,
294+ stateCell ( voteRow ) ,
324295 tableCell ( voteRow . up ) ,
325296 tableCell ( voteRow . down ) ,
326297 tableCell ( voteRow . totalVotes ) ,
@@ -371,37 +342,4 @@ sortButtons.forEach((button) => {
371342 } ) ;
372343} ) ;
373344
374- widthToggle ?. addEventListener ( "click" , ( ) => {
375- const expanded = widthToggle . getAttribute ( "aria-expanded" ) !== "true" ;
376- widthToggle . setAttribute ( "aria-expanded" , String ( expanded ) ) ;
377- widthToggle . textContent = expanded ? "Collapse Table Width" : "Expand Table Width" ;
378- if ( widthLayout ) {
379- widthLayout . dataset . toolboxVotesExpanded = String ( expanded ) ;
380- }
381- if ( widthStatus ) {
382- widthStatus . textContent = expanded
383- ? "Expanded table width; Admin side menu is collapsed."
384- : "Standard table width." ;
385- }
386- } ) ;
387-
388- metadataSave ?. addEventListener ( "click" , ( ) => {
389- if ( ! selectedToolId ) {
390- setStatus ( "Select a Toolbox row before updating metadata." ) ;
391- return ;
392- }
393- try {
394- const snapshot = updateToolboxVoteMetadata ( selectedToolId , {
395- group : groupEdit ?. value || "" ,
396- path : pathEdit ?. value || "" ,
397- releaseChannel : statusEdit ?. value || "planned" ,
398- } ) ;
399- renderSnapshot ( snapshot , "Toolbox metadata updated. Reload Toolbox Build Path to see the SSoT values." ) ;
400- selectRow ( selectedToolId ) ;
401- } catch ( error ) {
402- const message = error instanceof Error ? error . message : String ( error || "Toolbox metadata update unavailable." ) ;
403- setStatus ( `Toolbox metadata could not be updated. ${ message } ` ) ;
404- }
405- } ) ;
406-
407345renderToolboxVotes ( ) ;
0 commit comments