@@ -31,7 +31,6 @@ <h4>Data</h4>
3131 < th > </ th >
3232 </ tr >
3333 </ thead >
34- {% define_data_product_type products %}
3534 < tbody id ="manageDataTBody ">
3635 {% for product in products %}
3736 < tr data-file ="{{ product.product_id }} ">
@@ -81,7 +80,31 @@ <h4>Data</h4>
8180 >
8281 </ td >
8382 < td >
84- {% if product.data_product_type %} {{ product.get_type_display }} {% endif %}
83+ < div class ="dropdown ">
84+ < button
85+ class ="btn btn-secondary dropdown-toggle "
86+ type ="button "
87+ data-bs-toggle ="dropdown "
88+ aria-expanded ="false ">
89+ < span class ="button-text "> {{ product.data_product_type_label }}</ span >
90+ < span
91+ class ="spinner-border spinner-border-sm d-none "
92+ role ="status "
93+ aria-hidden ="true "> </ span >
94+ </ button >
95+ < ul class ="dropdown-menu " data-id ="{{ product.id }} ">
96+ {% for value, label in data_product_type_choices %}
97+ < li >
98+ < a
99+ class ="dropdown-item {% if value == product.data_product_type %}active{% endif %} "
100+ href ="# "
101+ data-value ="{{ value }} "
102+ > {{ label }}</ a
103+ >
104+ </ li >
105+ {% endfor %}
106+ </ ul >
107+ </ div >
85108 </ td >
86109 <!-- <td>
87110 {% if sharing_destinations %}
@@ -220,6 +243,78 @@ <h4>Data</h4>
220243 await actions [ action ] ?. ( ) ;
221244 } ) ;
222245
246+ // Event listener for handling data product type changes.
247+ tableBody . addEventListener ( "click" , async ( event ) => {
248+ const item = event . target . closest ( "a.dropdown-item[data-value]" ) ;
249+
250+ if ( ! item ) return ;
251+ event . preventDefault ( ) ;
252+
253+ const menu = item . closest ( "ul.dropdown-menu" ) ;
254+ const { id } = menu . dataset ;
255+ const { value } = item . dataset ;
256+ const label = item . textContent . trim ( ) ;
257+
258+ const dropdown = item . closest ( ".dropdown" ) ;
259+ const mainButton = dropdown . querySelector ( ".btn-secondary" ) ;
260+ const buttonText = mainButton . querySelector ( ".button-text" ) ;
261+ const spinner = mainButton . querySelector ( ".spinner-border" ) ;
262+
263+ buttonText . classList . add ( "d-none" ) ;
264+ spinner . classList . remove ( "d-none" ) ;
265+ mainButton . disabled = true ;
266+
267+ try {
268+ await updateDataProductType ( id , value ) ;
269+ buttonText . textContent = label ;
270+ menu . querySelectorAll ( ".dropdown-item" ) . forEach ( ( dropdownItem ) => {
271+ dropdownItem . classList . toggle ( "active" , dropdownItem === item ) ;
272+ } ) ;
273+ window . toast ?. show ( {
274+ label : "Data Product Type Updated" ,
275+ message : `Type changed to "${ label } ".` ,
276+ color : "success" ,
277+ } ) ;
278+ } catch ( error ) {
279+ window . toast ?. show ( {
280+ label : "Failed to Update Data Product Type" ,
281+ message : error . message ,
282+ color : "danger" ,
283+ } ) ;
284+ } finally {
285+ buttonText . classList . remove ( "d-none" ) ;
286+ spinner . classList . add ( "d-none" ) ;
287+ mainButton . disabled = false ;
288+ }
289+ } ) ;
290+
291+ /**
292+ * Updates the `data_product_type` of a data product.
293+ * @param {string } id - The unique identifier of the file.
294+ * @param {string } dataProductType - The new data product type.
295+ * @returns {Promise<void> } - Resolves when the request is completed.
296+ */
297+ const updateDataProductType = async ( id , dataProductType ) => {
298+ const url = `/api/dataproducttype/${ id } /` ;
299+
300+ const response = await fetch ( url , {
301+ method : "PATCH" ,
302+ headers : {
303+ "Content-Type" : "application/json" ,
304+ "X-CSRFToken" : "{{ csrf_token }}" ,
305+ } ,
306+ credentials : "same-origin" ,
307+ body : JSON . stringify ( { data_product_type : dataProductType } ) ,
308+ } ) ;
309+ if ( ! response . ok ) {
310+ // The error response may not be JSON (e.g. an HTML error page).
311+ const data = await response . json ( ) . catch ( ( ) => null ) ;
312+ throw new Error (
313+ data ?. data_product_type ?. [ 0 ] || "Failed to update data product type."
314+ ) ;
315+ }
316+ } ;
317+
223318 /**
224319 * Sends a file to Astro DataLab.
225320 * @param {string } id - The unique identifier of the file.
0 commit comments