From 072eec4004edb7a5778b087d8828082c03c0b6a1 Mon Sep 17 00:00:00 2001 From: Sylvain Huguet Date: Fri, 15 Mar 2024 00:15:16 +0100 Subject: [PATCH 1/9] Initial version --- .github/workflows/docker-image.yaml | 74 +++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/workflows/docker-image.yaml diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml new file mode 100644 index 000000000..4490f0a27 --- /dev/null +++ b/.github/workflows/docker-image.yaml @@ -0,0 +1,74 @@ +# +name: Docker Image CI + +# Configures this workflow to run every time a change is pushed to the +# branch called `master`. +on: + push: + branches: ['master'] + pull_request: + branches: ['master'] + schedule: + - cron: "0 2 * * 1-5" + + +# 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 }} + + # 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 }} From c7850fe18f1d45010c5f0dc9f4f2b0e1ccc35706 Mon Sep 17 00:00:00 2001 From: Sylvain Huguet Date: Fri, 15 Mar 2024 00:40:39 +0100 Subject: [PATCH 2/9] Tweaking the metadata/image tagging mechanism --- .github/workflows/docker-image.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index 4490f0a27..60e0c52ef 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -55,6 +55,15 @@ jobs: 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, From cc9d9b10635978e76f237c4596b5f898081a2216 Mon Sep 17 00:00:00 2001 From: Sylvain Huguet Date: Fri, 15 Mar 2024 00:43:02 +0100 Subject: [PATCH 3/9] fix indentation --- .github/workflows/docker-image.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index 60e0c52ef..0abd22641 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -56,14 +56,14 @@ jobs: 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) }} + 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, From 06789da119dc4b26f8f0a000804b6ada7c27dcc0 Mon Sep 17 00:00:00 2001 From: Sylvain Huguet Date: Fri, 15 Mar 2024 10:42:22 +0100 Subject: [PATCH 4/9] Renamed `master` branch to `main` to reflect upstream changes. --- .github/workflows/docker-image.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index 0abd22641..67c17c2ac 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -5,11 +5,7 @@ name: Docker Image CI # branch called `master`. on: push: - branches: ['master'] - pull_request: - branches: ['master'] - schedule: - - cron: "0 2 * * 1-5" + branches: ['main'] # Defines two custom environment variables for the workflow. These are used From f6279d020108301424b89852fb08a0a5178e09c8 Mon Sep 17 00:00:00 2001 From: Sylvain Huguet Date: Fri, 15 Mar 2024 10:51:12 +0100 Subject: [PATCH 5/9] Change branch name in comment too. --- .github/workflows/docker-image.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index 67c17c2ac..ba1aa4360 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -2,7 +2,7 @@ name: Docker Image CI # Configures this workflow to run every time a change is pushed to the -# branch called `master`. +# branch called `main`. on: push: branches: ['main'] From 509a6cbd314fa843287b1ac9ff6d0ab52060739d Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 16 Mar 2024 12:08:11 -0700 Subject: [PATCH 6/9] refactor to account for signup window and the location of the code --- src/globals.js | 15 --------------- src/initgui.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/globals.js b/src/globals.js index 5e31a7c3d..3c443394d 100644 --- a/src/globals.js +++ b/src/globals.js @@ -141,21 +141,6 @@ if (window.location !== window.parent.location) { window.desktop_height = window.innerHeight - window.toolbar_height - window.taskbar_height; window.desktop_width = window.innerWidth; -// recalculate desktop height and width on window resize -$( window ).on( "resize", function() { - const radio = window.desktop_width / window.innerWidth; - - window.desktop_height = window.innerHeight - window.toolbar_height - window.taskbar_height; - window.desktop_width = window.innerWidth; - - const { top } = $(".window-login").position(); - const width = $(".window-login").width(); - $(".window-login").css({ - left: (window.desktop_width - width) / 2, - top: top / radio, - }); -}); - // for now `active_element` is basically the last element that was clicked, // later on though (todo) `active_element` will also be set by keyboard movements // such as arrow keys, tab key, ... and when creating new windows... diff --git a/src/initgui.js b/src/initgui.js index 097dd0374..121594f4a 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -1976,4 +1976,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, + }); }); \ No newline at end of file From 8100edbef9367bbb33a0ba6e5847dec731f43744 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 16 Mar 2024 19:57:33 -0700 Subject: [PATCH 7/9] implement query param passing between browser window and app iframe --- src/UI/UIDesktop.js | 1 + src/helpers.js | 9 +++++++++ src/initgui.js | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/src/UI/UIDesktop.js b/src/UI/UIDesktop.js index 2926f433d..f16dbb2f0 100644 --- a/src/UI/UIDesktop.js +++ b/src/UI/UIDesktop.js @@ -930,6 +930,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, diff --git a/src/helpers.js b/src/helpers.js index a12fb405a..753f06202 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -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,14 @@ window.launch_app = async (options)=>{ else if(options.token){ iframe_url.searchParams.append('puter.auth.token', options.token); } + + // if options.params is set, add them to the URL as query params + if(options.params && options.params.length > 0){ + for (const property in options.params) { + iframe_url.searchParams.append(property, options.params[property]); + } + } + // Try to acquire app token from the server else{ let response = await fetch(window.api_origin + "/auth/get-user-app-token", { diff --git a/src/initgui.js b/src/initgui.js index 121594f4a..2b9392445 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -76,6 +76,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; + } } //-------------------------------------------------------------------------------------- From ec984ac81dae3cfdca338d8b2babed2c8a635cec Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 16 Mar 2024 19:59:36 -0700 Subject: [PATCH 8/9] Remove redundant logic --- src/helpers.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/helpers.js b/src/helpers.js index 753f06202..abd9e422a 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1941,13 +1941,6 @@ window.launch_app = async (options)=>{ iframe_url.searchParams.append('puter.auth.token', options.token); } - // if options.params is set, add them to the URL as query params - if(options.params && options.params.length > 0){ - for (const property in options.params) { - iframe_url.searchParams.append(property, options.params[property]); - } - } - // Try to acquire app token from the server else{ let response = await fetch(window.api_origin + "/auth/get-user-app-token", { From f3e4a12e57c5c89d8db6da93bc3eb8bdff723678 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 16 Mar 2024 20:13:48 -0700 Subject: [PATCH 9/9] Refactor `helpers.js` to reduce file size --- src/UI/UIDesktop.js | 3 +- src/UI/UIWindow.js | 3 +- src/helpers.js | 87 ------------------- .../determine_active_container_parent.js | 43 +++++++++ src/helpers/new_context_menu_item.js | 78 +++++++++++++++++ src/initgui.js | 1 + 6 files changed, 126 insertions(+), 89 deletions(-) create mode 100644 src/helpers/determine_active_container_parent.js create mode 100644 src/helpers/new_context_menu_item.js diff --git a/src/UI/UIDesktop.js b/src/UI/UIDesktop.js index f16dbb2f0..c25b69fd2 100644 --- a/src/UI/UIDesktop.js +++ b/src/UI/UIDesktop.js @@ -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), // ------------------------------------------- // - // ------------------------------------------- diff --git a/src/UI/UIWindow.js b/src/UI/UIWindow.js index 3a90926fe..6e5340b7a 100644 --- a/src/UI/UIWindow.js +++ b/src/UI/UIWindow.js @@ -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), // ------------------------------------------- // - // ------------------------------------------- diff --git a/src/helpers.js b/src/helpers.js index abd9e422a..7b0b795ed 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1979,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, @@ -2243,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: ``, - onClick: function(){ - create_folder(dirname, append_to_element); - } - }, - // divider - '-', - // Text Document - { - html: `Text Document`, - icon: ``, - onClick: async function(){ - create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.txt'}); - } - }, - // HTML Document - { - html: `HTML Document`, - icon: ``, - onClick: async function(){ - create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.html'}); - } - }, - // JPG Image - { - html: `JPG Image`, - 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. * @@ -3127,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", { diff --git a/src/helpers/determine_active_container_parent.js b/src/helpers/determine_active_container_parent.js new file mode 100644 index 000000000..32a8388d6 --- /dev/null +++ b/src/helpers/determine_active_container_parent.js @@ -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 . + */ + +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; \ No newline at end of file diff --git a/src/helpers/new_context_menu_item.js b/src/helpers/new_context_menu_item.js new file mode 100644 index 000000000..28f22298c --- /dev/null +++ b/src/helpers/new_context_menu_item.js @@ -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 . + */ + + +/** + * 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: ``, + onClick: function(){ + create_folder(dirname, append_to_element); + } + }, + // divider + '-', + // Text Document + { + html: `Text Document`, + icon: ``, + onClick: async function(){ + create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.txt'}); + } + }, + // HTML Document + { + html: `HTML Document`, + icon: ``, + onClick: async function(){ + create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.html'}); + } + }, + // JPG Image + { + html: `JPG Image`, + 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; \ No newline at end of file diff --git a/src/initgui.js b/src/initgui.js index 2b9392445..eada45ffc 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -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);