mirror of
https://github.com/HeyPuter/puter.git
synced 2026-09-25 22:55:58 +00:00
Merge branch 'main' of github.com:meetqy/puter
# Conflicts: # src/globals.js
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
#
|
||||
name: Docker Image CI
|
||||
|
||||
# Configures this workflow to run every time a change is pushed to the
|
||||
# branch called `main`.
|
||||
on:
|
||||
push:
|
||||
branches: ['main']
|
||||
|
||||
|
||||
# Defines two custom environment variables for the workflow. These are used
|
||||
# for the Container registry domain, and a name for the Docker image that
|
||||
# this workflow builds.
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
# There is a single job in this workflow. It's configured to run on the
|
||||
# latest available version of Ubuntu.
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions
|
||||
# in this job.
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Uses the `docker/login-action` action to log in to the Container
|
||||
# registry using the account and password that will publish the packages.
|
||||
# Once published, the packages are scoped to the account defined here.
|
||||
- name: Log in to GitHub Package Container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about)
|
||||
# to extract tags and labels that will be applied to the specified image.
|
||||
# The `id` "meta" allows the output of this step to be referenced in
|
||||
# a subsequent step. The `images` value provides the base name for the
|
||||
# tags and labels.
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=schedule
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
|
||||
type=sha
|
||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
|
||||
|
||||
# This step uses the `docker/build-push-action` action to build the
|
||||
# image, based on your repository's `Dockerfile`. If the build succeeds,
|
||||
# it pushes the image to GitHub Packages.
|
||||
# It uses the `context` parameter to define the build's context as the
|
||||
# set of files located in the specified path. For more information, see
|
||||
# "[Usage](https://github.com/docker/build-push-action#usage)" in the
|
||||
# README of the `docker/build-push-action` repository.
|
||||
# It uses the `tags` and `labels` parameters to tag and label the image
|
||||
# with the output from the "meta" step.
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
+3
-1
@@ -33,6 +33,7 @@ import UIWindowLogin from "./UIWindowLogin.js"
|
||||
import UIWindowQR from "./UIWindowQR.js"
|
||||
import UIWindowRefer from "./UIWindowRefer.js"
|
||||
import UITaskbar from "./UITaskbar.js"
|
||||
import new_context_menu_item from "../helpers/new_context_menu_item.js"
|
||||
|
||||
async function UIDesktop(options){
|
||||
let h = '';
|
||||
@@ -707,7 +708,7 @@ async function UIDesktop(options){
|
||||
// -------------------------------------------
|
||||
// New File
|
||||
// -------------------------------------------
|
||||
window.new_context_menu_item(desktop_path, el_desktop),
|
||||
new_context_menu_item(desktop_path, el_desktop),
|
||||
// -------------------------------------------
|
||||
// -
|
||||
// -------------------------------------------
|
||||
@@ -930,6 +931,7 @@ async function UIDesktop(options){
|
||||
name: app_launched_from_url,
|
||||
readURL: qparams.get('readURL'),
|
||||
maximized: qparams.get('maximized'),
|
||||
params: app_query_params ?? [],
|
||||
is_fullpage: window.is_fullpage_mode,
|
||||
window_options: {
|
||||
stay_on_top: false,
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ import UITaskbarItem from './UITaskbarItem.js';
|
||||
import UIWindowLogin from './UIWindowLogin.js';
|
||||
import UIWindowPublishWebsite from './UIWindowPublishWebsite.js';
|
||||
import UIWindowItemProperties from './UIWindowItemProperties.js';
|
||||
import new_context_menu_item from '../helpers/new_context_menu_item.js';
|
||||
|
||||
const el_body = document.getElementsByTagName('body')[0];
|
||||
|
||||
@@ -1898,7 +1899,7 @@ async function UIWindow(options) {
|
||||
// -------------------------------------------
|
||||
// New
|
||||
// -------------------------------------------
|
||||
window.new_context_menu_item($(el_window).attr('data-path'), el_window_body),
|
||||
new_context_menu_item($(el_window).attr('data-path'), el_window_body),
|
||||
// -------------------------------------------
|
||||
// -
|
||||
// -------------------------------------------
|
||||
|
||||
@@ -141,8 +141,6 @@ if (window.location !== window.parent.location) {
|
||||
window.desktop_height = window.innerHeight - window.toolbar_height - window.taskbar_height;
|
||||
window.desktop_width = window.innerWidth;
|
||||
|
||||
let isResize = false;
|
||||
|
||||
// recalculate desktop height and width on window resize
|
||||
$( window ).on( "resize", function() {
|
||||
const new_desktop_height = window.innerHeight - window.toolbar_height - window.taskbar_height;
|
||||
|
||||
+2
-87
@@ -1904,6 +1904,7 @@ window.launch_app = async (options)=>{
|
||||
|
||||
// add app_instance_id to URL
|
||||
iframe_url.searchParams.append('puter.app_instance_id', uuid);
|
||||
|
||||
// add app_id to URL
|
||||
iframe_url.searchParams.append('puter.app.id', app_info.uuid);
|
||||
|
||||
@@ -1939,6 +1940,7 @@ window.launch_app = async (options)=>{
|
||||
else if(options.token){
|
||||
iframe_url.searchParams.append('puter.auth.token', options.token);
|
||||
}
|
||||
|
||||
// Try to acquire app token from the server
|
||||
else{
|
||||
let response = await fetch(window.api_origin + "/auth/get-user-app-token", {
|
||||
@@ -1977,13 +1979,6 @@ window.launch_app = async (options)=>{
|
||||
window_class: 'window-app',
|
||||
update_window_url: true,
|
||||
app_uuid: app_info.uuid ?? app_info.uid,
|
||||
// has_head: options.has_head ?? true,
|
||||
// top: options.top ?? undefined,
|
||||
// left: options.left ?? undefined,
|
||||
// width: options.width ?? undefined,
|
||||
// height: options.height ?? undefined,
|
||||
// is_resizable: options.is_resizable ?? undefined,
|
||||
// window_css: options.window_css ?? undefined,
|
||||
top: options.maximized ? 0 : undefined,
|
||||
left: options.maximized ? 0 : undefined,
|
||||
height: options.maximized ? `calc(100% - ${window.taskbar_height + window.toolbar_height + 1}px)` : undefined,
|
||||
@@ -2241,63 +2236,6 @@ window.open_item = async function(options){
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a context menu item to create a new file/folder.
|
||||
*
|
||||
* @param {string} dirname - The directory path to create the item in
|
||||
* @param {HTMLElement} append_to_element - Element to append the new item to
|
||||
* @returns {Object} The context menu item object
|
||||
*/
|
||||
|
||||
window.new_context_menu_item = function(dirname, append_to_element){
|
||||
return {
|
||||
html: "New",
|
||||
items: [
|
||||
// New Folder
|
||||
{
|
||||
html: "New Folder",
|
||||
icon: `<img src="${html_encode(window.icons['folder.svg'])}" class="ctx-item-icon">`,
|
||||
onClick: function(){
|
||||
create_folder(dirname, append_to_element);
|
||||
}
|
||||
},
|
||||
// divider
|
||||
'-',
|
||||
// Text Document
|
||||
{
|
||||
html: `Text Document`,
|
||||
icon: `<img src="${html_encode(window.icons['file-text.svg'])}" class="ctx-item-icon">`,
|
||||
onClick: async function(){
|
||||
create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.txt'});
|
||||
}
|
||||
},
|
||||
// HTML Document
|
||||
{
|
||||
html: `HTML Document`,
|
||||
icon: `<img src="${html_encode(window.icons['file-html.svg'])}" class="ctx-item-icon">`,
|
||||
onClick: async function(){
|
||||
create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.html'});
|
||||
}
|
||||
},
|
||||
// JPG Image
|
||||
{
|
||||
html: `JPG Image`,
|
||||
icon: `<img src="${html_encode(window.icons['file-image.svg'])}" class="ctx-item-icon">`,
|
||||
onClick: async function(){
|
||||
var canvas = document.createElement("canvas");
|
||||
|
||||
canvas.width = 800;
|
||||
canvas.height = 600;
|
||||
|
||||
canvas.toBlob((blob) =>{
|
||||
create_file({dirname: dirname, append_to_element: append_to_element, name: 'New Image.jpg', content: blob});
|
||||
});
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the given items to the destination path.
|
||||
*
|
||||
@@ -3125,29 +3063,6 @@ window.getUsage = () => {
|
||||
|
||||
}
|
||||
|
||||
window.determine_active_container_parent = function(){
|
||||
// the container is either an ancestor of active element...
|
||||
let parent_container = $(active_element).closest('.item-container');
|
||||
// ... or a descendant of it...
|
||||
if(parent_container.length === 0){
|
||||
parent_container = $(active_element).find('.item-container');
|
||||
}
|
||||
// ... or siblings or cousins
|
||||
if(parent_container.length === 0){
|
||||
parent_container = $(active_element).closest('.window').find('.item-container');
|
||||
}
|
||||
// ... or the active element itself (if it's a container)
|
||||
if(parent_container.length === 0 && active_element && $(active_element).hasClass('item-container')){
|
||||
parent_container = $(active_element);
|
||||
}
|
||||
// ... or if there is no active element, the selected item that is not blurred
|
||||
if(parent_container.length === 0 && active_item_container){
|
||||
parent_container = active_item_container;
|
||||
}
|
||||
|
||||
return parent_container;
|
||||
}
|
||||
|
||||
window.getAppUIDFromOrigin = async function(origin) {
|
||||
try {
|
||||
const response = await fetch(window.api_origin + "/auth/app-uid-from-origin", {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (C) 2024 Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const determine_active_container_parent = function(){
|
||||
// the container is either an ancestor of active element...
|
||||
let parent_container = $(active_element).closest('.item-container');
|
||||
// ... or a descendant of it...
|
||||
if(parent_container.length === 0){
|
||||
parent_container = $(active_element).find('.item-container');
|
||||
}
|
||||
// ... or siblings or cousins
|
||||
if(parent_container.length === 0){
|
||||
parent_container = $(active_element).closest('.window').find('.item-container');
|
||||
}
|
||||
// ... or the active element itself (if it's a container)
|
||||
if(parent_container.length === 0 && active_element && $(active_element).hasClass('item-container')){
|
||||
parent_container = $(active_element);
|
||||
}
|
||||
// ... or if there is no active element, the selected item that is not blurred
|
||||
if(parent_container.length === 0 && active_item_container){
|
||||
parent_container = active_item_container;
|
||||
}
|
||||
|
||||
return parent_container;
|
||||
}
|
||||
|
||||
export default determine_active_container_parent;
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (C) 2024 Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Returns a context menu item to create a new folder and a variety of file types.
|
||||
*
|
||||
* @param {string} dirname - The directory path to create the item in
|
||||
* @param {HTMLElement} append_to_element - Element to append the new item to
|
||||
* @returns {Object} The context menu item object
|
||||
*/
|
||||
|
||||
const new_context_menu_item = function(dirname, append_to_element){
|
||||
return {
|
||||
html: "New",
|
||||
items: [
|
||||
// New Folder
|
||||
{
|
||||
html: "New Folder",
|
||||
icon: `<img src="${html_encode(window.icons['folder.svg'])}" class="ctx-item-icon">`,
|
||||
onClick: function(){
|
||||
create_folder(dirname, append_to_element);
|
||||
}
|
||||
},
|
||||
// divider
|
||||
'-',
|
||||
// Text Document
|
||||
{
|
||||
html: `Text Document`,
|
||||
icon: `<img src="${html_encode(window.icons['file-text.svg'])}" class="ctx-item-icon">`,
|
||||
onClick: async function(){
|
||||
create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.txt'});
|
||||
}
|
||||
},
|
||||
// HTML Document
|
||||
{
|
||||
html: `HTML Document`,
|
||||
icon: `<img src="${html_encode(window.icons['file-html.svg'])}" class="ctx-item-icon">`,
|
||||
onClick: async function(){
|
||||
create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.html'});
|
||||
}
|
||||
},
|
||||
// JPG Image
|
||||
{
|
||||
html: `JPG Image`,
|
||||
icon: `<img src="${html_encode(window.icons['file-image.svg'])}" class="ctx-item-icon">`,
|
||||
onClick: async function(){
|
||||
var canvas = document.createElement("canvas");
|
||||
|
||||
canvas.width = 800;
|
||||
canvas.height = 600;
|
||||
|
||||
canvas.toBlob((blob) =>{
|
||||
create_file({dirname: dirname, append_to_element: append_to_element, name: 'New Image.jpg', content: blob});
|
||||
});
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export default new_context_menu_item;
|
||||
@@ -33,6 +33,7 @@ import UIWindowChangeUsername from './UI/UIWindowChangeUsername.js';
|
||||
import update_last_touch_coordinates from './helpers/update_last_touch_coordinates.js';
|
||||
import update_title_based_on_uploads from './helpers/update_title_based_on_uploads.js';
|
||||
import PuterDialog from './UI/PuterDialog.js';
|
||||
import determine_active_container_parent from './helpers/determine_active_container_parent.js';
|
||||
|
||||
window.initgui = async function(){
|
||||
let url = new URL(window.location);
|
||||
@@ -76,6 +77,13 @@ window.initgui = async function(){
|
||||
const url_paths = window.location.pathname.split('/').filter(element => element);
|
||||
if(url_paths[0]?.toLocaleLowerCase() === 'app' && url_paths[1]){
|
||||
window.app_launched_from_url = url_paths[1];
|
||||
|
||||
// get query params, any param that doesn't start with 'puter.' will be passed to the app
|
||||
window.app_query_params = {};
|
||||
for (let [key, value] of url_query_params) {
|
||||
if(!key.startsWith('puter.'))
|
||||
app_query_params[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
@@ -1976,4 +1984,32 @@ function requestOpenerOrigin() {
|
||||
|
||||
$(document).on('click', '.generic-close-window-button', function(e){
|
||||
$(this).closest('.window').close();
|
||||
});
|
||||
|
||||
// Re-calculate desktop height and width on window resize and re-position the login and signup windows
|
||||
$(window).on("resize", function () {
|
||||
// If host env is popup, don't continue because the popup window has its own resize requirements.
|
||||
if (window.embedded_in_popup)
|
||||
return;
|
||||
|
||||
const ratio = window.desktop_width / window.innerWidth;
|
||||
|
||||
window.desktop_height = window.innerHeight - window.toolbar_height - window.taskbar_height;
|
||||
window.desktop_width = window.innerWidth;
|
||||
|
||||
// Re-center the login window
|
||||
const top = $(".window-login").position()?.top;
|
||||
const width = $(".window-login").width();
|
||||
$(".window-login").css({
|
||||
left: (window.desktop_width - width) / 2,
|
||||
top: top / ratio,
|
||||
});
|
||||
|
||||
// Re-center the create account window
|
||||
const top2 = $(".window-signup").position()?.top;
|
||||
const width2 = $(".window-signup").width();
|
||||
$(".window-signup").css({
|
||||
left: (window.desktop_width - width2) / 2,
|
||||
top: top2 / ratio,
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user