Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
joseivanlopez committed Oct 31, 2023
1 parent 8d96228 commit 36b6d80
Show file tree
Hide file tree
Showing 10 changed files with 549 additions and 22 deletions.
8 changes: 6 additions & 2 deletions web/src/client/software.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,11 @@ class BaseProductManager {
const email = proxy.Email;
const requirement = this.registrationRequirement(proxy.Requirement);

return (code.length === 0 ? null : { code, email, requirement });
const registration = { code, email, requirement };
if (code.length === 0) registration.code = null;
if (email.length === 0) registration.email = null;

return registration;
}

/**
Expand All @@ -138,7 +142,7 @@ class BaseProductManager {
*/
async register(code, email = "") {
const proxy = await this.client.proxy(REGISTRATION_IFACE, PRODUCT_PATH);
const result = await proxy.Register(code, { email });
const result = await proxy.Register(code, { Email: { t: "s", v: email } });

return {
success: result[0] === 0,
Expand Down
88 changes: 88 additions & 0 deletions web/src/components/core/EmailInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) [2023] SUSE LLC
*
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, contact SUSE LLC.
*
* To contact SUSE LLC about this file by physical or electronic mail, you may
* find current contact information at www.suse.com.
*/

import React, { useEffect, useState } from "react";
import { InputGroup, TextInput } from "@patternfly/react-core";
import { noop } from "~/utils";

/**
* Email validation.
*
* Code inspired by https://github.com/manishsaraan/email-validator/blob/master/index.js
*
* @param {string} email
* @returns {boolean}
*/
const validateEmail = (email) => {
const regexp = /^[-!#$%&'*+/0-9=?A-Z^_a-z`{|}~](\.?[-!#$%&'*+/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;

const validateFormat = (email) => {
const parts = email.split('@');

return parts.length === 2 && regexp.test(email);
};

const validateSizes = (email) => {
const [account, address] = email.split('@');

if (account.length > 64) return false;
if (address.length > 255) return false;

const domainParts = address.split('.');

if (domainParts.find(p => p.length > 63)) return false;

return true;
};

return validateFormat(email) && validateSizes(email);
};

/**
* Renders an email input field which validates its value.
* @component
*
* @param {string} id - The identifier for the field.
* @param {(boolean) => void} onValidate - Callback to be called everytime the input value is
* validated.
* @param {Object} props - Props matching the {@link https://www.patternfly.org/components/forms/text-input PF/TextInput},
* except `type` and `validated` that will be ignored.
*/
export default function EmailInput({ id, onValidate = noop, ...props }) {
const [isValid, setIsValid] = useState(true);

useEffect(() => {
const isValid = props.value.length === 0 || validateEmail(props.value);
setIsValid(isValid);
onValidate(isValid);
}, [onValidate, props.value, setIsValid]);

return (
<InputGroup>
<TextInput
{...props}
id={id}
type='email'
validated={isValid ? 'default' : 'error'}
/>
</InputGroup>
);
}
1 change: 1 addition & 0 deletions web/src/components/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export { default as FormLabel } from "./FormLabel";
export { default as FormValidationError } from "./FormValidationError";
export { default as Fieldset } from "./Fieldset";
export { default as Em } from "./Em";
export { default as EmailInput } from "./EmailInput";
export { default as If } from "./If";
export { default as Installation } from "./Installation";
export { default as InstallationFinished } from "./InstallationFinished";
Expand Down
22 changes: 13 additions & 9 deletions web/src/components/overview/ProductSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@

import React, { useEffect, useState } from "react";
import { Text } from "@patternfly/react-core";
import { useCancellablePromise } from "~/utils";
import { toValidationError, useCancellablePromise } from "~/utils";
import { useInstallerClient } from "~/context/installer";
import { useProduct } from "~/context/product";
import { Section, SectionSkeleton } from "~/components/core";
import { If, Section, SectionSkeleton } from "~/components/core";
import { _ } from "~/i18n";

const errorsFrom = (issues) => {
const errors = issues.filter(i => i.severity === "error");
return errors.map(e => ({ message: e.description }));
return errors.map(toValidationError);
};

export default function ProductSection() {
Expand All @@ -44,12 +44,16 @@ export default function ProductSection() {
}, [cancellablePromise, setIssues, software]);

const Content = ({ isLoading = false }) => {
if (isLoading) return <SectionSkeleton numRows={1} />;

return (
<Text>
{selectedProduct?.name}
</Text>
<If
condition={isLoading}
then={<SectionSkeleton numRows={1} />}
else={
<Text>
{selectedProduct?.name}
</Text>
}
/>
);
};

Expand All @@ -64,7 +68,7 @@ export default function ProductSection() {
icon="inventory_2"
errors={errors}
loading={isLoading}
path="/products"
path="/product"
>
<Content isLoading={isLoading} />
</Section>
Expand Down
14 changes: 5 additions & 9 deletions web/src/components/overview/SoftwareSection.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) [2022] SUSE LLC
* Copyright (c) [2022-2023] SUSE LLC
*
* All Rights Reserved.
*
Expand All @@ -20,13 +20,13 @@
*/

import React, { useReducer, useEffect } from "react";
import { BUSY } from "~/client/status";
import { Button } from "@patternfly/react-core";
import { ProgressText, Section } from "~/components/core";
import { Icon } from "~/components/layout";
import { ProgressText, Section } from "~/components/core";
import { toValidationError, useCancellablePromise } from "~/utils";
import { UsedSize } from "~/components/software";
import { useCancellablePromise } from "~/utils";
import { useInstallerClient } from "~/context/installer";
import { BUSY } from "~/client/status";
import { _ } from "~/i18n";

const initialState = {
Expand Down Expand Up @@ -78,10 +78,6 @@ export default function SoftwareSection({ showErrors }) {
return client.onStatusChange(updateStatus);
}, [client, cancellablePromise]);

useEffect(() => {
cancellablePromise(client.getStatus()).then(updateStatus);
}, [client, cancellablePromise]);

useEffect(() => {
const updateProposal = async () => {
const errors = await cancellablePromise(client.getIssues());
Expand Down Expand Up @@ -145,7 +141,7 @@ export default function SoftwareSection({ showErrors }) {
title={_("Software")}
icon="apps"
loading={state.busy}
errors={errors.map(e => ({ message: e.description }))}
errors={errors.map(toValidationError)}
path="/software"
>
<SectionContent />
Expand Down
Loading

0 comments on commit 36b6d80

Please sign in to comment.