Nariman Jelveh 7 ヶ月 前
コミット
d0940ccd21
2 ファイル変更101 行追加19 行削除
  1. 100 18
      src/dev-center/js/dev-center.js
  2. 1 1
      src/gui/src/IPC.js

+ 100 - 18
src/dev-center/js/dev-center.js

@@ -157,6 +157,9 @@ function refresh_app_list(show_loading = false) {
         $('#loading').show();
         $('#loading').show();
     // get apps
     // get apps
     setTimeout(function () {
     setTimeout(function () {
+        // uncheck the select all checkbox
+        $('.select-all-apps').prop('checked', false);
+
         puter.apps.list().then((apps_res) => {
         puter.apps.list().then((apps_res) => {
             $('#loading').hide();
             $('#loading').hide();
             apps = apps_res;
             apps = apps_res;
@@ -342,8 +345,22 @@ $(document).on('click', '.delete-app', async function (e) {
     let app_title = $(this).attr('data-app-title');
     let app_title = $(this).attr('data-app-title');
     let app_name = $(this).attr('data-app-name');
     let app_name = $(this).attr('data-app-name');
 
 
+    // get app
+    const app_data = await puter.apps.get(app_name);
+
+    if(app_data.metadata?.locked){
+        puter.ui.alert(`<strong>${app_data.title}</strong> is locked and cannot be deleted.`, [
+            {
+                label: 'Ok',
+            },
+        ], {
+            type: 'warning',
+        });
+        return;
+    }
+
     // confirm delete
     // confirm delete
-    const alert_resp = await puter.ui.alert(`Are you sure you want to premanently delete "${html_encode(app_title)}"?`,
+    const alert_resp = await puter.ui.alert(`Are you sure you want to premanently delete <strong>${html_encode(app_title)}</strong>?`,
         [
         [
             {
             {
                 label: 'Yes, delete permanently',
                 label: 'Yes, delete permanently',
@@ -360,8 +377,7 @@ $(document).on('click', '.delete-app', async function (e) {
         let init_ts = Date.now();
         let init_ts = Date.now();
         $('.deleting-app-modal')?.get(0)?.showModal();
         $('.deleting-app-modal')?.get(0)?.showModal();
         puter.apps.delete(app_name).then(async (app) => {
         puter.apps.delete(app_name).then(async (app) => {
-            setTimeout(
-                () => {
+                setTimeout(() => {
                     $('.deleting-app-modal')?.get(0)?.close();
                     $('.deleting-app-modal')?.get(0)?.close();
                     $(`.app-card[data-uid="${app_uid}"]`).fadeOut(200, function name(params) {
                     $(`.app-card[data-uid="${app_uid}"]`).fadeOut(200, function name(params) {
                         $(this).remove();
                         $(this).remove();
@@ -375,8 +391,8 @@ $(document).on('click', '.delete-app', async function (e) {
                         count_apps();
                         count_apps();
                     });
                     });
                 },
                 },
-                // make sure the modal was shown for at least 2 seconds
-                (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts));
+                    // make sure the modal was shown for at least 2 seconds
+                    (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts));
 
 
                 // get app directory
                 // get app directory
                 puter.fs.stat({
                 puter.fs.stat({
@@ -401,8 +417,8 @@ $(document).on('click', '.delete-app', async function (e) {
                         },
                         },
                     ]);
                     ]);
                 },
                 },
-                // make sure the modal was shown for at least 2 seconds
-                (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts));
+                    // make sure the modal was shown for at least 2 seconds
+                    (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts));
             })
             })
     }
     }
 })
 })
@@ -545,6 +561,13 @@ function generate_edit_app_section(app) {
                     <label for="edit-app-hide-titlebar" style="display: inline;">Hide window titlebar</label>
                     <label for="edit-app-hide-titlebar" style="display: inline;">Hide window titlebar</label>
                 </div>
                 </div>
 
 
+                <h3 style="border-bottom: 1px solid #EEE; margin-top: 50px; margin-bottom: 0px;">Misc</h3>
+                <div style="margin-top:30px;">
+                    <input type="checkbox" id="edit-app-locked" name="edit-app-locked" value="true" ${app.metadata?.locked ? 'checked' : ''}>
+                    <label for="edit-app-locked" style="display: inline;">Locked</label>
+                    <p>When locked, the app cannot be deleted. This is useful to prevent accidental deletion of important apps.</p>
+                </div>
+
                 <hr style="margin-top: 40px;">
                 <hr style="margin-top: 40px;">
                 <button type="button" class="edit-app-save-btn button button-primary">Save</button>
                 <button type="button" class="edit-app-save-btn button button-primary">Save</button>
             </form>
             </form>
@@ -938,6 +961,7 @@ $(document).on('click', '.edit-app-save-btn', async function (e) {
             },
             },
             window_resizable: $('#edit-app-window-resizable').is(":checked"),
             window_resizable: $('#edit-app-window-resizable').is(":checked"),
             hide_titlebar: $('#edit-app-hide-titlebar').is(":checked"),
             hide_titlebar: $('#edit-app-hide-titlebar').is(":checked"),
+            locked: $(`#edit-app-locked`).is(":checked") ?? false,
         },
         },
         filetypeAssociations: filetype_associations,
         filetypeAssociations: filetype_associations,
     }).then(async (app) => {
     }).then(async (app) => {
@@ -994,8 +1018,22 @@ $(document).on('click', '.delete-app-settings', async function (e) {
     let app_name = $(this).attr('data-app-name');
     let app_name = $(this).attr('data-app-name');
     let app_title = $(this).attr('data-app-title');
     let app_title = $(this).attr('data-app-title');
 
 
+    // check if app is locked
+    const app_data = await puter.apps.get(app_name);
+
+    if(app_data.metadata?.locked){
+        puter.ui.alert(`<strong>${app_data.title}</strong> is locked and cannot be deleted.`, [
+            {
+                label: 'Ok',
+            },
+        ], {
+            type: 'warning',
+        });
+        return;
+    }
+
     // confirm delete
     // confirm delete
-    const alert_resp = await puter.ui.alert(`Are you sure you want to premanently delete "${html_encode(app_title)}"?`,
+    const alert_resp = await puter.ui.alert(`Are you sure you want to premanently delete <strong>${html_encode(app_title)}</strong>?`,
         [
         [
             {
             {
                 label: 'Yes, delete permanently',
                 label: 'Yes, delete permanently',
@@ -1058,6 +1096,9 @@ $(document).on('click', '.back-to-main-btn', function (e) {
     $('#loading').show();
     $('#loading').show();
     setTimeout(function () {
     setTimeout(function () {
         puter.apps.list().then((apps_res) => {
         puter.apps.list().then((apps_res) => {
+            // uncheck the select all checkbox
+            $('.select-all-apps').prop('checked', false);
+
             $('#loading').hide();
             $('#loading').hide();
             apps = apps_res;
             apps = apps_res;
             if (apps.length > 0) {
             if (apps.length > 0) {
@@ -1186,7 +1227,7 @@ function generate_app_card(app) {
     // App info
     // App info
     h += `<td style="height: 60px; width: 450px; display: flex; flex-direction: row; overflow:hidden;">`;
     h += `<td style="height: 60px; width: 450px; display: flex; flex-direction: row; overflow:hidden;">`;
     // Icon
     // Icon
-    h += `<div class="got-to-edit-app" data-app-name="${html_encode(app.name)}" data-app-title="${html_encode(app.title)}" data-app-uid="${html_encode(app.uid)}" style="background-position: center; background-repeat: no-repeat; background-size: 92%; background-image:url(${app.icon === null ? './img/app.svg' : app.icon}); width: 60px; height: 60px; float:left; margin-bottom: -14px; color: #414b56; cursor: pointer; background-color: white; border-radius: 3px; flex-shrink:0;"></div>`;
+    h += `<div class="got-to-edit-app" data-app-name="${html_encode(app.name)}" data-app-title="${html_encode(app.title)}" data-app-locked="${html_encode(app.metadata?.locked)}" data-app-uid="${html_encode(app.uid)}" style="background-position: center; background-repeat: no-repeat; background-size: 92%; background-image:url(${app.icon === null ? './img/app.svg' : app.icon}); width: 60px; height: 60px; float:left; margin-bottom: -14px; color: #414b56; cursor: pointer; background-color: white; border-radius: 3px; flex-shrink:0;"></div>`;
     // Info
     // Info
     h += `<div style="float:left; padding-left: 10px;">`;
     h += `<div style="float:left; padding-left: 10px;">`;
     // Title
     // Title
@@ -1362,7 +1403,9 @@ function sort_apps() {
     sorted_apps.forEach(app => {
     sorted_apps.forEach(app => {
         $('#app-list-table > tbody').append(generate_app_card(app));
         $('#app-list-table > tbody').append(generate_app_card(app));
     });
     });
+
     count_apps();
     count_apps();
+
     // show apps that match search_query and hide apps that don't
     // show apps that match search_query and hide apps that don't
     if (search_query) {
     if (search_query) {
         // show apps that match search_query and hide apps that don't
         // show apps that match search_query and hide apps that don't
@@ -1788,7 +1831,7 @@ $(document).on('click', '.add-app-to-desktop', function (e) {
             overwrite: false,
             overwrite: false,
             appUID: app_uid,
             appUID: app_uid,
         }).then(async (uploaded) => {
         }).then(async (uploaded) => {
-            puter.ui.alert(`"${app_title}" shortcut has been added to your desktop.`, [
+            puter.ui.alert(`<strong>${app_title}</strong> shortcut has been added to your desktop.`, [
                 {
                 {
                     label: 'Ok',
                     label: 'Ok',
                     type: 'primary',
                     type: 'primary',
@@ -1909,7 +1952,9 @@ $('.refresh-app-list').on('click', function (e) {
             apps.forEach(app => {
             apps.forEach(app => {
                 $('#app-list-table > tbody').append(generate_app_card(app));
                 $('#app-list-table > tbody').append(generate_app_card(app));
             });
             });
+
             count_apps();
             count_apps();
+
             // preserve search query
             // preserve search query
             if (search_query) {
             if (search_query) {
                 // show apps that match search_query and hide apps that don't
                 // show apps that match search_query and hide apps that don't
@@ -2011,7 +2056,7 @@ $(document).on('click', '.delete-apps-btn', async function (e) {
 
 
     if (resp === 'delete') {
     if (resp === 'delete') {
         // disable delete button
         // disable delete button
-        $('.delete-apps-btn').addClass('disabled');
+        // $('.delete-apps-btn').addClass('disabled');
 
 
         // show 'deleting' modal
         // show 'deleting' modal
         $('.deleting-app-modal')?.get(0)?.showModal();
         $('.deleting-app-modal')?.get(0)?.showModal();
@@ -2025,6 +2070,43 @@ $(document).on('click', '.delete-apps-btn', async function (e) {
             const app_uid = $(app).attr('data-app-uid');
             const app_uid = $(app).attr('data-app-uid');
             const app_name = $(app).attr('data-app-name');
             const app_name = $(app).attr('data-app-name');
 
 
+            // get app
+            const app_data = await puter.apps.get(app_name);
+
+            if(app_data.metadata?.locked){
+                if(apps.length === 1){
+                    puter.ui.alert(`<strong>${app_data.title}</strong> is locked and cannot be deleted.`, [
+                        {
+                            label: 'Ok',
+                        },
+                    ], {
+                        type: 'warning',
+                    });
+
+                    break;
+                }
+
+                let resp = await puter.ui.alert(`<strong>${app_data.title}</strong> is locked and cannot be deleted.`, [
+                    {
+                        label: 'Skip and Continue',
+                        value: 'Continue',
+                        type: 'primary'
+                    },
+                    {
+                        label: 'Cancel',
+                    },
+                ], {
+                    type: 'warning',
+                });
+
+                if(resp === 'Cancel')
+                    break;
+                else if(resp === 'Continue')
+                    continue;
+                else
+                    continue;
+            }
+
             // delete app 
             // delete app 
             await puter.apps.delete(app_name)
             await puter.apps.delete(app_name)
 
 
@@ -2065,13 +2147,13 @@ $(document).on('click', '.delete-apps-btn', async function (e) {
         // close 'deleting' modal
         // close 'deleting' modal
         setTimeout(() => {
         setTimeout(() => {
             $('.deleting-app-modal')?.get(0)?.close();
             $('.deleting-app-modal')?.get(0)?.close();
-            // uncheck all checkboxes
-            $('.app-checkbox').prop('checked', false);
-            // disable delete button
-            $('.delete-apps-btn').addClass('disabled');
-            // reset the 'select all' checkbox
-            $('.select-all-apps').prop('indeterminate', false);
-            $('.select-all-apps').prop('checked', false);
+            if($('.app-checkbox:checked').length === 0){
+                // disable delete button
+                $('.delete-apps-btn').addClass('disabled');
+                // reset the 'select all' checkbox
+                $('.select-all-apps').prop('indeterminate', false);
+                $('.select-all-apps').prop('checked', false);
+            }
         }, (start_ts - Date.now()) > 500 ? 0 : 500);
         }, (start_ts - Date.now()) > 500 ? 0 : 500);
     }
     }
 })
 })

+ 1 - 1
src/gui/src/IPC.js

@@ -156,7 +156,7 @@ window.addEventListener('message', async (event) => {
     //--------------------------------------------------------
     //--------------------------------------------------------
     else if(event.data.msg === 'ALERT' && event.data.message !== undefined){
     else if(event.data.msg === 'ALERT' && event.data.message !== undefined){
         const alert_resp = await UIAlert({
         const alert_resp = await UIAlert({
-            message: html_encode(event.data.message),
+            message: event.data.message,
             buttons: event.data.buttons,
             buttons: event.data.buttons,
             type: event.data.options?.type,
             type: event.data.options?.type,
             window_options: {
             window_options: {