1
0
mirror of https://github.com/dkmstr/openuds-gui.git synced 2024-10-26 08:55:23 +03:00

fixing and refactoring frontend

This commit is contained in:
Adolfo Gómez García 2023-01-18 12:52:57 +01:00
parent 6bb8239e84
commit 23389fca6a
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
12 changed files with 74 additions and 101 deletions

View File

@ -5,8 +5,7 @@
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.2%
> 0.2% and not dead
last 2 versions
last 4 years
Firefox ESR
not dead

View File

@ -7,5 +7,10 @@
"axe/text-alternatives": "off",
"button-type": "off",
"typescript-config/consistent-casing": "off"
}
},
"browserslist": [
"defaults",
"not ie 11",
"not ie <= 10"
]
}

View File

@ -51,7 +51,7 @@ export class ModalComponent implements OnInit {
this.extra = ' (' + Math.floor(miliseconds / 1000) + ' ' + django.gettext('seconds') + ') ';
}
async initAlert(): Promise<void> {
async initAlert() {
const autoclose = this.data.autoclose || 0;
if (autoclose > 0) {
this.dialogRef.afterClosed().subscribe((res) => {

View File

@ -15,7 +15,7 @@ export class Plugin {
this.delay = api.config.launcher_wait_time;
}
async launchURL(url: string): Promise<void> {
async launchURL(url: string) {
// If uds url...
if (url.substring(0, 7) === 'udsa://') {
await this.processUDSUrl(url);
@ -45,27 +45,7 @@ export class Plugin {
* @param url uds url to be lauhcned
*/
private launchUDSUrl(url: string) {
let elem: HTMLIFrameElement = document.getElementById(
'hiddenUdsLauncherIFrame'
) as HTMLIFrameElement;
if (elem === null) {
const i = document.createElement('div');
i.id = 'testID';
i.innerHTML =
'<iframe id="hiddenUdsLauncherIFrame" src="about:blank" style="display:none"></iframe>';
document.body.appendChild(i);
elem = document.getElementById(
'hiddenUdsLauncherIFrame'
) as HTMLIFrameElement;
}
// Ensure all is ok
if (elem === null) {
throw new Error('Unable to create hidden iframe');
}
if (elem.contentWindow === null) {
throw new Error('Unable to get content window');
}
elem.contentWindow.location.href = url;
this.api.download(url);
}
/**
@ -74,7 +54,7 @@ export class Plugin {
* @param url uds url (udsa://serviceId/transportId)
* @returns nothing
*/
private async processUDSUrl(url: string): Promise<void> {
private async processUDSUrl(url: string) {
// Extract params from url, serviceId and transportId
const params = url.split('//')[1].split('/');
if (params.length !== 2) {
@ -96,7 +76,7 @@ export class Plugin {
// Connect close dialog to "cancel" variable
toPromise(dialog.afterClosed()).then(() => (cancel = true));
let readyTime = -1;
let readySinceTime = -1;
try {
// Enable service
const enabledData = await this.api.enabler(serviceId, transportId);
@ -119,7 +99,7 @@ export class Plugin {
while (!cancel) {
const data = await this.api.status(serviceId, transportId);
// Wait 5 times the default delay before notifying that client is not installed
if (readyTime > 0 && Date.now() - readyTime > this.delay * 5) {
if (readySinceTime > 0 && Date.now() - readySinceTime > this.delay * 5) {
dialog.componentInstance.data.title =
django.gettext('Service ready') +
' - ' +
@ -137,9 +117,9 @@ export class Plugin {
'</a>';
}
if (data.status === 'ready') {
if (readyTime === -1) {
if (readySinceTime === -1) {
// Service is ready, wait for client, update dialog text
readyTime = Date.now(); // Milisecodns
readySinceTime = Date.now(); // Milisecodns
dialog.componentInstance.data.title =
django.gettext('Service ready');
dialog.componentInstance.data.body = django.gettext(
@ -167,7 +147,7 @@ export class Plugin {
}
}
private async processExternalUrl(url: string): Promise<void> {
private async processExternalUrl(url: string) {
const dialog = await this.showAlert(
django.gettext('Please wait until the service is launched.'),
django.gettext(
@ -281,7 +261,7 @@ export class Plugin {
}
}
private async notifyError(error?: any): Promise<void> {
private async notifyError(error?: any) {
let msg: string = django.gettext(
'Error communicating with your service. Please, retry again.'
);

View File

@ -1,8 +1,8 @@
<div class="about">
<h1>Universal Desktop Services {{ api.config.version }} build {{ api.config.version_stamp }}</h1>
<h3><a href="http://www.udsenterprise.com" target="_blank"> &copy; 2012-{{ year }} Virtual Cable S.L.U.</a></h3>
<h3><a rel="noopener noreferrer" href="http://www.udsenterprise.com" target="_blank"> &copy; 2012-{{ year }} Virtual Cable S.L.U.</a></h3>
<h4>
<uds-translate>You can access UDS Open Source code at</uds-translate>&nbsp;<a href="https://github.com/dkmstr/openuds"
<uds-translate>You can access UDS Open Source code at</uds-translate>&nbsp;<a rel="noopener noreferrer" href="https://github.com/dkmstr/openuds"
target="_blank">OpenUDS github repository</a>
</h4>
<div class="components">
@ -10,15 +10,15 @@
<uds-translate>UDS has been developed using these components:</uds-translate>
</h2>
<ul>
<li><a href="https://www.python.org/">Python</a></li>
<li><a href="https://www.typescriptlang.org/" target="_blank">TypeScript</a></li>
<li><a href="https://www.djangoproject.com/" target="_blank">Django</a></li>
<li><a href="https://angular.io" target="_blank">Angular</a></li>
<li><a href="https://guac-dev.org/" target="_blank">Guacamole</a></li>
<li><a href="https://weasyprint.org/" target="_blank">weasyprint</a></li>
<li><a href="https://kde-look.org/content/show.php/Crystal+Project?content=60475)" target="_blank">Crystal project
<li><a rel="noopener noreferrer" href="https://www.python.org/" target="_blank">Python</a></li>
<li><a rel="noopener noreferrer" href="https://www.typescriptlang.org/" target="_blank">TypeScript</a></li>
<li><a rel="noopener noreferrer" href="https://www.djangoproject.com/" target="_blank">Django</a></li>
<li><a rel="noopener noreferrer" href="https://angular.io" target="_blank">Angular</a></li>
<li><a rel="noopener noreferrer" href="https://guac-dev.org/" target="_blank">Guacamole</a></li>
<li><a rel="noopener noreferrer" href="https://weasyprint.org/" target="_blank">weasyprint</a></li>
<li><a rel="noopener noreferrer" href="https://kde-look.org/content/show.php/Crystal+Project?content=60475)" target="_blank">Crystal project
icons</a></li>
<li><a href="https://github.com/NitruxSA/flattr-icons" target="_blank">Flattr Icons</a></li>
<li><a rel="noopener noreferrer" href="https://github.com/NitruxSA/flattr-icons" target="_blank">Flattr Icons</a></li>
</ul>
<p><small>* <uds-translate>If you find that we missed any component, please let us know</uds-translate></small></p>
</div>

View File

@ -10,7 +10,7 @@
</div>
<div class="plugins">
<div [class]="css(p)" *ngFor="let p of api.plugins" (click)="download(p.url)">
<div [class]="css(p)" *ngFor="let p of api.plugins" (click)="api.download(p.url)">
<div class="image">
<img [src]="img(p.name)">
</div>

View File

@ -15,10 +15,6 @@ export class ClientDownloadComponent implements OnInit {
ngOnInit() {
}
download(url: string) {
window.location.href = url;
}
img(image: string) {
return this.api.staticURL( 'modern/img/' + image + '.png');
}

View File

@ -9,7 +9,7 @@
</div>
<div class="actors">
<div [class]="css(p.name)" *ngFor="let p of actors" (click)="download(p.url)">
<div [class]="css(p.name)" *ngFor="let p of actors" (click)="api.download(p.url)">
<div class="image">
<img [src]="img(p.name)">
</div>

View File

@ -5,31 +5,27 @@ import { Downloadable } from '../../types/config';
@Component({
selector: 'uds-downloads',
templateUrl: './downloads.component.html',
styleUrls: ['./downloads.component.scss']
styleUrls: ['./downloads.component.scss'],
})
export class DownloadsComponent implements OnInit {
actors: Downloadable[] = [];
constructor(public api: UDSApiService) { }
constructor(public api: UDSApiService) {}
ngOnInit() {
this.actors = []; // Put legacy at end of downloadables...
// Sort legacy actors to the end of the list
this.actors = []; // Put legacy at end of downloadables...
const legacy: Downloadable[] = [];
this.api.actors.forEach(a => {
for (const a of this.api.actors) {
if (a.name.includes('legacy')) {
legacy.push(a);
} else {
this.actors.push(a);
}
});
legacy.forEach(l => {
}
for (const l of legacy) {
this.actors.push(l);
});
}
download(url: string) {
window.location.href = url;
}
}
img(filename: string) {
@ -52,5 +48,4 @@ export class DownloadsComponent implements OnInit {
}
return styles;
}
}

View File

@ -17,7 +17,7 @@ export class ErrorComponent implements OnInit {
await this.getError();
}
async getError(): Promise<void> {
async getError() {
const id = this.route.snapshot.paramMap.get('id') || '-1';
if (id === '19') { // 19 is MFA error, return to MFA
this.returnUrl = '/mfa';

View File

@ -42,6 +42,9 @@ export interface UDSApiServiceType {
/* Executes logout */
logout(): void;
/* Download file/launches a custom uro */
download(url: string): Promise<void>;
/* sleep milliseconds */
sleep(ms: number): Promise<void>;
/**

View File

@ -19,7 +19,6 @@ import { UDSApiServiceType } from './uds-api.service-type';
import { environment } from '../environments/environment';
const DARK_THEME = 'dark-theme';
const LIGHT_THEME = 'light-theme';
const TIMEOUT = 10000;
@ -32,14 +31,10 @@ const toPromise = <T>(observable: Observable<T>, wait?: number): Promise<T> => {
@Injectable()
export class UDSApiService implements UDSApiServiceType {
readonly user: User;
transportsWindow: Window|null = null;
transportsWindow: Window | null = null;
plugin: Plugin;
constructor(
private http: HttpClient,
public gui: UDSGuiService,
public router: Router
) {
constructor(private http: HttpClient, public gui: UDSGuiService, public router: Router) {
this.user = new User(udsData.profile);
this.plugin = new Plugin(this);
}
@ -91,32 +86,20 @@ export class UDSApiService implements UDSApiServiceType {
}
/* Client enabler */
async enabler(
serviceId: string,
transportId: string
): Promise<JSONEnabledService> {
const enabler = this.config.urls.enabler
.replace('param1', serviceId)
.replace('param2', transportId);
async enabler(serviceId: string, transportId: string): Promise<JSONEnabledService> {
const enabler = this.config.urls.enabler.replace('param1', serviceId).replace('param2', transportId);
return toPromise(this.http.get<JSONEnabledService>(enabler));
}
/* Check userService status */
async status(
serviceId: string,
transportId: string
): Promise<JSONStatusService> {
const status = this.config.urls.status
.replace('param1', serviceId)
.replace('param2', transportId);
async status(serviceId: string, transportId: string): Promise<JSONStatusService> {
const status = this.config.urls.status.replace('param1', serviceId).replace('param2', transportId);
return toPromise(this.http.get<JSONStatusService>(status));
}
/* Services resetter */
async action(action: string, serviceId: string): Promise<JSONService> {
const actionURL = this.config.urls.action
.replace('param1', serviceId)
.replace('param2', action);
const actionURL = this.config.urls.action.replace('param1', serviceId).replace('param2', action);
return toPromise(this.http.get<JSONService>(actionURL));
}
@ -131,9 +114,7 @@ export class UDSApiService implements UDSApiServiceType {
password: string,
domain: string
): Promise<any> {
const url = this.config.urls.updateTransportTicket
.replace('param1', ticketId)
.replace('param2', scrambler);
const url = this.config.urls.updateTransportTicket.replace('param1', ticketId).replace('param2', scrambler);
return toPromise(
this.http.post<any>(url, {
username,
@ -164,20 +145,14 @@ export class UDSApiService implements UDSApiServiceType {
* Gets services information
*/
async getServicesInformation(): Promise<JSONServicesInformation> {
return toPromise(
this.http.get<JSONServicesInformation>(this.config.urls.services)
);
return toPromise(this.http.get<JSONServicesInformation>(this.config.urls.services));
}
/**
* Gets error string from a code
*/
async getErrorInformation(errorCode: string): Promise<JSONErrorInformation> {
return toPromise(
this.http.get<JSONErrorInformation>(
this.config.urls.error.replace('9999', errorCode)
)
);
return toPromise(this.http.get<JSONErrorInformation>(this.config.urls.error.replace('9999', errorCode)));
}
/**
@ -200,6 +175,28 @@ export class UDSApiService implements UDSApiServiceType {
window.location.href = this.config.urls.logout;
}
async download(url: string): Promise<void> {
// Launch the download
// Create an iframe and set the src to the url
// This will trigger the download
// First, loof for an existing download iframe
let iframe = document.getElementById('download') as HTMLIFrameElement;
// If not found, create it
if (!iframe) {
iframe = document.createElement('iframe');
iframe.id = 'download';
iframe.style.display = 'none';
document.body.appendChild(iframe);
}
// Set the src to the url
iframe.src = url;
// onload in iframe will only be triggered if an html page is downloaded. If it is loaded, it's not a download
iframe.onload = () => {
alert('Error downloading file. Please try again later.');
};
//window.location.href = url;
}
sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
@ -215,9 +212,7 @@ export class UDSApiService implements UDSApiServiceType {
* @returns Observable
*/
async getAuthCustomJavascript(authId: string): Promise<string> {
return toPromise(
this.http.get(this.config.urls.customAuth + authId, {responseType: 'text'})
);
return toPromise(this.http.get(this.config.urls.customAuth + authId, { responseType: 'text' }));
}
// Switch dark/light theme