mirror of
https://github.com/HeyPuter/puter.git
synced 2026-08-13 01:32:10 +00:00
feat(start-menu): add "Add to Desktop" option for all apps (#2386)
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test-backend (24.x) (push) Has been cancelled
test / API tests (node env, api-test) (24.x) (push) Has been cancelled
test / puterjs (node env, vitest) (24.x) (push) Has been cancelled
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test-backend (24.x) (push) Has been cancelled
test / API tests (node env, api-test) (24.x) (push) Has been cancelled
test / puterjs (node env, vitest) (24.x) (push) Has been cancelled
This commit is contained in:
Generated
+28
@@ -1305,6 +1305,7 @@
|
||||
"version": "7.28.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
@@ -1621,6 +1622,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -1659,6 +1661,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -3431,6 +3434,7 @@
|
||||
"node_modules/@jimp/custom": {
|
||||
"version": "0.22.12",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "^0.22.12"
|
||||
}
|
||||
@@ -3461,6 +3465,7 @@
|
||||
"node_modules/@jimp/plugin-blit": {
|
||||
"version": "0.22.12",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/utils": "^0.22.12"
|
||||
},
|
||||
@@ -3471,6 +3476,7 @@
|
||||
"node_modules/@jimp/plugin-blur": {
|
||||
"version": "0.22.12",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/utils": "^0.22.12"
|
||||
},
|
||||
@@ -3491,6 +3497,7 @@
|
||||
"node_modules/@jimp/plugin-color": {
|
||||
"version": "0.22.12",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/utils": "^0.22.12",
|
||||
"tinycolor2": "^1.6.0"
|
||||
@@ -3528,6 +3535,7 @@
|
||||
"node_modules/@jimp/plugin-crop": {
|
||||
"version": "0.22.12",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/utils": "^0.22.12"
|
||||
},
|
||||
@@ -3631,6 +3639,7 @@
|
||||
"node_modules/@jimp/plugin-resize": {
|
||||
"version": "0.22.12",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/utils": "^0.22.12"
|
||||
},
|
||||
@@ -3641,6 +3650,7 @@
|
||||
"node_modules/@jimp/plugin-rotate": {
|
||||
"version": "0.22.12",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/utils": "^0.22.12"
|
||||
},
|
||||
@@ -3654,6 +3664,7 @@
|
||||
"node_modules/@jimp/plugin-scale": {
|
||||
"version": "0.22.12",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/utils": "^0.22.12"
|
||||
},
|
||||
@@ -3894,6 +3905,7 @@
|
||||
"node_modules/@opentelemetry/api": {
|
||||
"version": "1.9.0",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
@@ -5726,6 +5738,7 @@
|
||||
"version": "8.48.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.48.0",
|
||||
"@typescript-eslint/types": "8.48.0",
|
||||
@@ -6357,6 +6370,7 @@
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -7014,6 +7028,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.25",
|
||||
"caniuse-lite": "^1.0.30001754",
|
||||
@@ -7212,6 +7227,7 @@
|
||||
"node_modules/chai": {
|
||||
"version": "4.5.0",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"assertion-error": "^1.1.0",
|
||||
"check-error": "^1.0.3",
|
||||
@@ -8505,6 +8521,7 @@
|
||||
"node_modules/eslint": {
|
||||
"version": "9.39.1",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -14325,6 +14342,7 @@
|
||||
"version": "8.17.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
@@ -15766,6 +15784,7 @@
|
||||
"version": "5.9.3",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -15938,6 +15957,7 @@
|
||||
"version": "7.2.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -16029,6 +16049,7 @@
|
||||
"version": "4.0.14",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.0.14",
|
||||
"@vitest/mocker": "4.0.14",
|
||||
@@ -16142,6 +16163,7 @@
|
||||
"version": "5.103.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.8",
|
||||
@@ -16189,6 +16211,7 @@
|
||||
"version": "5.1.4",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@discoveryjs/json-ext": "^0.5.0",
|
||||
"@webpack-cli/configtest": "^2.1.1",
|
||||
@@ -16387,6 +16410,7 @@
|
||||
"node_modules/winston": {
|
||||
"version": "3.18.3",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@colors/colors": "^1.6.0",
|
||||
"@dabh/diagnostics": "^2.0.8",
|
||||
@@ -16504,6 +16528,7 @@
|
||||
"node_modules/ws": {
|
||||
"version": "8.18.3",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@@ -16693,6 +16718,7 @@
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
@@ -16813,6 +16839,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz",
|
||||
"integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
@@ -16822,6 +16849,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.49.1.tgz",
|
||||
"integrity": "sha512-kaNl/T7WzyMUQHQlVq7q0oV4Kev6+0xFwqzofryC66jgGMacd0QH5TwfpbUwSTby+SdAdprAe5UKMvBw4tKS5Q==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/api": "^1.0.0"
|
||||
},
|
||||
|
||||
+13
-13
@@ -35,12 +35,12 @@ import mime from '../lib/mime.js';
|
||||
const AI_APP_NAME = 'ai';
|
||||
|
||||
const parseItemMetadataForAI = (metadata) => {
|
||||
if (!metadata) {
|
||||
if ( ! metadata ) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(metadata);
|
||||
} catch (error) {
|
||||
} catch ( error ) {
|
||||
console.warn('Failed to parse item metadata for AI payload.', error);
|
||||
return undefined;
|
||||
}
|
||||
@@ -67,17 +67,17 @@ const buildAIPayloadFromItems = ($elements) => {
|
||||
|
||||
const ensureAIAppIframe = async () => {
|
||||
let $aiWindow = $(`.window[data-app="${AI_APP_NAME}"]`);
|
||||
if ($aiWindow.length === 0) {
|
||||
if ( $aiWindow.length === 0 ) {
|
||||
try {
|
||||
await launch_app({ name: AI_APP_NAME });
|
||||
} catch (error) {
|
||||
} catch ( error ) {
|
||||
console.error('Failed to launch AI app.', error);
|
||||
return null;
|
||||
}
|
||||
$aiWindow = $(`.window[data-app="${AI_APP_NAME}"]`);
|
||||
}
|
||||
|
||||
if ($aiWindow.length === 0) {
|
||||
if ( $aiWindow.length === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -88,12 +88,12 @@ const ensureAIAppIframe = async () => {
|
||||
|
||||
const sendSelectionToAIApp = async ($elements) => {
|
||||
const items = buildAIPayloadFromItems($elements);
|
||||
if (items.length === 0) {
|
||||
if ( items.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const aiIframe = await ensureAIAppIframe();
|
||||
if (!aiIframe || !aiIframe.contentWindow) {
|
||||
if ( !aiIframe || !aiIframe.contentWindow ) {
|
||||
await UIAlert({
|
||||
message: i18n('ai_app_unavailable'),
|
||||
});
|
||||
@@ -107,7 +107,7 @@ const sendSelectionToAIApp = async ($elements) => {
|
||||
}, '*');
|
||||
};
|
||||
|
||||
function UIItem(options){
|
||||
function UIItem (options) {
|
||||
const matching_appendto_count = $(options.appendTo).length;
|
||||
if ( matching_appendto_count > 1 ) {
|
||||
$(options.appendTo).each(function () {
|
||||
@@ -138,7 +138,7 @@ function UIItem(options){
|
||||
options.shortcut_to_path = options.shortcut_to_path ?? '';
|
||||
options.immutable = (options.immutable === false || options.immutable === 0 || options.immutable === undefined ? 0 : 1);
|
||||
options.sort_container_after_append = (options.sort_container_after_append !== undefined ? options.sort_container_after_append : false);
|
||||
const is_shared_with_me = (options.path !== `/${window.user.username}` && !options.path.startsWith(`/${window.user.username}/`));
|
||||
const is_shared_with_me = (options.path && options.path !== `/${window.user.username}` && !options.path.startsWith(`/${window.user.username}/`));
|
||||
|
||||
let website_url = window.determine_website_url(options.path);
|
||||
|
||||
@@ -988,9 +988,9 @@ function UIItem(options){
|
||||
// -------------------------------------------
|
||||
menu_items.push({
|
||||
html: i18n('open_in_ai'),
|
||||
onClick: async function(){
|
||||
onClick: async function () {
|
||||
await sendSelectionToAIApp($selected_items);
|
||||
}
|
||||
},
|
||||
});
|
||||
// -------------------------------------------
|
||||
// -
|
||||
@@ -1332,9 +1332,9 @@ function UIItem(options){
|
||||
// -------------------------------------------
|
||||
menu_items.push({
|
||||
html: i18n('open_in_ai'),
|
||||
onClick: async function(){
|
||||
onClick: async function () {
|
||||
await sendSelectionToAIApp($(el_item));
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -236,6 +236,26 @@ async function UITaskbar (options) {
|
||||
const $existingTaskbarItem = $(`.taskbar-item[data-app="${e.currentTarget.dataset.appName}"]`);
|
||||
const isPinned = $existingTaskbarItem.length > 0 && $existingTaskbarItem.attr('data-keep-in-taskbar') === 'true';
|
||||
|
||||
items.push({
|
||||
html: i18n('add_to_desktop'),
|
||||
onClick: async function () {
|
||||
try {
|
||||
const fileName = `${e.currentTarget.dataset.appTitle}.app`;
|
||||
const content = JSON.stringify({
|
||||
app: e.currentTarget.dataset.appName,
|
||||
title: e.currentTarget.dataset.appTitle,
|
||||
icon: e.currentTarget.dataset.appIcon,
|
||||
});
|
||||
await puter.fs.upload(new File([content], fileName), window.desktop_path, {
|
||||
generateThumbnails: true,
|
||||
});
|
||||
} catch ( err ) {
|
||||
console.error('Failed to add shortcut to desktop:', err);
|
||||
// Consider showing a user-facing error notification
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if ( ! isPinned ) {
|
||||
items.push({
|
||||
html: i18n('keep_in_taskbar'),
|
||||
|
||||
@@ -93,6 +93,22 @@ const item_icon = async (fsentry) => {
|
||||
return { image: trash_img, type: 'icon' };
|
||||
}
|
||||
// --------------------------------------------------
|
||||
// .app files
|
||||
// --------------------------------------------------
|
||||
else if ( fsentry.name && fsentry.name.toLowerCase().endsWith('.app') ) {
|
||||
try {
|
||||
const content = await puter.fs.read({ path: fsentry.path });
|
||||
const text = typeof content === 'string' ? content : await content.text();
|
||||
const data = JSON.parse(text);
|
||||
if ( data.icon ) {
|
||||
return { image: data.icon, type: 'icon' };
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return { image: window.icons['app.svg'], type: 'icon' };
|
||||
}
|
||||
// --------------------------------------------------
|
||||
// Directories
|
||||
// --------------------------------------------------
|
||||
else if ( fsentry.is_dir ) {
|
||||
|
||||
@@ -36,6 +36,32 @@ const open_item = async function (options) {
|
||||
const associated_app_name = $(el_item).attr('data-associated_app_name');
|
||||
const file_uid = $(el_item).attr('data-uid');
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Is this an app shortcut?
|
||||
//----------------------------------------------------------------
|
||||
const app_name = $(el_item).attr('data-app');
|
||||
if ( app_name ) {
|
||||
launch_app({ name: app_name });
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Is this an .app file?
|
||||
//----------------------------------------------------------------
|
||||
if ( item_path && item_path.toLowerCase().endsWith('.app') ) {
|
||||
try {
|
||||
const content = await puter.fs.read({ path: item_path });
|
||||
const text = typeof content === 'string' ? content : await content.text();
|
||||
const data = JSON.parse(text);
|
||||
if ( data.app ) {
|
||||
launch_app({ name: data.app });
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error reading .app file:', e);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Is this a shortcut whose source is perma-deleted?
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@@ -168,6 +168,7 @@ const en = {
|
||||
item: 'item',
|
||||
items_in_trash_cannot_be_renamed: 'This item can\'t be renamed because it\'s in the trash. To rename this item, first drag it out of the Trash.',
|
||||
jpeg_image: 'JPEG image',
|
||||
add_to_desktop: 'Add to Desktop',
|
||||
keep_in_taskbar: 'Keep in Taskbar',
|
||||
language: 'Language',
|
||||
license: 'License',
|
||||
|
||||
Reference in New Issue
Block a user