Skip to content

Commit 705b9de

Browse files
committed
Add basic sharing UI
1 parent b648817 commit 705b9de

File tree

4 files changed

+261
-2
lines changed

4 files changed

+261
-2
lines changed

src/UI/UIContextMenu.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ function UIContextMenu(options){
244244
})
245245
}
246246
}
247-
}, 200);
247+
}, 300);
248248
},
249249
//deactivates row when mouse leaves
250250
deactivate: function (e) {

src/UI/UIItem.js

+53
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
*/
1919

20+
import UIWindowShare from './UIWindowShare.js';
2021
import UIWindowPublishWebsite from './UIWindowPublishWebsite.js';
2122
import UIWindowItemProperties from './UIWindowItemProperties.js';
2223
import UIWindowSaveAccount from './UIWindowSaveAccount.js';
@@ -783,6 +784,35 @@ function UIItem(options){
783784
menu_items.push('-');
784785
}
785786
if(!are_trashed){
787+
menu_items.push({
788+
html: 'Share With…',
789+
onClick: async function(){
790+
// if(window.user.is_temp &&
791+
// !await UIWindowSaveAccount({
792+
// message: 'Please create an account to proceed.',
793+
// send_confirmation_code: true,
794+
// window_options: {
795+
// backdrop: true,
796+
// close_on_backdrop_click: false,
797+
// }
798+
// },))
799+
// return;
800+
// else if(!window.user.email_confirmed && !await UIWindowEmailConfirmationRequired())
801+
// return;
802+
803+
let items = [];
804+
$selected_items.each(function() {
805+
const ell = this;
806+
items.push({uid: $(ell).attr('data-uid'), path: $(ell).attr('data-path')});
807+
})
808+
UIWindowShare(items);
809+
}
810+
})
811+
// -------------------------------------------
812+
// -
813+
// -------------------------------------------
814+
menu_items.push({ is_divider: true });
815+
786816
// -------------------------------------------
787817
// Donwload
788818
// -------------------------------------------
@@ -1055,6 +1085,29 @@ function UIItem(options){
10551085
if(!is_trash && !is_trashed && options.is_dir)
10561086
menu_items.push('-');
10571087
}
1088+
// -------------------------------------------
1089+
// Share With…
1090+
// -------------------------------------------
1091+
if(!is_trashed && !is_trash){
1092+
menu_items.push({
1093+
html: 'Share With…',
1094+
onClick: async function(){
1095+
// if(window.user.is_temp &&
1096+
// !await UIWindowSaveAccount({
1097+
// message: 'Please create an account to proceed.',
1098+
// send_confirmation_code: true,
1099+
// window_options: {
1100+
// backdrop: true,
1101+
// close_on_backdrop_click: false,
1102+
// }
1103+
// }))
1104+
// return;
1105+
// else if(!window.user.email_confirmed && !await UIWindowEmailConfirmationRequired())
1106+
// return;
1107+
UIWindowShare([{uid: $(el_item).attr('data-uid'), path: $(el_item).attr('data-path')}]);
1108+
}
1109+
});
1110+
}
10581111

10591112
// -------------------------------------------
10601113
// Publish As Website

src/UI/UINotification.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function UINotification(options){
2323

2424
let h = '';
2525
h += `<div id="ui-notification__${window.global_element_id}" data-el-id="${window.global_element_id}" class="notification antialiased animate__animated animate__fadeInRight animate__slow">`;
26-
h += `<img class="notification-close" src="${html_encode(window.icons['close.svg'])}">`;
26+
h += `<img class="notification-close disable-user-select" src="${html_encode(window.icons['close.svg'])}">`;
2727
h += `<div class="notification-icon">`;
2828
h += `<img src="${html_encode(options.icon ?? window.icons['bell.svg'])}">`;
2929
h += `</div>`;

src/UI/UIWindowShare.js

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import UIWindow from './UIWindow.js'
2+
3+
async function UIWindowShare(items){
4+
return new Promise(async (resolve) => {
5+
let h = '';
6+
h += `<div style="padding: 30px 40px 20px; border-bottom: 1px solid #ced7e1;">`;
7+
// success
8+
h += `<div class="window-give-item-access-success">`;
9+
h += `<span class="hide-sharing-success-alert">✕</span>`
10+
h += `<img src="${html_encode(window.icons['c-check.svg'])}" style="width:50px; height:50px; display: block; margin:10px auto;">`;
11+
h += `<p style="text-align:center; margin-bottom:10px;">Shared with <strong class="access-recipient-print"></strong></p>`;
12+
h+= `</div>`;
13+
14+
// form
15+
h += `<form class="window-give-item-access-form">`;
16+
// error msg
17+
h += `<div class="error"></div>`;
18+
// username/email
19+
h += `<div style="overflow: hidden;">`;
20+
h += `<label style="margin-bottom: 10px;">The user you want to share ${ items.length > 1 ? `these items` : `this item`} with:</label>`;
21+
h += `<div style="display: flex;">`;
22+
//username/email
23+
h += `<input placeholder="username" class="access-recipient" style="border-right: none; margin-bottom: 10px; border-top-right-radius: 0; border-bottom-right-radius: 0;" type="text" autocomplete="recipient_email_username" spellcheck="false" autocorrect="off" autocapitalize="off" data-gramm_editor="false"/>`;
24+
// Share
25+
h += `<button class="give-access-btn button button-primary button-normal" style="border-top-left-radius: 0; border-bottom-left-radius: 0;">Share</button>`
26+
h += `</div>`;
27+
h += `</div>`;
28+
h += `</form>`;
29+
30+
//recipients
31+
// h += `<h2 style="font-size: 17px;
32+
// margin-bottom: 0px;
33+
// font-weight: 400;
34+
// color: #303d49;
35+
// text-shadow: 1px 1px white;">People with access</h2>`;
36+
// h += `<div class="share-recipients">`;
37+
// h += `</div>`;
38+
h += `</div>`;
39+
40+
const el_window = await UIWindow({
41+
title: 'Share With…',
42+
icon: null,
43+
uid: null,
44+
is_dir: false,
45+
body_content: h,
46+
draggable_body: false,
47+
has_head: true,
48+
selectable_body: false,
49+
draggable_body: false,
50+
allow_context_menu: false,
51+
is_resizable: false,
52+
is_droppable: false,
53+
init_center: true,
54+
allow_native_ctxmenu: true,
55+
allow_user_select: true,
56+
onAppend: function(this_window){
57+
$(this_window).find(`.access-recipient`).get(0).focus({preventScroll:true});
58+
},
59+
window_class: 'window-give-access',
60+
width: 550,
61+
window_css: {
62+
height: 'initial',
63+
},
64+
body_css: {
65+
width: 'initial',
66+
height: '100%',
67+
'background-color': 'rgb(245 247 249)',
68+
'backdrop-filter': 'blur(3px)',
69+
}
70+
})
71+
72+
// /stat
73+
let perms = [];
74+
for(let i=0; i<items.length; i++){
75+
$.ajax({
76+
url: api_origin + "/stat",
77+
type: 'POST',
78+
data: JSON.stringify({
79+
uid: items[i].uid,
80+
return_subdomains: false,
81+
return_permissions: true,
82+
}),
83+
async: false,
84+
contentType: "application/json",
85+
headers: {
86+
"Authorization": "Bearer "+auth_token
87+
},
88+
statusCode: {
89+
401: function () {
90+
logout();
91+
},
92+
},
93+
success: function (fsentry){
94+
perms.push(fsentry);
95+
},
96+
})
97+
}
98+
// if(perms.length > 0){
99+
// let printed_users = [];
100+
// let perm_list = '';
101+
// perms.forEach(fsentry => {
102+
// //owner
103+
// //check if this user has been printed here before, important for multiple items
104+
// if(!printed_users.includes(fsentry.owner.username)){
105+
// perm_list += `<div class="item-perm-recipient-card item-prop-perm-entry item-permission-owner" style="margin-bottom:5px; margin-top:5px; background-color: #f2f2f2;">`
106+
// if(fsentry.owner.username === window.user.username)
107+
// perm_list += `You (${fsentry.owner.email ?? fsentry.owner.username})`;
108+
// else
109+
// perm_list += fsentry.owner.email ?? fsentry.owner.username;
110+
// perm_list += `<div style="float:right;"><span class="permission-owner-badge">owner</span></div>`;
111+
// perm_list += `</div>`;
112+
// // add this user to the list of printed users
113+
// printed_users.push(fsentry.owner.username);
114+
// }
115+
116+
// // others with access
117+
// if(fsentry.permissions.length > 0){
118+
// fsentry.permissions.forEach(perm => {
119+
// //check if this user has been printed here before, important for multiple items
120+
// if(!printed_users.includes(perm.username)){
121+
// perm_list += `<div class="item-perm-recipient-card item-prop-perm-entry" data-perm-uid="${perm.uid}" style="margin-bottom:5px; margin-top:5px;">`
122+
// perm_list += `${perm.email ?? perm.username}`;
123+
// perm_list += `<div style="float:right;"><span class="remove-permission-link remove-permission-icon" data-perm-uid="${perm.uid}">✕</span></div>`;
124+
// perm_list += `</div>`;
125+
// // add this user to the list of printed users
126+
// printed_users.push(perm.username);
127+
// }
128+
// });
129+
// }
130+
// });
131+
// $(el_window).find('.share-recipients').append(`${perm_list}`);
132+
// }
133+
134+
$(el_window).find('.give-access-btn').on('click', async function(e){
135+
e.preventDefault();
136+
e.stopPropagation();
137+
138+
$(el_window).find('.error').hide();
139+
140+
let recipient_email, recipient_username;
141+
let recipient_id = $(el_window).find('.access-recipient').val();
142+
143+
// todo do some basic validation client-side
144+
if(recipient_id === null)
145+
return;
146+
147+
if(is_email(recipient_id))
148+
recipient_email = recipient_id;
149+
else
150+
recipient_username = recipient_id;
151+
152+
// disable 'Give Access' button
153+
$(el_window).find('.give-access-btn').prop('disabled', true);
154+
155+
let cancelled_due_to_error = false;
156+
let share_result;
157+
158+
$.ajax({
159+
url: puter.APIOrigin + "/share/item-by-username",
160+
type: "POST",
161+
headers: {
162+
"Content-Type": "application/json",
163+
"Authorization": "Bearer " + puter.authToken
164+
},
165+
data: JSON.stringify({
166+
path: items[0].path,
167+
username: recipient_username
168+
}),
169+
success: function(response) {
170+
// show success message
171+
$(el_window).find('.access-recipient-print').html(recipient_id);
172+
$(el_window).find('.window-give-item-access-success').show(100);
173+
},
174+
error: function(err) {
175+
console.error(err);
176+
// at this point 'username_not_found' and 'shared_with_self' are the only
177+
// errors that need to stop the loop
178+
if(err.responseJSON.code === "user_does_not_exist" || err.responseJSON.code === 'shared_with_self'){
179+
$(el_window).find('.error').html(err.responseJSON.message);
180+
$(el_window).find('.error').fadeIn();
181+
cancelled_due_to_error = true;
182+
}
183+
// re-enable share button
184+
$(el_window).find('.give-access-btn').prop('disabled', false);
185+
186+
}
187+
});
188+
189+
// finished
190+
if(!cancelled_due_to_error){
191+
$(el_window).find(`.access-recipient`).val('');
192+
}
193+
// re-enable share button
194+
$(el_window).find('.give-access-btn').prop('disabled', false);
195+
196+
return false;
197+
})
198+
199+
$(el_window).find('.hide-sharing-success-alert').on('click', function(){
200+
$(el_window).find('.window-give-item-access-success').hide(200);
201+
})
202+
203+
})
204+
}
205+
206+
export default UIWindowShare

0 commit comments

Comments
 (0)