Removed the old `d4cience.v2` theme and `admin` part of the `d4science` base theme
This commit is contained in:
parent
b9deaea561
commit
b9ae2f9b6b
|
@ -16,15 +16,10 @@
|
|||
"name": "d4science",
|
||||
"types": [
|
||||
"account",
|
||||
"admin",
|
||||
"email",
|
||||
"login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "d4science.v2",
|
||||
"types": [ "account" ]
|
||||
},
|
||||
{
|
||||
"name": "dante.d4science.org",
|
||||
"types": [ "login" ]
|
||||
|
|
|
@ -1,293 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${msg("accountManagementTitle")}</title>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<script>
|
||||
<#if properties.developmentMode?has_content && properties.developmentMode == "true">
|
||||
var developmentMode = true;
|
||||
var reactRuntime = 'react.development.js';
|
||||
var reactDOMRuntime = 'react-dom.development.js';
|
||||
var reactRouterRuntime = 'react-router-dom.js';
|
||||
<#else>
|
||||
var developmentMode = false;
|
||||
var reactRuntime = 'react.production.min.js';
|
||||
var reactDOMRuntime = 'react-dom.production.min.js';
|
||||
var reactRouterRuntime = 'react-router-dom.min.js';
|
||||
</#if>
|
||||
var authUrl = '${authUrl}';
|
||||
var baseUrl = '${baseUrl}';
|
||||
var realm = '${realm.name}';
|
||||
var resourceUrl = '${resourceUrl}';
|
||||
var isReactLoading = false;
|
||||
|
||||
<#if properties.logo?has_content>
|
||||
var brandImg = resourceUrl + '${properties.logo}';
|
||||
<#else>
|
||||
var brandImg = resourceUrl + '/public/logo.svg';
|
||||
</#if>
|
||||
|
||||
<#if properties.logoUrl?has_content>
|
||||
var brandUrl = '${properties.logoUrl}';
|
||||
<#else>
|
||||
var brandUrl = baseUrl;
|
||||
</#if>
|
||||
|
||||
var features = {
|
||||
isRegistrationEmailAsUsername : ${realm.registrationEmailAsUsername?c},
|
||||
isEditUserNameAllowed : ${realm.editUsernameAllowed?c},
|
||||
isInternationalizationEnabled : ${realm.isInternationalizationEnabled()?c},
|
||||
isLinkedAccountsEnabled : ${realm.identityFederationEnabled?c},
|
||||
isMyResourcesEnabled : ${(realm.userManagedAccessAllowed && isAuthorizationEnabled)?c},
|
||||
deleteAccountAllowed : ${deleteAccountAllowed?c},
|
||||
updateEmailFeatureEnabled: ${updateEmailFeatureEnabled?c},
|
||||
updateEmailActionEnabled: ${updateEmailActionEnabled?c},
|
||||
isViewGroupsEnabled : ${isViewGroupsEnabled?c}
|
||||
}
|
||||
|
||||
var availableLocales = [];
|
||||
<#list supportedLocales as locale, label>
|
||||
availableLocales.push({locale : '${locale}', label : '${label}'});
|
||||
</#list>
|
||||
|
||||
<#if referrer??>
|
||||
var referrer = '${referrer}';
|
||||
var referrerName = '${referrerName}';
|
||||
var referrerUri = '${referrer_uri}'.replace('&', '&');
|
||||
</#if>
|
||||
|
||||
<#if msg??>
|
||||
var locale = '${locale}';
|
||||
<#outputformat "JavaScript">
|
||||
var l18nMsg = JSON.parse('${msgJSON?js_string}');
|
||||
</#outputformat>
|
||||
<#else>
|
||||
var locale = 'en';
|
||||
var l18Msg = {};
|
||||
</#if>
|
||||
</script>
|
||||
|
||||
<#if properties.favIcon?has_content>
|
||||
<link rel="icon" href="${resourceUrl}${properties.favIcon}" type="image/x-icon"/>
|
||||
<#else>
|
||||
<link rel="icon" href="${resourceUrl}/public/favicon.ico" type="image/x-icon"/>
|
||||
</#if>
|
||||
|
||||
<script src="${authUrl}js/keycloak.js"></script>
|
||||
|
||||
<#if properties.developmentMode?has_content && properties.developmentMode == "true">
|
||||
<!-- Don't use this in production: -->
|
||||
<script src="${resourceUrl}/node_modules/react/umd/react.development.js" crossorigin></script>
|
||||
<script src="${resourceUrl}/node_modules/react-dom/umd/react-dom.development.js" crossorigin></script>
|
||||
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
|
||||
</#if>
|
||||
|
||||
<#if properties.extensions?has_content>
|
||||
<#list properties.extensions?split(' ') as script>
|
||||
<#if properties.developmentMode?has_content && properties.developmentMode == "true">
|
||||
<script type="text/babel" src="${resourceUrl}/${script}"></script>
|
||||
<#else>
|
||||
<script type="text/javascript" src="${resourceUrl}/${script}"></script>
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<#if properties.scripts?has_content>
|
||||
<#list properties.scripts?split(' ') as script>
|
||||
<script type="text/javascript" src="${resourceUrl}/${script}"></script>
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<script>
|
||||
var content = <#include "resources/content.json"/>
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="${resourceCommonUrl}/node_modules/@patternfly/react-core/dist/styles/base.css"/>
|
||||
<link rel="stylesheet" href="${resourceCommonUrl}/node_modules/@patternfly/patternfly/patternfly-addons.css"/>
|
||||
<link rel="stylesheet" href="${resourceUrl}/public/app.css"/>
|
||||
<link rel="stylesheet" href="${resourceUrl}/public/layout.css"/>
|
||||
|
||||
<#if properties.styles?has_content>
|
||||
<#list properties.styles?split(' ') as style>
|
||||
<link href="${resourceUrl}/${style}" rel="stylesheet"/>
|
||||
</#list>
|
||||
</#if>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script>
|
||||
var keycloak = new Keycloak({
|
||||
authServerUrl: authUrl,
|
||||
realm: realm,
|
||||
clientId: 'account-console'
|
||||
});
|
||||
keycloak.init({onLoad: 'check-sso', pkceMethod: 'S256', promiseType: 'native'}).then((authenticated) => {
|
||||
isReactLoading = true;
|
||||
toggleReact();
|
||||
if (!keycloak.authenticated) {
|
||||
document.getElementById("landingSignInButton").style.display='inline';
|
||||
document.getElementById("landingSignInLink").style.display='inline';
|
||||
} else {
|
||||
document.getElementById("landingSignOutButton").style.display='inline';
|
||||
document.getElementById("landingSignOutLink").style.display='inline';
|
||||
document.getElementById("landingLoggedInUser").innerHTML = loggedInUserName('${msg("unknownUser")}', '${msg("fullName")}');
|
||||
}
|
||||
|
||||
loadjs("/Main.js");
|
||||
}).catch(() => {
|
||||
alert('failed to initialize keycloak');
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="main_react_container" style="display:none;height:100%"></div>
|
||||
|
||||
<div id="spinner_screen" style="display:block; height:100%">
|
||||
<div style="width: 320px; height: 328px; text-align: center; position: absolute; top:0; bottom: 0; left: 0; right: 0; margin: auto;">
|
||||
<#if properties.logo?has_content>
|
||||
<img src="${resourceUrl}${properties.logoOnLoading}" alt="Logo" class="brand">
|
||||
<#else>
|
||||
<img src="${resourceUrl}/public/logo.svg" alt="Logo" class="brand">
|
||||
</#if>
|
||||
<p>${msg("loadingMessage")}</p>
|
||||
<div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: rgb(255, 255, 255); display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
|
||||
<path d="M10 50A40 40 0 0 0 90 50A40 42 0 0 1 10 50" fill="#5DBCD2" stroke="none" transform="rotate(16.3145 50 51)">
|
||||
<animateTransform attributeName="transform" type="rotate" dur="1s" repeatCount="indefinite" keyTimes="0;1" values="0 50 51;360 50 51"></animateTransform>
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="welcomeScreen" style="display:none;height:100%">
|
||||
<div class="pf-c-page" id="page-layout-default-nav">
|
||||
<header role="banner" class="pf-c-page__header">
|
||||
<div class="pf-c-page__header-brand">
|
||||
<#if properties.logoUrl?has_content>
|
||||
<a id="landingLogo" class="pf-c-page__header-brand-link" href="${properties.logoUrl}">
|
||||
<#else>
|
||||
<a id="landingLogo" class="pf-c-page__header-brand-link" href="${baseUrl}">
|
||||
</#if>
|
||||
<#if properties.logo?has_content>
|
||||
<img class="pf-c-brand brand" src="${resourceUrl}${properties.logo}" alt="Logo">
|
||||
<#else>
|
||||
<img class="pf-c-brand brand" src="${resourceUrl}/public/logo.svg" alt="Logo">
|
||||
</#if>
|
||||
</a>
|
||||
</div>
|
||||
<div class="pf-c-page__header-tools">
|
||||
<#if referrer?has_content && referrer_uri?has_content>
|
||||
<div class="pf-c-page__header-tools-group pf-m-icons pf-u-display-none pf-u-display-flex-on-md">
|
||||
<a id="landingReferrerLink" href="${referrer_uri}" class="pf-c-button pf-m-link" tabindex="0">
|
||||
<span class="pf-c-button__icon pf-m-start">
|
||||
<i class="pf-icon pf-icon-arrow" aria-hidden="true"></i>
|
||||
</span>
|
||||
${msg("backTo",referrerName)}
|
||||
</a>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<div class="pf-c-page__header-tools-group pf-m-icons pf-u-display-none pf-u-display-flex-on-md pf-u-mr-md">
|
||||
<button id="landingSignInButton" tabindex="0" style="display:none" onclick="keycloak.login();" class="pf-c-button pf-m-primary" type="button">${msg("doSignIn")}</button>
|
||||
<button id="landingSignOutButton" tabindex="0" style="display:none" onclick="keycloak.logout();" class="pf-c-button pf-m-primary" type="button">${msg("doSignOut")}</button>
|
||||
</div>
|
||||
|
||||
<!-- Kebab for mobile -->
|
||||
<div class="pf-c-page__header-tools-group pf-u-display-none-on-md">
|
||||
<div id="landingMobileKebab" class="pf-c-dropdown pf-m-mobile" onclick="toggleMobileDropdown();"> <!-- pf-m-expanded -->
|
||||
<button aria-label="Actions" tabindex="0" id="landingMobileKebabButton" class="pf-c-dropdown__toggle pf-m-plain" type="button" aria-expanded="true" aria-haspopup="true">
|
||||
<svg fill="currentColor" height="1em" width="1em" viewBox="0 0 192 512" aria-hidden="true" role="img" style="vertical-align: -0.125em;"><path d="M96 184c39.8 0 72 32.2 72 72s-32.2 72-72 72-72-32.2-72-72 32.2-72 72-72zM24 80c0 39.8 32.2 72 72 72s72-32.2 72-72S135.8 8 96 8 24 40.2 24 80zm0 352c0 39.8 32.2 72 72 72s72-32.2 72-72-32.2-72-72-72-72 32.2-72 72z" transform=""></path></svg>
|
||||
</button>
|
||||
<ul id="landingMobileDropdown" aria-labelledby="landingMobileKebabButton" class="pf-c-dropdown__menu pf-m-align-right" role="menu" style="display:none">
|
||||
<#if referrer?has_content && referrer_uri?has_content>
|
||||
<li role="none">
|
||||
<a id="landingMobileReferrerLink" href="${referrer_uri}" role="menuitem" tabindex="0" aria-disabled="false" class="pf-c-dropdown__menu-item">${msg("backTo",referrerName)}</a>
|
||||
</li>
|
||||
</#if>
|
||||
|
||||
<li id="landingSignInLink" role="none" style="display:none">
|
||||
<a onclick="keycloak.login();" role="menuitem" tabindex="0" aria-disabled="false" class="pf-c-dropdown__menu-item">${msg("doLogIn")}</a>
|
||||
</li>
|
||||
<li id="landingSignOutLink" role="none" style="display:none">
|
||||
<a onclick="keycloak.logout();" role="menuitem" tabindex="0" aria-disabled="false" class="pf-c-dropdown__menu-item">${msg("doSignOut")}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span id="landingLoggedInUser"></span>
|
||||
|
||||
</div> <!-- end header tools -->
|
||||
</header>
|
||||
|
||||
<main role="main" class="pf-c-page__main">
|
||||
<section class="pf-c-page__main-section pf-m-limit-width pf-m-light pf-m-shadow-bottom">
|
||||
<div class="pf-c-page__main-body">
|
||||
<div class="pf-c-content" id="landingWelcomeMessage">
|
||||
<h1>${msg("accountManagementWelcomeMessage")}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section pf-m-limit-width pf-m-overflow-scroll">
|
||||
<div class="pf-c-page__main-body">
|
||||
<div class="pf-l-gallery pf-m-gutter">
|
||||
<#assign content=theme.apply("content.json")?eval>
|
||||
<#list content as item>
|
||||
<div class="pf-l-gallery__item" id="landing-${item.id}">
|
||||
<div class="pf-c-card pf-m-full-height">
|
||||
<div>
|
||||
<div class="pf-c-card__title pf-c-content">
|
||||
<h2 class="pf-u-display-flex pf-u-w-100 pf-u-flex-direction-column">
|
||||
<#if item.icon??>
|
||||
<i class="pf-icon ${item.icon}"></i>
|
||||
<#elseif item.iconSvg??>
|
||||
<img src="${item.iconSvg}" alt="icon"/>
|
||||
</#if>
|
||||
${msg(item.label)}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<#if item.descriptionLabel??>
|
||||
<p class="pf-u-mb-md">${msg(item.descriptionLabel)}</p>
|
||||
</#if>
|
||||
<#if item.content??>
|
||||
<#list item.content as sub>
|
||||
<div id="landing-${sub.id}">
|
||||
<a onclick="toggleReact(); window.location.hash='${sub.path}'">${msg(sub.label)}</a>
|
||||
</div>
|
||||
</#list>
|
||||
<#else>
|
||||
<a id="landing-${item.id}" onclick="toggleReact(); window.location.hash = '${item.path}'">${msg(item.label)}</a>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const removeHidden = (content) => {
|
||||
content.forEach(c => {
|
||||
if (c.hidden && eval(c.hidden)) {
|
||||
document.getElementById('landing-' + c.id).remove();
|
||||
}
|
||||
if (c.content) removeHidden(c.content);
|
||||
});
|
||||
}
|
||||
removeHidden(content);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,24 +0,0 @@
|
|||
accountManagementWelcomeMessage=Welcome to Keycloak Extended Account Console
|
||||
|
||||
personalBasicInfoHtmlTitle=Basic information
|
||||
accountExtraInfoHtmlTitleHome=Profile settings
|
||||
accountExtraSubMessageHome=Handle extra profile settings
|
||||
accountExtraInfoHtmlTitle=Profile settings
|
||||
accountExtraSubMessage=Handle profile: add/update your avatar, delete your account
|
||||
|
||||
avatarLabel=Avatar
|
||||
uploadLabel=Select image file
|
||||
dragdropInfo=Drag and drop an image file or upload one
|
||||
browseButton=Browse
|
||||
clearButton=Clear
|
||||
avatarInfo=A 100x100px size is suggested. Images exceding 250x250px will be resized to 250px width or height mantaining their ratio. The maximum file size permitted is 1MB.
|
||||
avatarUpdatedMessage=Avatar successfully updated
|
||||
error-noAvatarFound=No avatar found on server
|
||||
|
||||
deleteAccount=Delete Account
|
||||
deleteAccountInfoMessage=Deleting your account will disable your profile and remove your name and photo you''ve shared on D4Science gateway(s). Some information may still be visible to others, such as your name in the posts and private messages you sent.<br/>All files and folders you created of your workspace will be removed.
|
||||
deleteAccountDialogHeader=Confirm account delete
|
||||
deleteAccountWarningMessage=Clicking on the "Confirm" button is an undoable operation, your account will be removed and you'll be automatically logged out from all your sessions.
|
||||
deleteAccountConfirmMessage=<br/>Do you really want to remove your account? <strong>NOTE: This action is irreversible!</strong>
|
||||
doDeleteConfirm=Confirm
|
||||
accountDeletedMessage=Your account has been deleted
|
|
@ -1,24 +0,0 @@
|
|||
accountManagementWelcomeMessage=Benvenuto nella gestione estesa degli account di Keycloak
|
||||
|
||||
personalBasicInfoHtmlTitle=Informazioni base
|
||||
accountExtraInfoHtmlTitleHome=Impostazioni profilo
|
||||
accountExtraSubMessageHome=Gestisce ulteriori impostazioni associate al profilo
|
||||
accountExtraInfoHtmlTitle=Impostazioni del profilo
|
||||
accountExtraSubMessage=Gestisce il profilo: aggiunta/modifica dell''avatar, cancellazione dell''account
|
||||
|
||||
avatarLabel=Avatar
|
||||
uploadLabel=Seleziona un''immagine
|
||||
dragdropInfo=Trascina qui un file immagine o selezionalo
|
||||
browseButton=Seleziona
|
||||
clearButton=Cancella
|
||||
avatarInfo=Si consiglia una dimensione di 100x100px. Le immagini che eccedono 250x250px saranno ridimensionate a 250px di larghezza o altezza mantenendo il loro rapporto. La massima dimensione consentita del file \u00e8 di 1MB.
|
||||
avatarUpdatedMessage=Avatar aggiornato con successo
|
||||
error-noAvatarFound=Avatar non trovato sul server
|
||||
|
||||
deleteAccount=Delete Account
|
||||
deleteAccountInfoMessage=La cancellazione del proprio account disabiliter\u00e0 il profilo e rimuover\u00e0 il nome e le foto condivise sul/sui gateway D4Science. Alcune informazioni potrebbero risultare ancora visibili agli altri utenti, come il nome nei post e nei messaggi privati inviati.<br/>Tutti i file e le cartelle create nel workspace personale saranno rimosse.
|
||||
deleteAccountDialogHeader=Conferma cancellazione account
|
||||
deleteAccountWarningMessage=Cliccando sul bottone "Conferma" si avvier\u00e0 un''operazione non annullabile, l''account personale sar\u00e0 rimosso e saranno terminate tutte le sessioni aperte nei vari siti.
|
||||
deleteAccountConfirmMessage=<br/>Si vuole veramente cancellare il proprio account? <strong>NOTA BENE: Questa azione \u00e8 irreversibile!</strong>
|
||||
doDeleteConfirm=Conferma
|
||||
accountDeletedMessage=L''account \u00e8 stato cancellato
|
|
@ -1,84 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": "personal-info",
|
||||
"path": "personal-info",
|
||||
"icon": "pf-icon-user",
|
||||
"label": "personalInfoSidebarTitle",
|
||||
"descriptionLabel": "personalInfoIntroMessage",
|
||||
"content" : [
|
||||
{
|
||||
"id": "personal-info-base",
|
||||
"path": "personal-info-base",
|
||||
"label": "personalBasicInfoHtmlTitle",
|
||||
"modulePath": "/content/account-page/AccountPage.js",
|
||||
"componentName": "AccountPage"
|
||||
},
|
||||
{
|
||||
"id": "account-extra",
|
||||
"path": "account-extra",
|
||||
"label": "accountExtraInfoHtmlTitleHome",
|
||||
"modulePath": "/content/d4science-page/AccountExtraPage.js",
|
||||
"componentName": "AccountExtraPage"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "security",
|
||||
"icon": "pf-icon-security",
|
||||
"label": "accountSecuritySidebarTitle",
|
||||
"descriptionLabel": "accountSecurityIntroMessage",
|
||||
"content": [
|
||||
{
|
||||
"id": "signingin",
|
||||
"path": "security/signingin",
|
||||
"label": "signingInSidebarTitle",
|
||||
"modulePath": "/content/signingin-page/SigningInPage.js",
|
||||
"componentName": "SigningInPage"
|
||||
},
|
||||
{
|
||||
"id": "device-activity",
|
||||
"path": "security/device-activity",
|
||||
"label": "deviceActivitySidebarTitle",
|
||||
"modulePath": "/content/device-activity-page/DeviceActivityPage.js",
|
||||
"componentName": "DeviceActivityPage"
|
||||
},
|
||||
{
|
||||
"id": "linked-accounts",
|
||||
"path": "security/linked-accounts",
|
||||
"label": "linkedAccountsSidebarTitle",
|
||||
"modulePath": "/content/linked-accounts-page/LinkedAccountsPage.js",
|
||||
"componentName": "LinkedAccountsPage",
|
||||
"hidden": "!features.isLinkedAccountsEnabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "applications",
|
||||
"icon": "pf-icon-applications",
|
||||
"path": "applications",
|
||||
"label": "applications",
|
||||
"descriptionLabel": "applicationsIntroMessage",
|
||||
"modulePath": "/content/applications-page/ApplicationsPage.js",
|
||||
"componentName": "ApplicationsPage"
|
||||
},
|
||||
{
|
||||
"id": "groups",
|
||||
"path": "groups",
|
||||
"icon": "pf-icon-server-group",
|
||||
"label": "groupLabel",
|
||||
"descriptionLabel": "groupDescriptionLabel",
|
||||
"modulePath": "/content/group-page/GroupsPage.js",
|
||||
"componentName": "GroupsPage",
|
||||
"hidden": "!features.isViewGroupsEnabled"
|
||||
},
|
||||
{
|
||||
"id": "resources",
|
||||
"icon": "pf-icon-repository",
|
||||
"path": "resources",
|
||||
"label": "resources",
|
||||
"descriptionLabel": "resourceIntroMessage",
|
||||
"modulePath": "/content/my-resources-page/MyResourcesPage.js",
|
||||
"componentName": "MyResourcesPage",
|
||||
"hidden": "!features.isMyResourcesEnabled"
|
||||
}
|
||||
]
|
|
@ -1,110 +0,0 @@
|
|||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
|
||||
import * as React from "../../../resources/web_modules/react.js";
|
||||
import { PageSection, PageSectionVariants, Button, Grid, GridItem, ExpandableSection, Modal } from "../../../resources/web_modules/@patternfly/react-core.js";
|
||||
import { AccountServiceContext } from "../../account-service/AccountServiceContext.js";
|
||||
import { Msg } from "../../widgets/Msg.js";
|
||||
import { ContentPage } from "../ContentPage.js";
|
||||
import { ContentAlert } from "../ContentAlert.js";
|
||||
import { AvatarForm } from "./AvatarForm.js";
|
||||
export class AccountExtraPage extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props);
|
||||
|
||||
_defineProperty(this, "context", void 0);
|
||||
|
||||
_defineProperty(this, "DEFAULT_STATE", {
|
||||
isModalOpen: false
|
||||
});
|
||||
|
||||
_defineProperty(this, "state", this.DEFAULT_STATE);
|
||||
|
||||
_defineProperty(this, "handleModalToggle", open => {
|
||||
this.setState({
|
||||
isModalOpen: open
|
||||
});
|
||||
});
|
||||
|
||||
_defineProperty(this, "modalConfirmDelete", event => {
|
||||
const accountUrl = this.context["accountUrl"];
|
||||
const deleteUrl = accountUrl + "-delete/request-delete";
|
||||
this.context.doPost(deleteUrl, {}).then(() => {
|
||||
ContentAlert.success('accountDeletedMessage');
|
||||
window.location.reload();
|
||||
});
|
||||
this.setState({
|
||||
isModalOpen: false
|
||||
});
|
||||
});
|
||||
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
render() {
|
||||
const accountUrl = this.context["accountUrl"];
|
||||
return /*#__PURE__*/React.createElement(ContentPage, {
|
||||
title: "accountExtraInfoHtmlTitle",
|
||||
introMessage: "accountExtraSubMessage"
|
||||
}, /*#__PURE__*/React.createElement(PageSection, {
|
||||
isFilled: true,
|
||||
variant: PageSectionVariants.light
|
||||
}, /*#__PURE__*/React.createElement(AvatarForm, {
|
||||
accountUrl: accountUrl
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
id: "delete-account",
|
||||
style: {
|
||||
marginTop: "30px"
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(ExpandableSection, {
|
||||
toggleText: Msg.localize('deleteAccount'),
|
||||
displaySize: "large"
|
||||
}, /*#__PURE__*/React.createElement(Grid, {
|
||||
hasGutter: true
|
||||
}, /*#__PURE__*/React.createElement(GridItem, {
|
||||
span: 8
|
||||
}, /*#__PURE__*/React.createElement("p", {
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: Msg.localize('deleteAccountInfoMessage')
|
||||
}
|
||||
})), /*#__PURE__*/React.createElement(GridItem, {
|
||||
span: 4
|
||||
}, /*#__PURE__*/React.createElement(Button, {
|
||||
id: "delete-account-btn",
|
||||
variant: "danger",
|
||||
onClick: e => this.handleModalToggle(true),
|
||||
className: "delete-button"
|
||||
}, /*#__PURE__*/React.createElement(Msg, {
|
||||
msgKey: "doDelete"
|
||||
}))))), /*#__PURE__*/React.createElement(Modal, {
|
||||
width: '50%',
|
||||
title: Msg.localize('deleteAccountDialogHeader'),
|
||||
isOpen: this.state.isModalOpen,
|
||||
onClose: () => this.handleModalToggle(false),
|
||||
actions: [/*#__PURE__*/React.createElement(Button, {
|
||||
key: "confirm",
|
||||
variant: "danger",
|
||||
onClick: this.modalConfirmDelete
|
||||
}, /*#__PURE__*/React.createElement(Msg, {
|
||||
msgKey: "doDeleteConfirm"
|
||||
})), /*#__PURE__*/React.createElement(Button, {
|
||||
key: "cancel",
|
||||
variant: "secondary",
|
||||
onClick: e => this.handleModalToggle(false)
|
||||
}, /*#__PURE__*/React.createElement(Msg, {
|
||||
msgKey: "doCancel"
|
||||
}))]
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: Msg.localize('deleteAccountWarningMessage')
|
||||
}
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: Msg.localize('deleteAccountConfirmMessage')
|
||||
}
|
||||
})))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_defineProperty(AccountExtraPage, "contextType", AccountServiceContext);
|
||||
//# sourceMappingURL=AccountExtraPage.js.map
|
File diff suppressed because one or more lines are too long
|
@ -1,193 +0,0 @@
|
|||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
|
||||
import * as React from "../../../resources/web_modules/react.js";
|
||||
import { Form, FormGroup, ActionGroup, FileUpload, Avatar, Button, Tooltip } from "../../../resources/web_modules/@patternfly/react-core.js";
|
||||
import { OutlinedQuestionCircleIcon } from "../../../resources/web_modules/@patternfly/react-icons.js";
|
||||
import { AccountServiceContext } from "../../account-service/AccountServiceContext.js";
|
||||
import { ContentAlert } from "../ContentAlert.js";
|
||||
import { Msg } from "../../widgets/Msg.js";
|
||||
export class AvatarForm extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props);
|
||||
|
||||
_defineProperty(this, "context", void 0);
|
||||
|
||||
_defineProperty(this, "handleFileInputChange", void 0);
|
||||
|
||||
_defineProperty(this, "imageScale", (imgData, callback) => {
|
||||
var img = new Image();
|
||||
img.src = imgData;
|
||||
|
||||
img.onload = event => {
|
||||
var canvas = document.createElement("canvas");
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0);
|
||||
var MAX_WIDTH = 250;
|
||||
var MAX_HEIGHT = 250;
|
||||
var width = img.width;
|
||||
var height = img.height;
|
||||
|
||||
if (width > height) {
|
||||
if (width > MAX_WIDTH) {
|
||||
height *= MAX_WIDTH / width;
|
||||
width = MAX_WIDTH;
|
||||
}
|
||||
} else {
|
||||
if (height > MAX_HEIGHT) {
|
||||
width *= MAX_HEIGHT / height;
|
||||
height = MAX_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
canvas.toBlob(callback);
|
||||
};
|
||||
});
|
||||
|
||||
_defineProperty(this, "handleSubmit", event => {
|
||||
event.preventDefault();
|
||||
const form = event.target;
|
||||
var formData = new FormData(form);
|
||||
formData.append("image", this.state.imageBlob);
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState == 4) {
|
||||
if (200 <= xhr.status && xhr.status <= 204) {
|
||||
ContentAlert.success('avatarUpdatedMessage');
|
||||
} else {
|
||||
ContentAlert.danger(xhr.response);
|
||||
} // force reload avatar
|
||||
|
||||
|
||||
this.setState({
|
||||
errors: {
|
||||
avatar: ""
|
||||
},
|
||||
imageBlob: null,
|
||||
filename: "",
|
||||
avatarSrc: this.state.avatarUrl
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open(form.method, form.action, true);
|
||||
xhr.send(formData);
|
||||
});
|
||||
|
||||
_defineProperty(this, "handleError", event => {
|
||||
this.setState({
|
||||
errors: {
|
||||
avatar: Msg.localize('error-noAvatarFound')
|
||||
},
|
||||
avatarSrc: ""
|
||||
});
|
||||
});
|
||||
|
||||
this.context = context;
|
||||
var currentAvatar = props.accountUrl + "-avatar";
|
||||
this.state = {
|
||||
errors: {
|
||||
avatar: ''
|
||||
},
|
||||
imageBlob: null,
|
||||
filename: "",
|
||||
avatarUrl: currentAvatar,
|
||||
avatarSrc: currentAvatar,
|
||||
noAvatarSrc: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjAuMiwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzNiAzNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzYgMzY7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDojRjBGMEYwO30KCS5zdDF7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDojRDJEMkQyO30KCS5zdDJ7ZmlsbDojQjhCQkJFO30KCS5zdDN7ZmlsbDojRDJEMkQyO30KPC9zdHlsZT4KPHJlY3QgY2xhc3M9InN0MCIgd2lkdGg9IjM2IiBoZWlnaHQ9IjM2Ii8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0xNy43LDIwLjFjLTMuNSwwLTYuNC0yLjktNi40LTYuNHMyLjktNi40LDYuNC02LjRzNi40LDIuOSw2LjQsNi40UzIxLjMsMjAuMSwxNy43LDIwLjF6Ii8+CjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMy4zLDM2bDAtNi43Yy0yLDAuNC0yLjksMS40LTMuMSwzLjVMMTAuMSwzNkgxMy4zeiIvPgo8cGF0aCBjbGFzcz0ic3QzIiBkPSJNMTAuMSwzNmwwLjEtMy4yYzAuMi0yLjEsMS4xLTMuMSwzLjEtMy41bDAsNi43aDkuNGwwLTYuN2MyLDAuNCwyLjksMS40LDMuMSwzLjVsMC4xLDMuMmg0LjcKCWMtMC40LTMuOS0xLjMtOS0yLjktMTFjLTEuMS0xLjQtMi4zLTIuMi0zLjUtMi42cy0xLjgtMC42LTYuMy0wLjZzLTYuMSwwLjctNi4xLDAuN2MtMS4yLDAuNC0yLjQsMS4yLTMuNCwyLjYKCUM2LjcsMjcsNS44LDMyLjIsNS40LDM2SDEwLjF6Ii8+CjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0yNS45LDM2bC0wLjEtMy4yYy0wLjItMi4xLTEuMS0zLjEtMy4xLTMuNWwwLDYuN0gyNS45eiIvPgo8L3N2Zz4="
|
||||
};
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onloadend = event => {
|
||||
var imgData = String(event.target.result);
|
||||
this.imageScale(imgData, blob => {
|
||||
this.setState({
|
||||
imageBlob: blob,
|
||||
avatarSrc: URL.createObjectURL(blob)
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.handleFileInputChange = (file, filename) => {
|
||||
if (filename != "") {
|
||||
this.setState({
|
||||
filename: filename
|
||||
});
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
this.setState({
|
||||
imageBlob: null,
|
||||
filename: "",
|
||||
avatarSrc: currentAvatar
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
filename,
|
||||
avatarUrl,
|
||||
avatarSrc,
|
||||
noAvatarSrc
|
||||
} = this.state;
|
||||
const avatarStyle = {
|
||||
objectFit: 'cover',
|
||||
width: '150px',
|
||||
height: '150px',
|
||||
border: '1px solid lightgray',
|
||||
boxShadow: 'lightgray 6px 3px 10px 2px'
|
||||
};
|
||||
return /*#__PURE__*/React.createElement(Form, {
|
||||
id: "avatarForm",
|
||||
method: "post",
|
||||
action: avatarUrl,
|
||||
encType: "multipart/form-data",
|
||||
onSubmit: event => this.handleSubmit(event)
|
||||
}, /*#__PURE__*/React.createElement(FormGroup, {
|
||||
label: Msg.localize('avatarLabel'),
|
||||
fieldId: "avatar-current-or-preview",
|
||||
helperTextInvalid: this.state.errors.avatar,
|
||||
validated: this.state.errors.avatar === '' ? 'success' : 'error'
|
||||
}, avatarSrc !== "" ? /*#__PURE__*/React.createElement(Avatar, {
|
||||
src: avatarSrc,
|
||||
style: avatarStyle,
|
||||
alt: "Avatar image preview",
|
||||
onError: this.handleError
|
||||
}) : /*#__PURE__*/React.createElement(Avatar, {
|
||||
src: noAvatarSrc,
|
||||
style: avatarStyle,
|
||||
alt: "No avatar found"
|
||||
})), /*#__PURE__*/React.createElement(FormGroup, {
|
||||
fieldId: "avatar-upload",
|
||||
label: /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Msg, {
|
||||
msgKey: "uploadLabel"
|
||||
}), ' ', /*#__PURE__*/React.createElement(Tooltip, {
|
||||
content: /*#__PURE__*/React.createElement(Msg, {
|
||||
msgKey: "avatarInfo"
|
||||
})
|
||||
}, /*#__PURE__*/React.createElement(OutlinedQuestionCircleIcon, null)))
|
||||
}, /*#__PURE__*/React.createElement(FileUpload, {
|
||||
id: "simple-file",
|
||||
filename: filename,
|
||||
filenamePlaceholder: Msg.localize('dragdropInfo'),
|
||||
browseButtonText: Msg.localize('browseButton'),
|
||||
clearButtonText: Msg.localize('clearButton'),
|
||||
onChange: this.handleFileInputChange
|
||||
})), /*#__PURE__*/React.createElement(ActionGroup, null, /*#__PURE__*/React.createElement(Button, {
|
||||
id: "save-btn",
|
||||
type: "submit",
|
||||
variant: "primary",
|
||||
isDisabled: filename === ""
|
||||
}, /*#__PURE__*/React.createElement(Msg, {
|
||||
msgKey: "doSave"
|
||||
}))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_defineProperty(AvatarForm, "contextType", AccountServiceContext);
|
||||
//# sourceMappingURL=AvatarForm.js.map
|
File diff suppressed because one or more lines are too long
|
@ -1,23 +0,0 @@
|
|||
body {
|
||||
/* --pf-global--FontFamily--sans-serif: Comic Sans MS; */
|
||||
/* --pf-global--FontFamily--heading--sans-serif: Comic Sans MS; */
|
||||
|
||||
--pf-global--BackgroundColor--dark-100: #303030;
|
||||
|
||||
--pf-global--Color--100: #151515;
|
||||
|
||||
}
|
||||
|
||||
.pf-c-nav__list .pf-c-nav__link {
|
||||
--pf-c-nav__list-link--Color: #303030;
|
||||
--pf-c-nav__list-link--m-current--Color: #151515;
|
||||
}
|
||||
|
||||
.pf-c-nav__simple-list .pf-c-nav__link {
|
||||
--pf-c-nav__simple-list-link--Color: #303030;
|
||||
--pf-c-nav__simple-list-link--m-current--Color: #151515;
|
||||
}
|
||||
|
||||
.brand {
|
||||
height: 50px !important;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 28 KiB |
Binary file not shown.
Before Width: | Height: | Size: 28 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
|
@ -1,90 +0,0 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { PageSection, PageSectionVariants,Button, Grid, GridItem, ExpandableSection, Modal } from '@patternfly/react-core';
|
||||
import { AccountServiceContext } from '../../account-service/AccountServiceContext';
|
||||
import { Msg } from '../../widgets/Msg';
|
||||
import { ContentPage } from '../ContentPage';
|
||||
import { ContentAlert } from '../ContentAlert';
|
||||
import { AvatarForm } from './AvatarForm';
|
||||
|
||||
interface AccountExtraPageProps {
|
||||
}
|
||||
|
||||
interface AccountExtraPageState {
|
||||
isModalOpen: boolean;
|
||||
}
|
||||
|
||||
export class AccountExtraPage extends React.Component<AccountExtraPageProps, AccountExtraPageState> {
|
||||
static contextType = AccountServiceContext;
|
||||
context: React.ContextType<typeof AccountServiceContext>;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { isModalOpen: false }
|
||||
}
|
||||
|
||||
private handleModalToggle = (open: boolean) => {
|
||||
this.setState({ isModalOpen: open })
|
||||
}
|
||||
|
||||
private modalConfirmDelete = (event: any) => {
|
||||
const accountUrl = this.context!["accountUrl"]
|
||||
const deleteUrl = accountUrl + "-delete/request-delete"
|
||||
this.context!.doPost<void>(deleteUrl, {})
|
||||
.then(() => {
|
||||
ContentAlert.success('accountDeletedMessage')
|
||||
window.location.reload();
|
||||
})
|
||||
this.setState({ isModalOpen: false })
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const accountUrl = this.context!["accountUrl"]
|
||||
|
||||
return (
|
||||
<ContentPage title="accountExtraInfoHtmlTitle"
|
||||
introMessage="accountExtraSubMessage"
|
||||
>
|
||||
<PageSection isFilled variant={PageSectionVariants.light}>
|
||||
<AvatarForm accountUrl={accountUrl} />
|
||||
|
||||
<div id="delete-account" style={{marginTop:"30px"}}>
|
||||
<ExpandableSection toggleText={Msg.localize('deleteAccount')} displaySize="large">
|
||||
<Grid hasGutter>
|
||||
<GridItem span={8}>
|
||||
<p dangerouslySetInnerHTML={{ __html: Msg.localize('deleteAccountInfoMessage')}} />
|
||||
</GridItem>
|
||||
<GridItem span={4}>
|
||||
<Button id="delete-account-btn" variant="danger"
|
||||
onClick={(e) => this.handleModalToggle(true)} className="delete-button"
|
||||
>
|
||||
<Msg msgKey="doDelete" />
|
||||
</Button>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
</ExpandableSection>
|
||||
|
||||
<Modal
|
||||
width={'50%'}
|
||||
title={Msg.localize('deleteAccountDialogHeader')}
|
||||
isOpen={this.state.isModalOpen}
|
||||
onClose={() => this.handleModalToggle(false)}
|
||||
actions={[
|
||||
<Button key="confirm" variant="danger" onClick={this.modalConfirmDelete}>
|
||||
<Msg msgKey="doDeleteConfirm" />
|
||||
</Button>,
|
||||
<Button key="cancel" variant="secondary" onClick={(e) => this.handleModalToggle(false)}>
|
||||
<Msg msgKey="doCancel" />
|
||||
</Button>
|
||||
]}
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: Msg.localize('deleteAccountWarningMessage')}} />
|
||||
<div dangerouslySetInnerHTML={{ __html: Msg.localize('deleteAccountConfirmMessage')}} />
|
||||
</Modal>
|
||||
</div>
|
||||
</PageSection>
|
||||
|
||||
</ContentPage>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,190 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import * as CSS from 'csstype';
|
||||
|
||||
import { Form, FormGroup, ActionGroup, FileUpload, Avatar, Button, Tooltip } from "@patternfly/react-core";
|
||||
import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons';
|
||||
import { AccountServiceContext } from '../../account-service/AccountServiceContext';
|
||||
import { ContentAlert } from '../ContentAlert';
|
||||
import { Msg } from '../../widgets/Msg';
|
||||
|
||||
|
||||
interface AvatarFormProps {
|
||||
accountUrl: string;
|
||||
}
|
||||
|
||||
interface AvatarFormState {
|
||||
errors: any;
|
||||
imageBlob: any;
|
||||
filename: string;
|
||||
avatarUrl: string;
|
||||
avatarSrc: string;
|
||||
noAvatarSrc: string;
|
||||
}
|
||||
|
||||
export class AvatarForm extends React.Component<AvatarFormProps, AvatarFormState> {
|
||||
static contextType = AccountServiceContext;
|
||||
context: React.ContextType<typeof AccountServiceContext>;
|
||||
private handleFileInputChange: any;
|
||||
|
||||
constructor(props: AvatarFormProps, context: React.ContextType<typeof AccountServiceContext>) {
|
||||
super(props);
|
||||
this.context = context;
|
||||
|
||||
var currentAvatar = props.accountUrl + "-avatar"
|
||||
this.state = {
|
||||
errors: {avatar: ''},
|
||||
imageBlob: null,
|
||||
filename: "",
|
||||
avatarUrl: currentAvatar,
|
||||
avatarSrc: currentAvatar,
|
||||
noAvatarSrc: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjAuMiwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzNiAzNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzYgMzY7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDojRjBGMEYwO30KCS5zdDF7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDojRDJEMkQyO30KCS5zdDJ7ZmlsbDojQjhCQkJFO30KCS5zdDN7ZmlsbDojRDJEMkQyO30KPC9zdHlsZT4KPHJlY3QgY2xhc3M9InN0MCIgd2lkdGg9IjM2IiBoZWlnaHQ9IjM2Ii8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0xNy43LDIwLjFjLTMuNSwwLTYuNC0yLjktNi40LTYuNHMyLjktNi40LDYuNC02LjRzNi40LDIuOSw2LjQsNi40UzIxLjMsMjAuMSwxNy43LDIwLjF6Ii8+CjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMy4zLDM2bDAtNi43Yy0yLDAuNC0yLjksMS40LTMuMSwzLjVMMTAuMSwzNkgxMy4zeiIvPgo8cGF0aCBjbGFzcz0ic3QzIiBkPSJNMTAuMSwzNmwwLjEtMy4yYzAuMi0yLjEsMS4xLTMuMSwzLjEtMy41bDAsNi43aDkuNGwwLTYuN2MyLDAuNCwyLjksMS40LDMuMSwzLjVsMC4xLDMuMmg0LjcKCWMtMC40LTMuOS0xLjMtOS0yLjktMTFjLTEuMS0xLjQtMi4zLTIuMi0zLjUtMi42cy0xLjgtMC42LTYuMy0wLjZzLTYuMSwwLjctNi4xLDAuN2MtMS4yLDAuNC0yLjQsMS4yLTMuNCwyLjYKCUM2LjcsMjcsNS44LDMyLjIsNS40LDM2SDEwLjF6Ii8+CjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0yNS45LDM2bC0wLjEtMy4yYy0wLjItMi4xLTEuMS0zLjEtMy4xLTMuNWwwLDYuN0gyNS45eiIvPgo8L3N2Zz4="
|
||||
}
|
||||
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function (event: any) {
|
||||
var imgData = String(event.target!.result)
|
||||
this.imageScale(imgData, (blob: Blob) => {
|
||||
this.setState({
|
||||
imageBlob: blob,
|
||||
avatarSrc: URL.createObjectURL(blob)
|
||||
})
|
||||
})
|
||||
}.bind(this)
|
||||
|
||||
this.handleFileInputChange = (file: File, filename: string) => {
|
||||
if (filename != "") {
|
||||
this.setState({ filename: filename })
|
||||
reader.readAsDataURL(file)
|
||||
} else {
|
||||
this.setState({
|
||||
imageBlob: null,
|
||||
filename: "",
|
||||
avatarSrc: currentAvatar
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private imageScale = (imgData: string, callback: any) => {
|
||||
var img = new Image()
|
||||
img.src = imgData
|
||||
img.onload = (event: Event) => {
|
||||
var canvas = document.createElement("canvas")
|
||||
var ctx = canvas.getContext("2d")
|
||||
ctx!.drawImage(img, 0, 0)
|
||||
|
||||
var MAX_WIDTH = 250
|
||||
var MAX_HEIGHT = 250
|
||||
var width = img.width
|
||||
var height = img.height
|
||||
|
||||
if (width > height) {
|
||||
if (width > MAX_WIDTH) {
|
||||
height *= MAX_WIDTH / width
|
||||
width = MAX_WIDTH
|
||||
}
|
||||
} else {
|
||||
if (height > MAX_HEIGHT) {
|
||||
width *= MAX_HEIGHT / height
|
||||
height = MAX_HEIGHT
|
||||
}
|
||||
}
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
ctx = canvas.getContext("2d")
|
||||
ctx!.drawImage(img, 0, 0, width, height)
|
||||
canvas.toBlob(callback)
|
||||
}
|
||||
}
|
||||
|
||||
private handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||
event.preventDefault()
|
||||
const form = event.target as HTMLFormElement
|
||||
var formData = new FormData(form)
|
||||
formData.append("image", this.state.imageBlob)
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState == 4) {
|
||||
if (200 <= xhr.status && xhr.status <= 204) {
|
||||
ContentAlert.success('avatarUpdatedMessage')
|
||||
} else {
|
||||
ContentAlert.danger(xhr.response)
|
||||
}
|
||||
// force reload avatar
|
||||
this.setState({
|
||||
errors: {avatar: ""},
|
||||
imageBlob: null,
|
||||
filename: "",
|
||||
avatarSrc: this.state.avatarUrl
|
||||
})
|
||||
}
|
||||
}
|
||||
xhr.open(form.method, form.action, true);
|
||||
xhr.send(formData);
|
||||
}
|
||||
|
||||
private handleError = (event: any) => {
|
||||
this.setState({
|
||||
errors: {avatar: Msg.localize('error-noAvatarFound')},
|
||||
avatarSrc: ""
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { filename, avatarUrl, avatarSrc, noAvatarSrc } = this.state
|
||||
const avatarStyle: CSS.Properties = {
|
||||
objectFit: 'cover',
|
||||
width: '150px', height: '150px',
|
||||
border: '1px solid lightgray',
|
||||
boxShadow: 'lightgray 6px 3px 10px 2px'
|
||||
}
|
||||
return (
|
||||
<Form id="avatarForm" method="post"
|
||||
action={avatarUrl} encType="multipart/form-data"
|
||||
onSubmit={event => this.handleSubmit(event)}
|
||||
>
|
||||
<FormGroup label={Msg.localize('avatarLabel')}
|
||||
fieldId="avatar-current-or-preview"
|
||||
helperTextInvalid={this.state.errors.avatar}
|
||||
validated={this.state.errors.avatar === '' ? 'success' : 'error'}
|
||||
>
|
||||
{ avatarSrc !== ""
|
||||
? <Avatar src={avatarSrc} style={avatarStyle} alt="Avatar image preview" onError={this.handleError}/>
|
||||
: <Avatar src={noAvatarSrc} style={avatarStyle} alt="No avatar found" />
|
||||
}
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
fieldId="avatar-upload"
|
||||
label={<span>
|
||||
<Msg msgKey="uploadLabel" />
|
||||
{' '}
|
||||
<Tooltip content={<Msg msgKey="avatarInfo" />}>
|
||||
<OutlinedQuestionCircleIcon />
|
||||
</Tooltip>
|
||||
</span>}
|
||||
>
|
||||
<FileUpload
|
||||
id="simple-file"
|
||||
filename={filename}
|
||||
filenamePlaceholder={Msg.localize('dragdropInfo')}
|
||||
browseButtonText={Msg.localize('browseButton')}
|
||||
clearButtonText={Msg.localize('clearButton')}
|
||||
onChange={this.handleFileInputChange}
|
||||
/>
|
||||
|
||||
</FormGroup>
|
||||
|
||||
<ActionGroup>
|
||||
<Button
|
||||
id="save-btn" type="submit"
|
||||
variant="primary"
|
||||
isDisabled={filename === ""}
|
||||
>
|
||||
<Msg msgKey="doSave" />
|
||||
</Button>
|
||||
</ActionGroup>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
parent=keycloak.v2
|
||||
|
||||
# This is the logo in upper lefthand corner.
|
||||
# It must be a relative path.
|
||||
logo=/public/d4science-logo.png
|
||||
logoOnLoading=/public/d4science-logo-black.png
|
||||
|
||||
# This is the link followed when clicking on the logo.
|
||||
# It can be any valid URL, including an external site.
|
||||
logoUrl=https://www.d4science.org/
|
||||
|
||||
# This is the icon for the account console.
|
||||
# It must be a relative path.
|
||||
favIcon=/public/favicon.ico
|
Loading…
Reference in New Issue