diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js
index c6eab46c79..d9957a7e19 100644
--- a/src/dev-center/js/dev-center.js
+++ b/src/dev-center/js/dev-center.js
@@ -288,6 +288,8 @@ async function create_app(title, source_path = null, items = null) {
})
.then(async (app) => {
+ $('.new-app-modal').get(0).close();
+ window.location.reload();
let app_dir;
// ----------------------------------------------------
// Create app directory in AppData
@@ -313,6 +315,8 @@ async function create_app(title, source_path = null, items = null) {
maximizeOnStart: false,
background: false,
}).then(async (app) => {
+ $('.new-app-modal').get(0).close();
+ window.location.reload();
// refresh app list
puter.apps.list().then(async (resp) => {
apps = resp;
@@ -555,8 +559,8 @@ function generate_edit_app_section(app) {
File Associations
-
A list of file type specifiers. For example if you include .txt
your apps could be opened when a user clicks on a TXT file.
- A comma-separated list of file type specifiers. For example if you include .txt
, your apps could be opened when a user clicks on a TXT file.
+
@@ -762,63 +766,6 @@ async function edit_app_section(cur_app_name) {
toggleResetButton(); // Ensure Reset button is initially disabled
$('#edit-app').show();
- const filetype_association_input = document.querySelector('textarea[id=edit-app-filetype-associations]');
- let tagify = new Tagify(filetype_association_input, {
- pattern: /\.(?:[a-z0-9]+)|(?:[a-z]+\/(?:[a-z0-9.-]+|\*))/,
- delimiters: ", ",
- enforceWhitelist: false,
- dropdown : {
- // show the dropdown immediately on focus (0 character typed)
- enabled: 0,
- },
- whitelist: [
- // MIME type patterns
- "text/*", "image/*", "audio/*", "video/*", "application/*",
-
- // Documents
- ".doc", ".docx", ".pdf", ".txt", ".odt", ".rtf", ".tex", ".md", ".pages", ".epub", ".mobi", ".azw", ".azw3", ".djvu", ".xps", ".oxps", ".fb2", ".textile", ".markdown", ".asciidoc", ".rst", ".wpd", ".wps", ".abw", ".zabw",
-
- // Spreadsheets
- ".xls", ".xlsx", ".csv", ".ods", ".numbers", ".tsv", ".gnumeric", ".xlt", ".xltx", ".xlsm", ".xltm", ".xlam", ".xlsb",
-
- // Presentations
- ".ppt", ".pptx", ".key", ".odp", ".pps", ".ppsx", ".pptm", ".potx", ".potm", ".ppam",
-
- // Images
- ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".tif", ".svg", ".webp", ".ico", ".psd", ".ai", ".eps", ".raw", ".cr2", ".nef", ".orf", ".sr2", ".heic", ".heif", ".avif", ".jxr", ".hdp", ".wdp", ".jng", ".xcf", ".pgm", ".pbm", ".ppm", ".pnm",
-
- // Video
- ".mp4", ".avi", ".mov", ".wmv", ".mkv", ".flv", ".webm", ".m4v", ".mpeg", ".mpg", ".3gp", ".3g2", ".ogv", ".vob", ".drc", ".gifv", ".mng", ".qt", ".yuv", ".rm", ".rmvb", ".asf", ".amv", ".m2v", ".svi",
-
- // Audio
- ".mp3", ".wav", ".aac", ".flac", ".ogg", ".m4a", ".wma", ".aiff", ".alac", ".ape", ".au", ".mid", ".midi", ".mka", ".pcm", ".ra", ".ram", ".snd", ".wv", ".opus",
-
- // Code/Development
- ".js", ".ts", ".html", ".css", ".json", ".xml", ".php", ".py", ".java", ".cpp", ".c", ".cs", ".h", ".hpp", ".hxx", ".rs", ".go", ".rb", ".pl", ".swift", ".kt", ".kts", ".scala", ".coffee", ".sass", ".scss", ".less", ".jsx", ".tsx", ".vue", ".sh", ".bash", ".zsh", ".fish", ".ps1", ".bat", ".cmd", ".sql", ".r", ".dart", ".f", ".f90", ".for", ".lua", ".m", ".mm", ".clj", ".erl", ".ex", ".exs", ".elm", ".hs", ".lhs", ".lisp", ".ml", ".mli", ".nim", ".pl", ".rkt", ".v", ".vhd",
-
- // Archives
- ".zip", ".rar", ".7z", ".tar", ".gz", ".bz2", ".xz", ".z", ".lz", ".lzma", ".tlz", ".txz", ".tgz", ".tbz2", ".bz", ".br", ".lzo", ".ar", ".cpio", ".shar", ".lrz", ".lz4", ".lz2", ".rz", ".sfark", ".sz", ".zoo",
-
- // Database
- ".db", ".sql", ".sqlite", ".sqlite3", ".dbf", ".mdb", ".accdb", ".db3", ".s3db", ".dbx",
-
- // Fonts
- ".ttf", ".otf", ".woff", ".woff2", ".eot", ".pfa", ".pfb", ".sfd",
-
- // CAD and 3D
- ".dwg", ".dxf", ".stl", ".obj", ".fbx", ".dae", ".3ds", ".blend", ".max", ".ma", ".mb", ".c4d", ".skp", ".usd", ".usda", ".usdc", ".abc",
-
- // Scientific/Technical
- ".mat", ".fig", ".nb", ".cdf", ".fits", ".fts", ".fit", ".gmsh", ".msh", ".fem", ".neu", ".hdf", ".h5", ".nx", ".unv",
-
- // System
- ".exe", ".dll", ".so", ".dylib", ".app", ".dmg", ".iso", ".img", ".bin", ".msi", ".apk", ".ipa", ".deb", ".rpm",
-
- // Directory
- ".directory"
- ],
- })
-
// --------------------------------------------------------
// Dragster
// --------------------------------------------------------
@@ -859,7 +806,7 @@ async function edit_app_section(cur_app_name) {
dropped_items = items[0].path;
$('.drop-area').removeClass('drop-area-hover');
$('.drop-area').addClass('drop-area-ready-to-deploy');
- drop_area_content = `
index.html
Ready to deploy 🚀
Cancel
`;
+ drop_area_content = `
index.html
Ready to deploy 🚀
`;
$('.drop-area').html(drop_area_content);
// enable deploy button
@@ -893,7 +840,7 @@ async function edit_app_section(cur_app_name) {
dropped_items = items;
$('.drop-area').removeClass('drop-area-hover');
$('.drop-area').addClass('drop-area-ready-to-deploy');
- drop_area_content = `
${items.length} items
Ready to deploy 🚀
Cancel
`;
+ drop_area_content = `
${items.length} items
Ready to deploy 🚀
`;
$('.drop-area').html(drop_area_content);
// enable deploy button
@@ -934,7 +881,7 @@ async function edit_app_section(cur_app_name) {
$('.drop-area').removeClass('drop-area-hover');
$('.drop-area').addClass('drop-area-ready-to-deploy');
- drop_area_content = `
${rootItems}
Ready to deploy 🚀
Cancel
`;
+ drop_area_content = `
${rootItems}
Ready to deploy 🚀
`;
$('.drop-area').html(drop_area_content);
// enable deploy button
@@ -1008,7 +955,7 @@ async function edit_app_section(cur_app_name) {
rootItems = html_encode(rootItems);
$('.drop-area').removeClass('drop-area-hover');
$('.drop-area').addClass('drop-area-ready-to-deploy');
- drop_area_content = `
${rootItems}
Ready to deploy 🚀
Cancel
`;
+ drop_area_content = `
${rootItems}
Ready to deploy 🚀
`;
$('.drop-area').html(drop_area_content);
// enable deploy button
@@ -1159,32 +1106,6 @@ $(document).on('click', '.edit-app-save-btn', async function (e) {
}
}
- // parse filetype_associations
-
- filetype_associations = JSON.parse(filetype_associations);
- filetype_associations = filetype_associations.map((type) => {
- const fileType = type.value;
-
-
- if (
- !fileType ||
- fileType === "." ||
- fileType === "/"
- ) {
- error = `
File Association Type must be valid.`;
- return null; // Return null for invalid cases
- }
- const lower = fileType.toLocaleLowerCase();
-
- if (fileType.includes("/")) {
- return lower;
- } else if (fileType.includes(".")) {
- return "." + lower.split(".")[1];
- } else {
- return "." + lower;
- }
- }).filter(Boolean);
-
// error?
if (error) {
$('#edit-app-error').show();
@@ -1196,8 +1117,8 @@ $(document).on('click', '.edit-app-save-btn', async function (e) {
// show working spinner
puter.ui.showSpinner();
-
-
+ // parse filetype_associations
+ filetype_associations = filetype_associations.split(',').map(element => element.trim());
// disable submit button
$('.edit-app-save-btn').prop('disabled', true);
@@ -1721,130 +1642,14 @@ function sort_apps() {
}
}
-/**
- * Checks if the items being deployed contain a .git directory
- * @param {Array|string} items - Items to check (can be path string or array of items)
- * @returns {Promise
} - True if .git directory is found
- */
-async function hasGitDirectory(items) {
- // Case 1: Single Puter path
- if (typeof items === 'string' && (items.startsWith('/') || items.startsWith('~'))) {
- const stat = await puter.fs.stat(items);
- if (stat.is_dir) {
- const files = await puter.fs.readdir(items);
- return files.some(file => file.name === '.git' && file.is_dir);
- }
- return false;
- }
-
- // Case 2: Array of Puter items
- if (Array.isArray(items) && items[0]?.uid) {
- return items.some(item => item.name === '.git' && item.is_dir);
- }
-
- // Case 3: Local items (DataTransferItems)
- if (Array.isArray(items)) {
- for (let item of items) {
- if (item.fullPath?.includes('/.git/') ||
- item.path?.includes('/.git/') ||
- item.filepath?.includes('/.git/')) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-/**
- * Shows a warning dialog about .git directory deployment
- * @returns {Promise} - True if the user wants to proceed with deployment
- */
-async function showGitWarningDialog() {
- try {
- // Check if the user has chosen to skip the warning
- const skipWarning = await puter.kv.get('skip-git-warning');
-
- // Log retrieved value for debugging
- console.log('Retrieved skip-git-warning:', skipWarning);
-
- // If the user opted to skip the warning, proceed without showing it
- if (skipWarning === true) {
- return true;
- }
- } catch (error) {
- console.error('Error accessing KV store:', error);
- // If KV store access fails, fall back to showing the dialog
- }
-
- // Create the modal dialog
- const modal = document.createElement('div');
- modal.innerHTML = `
-
-
Warning: Git Repository Detected
-
A .git directory was found in your deployment files. Deploying .git directories may:
-
- Expose sensitive information like commit history and configuration
- Significantly increase deployment size
-
-
-
- Don't show this warning again
-
-
- Cancel
- Continue Deployment
-
-
-
- `;
- document.body.appendChild(modal);
-
- return new Promise((resolve) => {
- // Handle "Continue Deployment"
- document.getElementById('continue-deployment').addEventListener('click', async () => {
- try {
- const skipChecked = document.getElementById('skip-git-warning')?.checked;
- if (skipChecked) {
- console.log("Saving 'skip-git-warning' preference as true");
- await puter.kv.set('skip-git-warning', true);
- }
- } catch (error) {
- console.error('Error saving user preference to KV store:', error);
- } finally {
- document.body.removeChild(modal);
- resolve(true); // Continue deployment
- }
- });
-
- // Handle "Cancel Deployment"
- document.getElementById('cancel-deployment').addEventListener('click', () => {
- document.body.removeChild(modal);
- resolve(false); // Cancel deployment
- });
- });
-}
-
window.deploy = async function (app, items) {
- // Check for .git directory before proceeding
- try {
- if (await hasGitDirectory(items)) {
- const shouldProceed = await showGitWarningDialog();
- if (!shouldProceed) {
- reset_drop_area();
- return;
- }
- }
- } catch (err) {
- console.error('Error checking for .git directory:', err);
- }
let appdata_dir, current_app_dir;
// disable deploy button
$('.deploy-btn').addClass('disabled');
// change drop area text
- $('.drop-area').html(deploying_spinner + ' Deploying (0%)
');
+ $('.drop-area').html(deploying_spinner + ' Deploying (0%)
Cancel
');
if (typeof items === 'string' && (items.startsWith('/') || items.startsWith('~'))) {
$('.drop-area').removeClass('drop-area-hover');
@@ -2215,7 +2020,7 @@ $(document).on('click', '.insta-deploy-existing-app-deploy-btn', function (e) {
$('.drop-area').removeClass('drop-area-hover');
$('.drop-area').addClass('drop-area-ready-to-deploy');
- let drop_area_content = `Ready to deploy 🚀
Cancel
`;
+ let drop_area_content = `Ready to deploy 🚀
Cancel
`;
$('.drop-area').html(drop_area_content);
// deploy
@@ -2657,9 +2462,32 @@ function enable_window_settings(){
$('#edit-app-hide-titlebar').prop('disabled', false);
}
-$(document).on('click', '.reset-deploy', function (e) {
- reset_drop_area();
-})
+$(document).on('click', '.reset-deploy', async function (e) {
+ // Display a confirmation dialog to ask the user
+ const alert_resp = await puter.ui.alert(
+ 'Are you sure you want to cancel the deployment?',
+ [
+ {
+ label: 'Yes, cancel deployment',
+ value: 'cancel',
+ type: 'danger', // This can style the button as red/danger
+ },
+ {
+ label: 'No, keep it',
+ value: 'keep'
+ }
+ ]
+ );
+
+ if (alert_resp === 'cancel') {
+ // If the user clicks "Yes, cancel deployment", reset the drop area
+ reset_drop_area();
+ } else {
+ // If the user clicks "No, keep it", do nothing or log it
+ console.log('Deployment is not canceled.');
+ }
+});
+
$(document).on('click', '.sidebar-toggle', function (e) {
$('.sidebar').toggleClass('open');