mirror of
https://github.com/HeyPuter/puter
synced 2024-11-15 06:15:47 +00:00
Merge pull request #282 from HeyPuter/eric/task-manager
Add a task manager
This commit is contained in:
commit
b897598fac
@ -35,6 +35,7 @@ import new_context_menu_item from "../helpers/new_context_menu_item.js"
|
|||||||
import refresh_item_container from "../helpers/refresh_item_container.js"
|
import refresh_item_container from "../helpers/refresh_item_container.js"
|
||||||
import changeLanguage from "../i18n/i18nChangeLanguage.js"
|
import changeLanguage from "../i18n/i18nChangeLanguage.js"
|
||||||
import UIWindowSettings from "./Settings/UIWindowSettings.js"
|
import UIWindowSettings from "./Settings/UIWindowSettings.js"
|
||||||
|
import UIWindowTaskManager from "./UIWindowTaskManager.js"
|
||||||
|
|
||||||
async function UIDesktop(options){
|
async function UIDesktop(options){
|
||||||
let h = '';
|
let h = '';
|
||||||
@ -1190,7 +1191,7 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// Change Password
|
// Settings
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
{
|
{
|
||||||
html: i18n('settings'),
|
html: i18n('settings'),
|
||||||
@ -1199,6 +1200,15 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
// Task Manager
|
||||||
|
//--------------------------------------------------
|
||||||
|
{
|
||||||
|
html: i18n('task_manager'),
|
||||||
|
onClick: async function(){
|
||||||
|
UIWindowTaskManager();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//--------------------------------------------------
|
||||||
// Contact Us
|
// Contact Us
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
{
|
{
|
||||||
|
@ -2773,6 +2773,7 @@ window.sidebar_item_droppable = (el_window)=>{
|
|||||||
// closes a window
|
// closes a window
|
||||||
$.fn.close = async function(options) {
|
$.fn.close = async function(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
console.log(options);
|
||||||
$(this).each(async function() {
|
$(this).each(async function() {
|
||||||
const el_iframe = $(this).find('.window-app-iframe');
|
const el_iframe = $(this).find('.window-app-iframe');
|
||||||
const app_uses_sdk = el_iframe.length > 0 && el_iframe.attr('data-appUsesSDK') === 'true';
|
const app_uses_sdk = el_iframe.length > 0 && el_iframe.attr('data-appUsesSDK') === 'true';
|
||||||
|
263
src/UI/UIWindowTaskManager.js
Normal file
263
src/UI/UIWindowTaskManager.js
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
import { END_HARD, END_SOFT } from "../definitions.js";
|
||||||
|
import UIAlert from "./UIAlert.js";
|
||||||
|
import UIContextMenu from "./UIContextMenu.js";
|
||||||
|
import UIWindow from "./UIWindow.js";
|
||||||
|
|
||||||
|
const UIWindowTaskManager = async function UIWindowTaskManager () {
|
||||||
|
const svc_process = globalThis.services.get('process');
|
||||||
|
|
||||||
|
const w = await UIWindow({
|
||||||
|
title: i18n('task_manager'),
|
||||||
|
icon: globalThis.icons['cog.svg'],
|
||||||
|
uid: null,
|
||||||
|
is_dir: false,
|
||||||
|
message: 'message',
|
||||||
|
app: 'taskmgr',
|
||||||
|
// body_icon: options.body_icon,
|
||||||
|
// backdrop: options.backdrop ?? false,
|
||||||
|
is_resizable: true,
|
||||||
|
is_droppable: false,
|
||||||
|
has_head: true,
|
||||||
|
selectable_body: true,
|
||||||
|
draggable_body: false,
|
||||||
|
allow_context_menu: true,
|
||||||
|
// allow_native_ctxmenu: true,
|
||||||
|
show_in_taskbar: true,
|
||||||
|
dominant: true,
|
||||||
|
body_content: '',
|
||||||
|
width: 350,
|
||||||
|
// parent_uuid: options.parent_uuid,
|
||||||
|
// ...options.window_options,
|
||||||
|
window_css:{
|
||||||
|
height: 'initial',
|
||||||
|
},
|
||||||
|
body_css: {
|
||||||
|
width: 'initial',
|
||||||
|
padding: '20px',
|
||||||
|
// 'background-color': `hsla(
|
||||||
|
// var(--primary-hue),
|
||||||
|
// calc(max(var(--primary-saturation) - 15%, 0%)),
|
||||||
|
// calc(min(100%,var(--primary-lightness) + 20%)), .91)`,
|
||||||
|
'background-color': `hsla(
|
||||||
|
var(--primary-hue),
|
||||||
|
var(--primary-saturation),
|
||||||
|
var(--primary-lightness),
|
||||||
|
var(--primary-alpha))`,
|
||||||
|
'backdrop-filter': 'blur(3px)',
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const w_body = w.querySelector('.window-body');
|
||||||
|
w_body.classList.add('taskmgr');
|
||||||
|
|
||||||
|
const Indent = ({ has_trunk, has_branch }) => {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.classList.add('taskmgr-indentcell');
|
||||||
|
if ( has_trunk ) {
|
||||||
|
// Add new child element
|
||||||
|
const el_indentcell_child = document.createElement('div');
|
||||||
|
el_indentcell_child.classList.add('taskmgr-indentcell-trunk');
|
||||||
|
el.appendChild(el_indentcell_child);
|
||||||
|
}
|
||||||
|
if ( has_branch ) {
|
||||||
|
const el_indentcell_child = document.createElement('div');
|
||||||
|
el_indentcell_child.classList.add('taskmgr-indentcell-branch');
|
||||||
|
el.appendChild(el_indentcell_child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
appendTo (parent) {
|
||||||
|
parent.appendChild(el);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const Task = ({ placement, name }) => {
|
||||||
|
const {
|
||||||
|
indent_level, last_item,
|
||||||
|
parent_last_item,
|
||||||
|
} = placement;
|
||||||
|
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.classList.add('taskmgr-task');
|
||||||
|
|
||||||
|
for ( let i=0; i < indent_level; i++ ) {
|
||||||
|
const last_cell = i === indent_level - 1;
|
||||||
|
Indent({
|
||||||
|
has_trunk: (last_cell && ( ! last_item )) ||
|
||||||
|
(!last_cell && !parent_last_item[i+1]),
|
||||||
|
has_branch: last_cell
|
||||||
|
}).appendTo(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
const el_title = document.createElement('div');
|
||||||
|
el_title.classList.add('taskmgr-task-title');
|
||||||
|
el_title.innerText = name;
|
||||||
|
el.appendChild(el_title);
|
||||||
|
|
||||||
|
return {
|
||||||
|
el () { return el; },
|
||||||
|
appendTo (parent) {
|
||||||
|
parent.appendChild(el);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://codepen.io/fomkin/pen/gOgoBVy
|
||||||
|
const Table = ({ headings }) => {
|
||||||
|
const el_table = $(`
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
${headings.map(heading =>
|
||||||
|
`<th><span>${heading}<span></th>`).join('')}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
`)[0];
|
||||||
|
|
||||||
|
const el_tbody = el_table.querySelector('tbody');
|
||||||
|
|
||||||
|
return {
|
||||||
|
el () { return el_table; },
|
||||||
|
add (el) {
|
||||||
|
if ( typeof el.el === 'function' ) el = el.el();
|
||||||
|
el_tbody.appendChild(el);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
clear () {
|
||||||
|
el_tbody.innerHTML = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const Row = () => {
|
||||||
|
const el_tr = document.createElement('tr');
|
||||||
|
return {
|
||||||
|
attach (parent) {
|
||||||
|
parent.appendChild(el_tr);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
el () { return el_tr; },
|
||||||
|
add (el) {
|
||||||
|
if ( typeof el.el === 'function' ) el = el.el();
|
||||||
|
const el_td = document.createElement('td');
|
||||||
|
el_td.appendChild(el);
|
||||||
|
el_tr.appendChild(el_td);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const el_taskarea = document.createElement('div');
|
||||||
|
el_taskarea.classList.add('taskmgr-taskarea');
|
||||||
|
|
||||||
|
const tasktable = Table({
|
||||||
|
headings: [
|
||||||
|
i18n('taskmgr_header_name'),
|
||||||
|
i18n('taskmgr_header_type'),
|
||||||
|
i18n('taskmgr_header_status'),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
el_taskarea.appendChild(tasktable.el());
|
||||||
|
|
||||||
|
const end_process_ = async (process, force) => {
|
||||||
|
let confirmation;
|
||||||
|
|
||||||
|
if ( process.is_init() ) {
|
||||||
|
if ( ! force ) {
|
||||||
|
confirmation = i18n('close_all_windows_confirm');
|
||||||
|
} else {
|
||||||
|
confirmation = i18n('restart_puter_confirm');
|
||||||
|
}
|
||||||
|
} else if ( force ) {
|
||||||
|
confirmation = i18n('end_process_force_confirm');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( confirmation ) {
|
||||||
|
const alert_resp = await UIAlert({
|
||||||
|
message: confirmation,
|
||||||
|
buttons:[
|
||||||
|
{
|
||||||
|
label: i18n('yes'),
|
||||||
|
value: true,
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n('no'),
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
if ( ! alert_resp ) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.signal(force ? END_HARD : END_SOFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const iter_tasks = (items, { indent_level, parent_last_item }) => {
|
||||||
|
for ( let i=0 ; i < items.length; i++ ) {
|
||||||
|
const row = Row();
|
||||||
|
const item = items[i];
|
||||||
|
const last_item = i === items.length - 1;
|
||||||
|
row.add(Task({
|
||||||
|
placement: {
|
||||||
|
parent_last_item,
|
||||||
|
indent_level,
|
||||||
|
last_item,
|
||||||
|
},
|
||||||
|
name: item.name
|
||||||
|
}));
|
||||||
|
row.add($(`<span>${i18n('process_type_' + item.type)}</span>`)[0])
|
||||||
|
row.add($(`<span>${i18n('process_status_' + item.status.i18n_key)}</span>`)[0])
|
||||||
|
tasktable.add(row);
|
||||||
|
|
||||||
|
$(row.el()).on('contextmenu', () => {
|
||||||
|
UIContextMenu({
|
||||||
|
parent_element: $(el_taskarea),
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
html: i18n('close'),
|
||||||
|
onClick: () => {
|
||||||
|
end_process_(item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
html: i18n('force_quit'),
|
||||||
|
onClick: () => {
|
||||||
|
end_process_(item, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
const children = svc_process.get_children_of(item.uuid);
|
||||||
|
if ( children ) {
|
||||||
|
iter_tasks(children, {
|
||||||
|
indent_level: indent_level + 1,
|
||||||
|
parent_last_item:
|
||||||
|
[...parent_last_item, last_item],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
tasktable.clear();
|
||||||
|
const processes = [svc_process.get_init()];
|
||||||
|
iter_tasks(processes, { indent_level: 0, parent_last_item: [] });
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
w.on_close = () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
w_body.appendChild(el_taskarea);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UIWindowTaskManager;
|
@ -1,4 +1,5 @@
|
|||||||
import UIWindow from "./UIWindow.js";
|
import UIWindow from "./UIWindow.js";
|
||||||
|
import UIWindowColorPicker from "./UIWindowColorPicker.js";
|
||||||
|
|
||||||
const UIWindowThemeDialog = async function UIWindowThemeDialog (options) {
|
const UIWindowThemeDialog = async function UIWindowThemeDialog (options) {
|
||||||
options = options ?? {};
|
options = options ?? {};
|
||||||
@ -114,6 +115,12 @@ const UIWindowThemeDialog = async function UIWindowThemeDialog (options) {
|
|||||||
svc_theme.reset();
|
svc_theme.reset();
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
Button({ label: i18n('reset_colors') })
|
||||||
|
.appendTo(w_body)
|
||||||
|
.onPress(() => {
|
||||||
|
UIWindowColorPicker();
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
Slider({
|
Slider({
|
||||||
label: i18n('hue'),
|
label: i18n('hue'),
|
||||||
|
@ -3782,3 +3782,113 @@ label {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.taskmgr {
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* could have been avoided with box-sizing: border-box */
|
||||||
|
height: calc(100% - 30px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
--scale: 2pt;
|
||||||
|
--line-color: #6e6e6ebd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-taskarea {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: rgba(255,255,255,0.8);
|
||||||
|
border: 2px inset rgba(127, 127, 127, 0.3);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-taskarea table thead {
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-taskarea table th {
|
||||||
|
-webkit-box-shadow: 0 1px 4px -2px rgba(0,0,0,0.2);
|
||||||
|
box-shadow: 0 1px 4px -2px rgba(0,0,0,0.2);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
position: sticky;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 0;
|
||||||
|
top: 0;
|
||||||
|
background-color: hsla(0, 0%, 100%, 0.8);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-taskarea table th > span {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
/* we set borders on this span because */
|
||||||
|
/* borders fly away from sticky headers */
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
|
||||||
|
/* padding order: top right bottom left */
|
||||||
|
padding:
|
||||||
|
calc(10 * var(--scale))
|
||||||
|
calc(2.5 * var(--scale))
|
||||||
|
calc(5 * var(--scale))
|
||||||
|
calc(2.5 * var(--scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-taskarea table th:not(:last-of-type) > span {
|
||||||
|
/* we set borders on this span because */
|
||||||
|
/* borders fly away from sticky headers */
|
||||||
|
border-right: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-taskarea table td {
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-taskarea table td > span {
|
||||||
|
padding: 0 calc(2.5 * var(--scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-indentcell {
|
||||||
|
position: relative;
|
||||||
|
align-items: right;
|
||||||
|
width: calc(10 * var(--scale));
|
||||||
|
height: calc(10 * var(--scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-indentcell-trunk {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: calc(5 * var(--scale));
|
||||||
|
width: calc(5 * var(--scale));
|
||||||
|
height: calc(10 * var(--scale));
|
||||||
|
border-left: 2px solid var(--line-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-indentcell-branch {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: calc(5 * var(--scale));
|
||||||
|
width: calc(5 * var(--scale));
|
||||||
|
height: calc(5 * var(--scale));
|
||||||
|
border-left: 2px solid var(--line-color);
|
||||||
|
border-bottom: 2px solid var(--line-color);
|
||||||
|
border-radius: 0 0 0 calc(2.5 * var(--scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-task {
|
||||||
|
display: flex;
|
||||||
|
height: calc(10 * var(--scale));
|
||||||
|
line-height: calc(10 * var(--scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskmgr-task-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-left: calc(2.5 * var(--scale));
|
||||||
|
}
|
@ -19,3 +19,94 @@
|
|||||||
export class Service {
|
export class Service {
|
||||||
//
|
//
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PROCESS_INITIALIZING = { i18n_key: 'initializing' };
|
||||||
|
export const PROCESS_RUNNING = { i18n_key: 'running' };
|
||||||
|
|
||||||
|
// Something is cloning these objects, so '===' checks don't work.
|
||||||
|
// To work around this, the `i` property is used to compare them.
|
||||||
|
export const END_SOFT = { i: 0, end: true, i18n_key: 'end_soft' };
|
||||||
|
export const END_HARD = { i: 1, end: true, i18n_key: 'end_hard' };
|
||||||
|
|
||||||
|
export class Process {
|
||||||
|
constructor ({ uuid, parent, name, meta }) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.parent = parent;
|
||||||
|
this.name = name;
|
||||||
|
this.meta = meta;
|
||||||
|
this.references = {};
|
||||||
|
|
||||||
|
this.status = PROCESS_INITIALIZING;
|
||||||
|
|
||||||
|
this._construct();
|
||||||
|
}
|
||||||
|
_construct () {}
|
||||||
|
|
||||||
|
chstatus (status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_init () {}
|
||||||
|
|
||||||
|
signal (sig) {
|
||||||
|
this._signal(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
get type () {
|
||||||
|
const _to_type_name = (name) => {
|
||||||
|
return name.replace(/Process$/, '').toLowerCase();
|
||||||
|
};
|
||||||
|
return this.type_ || _to_type_name(this.constructor.name) ||
|
||||||
|
'invalid'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export class InitProcess extends Process {
|
||||||
|
static created_ = false;
|
||||||
|
|
||||||
|
is_init () { return true; }
|
||||||
|
|
||||||
|
_construct () {
|
||||||
|
this.name = 'Puter';
|
||||||
|
|
||||||
|
if (InitProcess.created_) {
|
||||||
|
throw new Error('InitProccess already created');
|
||||||
|
}
|
||||||
|
|
||||||
|
InitProcess.created_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_signal (sig) {
|
||||||
|
const svc_process = globalThis.services.get('process');
|
||||||
|
for ( const process of svc_process.processes ) {
|
||||||
|
if ( process === this ) continue;
|
||||||
|
process.signal(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( sig.i !== END_HARD.i ) return;
|
||||||
|
|
||||||
|
// Currently this is the only way to terminate `init`.
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PortalProcess extends Process {
|
||||||
|
_construct () { this.type_ = 'app' }
|
||||||
|
_signal (sig) {
|
||||||
|
if ( sig.end ) {
|
||||||
|
$(this.references.el_win).close({
|
||||||
|
bypass_iframe_messaging: sig.i === END_HARD.i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export class PseudoProcess extends Process {
|
||||||
|
_construct () { this.type_ = 'ui' }
|
||||||
|
_signal (sig) {
|
||||||
|
if ( sig.end ) {
|
||||||
|
$(this.references.el_win).close({
|
||||||
|
bypass_iframe_messaging: sig.i === END_HARD.i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -36,6 +36,7 @@ import update_username_in_gui from './helpers/update_username_in_gui.js';
|
|||||||
import update_title_based_on_uploads from './helpers/update_title_based_on_uploads.js';
|
import update_title_based_on_uploads from './helpers/update_title_based_on_uploads.js';
|
||||||
import content_type_to_icon from './helpers/content_type_to_icon.js';
|
import content_type_to_icon from './helpers/content_type_to_icon.js';
|
||||||
import UIWindowDownloadDirProg from './UI/UIWindowDownloadDirProg.js';
|
import UIWindowDownloadDirProg from './UI/UIWindowDownloadDirProg.js';
|
||||||
|
import { PROCESS_RUNNING, PortalProcess, PseudoProcess } from "./definitions.js";
|
||||||
|
|
||||||
window.is_auth = ()=>{
|
window.is_auth = ()=>{
|
||||||
if(localStorage.getItem("auth_token") === null || auth_token === null)
|
if(localStorage.getItem("auth_token") === null || auth_token === null)
|
||||||
@ -1680,10 +1681,30 @@ window.launch_app = async (options)=>{
|
|||||||
// add file_signature to options
|
// add file_signature to options
|
||||||
file_signature = file_signature.items;
|
file_signature = file_signature.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------
|
||||||
|
// Create entry to track the "portal"
|
||||||
|
// (portals are processese in Puter's GUI)
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
let el_win;
|
||||||
|
let process;
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
// Explorer
|
// Explorer
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
if(options.name === 'explorer'){
|
if(options.name === 'explorer'){
|
||||||
|
process = new PseudoProcess({
|
||||||
|
uuid,
|
||||||
|
name: 'explorer',
|
||||||
|
parent: options.parent_instance_id,
|
||||||
|
meta: {
|
||||||
|
launch_options: options,
|
||||||
|
app_info: app_info,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const svc_process = globalThis.services.get('process');
|
||||||
|
svc_process.register(process);
|
||||||
if(options.path === window.home_path){
|
if(options.path === window.home_path){
|
||||||
title = 'Home';
|
title = 'Home';
|
||||||
icon = window.icons['folder-home.svg'];
|
icon = window.icons['folder-home.svg'];
|
||||||
@ -1697,7 +1718,7 @@ window.launch_app = async (options)=>{
|
|||||||
title = path.dirname(options.path);
|
title = path.dirname(options.path);
|
||||||
|
|
||||||
// open window
|
// open window
|
||||||
UIWindow({
|
el_win = UIWindow({
|
||||||
element_uuid: uuid,
|
element_uuid: uuid,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
path: options.path ?? window.home_path,
|
path: options.path ?? window.home_path,
|
||||||
@ -1713,6 +1734,18 @@ window.launch_app = async (options)=>{
|
|||||||
// All other apps
|
// All other apps
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
else{
|
else{
|
||||||
|
process = new PortalProcess({
|
||||||
|
uuid,
|
||||||
|
name: app_info.name,
|
||||||
|
parent: options.parent_instance_id,
|
||||||
|
meta: {
|
||||||
|
launch_options: options,
|
||||||
|
app_info: app_info,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const svc_process = globalThis.services.get('process');
|
||||||
|
svc_process.register(process);
|
||||||
|
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
// iframe_url
|
// iframe_url
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
@ -1808,7 +1841,7 @@ window.launch_app = async (options)=>{
|
|||||||
|
|
||||||
console.log('backgrounded??', app_info.background);
|
console.log('backgrounded??', app_info.background);
|
||||||
|
|
||||||
const el_win = UIWindow({
|
el_win = UIWindow({
|
||||||
element_uuid: uuid,
|
element_uuid: uuid,
|
||||||
title: title,
|
title: title,
|
||||||
iframe_url: iframe_url.href,
|
iframe_url: iframe_url.href,
|
||||||
@ -1859,6 +1892,18 @@ window.launch_app = async (options)=>{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const el = await el_win;
|
||||||
|
console.log('RESOV', el);
|
||||||
|
$(el).on('remove', () => {
|
||||||
|
const svc_process = globalThis.services.get('process');
|
||||||
|
svc_process.unregister(process.uuid);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.references.el_win = el;
|
||||||
|
process.chstatus(PROCESS_RUNNING);
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.open_item = async function(options){
|
window.open_item = async function(options){
|
||||||
|
@ -39,7 +39,9 @@ const en = {
|
|||||||
change_password: "Change Password",
|
change_password: "Change Password",
|
||||||
change_ui_colors: "Change UI Colors",
|
change_ui_colors: "Change UI Colors",
|
||||||
change_username: "Change Username",
|
change_username: "Change Username",
|
||||||
|
close: 'Close',
|
||||||
close_all_windows: "Close All Windows",
|
close_all_windows: "Close All Windows",
|
||||||
|
close_all_windows_confirm: "Are you sure you want to close all windows?",
|
||||||
close_all_windows_and_log_out: 'Close Windows and Log Out',
|
close_all_windows_and_log_out: 'Close Windows and Log Out',
|
||||||
change_always_open_with: "Do you want to always open this type of file with",
|
change_always_open_with: "Do you want to always open this type of file with",
|
||||||
color: 'Color',
|
color: 'Color',
|
||||||
@ -88,11 +90,15 @@ const en = {
|
|||||||
empty_trash: 'Empty Trash',
|
empty_trash: 'Empty Trash',
|
||||||
empty_trash_confirmation: `Are you sure you want to permanently delete the items in Trash?`,
|
empty_trash_confirmation: `Are you sure you want to permanently delete the items in Trash?`,
|
||||||
emptying_trash: 'Emptying Trash…',
|
emptying_trash: 'Emptying Trash…',
|
||||||
|
end_hard: "End Hard",
|
||||||
|
end_process_force_confirm: "Are you sure you want to force-quit this process?",
|
||||||
|
end_soft: "End Soft",
|
||||||
enter_password_to_confirm_delete_user: "Enter your password to confirm account deletion",
|
enter_password_to_confirm_delete_user: "Enter your password to confirm account deletion",
|
||||||
feedback: "Feedback",
|
feedback: "Feedback",
|
||||||
feedback_c2a: "Please use the form below to send us your feedback, comments, and bug reports.",
|
feedback_c2a: "Please use the form below to send us your feedback, comments, and bug reports.",
|
||||||
feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.",
|
feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.",
|
||||||
fit: "Fit",
|
fit: "Fit",
|
||||||
|
force_quit: 'Force Quit',
|
||||||
forgot_pass_c2a: "Forgot password?",
|
forgot_pass_c2a: "Forgot password?",
|
||||||
from: "From",
|
from: "From",
|
||||||
general: "General",
|
general: "General",
|
||||||
@ -154,6 +160,11 @@ const en = {
|
|||||||
privacy: "Privacy",
|
privacy: "Privacy",
|
||||||
proceed_to_login: 'Proceed to login',
|
proceed_to_login: 'Proceed to login',
|
||||||
proceed_with_account_deletion: "Proceed with Account Deletion",
|
proceed_with_account_deletion: "Proceed with Account Deletion",
|
||||||
|
process_status_initializing: "Initializing",
|
||||||
|
process_status_running: "Running",
|
||||||
|
process_type_app: 'App',
|
||||||
|
process_type_init: 'Init',
|
||||||
|
process_type_ui: 'UI',
|
||||||
properties: "Properties",
|
properties: "Properties",
|
||||||
publish: "Publish",
|
publish: "Publish",
|
||||||
publish_as_website: 'Publish as website',
|
publish_as_website: 'Publish as website',
|
||||||
@ -172,6 +183,7 @@ const en = {
|
|||||||
replace_all: 'Replace All',
|
replace_all: 'Replace All',
|
||||||
resend_confirmation_code: "Re-send Confirmation Code",
|
resend_confirmation_code: "Re-send Confirmation Code",
|
||||||
reset_colors: "Reset Colors",
|
reset_colors: "Reset Colors",
|
||||||
|
restart_puter_confirm: "Are you sure you want to restart Puter?",
|
||||||
restore: "Restore",
|
restore: "Restore",
|
||||||
saturation: 'Saturation',
|
saturation: 'Saturation',
|
||||||
save_account: 'Save account',
|
save_account: 'Save account',
|
||||||
@ -203,6 +215,10 @@ const en = {
|
|||||||
storage_usage: "Storage Usage",
|
storage_usage: "Storage Usage",
|
||||||
storage_puter_used: 'used by Puter',
|
storage_puter_used: 'used by Puter',
|
||||||
taking_longer_than_usual: 'Taking a little longer than usual. Please wait...',
|
taking_longer_than_usual: 'Taking a little longer than usual. Please wait...',
|
||||||
|
task_manager: "Task Manager",
|
||||||
|
taskmgr_header_name: "Name",
|
||||||
|
taskmgr_header_status: "Status",
|
||||||
|
taskmgr_header_type: "Type",
|
||||||
terms: "Terms",
|
terms: "Terms",
|
||||||
text_document: 'Text document',
|
text_document: 'Text document',
|
||||||
tos_fineprint: `By clicking 'Create Free Account' you agree to Puter's {{link=terms}}Terms of Service{{/link}} and {{link=privacy}}Privacy Policy{{/link}}.`,
|
tos_fineprint: `By clicking 'Create Free Account' you agree to Puter's {{link=terms}}Terms of Service{{/link}} and {{link=privacy}}Privacy Policy{{/link}}.`,
|
||||||
|
@ -36,6 +36,9 @@ import PuterDialog from './UI/PuterDialog.js';
|
|||||||
import determine_active_container_parent from './helpers/determine_active_container_parent.js';
|
import determine_active_container_parent from './helpers/determine_active_container_parent.js';
|
||||||
import { ThemeService } from './services/ThemeService.js';
|
import { ThemeService } from './services/ThemeService.js';
|
||||||
import { BroadcastService } from './services/BroadcastService.js';
|
import { BroadcastService } from './services/BroadcastService.js';
|
||||||
|
import UIWindowTaskManager from './UI/UIWindowTaskManager.js';
|
||||||
|
import { ProcessService } from './services/ProcessService.js';
|
||||||
|
import { PROCESS_RUNNING } from './definitions.js';
|
||||||
|
|
||||||
const launch_services = async function () {
|
const launch_services = async function () {
|
||||||
const services_l_ = [];
|
const services_l_ = [];
|
||||||
@ -51,10 +54,17 @@ const launch_services = async function () {
|
|||||||
|
|
||||||
register('broadcast', new BroadcastService());
|
register('broadcast', new BroadcastService());
|
||||||
register('theme', new ThemeService());
|
register('theme', new ThemeService());
|
||||||
|
register('process', new ProcessService())
|
||||||
|
|
||||||
for (const [_, instance] of services_l_) {
|
for (const [_, instance] of services_l_) {
|
||||||
await instance._init();
|
await instance._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set init process status
|
||||||
|
{
|
||||||
|
const svc_process = globalThis.services.get('process');
|
||||||
|
svc_process.get_init().chstatus(PROCESS_RUNNING);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.initgui = async function(){
|
window.initgui = async function(){
|
||||||
|
70
src/services/ProcessService.js
Normal file
70
src/services/ProcessService.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { InitProcess, Service } from "../definitions.js";
|
||||||
|
|
||||||
|
// The NULL UUID is also the UUID for the init process.
|
||||||
|
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
|
||||||
|
|
||||||
|
export class ProcessService extends Service {
|
||||||
|
async _init () {
|
||||||
|
this.processes = [];
|
||||||
|
this.processes_map = new Map();
|
||||||
|
this.uuid_to_treelist = new Map();
|
||||||
|
|
||||||
|
const root = new InitProcess({
|
||||||
|
uuid: NULL_UUID,
|
||||||
|
});
|
||||||
|
this.register_(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
get_init () {
|
||||||
|
return this.processes_map.get(NULL_UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
get_children_of (uuid) {
|
||||||
|
if ( ! uuid ) {
|
||||||
|
uuid = NULL_UUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.uuid_to_treelist.get(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
register (process) {
|
||||||
|
this.register_(process);
|
||||||
|
this.attach_to_parent_(process);
|
||||||
|
}
|
||||||
|
|
||||||
|
register_ (process) {
|
||||||
|
this.processes.push(process);
|
||||||
|
this.processes_map.set(process.uuid, process);
|
||||||
|
this.uuid_to_treelist.set(process.uuid, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
attach_to_parent_ (process) {
|
||||||
|
process.parent = process.parent ?? NULL_UUID;
|
||||||
|
const parent_list = this.uuid_to_treelist.get(process.parent);
|
||||||
|
parent_list.push(process);
|
||||||
|
}
|
||||||
|
|
||||||
|
unregister (uuid) {
|
||||||
|
const process = this.processes_map.get(uuid);
|
||||||
|
if ( ! process ) {
|
||||||
|
throw new Error(`Process with uuid ${uuid} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.processes_map.delete(uuid);
|
||||||
|
this.processes.splice(this.processes.indexOf(process), 1);
|
||||||
|
|
||||||
|
const parent_list = this.uuid_to_treelist.get(process.parent);
|
||||||
|
parent_list.splice(parent_list.indexOf(process), 1);
|
||||||
|
|
||||||
|
const children = this.uuid_to_treelist.get(process.uuid);
|
||||||
|
|
||||||
|
delete this.uuid_to_treelist[process.uuid];
|
||||||
|
this.processes.splice(this.processes.indexOf(process), 1);
|
||||||
|
|
||||||
|
// Transfer children to init process
|
||||||
|
for ( const child of children ) {
|
||||||
|
child.parent = NULL_UUID;
|
||||||
|
this.attach_to_parent_(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user