KEYCLOAK-11201: Use snowpack instead of SystemJs.
Co-authored-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
parent
bf8316eefa
commit
a827d20a90
43 changed files with 8291 additions and 4180 deletions
|
@ -196,7 +196,7 @@ public class DeviceActivityTest extends BaseAccountPageTest {
|
|||
|
||||
@Test
|
||||
public void timesTests() {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE, MMMM d, yyyy h:mm a", Locale.ENGLISH);
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy, h:mm a", Locale.ENGLISH);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDateTime nowPlus1 = now.plusMinutes(1);
|
||||
String nowStr = now.format(formatter);
|
||||
|
|
|
@ -46,13 +46,13 @@ public class MyResourcesPage extends AbstractLoggedInPage {
|
|||
public void createShare(String userName) {
|
||||
driver.findElement(By.id("username")).sendKeys(userName);
|
||||
driver.findElement(By.id("add")).click();
|
||||
driver.findElement(By.id("remove_pf-random-id-0")).click();
|
||||
driver.findElement(By.id("remove_pf-random-id-1")).click();
|
||||
driver.findElement(By.id("done")).click();
|
||||
}
|
||||
|
||||
public void removeAllPermissions() {
|
||||
driver.findElement(By.id("remove_pf-random-id-0")).click();
|
||||
driver.findElement(By.id("remove_pf-random-id-1")).click();
|
||||
driver.findElement(By.id("remove_pf-random-id-2")).click();
|
||||
driver.findElement(By.id("done")).click();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
|
|||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class SigningInPage extends AbstractLoggedInPage {
|
||||
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("MMMM d, yyyy h:mm a", Locale.ENGLISH);
|
||||
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("MMMM d, yyyy, h:mm a", Locale.ENGLISH);
|
||||
|
||||
private static final String CATEG_TITLE = "-categ-title";
|
||||
|
||||
|
|
266
themes/pom.xml
266
themes/pom.xml
|
@ -112,275 +112,9 @@
|
|||
<exclude>**/.*</exclude>
|
||||
<!-- Remove once rcue stops shipping this file -->
|
||||
<exclude>**/git-Logo.svg</exclude>
|
||||
<!-- Remove once account2 manual filter list is removed -->
|
||||
<exclude>**/keycloak-preview/account/resources/node_modules/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<!-- account2 manual filter list -->
|
||||
<!--
|
||||
To update, use network log in browser, navigate around account2, export
|
||||
log as HAR json, then run this command to get the new list of includes:
|
||||
jq -r '.log.entries | .[] | .request.url' /tmp/localhost.har | sed -r 's|^.*/keycloak-preview/(node_modules/.*)$|<include>**/\1</include>|;tx;d;:x' | sort -Vu | xclip -selection clipboard
|
||||
-->
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>**/node_modules/axios/dist/axios.min.js</include>
|
||||
<include>**/node_modules/camel-case/camel-case.js</include>
|
||||
<include>**/node_modules/emotion/dist/emotion.umd.min.js</include>
|
||||
<include>**/node_modules/exenv/index.js</include>
|
||||
<include>**/node_modules/focus-trap-react/dist/focus-trap-react.js</include>
|
||||
<include>**/node_modules/focus-trap/dist/focus-trap.min.js</include>
|
||||
<include>**/node_modules/lower-case/lower-case.js</include>
|
||||
<include>**/node_modules/moment/min/moment-with-locales.min.js</include>
|
||||
<include>**/node_modules/no-case/no-case.js</include>
|
||||
<include>**/node_modules/no-case/vendor/camel-case-regexp.js</include>
|
||||
<include>**/node_modules/no-case/vendor/camel-case-upper-regexp.js</include>
|
||||
<include>**/node_modules/no-case/vendor/non-word-regexp.js</include>
|
||||
<include>**/node_modules/prop-types/prop-types.min.js</include>
|
||||
<include>**/node_modules/react-dom/umd/react-dom.production.min.js</include>
|
||||
<include>**/node_modules/react-router-dom/umd/react-router-dom.min.js</include>
|
||||
<include>**/node_modules/react/umd/react.production.min.js</include>
|
||||
<include>**/node_modules/systemjs/dist/system.src.js</include>
|
||||
<include>**/node_modules/tippy.js/dist/tippy.min.js</include>
|
||||
<include>**/node_modules/upper-case/upper-case.js</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-bold.ttf</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-bold.woff2</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-bold.woff</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-light-italic.woff2</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-light.woff2</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-regular.woff2</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-semibold.ttf</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-semibold.woff2</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-semibold.woff</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/webfonts/fa-solid-900.ttf</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/webfonts/fa-solid-900.woff</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/webfonts/fa-solid-900.ttf</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/fonts/webfonts/fa-solid-900.woff2</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/images/img_avatar.svg</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/assets/pficon/pficon.woff2</include>
|
||||
<include>**/node_modules/@patternfly/patternfly/patternfly.min.css</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Alert/AlertActionCloseButton.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Alert/AlertActionLink.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Alert/AlertIcon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Alert/Alert.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Alert/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Avatar/Avatar.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Avatar/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Backdrop/Backdrop.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Backdrop/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/BackgroundImage/BackgroundImage.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/BackgroundImage/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Badge/Badge.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Badge/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Brand/Brand.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Brand/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Button/Button.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Button/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Card/Card.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Card/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/ChipGroup/ChipButton.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/ChipGroup/ChipGroupToolbarItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/ChipGroup/ChipGroup.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/ChipGroup/Chip.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/ChipGroup/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataListAction.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataListCell.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataListCheck.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataListContent.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataListItemCells.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataListItemRow.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataListItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataListToggle.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/DataList.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/DataList/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/DropdownGroup.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/DropdownItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/DropdownMenu.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/DropdownToggleCheckbox.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/DropdownToggle.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/Dropdown.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/Item.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/KebabToggle.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/Separator.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/Toggle.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/dropdownConstants.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Dropdown/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/EmptyState/EmptyStateBody.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/EmptyState/EmptyStateIcon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/EmptyState/EmptyStateSecondaryActions.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/EmptyState/EmptyState.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/EmptyState/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Form/ActionGroup.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Form/FormContext.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Form/FormGroup.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Form/FormHelperText.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Form/Form.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Form/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/FormSelect/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/FormSelect/FormSelect.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/FormSelect/FormSelectOption.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/FormSelect/FormSelectOptionGroup.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Modal/ModalBoxBody.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Modal/ModalBoxCloseButton.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Modal/ModalBoxFooter.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Modal/ModalBoxHeader.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Modal/ModalBox.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Modal/ModalContent.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Modal/Modal.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Modal/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Nav/NavExpandable.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Nav/NavGroup.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Nav/NavItemSeparator.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Nav/NavItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Nav/NavList.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Nav/NavVariants.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Nav/Nav.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Nav/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Page/PageHeader.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Page/PageSection.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Page/PageSidebar.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Page/Page.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Page/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Switch/Switch.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Switch/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tabs/TabContent.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tabs/Tabs.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tabs/Tab.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tabs/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/TextInput/TextInput.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/TextInput/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Text/TextContent.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Text/TextListItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Text/TextList.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Text/Text.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Text/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Title/Title.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Title/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tooltip/TooltipArrow.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tooltip/TooltipContent.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tooltip/Tooltip.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tooltip/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/Tooltip/styles.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/components/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/helpers/GenerateId/GenerateId.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/helpers/componentShape.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/helpers/constants.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/helpers/htmlConstants.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/helpers/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/helpers/typeUtils.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/helpers/util.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Bullseye/Bullseye.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Bullseye/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Gallery/GalleryItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Gallery/Gallery.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Gallery/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Grid/GridItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Grid/Grid.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Grid/gridUtils.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Grid/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Level/LevelItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Level/Level.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Level/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Stack/StackItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Stack/Stack.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Stack/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Toolbar/ToolbarGroup.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Toolbar/ToolbarItem.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Toolbar/ToolbarSection.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Toolbar/Toolbar.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/Toolbar/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/layouts/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/styles/gutters.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/styles/sizes.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Alert/alert.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/AppLauncher/app-launcher.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Avatar/avatar.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Backdrop/backdrop.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/BackgroundImage/background-image.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Badge/badge.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Button/button.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Card/card.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/ChipGroup/chip-group.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Chip/chip.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Content/content.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/DataList/data-list.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Dropdown/dropdown.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/EmptyState/empty-state.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/FormControl/form-control.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Form/form.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/ModalBox/modal-box.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Nav/nav.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Page/page.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Switch/switch.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Tabs/tabs.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Title/title.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/components/Tooltip/tooltip.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/layouts/Bullseye/bullseye.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/layouts/Gallery/gallery.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/layouts/Grid/grid.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/layouts/Level/level.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/layouts/Stack/stack.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-core/dist/umd/@patternfly/patternfly/utilities/Accessibility/accessibility.css.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/common.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/createIcon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/amazon-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/angle-down-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/angle-left-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/angle-right-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/arrow-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/bars-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/bitbucket-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/builder-image-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/caret-down-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/check-circle-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/check-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/chrome-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/cube-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/edge-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/edit-alt-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/ellipsis-v-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/exclamation-circle-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/exclamation-triangle-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/facebook-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/firefox-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/github-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/gitlab-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/globe-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/google-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/info-alt-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/info-circle-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/instagram-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/internet-explorer-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/linkedin-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/link-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/microsoft-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/openshift-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/opera-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/passport-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/paypal-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/plus-circle-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/redo-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/remove2-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/safari-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/share-alt-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/stack-overflow-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/times-circle-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/times-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/twitter-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/unlink-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/user-check-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/warning-triangle-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/icons/yandex-international-icon.js</include>
|
||||
<include>**/node_modules/@patternfly/react-icons/dist/umd/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-styles/dist/umd/StyleSheet.js</include>
|
||||
<include>**/node_modules/@patternfly/react-styles/dist/umd/index.js</include>
|
||||
<include>**/node_modules/@patternfly/react-styles/dist/umd/utils.js</include>
|
||||
<include>**/node_modules/@patternfly/react-tokens/dist/umd/index.js</include>
|
||||
<include>**/node_modules/@tippy.js/react/dist/Tippy.min.js</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
|
|
|
@ -105,6 +105,8 @@
|
|||
</#list>
|
||||
</#if>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="${resourceUrl}/public/base.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="${resourceUrl}/public/app.css"/>
|
||||
<link href="${resourceUrl}/public/layout.css" rel="stylesheet"/>
|
||||
</head>
|
||||
|
||||
|
@ -128,13 +130,8 @@
|
|||
document.getElementById("landingLoggedInUser").innerHTML = loggedInUserName('${msg("unknownUser")}', '${msg("fullName")}');
|
||||
}
|
||||
|
||||
loadjs("/node_modules/systemjs/dist/system.src.js", function() {
|
||||
loadjs("/systemjs.config.js", function() {
|
||||
System.import('${resourceUrl}/Main.js').catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
loadjs("/app/Main.js");
|
||||
|
||||
}).error(function() {
|
||||
alert('failed to initialize keycloak');
|
||||
});
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"plugins": [
|
||||
[
|
||||
"snowpack/assets/babel-plugin.js",
|
||||
{
|
||||
"webModulesUrl": "./web_modules",
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"presets": [
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript"
|
||||
]
|
||||
}
|
|
@ -13,8 +13,12 @@ node_modules
|
|||
|
||||
# Don't ignore these
|
||||
!keycloak.js
|
||||
!systemjs.config.extras.js
|
||||
!systemjs.config.js
|
||||
!snowpack.config.js
|
||||
!.eslintrc.js
|
||||
!WelcomePageScripts.js
|
||||
!content.js
|
||||
|
||||
public/app.css
|
||||
public/base.css
|
||||
public/assets/
|
||||
web_modules/
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -29,13 +29,11 @@ var toggleReact = function () {
|
|||
if (reactScreen) reactScreen.style.display = 'block';
|
||||
if (reactScreen) reactScreen.style.height = '100%';
|
||||
} else if (!isWelcomePage() && isReactLoading) {
|
||||
loadPatternFly();
|
||||
if (welcomeScreen) welcomeScreen.style.display = 'none';
|
||||
if (reactScreen) reactScreen.style.display = 'none';
|
||||
if (spinnerScreen) spinnerScreen.style.display = 'block';
|
||||
if (spinnerScreen) spinnerScreen.style.height = '100%';
|
||||
} else {
|
||||
loadPatternFly();
|
||||
if (reactScreen) reactScreen.style.display = 'none';
|
||||
if (spinnerScreen) spinnerScreen.style.display = 'none';
|
||||
if (welcomeScreen) welcomeScreen.style.display = 'block';
|
||||
|
@ -43,16 +41,6 @@ var toggleReact = function () {
|
|||
}
|
||||
};
|
||||
|
||||
var patternFlyHasLoaded = false;
|
||||
var loadPatternFly = function () {
|
||||
if (patternFlyHasLoaded) return;
|
||||
const link = document.createElement("link");
|
||||
link.rel="stylesheet";
|
||||
link.href=resourceUrl + "/node_modules/@patternfly/patternfly/patternfly.min.css";
|
||||
document.head.appendChild(link);
|
||||
patternFlyHasLoaded = true;
|
||||
}
|
||||
|
||||
function loggedInUserName() {
|
||||
let userName = l18nMsg['unknownUser'];
|
||||
if (keycloak.tokenParsed) {
|
||||
|
@ -73,9 +61,8 @@ function loggedInUserName() {
|
|||
var loadjs = function (url, loadListener) {
|
||||
const script = document.createElement("script");
|
||||
script.src = resourceUrl + url;
|
||||
script.type = "module";
|
||||
if (loadListener)
|
||||
script.addEventListener("load", loadListener);
|
||||
document.head.appendChild(script);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
import * as React from 'react';
|
||||
|
||||
import * as moment from 'moment';
|
||||
|
||||
import {KeycloakService} from './keycloak-service/keycloak.service';
|
||||
|
||||
import {PageNav} from './PageNav';
|
||||
|
@ -42,7 +40,6 @@ declare const resourceUrl: string;
|
|||
declare const brandImg: string;
|
||||
declare const brandUrl: string;
|
||||
|
||||
|
||||
export interface AppProps {};
|
||||
export class App extends React.Component<AppProps> {
|
||||
private kcSvc: KeycloakService = KeycloakService.Instance;
|
||||
|
@ -60,9 +57,6 @@ export class App extends React.Component<AppProps> {
|
|||
this.kcSvc.login();
|
||||
}
|
||||
|
||||
// globally set up locale for date formatting
|
||||
moment.locale(locale);
|
||||
|
||||
const username = (
|
||||
<span style={{marginLeft: '10px'}} id="loggedInUser">{loggedInUserName()}</span>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -70,7 +70,7 @@ function isChildOf(parent: Expansion, child: PageDef): boolean {
|
|||
if (isExpansion(item) && isChildOf(item, child)) return true;
|
||||
if (parent.groupId === child.groupId) return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -91,10 +91,10 @@ function createNavItems(activePage: PageDef, contentParam: ContentItem[], groupN
|
|||
const page: PageDef = item as PageDef;
|
||||
return <NavItem id={navLinkId}
|
||||
groupId={item.groupId}
|
||||
itemId={item.itemId}
|
||||
key={item.itemId}
|
||||
to={'#/app/' + page.path}
|
||||
isActive={activePage.itemId === item.itemId}
|
||||
itemId={item.itemId}
|
||||
key={item.itemId}
|
||||
to={'#/app/' + page.path}
|
||||
isActive={activePage.itemId === item.itemId}
|
||||
type="button">
|
||||
{Msg.localize(page.label, page.labelParams)}
|
||||
</NavItem>
|
||||
|
@ -112,7 +112,7 @@ export function makeNavItems(activePage: PageDef): React.ReactNode {
|
|||
function setIds(contentParam: ContentItem[], groupNum: number): number {
|
||||
if (typeof contentParam === 'undefined') return groupNum;
|
||||
let expansionGroupNum = groupNum;
|
||||
|
||||
|
||||
for (let i = 0; i < contentParam.length; i++) {
|
||||
const item: ContentItem = contentParam[i];
|
||||
if (isExpansion(item)) {
|
||||
|
@ -126,7 +126,7 @@ function setIds(contentParam: ContentItem[], groupNum: number): number {
|
|||
item.itemId = itemId(groupNum, i);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return expansionGroupNum;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ export function initGroupAndItemIds(): void {
|
|||
setIds(content, 0);
|
||||
console.log({content});
|
||||
}
|
||||
|
||||
|
||||
// get rid of Expansions and put all PageDef items into a single array
|
||||
export function flattenContent(pageDefs: ContentItem[]): PageDef[] {
|
||||
const flat: PageDef[] = [];
|
||||
|
@ -153,7 +153,7 @@ export function flattenContent(pageDefs: ContentItem[]): PageDef[] {
|
|||
export function makeRoutes(): React.ReactNode {
|
||||
if (typeof content === 'undefined') return (<span/>);
|
||||
|
||||
const pageDefs: PageDef[] = flattenContent(content);
|
||||
const pageDefs: PageDef[] = flattenContent(content);
|
||||
|
||||
const routes: React.ReactElement<Route>[] = pageDefs.map((page: PageDef) => {
|
||||
if (isModulePageDef(page)) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,19 +16,18 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import {System} from 'systemjs';
|
||||
|
||||
import {HashRouter} from 'react-router-dom';
|
||||
|
||||
import {App} from './app/App';
|
||||
import {ContentItem, ModulePageDef, flattenContent, initGroupAndItemIds, isExpansion, isModulePageDef} from './app/ContentPages';
|
||||
import {App} from './App';
|
||||
import {ContentItem, ModulePageDef, flattenContent, initGroupAndItemIds, isExpansion, isModulePageDef} from './ContentPages';
|
||||
|
||||
declare let isReactLoading: boolean;
|
||||
declare function toggleReact(): void;
|
||||
|
||||
export interface MainProps {}
|
||||
export class Main extends React.Component<MainProps> {
|
||||
|
||||
|
||||
public constructor(props: MainProps) {
|
||||
super(props);
|
||||
}
|
||||
|
@ -56,7 +55,7 @@ function removeHidden(items: ContentItem[]): ContentItem[] {
|
|||
|
||||
for (let item of items) {
|
||||
if (item.hidden) continue;
|
||||
|
||||
|
||||
if (isExpansion(item)) {
|
||||
visible.push(item);
|
||||
item.content = removeHidden(item.content);
|
||||
|
@ -76,7 +75,8 @@ initGroupAndItemIds();
|
|||
|
||||
function loadModule(modulePage: ModulePageDef): Promise<ModulePageDef> {
|
||||
return new Promise ((resolve, reject) => {
|
||||
System.import(resourceUrl + modulePage.modulePath).then( (module: React.Component) => {
|
||||
console.log('loading: ' + resourceUrl + modulePage.modulePath);
|
||||
import(resourceUrl + modulePage.modulePath).then( (module: React.Component) => {
|
||||
modulePage.module = module;
|
||||
resolve(modulePage);
|
||||
}).catch((error: Error) => {
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -19,19 +19,19 @@ import {withRouter, RouteComponentProps} from 'react-router-dom';
|
|||
import {Nav, NavList} from '@patternfly/react-core';
|
||||
|
||||
import {makeNavItems, flattenContent, ContentItem, PageDef} from './ContentPages';
|
||||
|
||||
|
||||
declare const content: ContentItem[];
|
||||
|
||||
export interface PageNavProps extends RouteComponentProps {}
|
||||
|
||||
|
||||
export interface PageNavState {}
|
||||
|
||||
class PageNavigation extends React.Component<PageNavProps, PageNavState> {
|
||||
|
||||
|
||||
public constructor(props: PageNavProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
|
||||
private findActiveItem(): PageDef {
|
||||
const currentPath: string = this.props.location.pathname;
|
||||
const items: PageDef[] = flattenContent(content);
|
||||
|
@ -45,7 +45,7 @@ class PageNavigation extends React.Component<PageNavProps, PageNavState> {
|
|||
|
||||
return firstItem;
|
||||
}
|
||||
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const activeItem: PageDef = this.findActiveItem();
|
||||
return (
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
|
||||
import {Dropdown, KebabToggle, Toolbar, ToolbarGroup, ToolbarItem} from '@patternfly/react-core';
|
||||
|
||||
import {ReferrerDropdownItem} from './widgets/ReferrerDropdownItem';
|
||||
|
@ -33,18 +33,18 @@ export class PageToolbar extends React.Component<PageToolbarProps, PageToolbarSt
|
|||
|
||||
public constructor(props: PageToolbarProps) {
|
||||
super(props);
|
||||
|
||||
|
||||
this.state = {
|
||||
isKebabDropdownOpen: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private onKebabDropdownToggle = (isKebabDropdownOpen: boolean) => {
|
||||
this.setState({
|
||||
isKebabDropdownOpen
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const kebabDropdownItems = [];
|
||||
if (this.hasReferrer) {
|
||||
|
@ -52,9 +52,9 @@ export class PageToolbar extends React.Component<PageToolbarProps, PageToolbarSt
|
|||
<ReferrerDropdownItem key='referrerDropdownItem'/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
kebabDropdownItems.push(<LogoutDropdownItem key='LogoutDropdownItem'/>);
|
||||
|
||||
|
||||
return (
|
||||
<Toolbar>
|
||||
{this.hasReferrer &&
|
||||
|
@ -64,12 +64,12 @@ export class PageToolbar extends React.Component<PageToolbarProps, PageToolbarSt
|
|||
</ToolbarItem>
|
||||
</ToolbarGroup>
|
||||
}
|
||||
|
||||
|
||||
<ToolbarGroup key='secondGroup'>
|
||||
<ToolbarItem className="pf-m-icons" key='logout'>
|
||||
<LogoutButton/>
|
||||
</ToolbarItem>
|
||||
|
||||
|
||||
<ToolbarItem key='kebab' className="pf-m-mobile">
|
||||
<Dropdown
|
||||
isPlain
|
||||
|
|
|
@ -15,111 +15,127 @@
|
|||
* the License.
|
||||
*/
|
||||
|
||||
//import {KeycloakNotificationService} from '../notification/keycloak-notification.service';
|
||||
import {KeycloakService} from '../keycloak-service/keycloak.service';
|
||||
import Axios, {AxiosRequestConfig, AxiosResponse, AxiosError} from 'axios';
|
||||
import {ContentAlert} from '../content/ContentAlert';
|
||||
|
||||
//import {NotificationType} from 'patternfly-ng/notification';*/
|
||||
type ConfigResolve = (config: RequestInit) => void;
|
||||
|
||||
type AxiosResolve = (response: AxiosResponse) => void;
|
||||
type ConfigResolve = (config: AxiosRequestConfig) => void;
|
||||
type ErrorReject = (error: Error) => void;
|
||||
export interface HttpResponse<T = {}> extends Response {
|
||||
data?: T;
|
||||
}
|
||||
|
||||
/**
|
||||
export interface RequestInitWithParams extends RequestInit {
|
||||
params?: {[name: string]: string | number};
|
||||
}
|
||||
|
||||
export class AccountServiceError extends Error {
|
||||
constructor(public response: HttpResponse) {
|
||||
super(response.statusText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.
|
||||
*/
|
||||
export class AccountServiceClient {
|
||||
private static instance: AccountServiceClient = new AccountServiceClient();
|
||||
|
||||
class AccountServiceClient {
|
||||
private kcSvc: KeycloakService = KeycloakService.Instance;
|
||||
private accountUrl: string = this.kcSvc.authServerUrl() + 'realms/' + this.kcSvc.realm() + '/account';
|
||||
|
||||
private constructor() {}
|
||||
constructor() {}
|
||||
|
||||
public static get Instance(): AccountServiceClient {
|
||||
return AccountServiceClient.instance;
|
||||
}
|
||||
|
||||
public doGet(endpoint: string,
|
||||
config?: AxiosRequestConfig): Promise<AxiosResponse> {
|
||||
public async doGet<T>(endpoint: string,
|
||||
config?: RequestInitWithParams): Promise<HttpResponse<T>> {
|
||||
return this.doRequest(endpoint, {...config, method: 'get'});
|
||||
}
|
||||
|
||||
public doDelete(endpoint: string,
|
||||
config?: AxiosRequestConfig): Promise<AxiosResponse> {
|
||||
public async doDelete<T>(endpoint: string,
|
||||
config?: RequestInitWithParams): Promise<HttpResponse<T>> {
|
||||
return this.doRequest(endpoint, {...config, method: 'delete'});
|
||||
}
|
||||
|
||||
public doPut(endpoint: string,
|
||||
config?: AxiosRequestConfig): Promise<AxiosResponse> {
|
||||
return this.doRequest(endpoint, {...config,
|
||||
method: 'put',
|
||||
headers: {'Content-Type': 'application/json'}
|
||||
}
|
||||
);
|
||||
public async doPost<T>(endpoint: string,
|
||||
body: string | {},
|
||||
config?: RequestInitWithParams): Promise<HttpResponse<T>> {
|
||||
return this.doRequest(endpoint, {...config, body: JSON.stringify(body), method: 'post'});
|
||||
}
|
||||
|
||||
public doPost(endpoint: string,
|
||||
config?: AxiosRequestConfig): Promise<AxiosResponse> {
|
||||
return this.doRequest(endpoint, {...config, method: 'post'});
|
||||
public async doPut<T>(endpoint: string,
|
||||
body: string | {},
|
||||
config?: RequestInitWithParams): Promise<HttpResponse<T>> {
|
||||
return this.doRequest(endpoint, {...config, body: JSON.stringify(body), method: 'put'});
|
||||
}
|
||||
|
||||
public doRequest(endpoint: string,
|
||||
config?: AxiosRequestConfig): Promise<AxiosResponse> {
|
||||
public async doRequest<T>(endpoint: string,
|
||||
config?: RequestInitWithParams): Promise<HttpResponse<T>> {
|
||||
|
||||
return new Promise((resolve: AxiosResolve, reject: ErrorReject) => {
|
||||
this.makeConfig(endpoint, config)
|
||||
.then((config: AxiosRequestConfig) => {
|
||||
this.axiosRequest(config, resolve, reject);
|
||||
}).catch( (error: AxiosError) => {
|
||||
this.handleError(error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
const response: HttpResponse<T> = await fetch(this.makeUrl(endpoint, config).toString(),
|
||||
await this.makeConfig(config));
|
||||
|
||||
try {
|
||||
response.data = await response.json();
|
||||
} catch (e) {} // ignore. Might be empty
|
||||
|
||||
if (!response.ok) {
|
||||
this.handleError(response);
|
||||
throw new AccountServiceError(response);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private axiosRequest(config: AxiosRequestConfig,
|
||||
resolve: AxiosResolve,
|
||||
reject: ErrorReject): void {
|
||||
Axios.request(config)
|
||||
.then((response: AxiosResponse) => {
|
||||
resolve(response);
|
||||
})
|
||||
.catch((error: AxiosError) => {
|
||||
this.handleError(error);
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
private handleError(error: AxiosError): void {
|
||||
if (error != null && error.response != null && error.response.status === 401) {
|
||||
private handleError(response: HttpResponse): void {
|
||||
if (response != null && response.status === 401) {
|
||||
// session timed out?
|
||||
this.kcSvc.login();
|
||||
}
|
||||
console.log(error);
|
||||
|
||||
if (error != null && error.response != null && error.response.data != null && error.response.data.errorMessage) {
|
||||
ContentAlert.danger(error.response.data.errorMessage);
|
||||
if (response != null && response.data != null && response.data.hasOwnProperty('errorMessage')) {
|
||||
ContentAlert.danger(response.data['errorMessage']);
|
||||
} else {
|
||||
ContentAlert.danger(error.name + ': ' + error.message);
|
||||
ContentAlert.danger(response.statusText);
|
||||
}
|
||||
}
|
||||
|
||||
private makeConfig(endpoint: string, config: AxiosRequestConfig = {}): Promise<AxiosRequestConfig> {
|
||||
private makeUrl(endpoint: string, config?: RequestInitWithParams): URL {
|
||||
if (endpoint.startsWith('http')) return new URL(endpoint);
|
||||
const url = new URL(this.accountUrl + endpoint);
|
||||
|
||||
// add request params
|
||||
if (config && config.hasOwnProperty('params')) {
|
||||
const params: {[name: string]: string} = config.params as {} || {};
|
||||
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]))
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
private makeConfig(config: RequestInit = {}): Promise<RequestInit> {
|
||||
return new Promise( (resolve: ConfigResolve) => {
|
||||
this.kcSvc.getToken()
|
||||
.then( (token: string) => {
|
||||
resolve( {
|
||||
...config,
|
||||
baseURL: this.accountUrl,
|
||||
url: endpoint,
|
||||
headers: {...config.headers, Authorization: 'Bearer ' + token}
|
||||
headers: {'Content-Type': 'application/json',
|
||||
...config.headers,
|
||||
Authorization: 'Bearer ' + token}
|
||||
});
|
||||
}).catch(() => {
|
||||
this.kcSvc.login();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const AccountService: AccountServiceClient = new AccountServiceClient();
|
||||
export default AccountService;
|
||||
|
||||
window.addEventListener("unhandledrejection", (event: PromiseRejectionEvent) => {
|
||||
event.promise.catch(error => {
|
||||
if (error instanceof AccountServiceError) {
|
||||
// We already handled the error. Ignore unhandled rejection.
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -17,7 +17,7 @@
|
|||
import * as React from 'react';
|
||||
import {Alert, AlertActionCloseButton} from '@patternfly/react-core';
|
||||
import {Msg} from '../widgets/Msg';
|
||||
|
||||
|
||||
interface ContentAlertProps {}
|
||||
|
||||
type AlertVariant = 'success' | 'danger' | 'warning' | 'info';
|
||||
|
@ -31,53 +31,53 @@ export class ContentAlert extends React.Component<ContentAlertProps, ContentAler
|
|||
|
||||
private constructor(props: ContentAlertProps) {
|
||||
super(props);
|
||||
|
||||
|
||||
this.state = {isVisible: false, message: '', variant: 'success'};
|
||||
ContentAlert.instance = this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param message A literal text message or localization key.
|
||||
*/
|
||||
public static success(message: string, params?: string[]): void {
|
||||
ContentAlert.instance.postAlert('success', message, params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param message A literal text message or localization key.
|
||||
*/
|
||||
public static danger(message: string, params?: string[]): void {
|
||||
ContentAlert.instance.postAlert('danger', message, params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param message A literal text message or localization key.
|
||||
*/
|
||||
public static warning(message: string, params?: string[]): void {
|
||||
ContentAlert.instance.postAlert('warning', message, params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param message A literal text message or localization key.
|
||||
*/
|
||||
public static info(message: string, params?: string[]): void {
|
||||
ContentAlert.instance.postAlert('info', message, params);
|
||||
}
|
||||
|
||||
|
||||
private hideAlert = () => {
|
||||
this.setState({isVisible: false});
|
||||
}
|
||||
|
||||
|
||||
private postAlert = (variant: AlertVariant, message: string, params?: string[]) => {
|
||||
this.setState({isVisible: true,
|
||||
message: Msg.localize(message, params),
|
||||
this.setState({isVisible: true,
|
||||
message: Msg.localize(message, params),
|
||||
variant});
|
||||
|
||||
|
||||
if (variant !== 'danger') {
|
||||
setTimeout(() => this.setState({isVisible: false}), 5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
|
|
@ -13,12 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { ActionGroup, Button, Form, FormGroup, TextInput } from '@patternfly/react-core';
|
||||
|
||||
import { AccountServiceClient } from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import { Features } from '../../widgets/features';
|
||||
import { Msg } from '../../widgets/Msg';
|
||||
import { ContentPage } from '../ContentPage';
|
||||
|
@ -74,15 +72,15 @@ export class AccountPage extends React.Component<AccountPageProps, AccountPageSt
|
|||
}
|
||||
|
||||
private fetchPersonalInfo(): void {
|
||||
AccountServiceClient.Instance.doGet("/")
|
||||
.then((response: AxiosResponse<FormFields>) => {
|
||||
AccountService.doGet<FormFields>("/")
|
||||
.then((response: HttpResponse<FormFields>) => {
|
||||
this.setState(this.DEFAULT_STATE);
|
||||
const formFields = response.data;
|
||||
if (!formFields.attributes || !formFields.attributes.locale) {
|
||||
formFields.attributes = { locale: [locale] };
|
||||
if (!formFields!.attributes || !formFields!.attributes.locale) {
|
||||
formFields!.attributes = { locale: [locale] };
|
||||
}
|
||||
|
||||
this.setState({...{ formFields: formFields }});
|
||||
this.setState({...{ formFields: formFields as FormFields }});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,8 +104,8 @@ export class AccountPage extends React.Component<AccountPageProps, AccountPageSt
|
|||
const isValid = form.checkValidity();
|
||||
if (isValid) {
|
||||
const reqData: FormFields = { ...this.state.formFields };
|
||||
AccountServiceClient.Instance.doPost("/", { data: reqData })
|
||||
.then(() => { // to use response, say ((response: AxiosResponse<FormFields>) => {
|
||||
AccountService.doPost<void>("/", reqData)
|
||||
.then(() => {
|
||||
ContentAlert.success('accountUpdatedMessage');
|
||||
if (locale !== this.state.formFields.attributes!.locale![0]) {
|
||||
window.location.reload();
|
||||
|
@ -202,7 +200,7 @@ export class AccountPage extends React.Component<AccountPageProps, AccountPageSt
|
|||
>
|
||||
</TextInput>
|
||||
</FormGroup>
|
||||
{features.isInternationalizationEnabled && <FormGroup
|
||||
{features.isInternationalizationEnabled && <FormGroup
|
||||
label={Msg.localize('selectLocale')}
|
||||
isRequired
|
||||
fieldId="locale"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { AxiosResponse } from 'axios';
|
||||
|
||||
import {
|
||||
DataList,
|
||||
|
@ -32,7 +31,7 @@ import {
|
|||
import { InfoAltIcon, CheckIcon, BuilderImageIcon } from '@patternfly/react-icons';
|
||||
import { ContentPage } from '../ContentPage';
|
||||
import { ContinueCancelModal } from '../../widgets/ContinueCancelModal';
|
||||
import { AccountServiceClient } from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import { Msg } from '../../widgets/Msg';
|
||||
|
||||
declare const locale: string;
|
||||
|
@ -82,7 +81,7 @@ export class ApplicationsPage extends React.Component<ApplicationsPageProps, App
|
|||
}
|
||||
|
||||
private removeConsent = (clientId: string) => {
|
||||
AccountServiceClient.Instance.doDelete("/applications/" + clientId + "/consent")
|
||||
AccountService.doDelete("/applications/" + clientId + "/consent")
|
||||
.then(() => {
|
||||
this.fetchApplications();
|
||||
});
|
||||
|
@ -95,9 +94,9 @@ export class ApplicationsPage extends React.Component<ApplicationsPageProps, App
|
|||
};
|
||||
|
||||
private fetchApplications(): void {
|
||||
AccountServiceClient.Instance.doGet("/applications")
|
||||
.then((response: AxiosResponse<Application[]>) => {
|
||||
const applications = response.data;
|
||||
AccountService.doGet<Application[]>("/applications")
|
||||
.then((response: HttpResponse<Application[]>) => {
|
||||
const applications = response.data || [];
|
||||
this.setState({
|
||||
isRowOpen: new Array(applications.length).fill(false),
|
||||
applications: applications
|
||||
|
|
|
@ -15,10 +15,9 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as moment from 'moment';
|
||||
import {AxiosResponse} from 'axios';
|
||||
|
||||
import {AccountServiceClient} from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import TimeUtil from '../../util/TimeUtil';
|
||||
|
||||
import {
|
||||
Bullseye,
|
||||
|
@ -104,26 +103,26 @@ export class DeviceActivityPage extends React.Component<DeviceActivityPageProps,
|
|||
}
|
||||
|
||||
private signOutAll = () => {
|
||||
AccountServiceClient.Instance.doDelete("/sessions")
|
||||
AccountService.doDelete("/sessions")
|
||||
.then( () => {
|
||||
KeycloakService.Instance.logout(baseUrl);
|
||||
});
|
||||
}
|
||||
|
||||
private signOutSession = (device: Device, session: Session) => {
|
||||
AccountServiceClient.Instance.doDelete("/sessions/" + session.id)
|
||||
AccountService.doDelete("/sessions/" + session.id)
|
||||
.then (() => {
|
||||
this.fetchDevices();
|
||||
ContentAlert.success(Msg.localize('signedOutSession', [session.browser, device.os]));
|
||||
ContentAlert.success('signedOutSession', [session.browser, device.os]);
|
||||
});
|
||||
}
|
||||
|
||||
private fetchDevices(): void {
|
||||
AccountServiceClient.Instance.doGet("/sessions/devices")
|
||||
.then((response: AxiosResponse<Device[]>) => {
|
||||
AccountService.doGet<Device[]>("/sessions/devices")
|
||||
.then((response: HttpResponse<Device[]>) => {
|
||||
console.log({response});
|
||||
|
||||
let devices: Device[] = this.moveCurrentToTop(response.data);
|
||||
let devices: Device[] = this.moveCurrentToTop(response.data as Device[]);
|
||||
|
||||
this.setState({
|
||||
devices: devices
|
||||
|
@ -155,7 +154,7 @@ export class DeviceActivityPage extends React.Component<DeviceActivityPageProps,
|
|||
}
|
||||
|
||||
private time(time: number): string {
|
||||
return moment(time * 1000).format('LLLL');
|
||||
return TimeUtil.format(time * 1000);
|
||||
}
|
||||
|
||||
private elementId(item: string, session: Session): string {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,19 +16,18 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom';
|
||||
import {AxiosResponse} from 'axios';
|
||||
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
DataList,
|
||||
DataList,
|
||||
DataListAction,
|
||||
DataListItemCells,
|
||||
DataListItemCells,
|
||||
DataListCell,
|
||||
DataListItemRow,
|
||||
DataListItemRow,
|
||||
Stack,
|
||||
StackItem,
|
||||
Title,
|
||||
Title,
|
||||
TitleLevel,
|
||||
DataListItem,
|
||||
} from '@patternfly/react-core';
|
||||
|
@ -37,7 +36,7 @@ import {
|
|||
BitbucketIcon,
|
||||
CubeIcon,
|
||||
FacebookIcon,
|
||||
GithubIcon,
|
||||
GithubIcon,
|
||||
GitlabIcon,
|
||||
GoogleIcon,
|
||||
InstagramIcon,
|
||||
|
@ -51,7 +50,7 @@ import {
|
|||
UnlinkIcon
|
||||
} from '@patternfly/react-icons';
|
||||
|
||||
import {AccountServiceClient} from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import {Msg} from '../../widgets/Msg';
|
||||
import {ContentPage} from '../ContentPage';
|
||||
import {createRedirect} from '../../util/RedirectUri';
|
||||
|
@ -77,7 +76,7 @@ interface LinkedAccountsPageState {
|
|||
* @author Stan Silvert
|
||||
*/
|
||||
class LinkedAccountsPage extends React.Component<LinkedAccountsPageProps, LinkedAccountsPageState> {
|
||||
|
||||
|
||||
public constructor(props: LinkedAccountsPageProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -89,11 +88,11 @@ class LinkedAccountsPage extends React.Component<LinkedAccountsPageProps, Linked
|
|||
}
|
||||
|
||||
private getLinkedAccounts(): void {
|
||||
AccountServiceClient.Instance.doGet("/linked-accounts")
|
||||
.then((response: AxiosResponse<LinkedAccount[]>) => {
|
||||
AccountService.doGet<LinkedAccount[]>("/linked-accounts")
|
||||
.then((response: HttpResponse<LinkedAccount[]>) => {
|
||||
console.log({response});
|
||||
const linkedAccounts = response.data.filter((account) => account.connected);
|
||||
const unLinkedAccounts = response.data.filter((account) => !account.connected);
|
||||
const linkedAccounts = response.data!.filter((account) => account.connected);
|
||||
const unLinkedAccounts = response.data!.filter((account) => !account.connected);
|
||||
this.setState({linkedAccounts: linkedAccounts, unLinkedAccounts: unLinkedAccounts});
|
||||
});
|
||||
}
|
||||
|
@ -101,8 +100,8 @@ class LinkedAccountsPage extends React.Component<LinkedAccountsPageProps, Linked
|
|||
private unLinkAccount(account: LinkedAccount): void {
|
||||
const url = '/linked-accounts/' + account.providerName;
|
||||
|
||||
AccountServiceClient.Instance.doDelete(url)
|
||||
.then((response: AxiosResponse) => {
|
||||
AccountService.doDelete<void>(url)
|
||||
.then((response: HttpResponse<void>) => {
|
||||
console.log({response});
|
||||
this.getLinkedAccounts();
|
||||
});
|
||||
|
@ -113,10 +112,10 @@ class LinkedAccountsPage extends React.Component<LinkedAccountsPageProps, Linked
|
|||
|
||||
const redirectUri: string = createRedirect(this.props.location.pathname);
|
||||
|
||||
AccountServiceClient.Instance.doGet(url, { params: {providerId: account.providerName, redirectUri}})
|
||||
.then((response: AxiosResponse<{accountLinkUri: string}>) => {
|
||||
AccountService.doGet<{accountLinkUri: string}>(url, { params: {providerId: account.providerName, redirectUri}})
|
||||
.then((response: HttpResponse<{accountLinkUri: string}>) => {
|
||||
console.log({response});
|
||||
window.location.href = response.data.accountLinkUri;
|
||||
window.location.href = response.data!.accountLinkUri;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -141,7 +140,7 @@ class LinkedAccountsPage extends React.Component<LinkedAccountsPageProps, Linked
|
|||
<DataList id="unlinked-idps" aria-label='foo'>
|
||||
{this.makeRows(this.state.unLinkedAccounts, false)}
|
||||
</DataList>
|
||||
</StackItem>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</ContentPage>
|
||||
);
|
||||
|
@ -173,7 +172,7 @@ class LinkedAccountsPage extends React.Component<LinkedAccountsPageProps, Linked
|
|||
|
||||
return (
|
||||
<> {
|
||||
|
||||
|
||||
accounts.map( (account: LinkedAccount) => (
|
||||
<DataListItem id={`${account.providerAlias}-idp`} key={account.providerName} aria-labelledby="simple-item1">
|
||||
<DataListItemRow key={account.providerName}>
|
||||
|
@ -190,9 +189,9 @@ class LinkedAccountsPage extends React.Component<LinkedAccountsPageProps, Linked
|
|||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
))
|
||||
|
||||
|
||||
} </>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -200,7 +199,7 @@ class LinkedAccountsPage extends React.Component<LinkedAccountsPageProps, Linked
|
|||
if (account.social) {
|
||||
return (<Badge><Msg msgKey='socialLogin'/></Badge>);
|
||||
}
|
||||
|
||||
|
||||
return (<Badge style={{backgroundColor: "green"}} ><Msg msgKey='systemDefined'/></Badge>);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import { EditAltIcon } from '@patternfly/react-icons';
|
|||
|
||||
import { Resource, Permission, Scope } from './MyResourcesPage';
|
||||
import { Msg } from '../../widgets/Msg';
|
||||
import { AccountServiceClient } from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import { ContentAlert } from '../ContentAlert';
|
||||
|
||||
interface EditTheResourceProps {
|
||||
|
@ -74,7 +74,7 @@ export class EditTheResource extends React.Component<EditTheResourceProps, EditT
|
|||
|
||||
async deletePermission(permission: Permission, scope: Scope): Promise<void> {
|
||||
permission.scopes.splice(permission.scopes.indexOf(scope), 1);
|
||||
await AccountServiceClient.Instance.doPut(`/resources/${this.props.resource._id}/permissions`, {data: [permission]});
|
||||
await AccountService.doPut(`/resources/${this.props.resource._id}/permissions`, [permission]);
|
||||
ContentAlert.success(Msg.localize('shareSuccess'));
|
||||
this.props.onClose(this.props.resource, this.props.row);
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ export class EditTheResource extends React.Component<EditTheResourceProps, EditT
|
|||
{p.username}
|
||||
</DataListCell>,
|
||||
<DataListCell key={'permission-' + row} width={5}>
|
||||
<ChipGroup>
|
||||
<ChipGroup withToolbar>
|
||||
<ChipGroupToolbarItem key='permissions' categoryName={Msg.localize('permissions')}>
|
||||
{
|
||||
p.scopes.length > 0 && p.scopes.map(scope => (
|
||||
|
|
|
@ -15,13 +15,12 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import {AxiosResponse} from 'axios';
|
||||
|
||||
import parse from '../../util/ParseLink';
|
||||
|
||||
import { Button, Level, LevelItem, Stack, StackItem, Tab, Tabs, TextInput } from '@patternfly/react-core';
|
||||
|
||||
import {AccountServiceClient} from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
|
||||
import {ResourcesTable} from './ResourcesTable';
|
||||
import {ContentPage} from '../ContentPage';
|
||||
|
@ -102,7 +101,7 @@ export class MyResourcesPage extends React.Component<MyResourcesPageProps, MyRes
|
|||
|
||||
private isSharedWithMeTab(): boolean {
|
||||
return this.state.activeTabKey === SHARED_WITH_ME_TAB;
|
||||
}
|
||||
}
|
||||
|
||||
private hasNext(): boolean {
|
||||
if (this.isSharedWithMeTab()) {
|
||||
|
@ -137,9 +136,9 @@ export class MyResourcesPage extends React.Component<MyResourcesPageProps, MyRes
|
|||
}
|
||||
|
||||
private fetchResources(url: string, extraParams?: Record<string, string|number>): void {
|
||||
AccountServiceClient.Instance.doGet(url, {params: extraParams})
|
||||
.then((response: AxiosResponse<Resource[]>) => {
|
||||
const resources: Resource[] = response.data;
|
||||
AccountService.doGet<Resource[]>(url, {params: extraParams})
|
||||
.then((response: HttpResponse<Resource[]>) => {
|
||||
const resources: Resource[] = response.data || [];
|
||||
resources.forEach((resource: Resource) => resource.shareRequests = []);
|
||||
|
||||
// serialize the Scope objects from JSON so that toString() will work.
|
||||
|
@ -164,9 +163,9 @@ export class MyResourcesPage extends React.Component<MyResourcesPageProps, MyRes
|
|||
}
|
||||
|
||||
private fetchShareRequests(resource: Resource): void {
|
||||
AccountServiceClient.Instance.doGet('/resources/' + resource._id + '/permissions/requests')
|
||||
.then((response: AxiosResponse<Permission[]>) => {
|
||||
resource.shareRequests = response.data;
|
||||
AccountService.doGet('/resources/' + resource._id + '/permissions/requests')
|
||||
.then((response: HttpResponse<Permission[]>) => {
|
||||
resource.shareRequests = response.data || [];
|
||||
if (resource.shareRequests.length > 0) {
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
@ -174,8 +173,9 @@ export class MyResourcesPage extends React.Component<MyResourcesPageProps, MyRes
|
|||
}
|
||||
|
||||
private fetchPending = async () => {
|
||||
const response = await AccountServiceClient.Instance.doGet(`/resources/pending-requests`);
|
||||
response.data.forEach((pendingRequest: Resource) => {
|
||||
const response: HttpResponse<Resource[]> = await AccountService.doGet(`/resources/pending-requests`);
|
||||
const resources: Resource[] = response.data || [];
|
||||
resources.forEach((pendingRequest: Resource) => {
|
||||
this.state.sharedWithMe.data.forEach(resource => {
|
||||
if (resource._id === pendingRequest._id) {
|
||||
resource.shareRequests = [{username: 'me', scopes: pendingRequest.scopes}]
|
||||
|
@ -185,8 +185,8 @@ export class MyResourcesPage extends React.Component<MyResourcesPageProps, MyRes
|
|||
});
|
||||
}
|
||||
|
||||
private parseResourceResponse(response: AxiosResponse<Resource[]>): PaginatedResources {
|
||||
const links: string = response.headers.link;
|
||||
private parseResourceResponse(response: HttpResponse<Resource[]>): PaginatedResources {
|
||||
const links: string | undefined = response.headers.get('link') || undefined;
|
||||
const parsed = parse(links);
|
||||
|
||||
let next = '';
|
||||
|
@ -197,7 +197,7 @@ export class MyResourcesPage extends React.Component<MyResourcesPageProps, MyRes
|
|||
if (parsed.prev) prev = parsed.prev;
|
||||
}
|
||||
|
||||
const resources = response.data;
|
||||
const resources: Resource[] = response.data || [];
|
||||
|
||||
return {nextUrl: next, prevUrl: prev, data: resources};
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ export class MyResourcesPage extends React.Component<MyResourcesPageProps, MyRes
|
|||
<LevelItem>
|
||||
{this.hasPrevious() && <Button onClick={this.handlePreviousClick}><<Msg msgKey='previousPage'/></Button>}
|
||||
</LevelItem>
|
||||
|
||||
|
||||
<LevelItem>
|
||||
{this.hasPrevious() && <Button onClick={this.handleFirstPageClick}><Msg msgKey='firstPage'/></Button>}
|
||||
</LevelItem>
|
||||
|
@ -252,7 +252,7 @@ export class MyResourcesPage extends React.Component<MyResourcesPageProps, MyRes
|
|||
this.setState({nameFilter: value});
|
||||
this.fetchFilteredResources({name: value});
|
||||
}
|
||||
|
||||
|
||||
private clearNextPrev(): void {
|
||||
const newMyResources: PaginatedResources = this.state.myResources;
|
||||
newMyResources.nextUrl = '';
|
||||
|
|
|
@ -17,7 +17,7 @@ import * as React from 'react';
|
|||
import { Button, Modal, Text, Badge, DataListItem, DataList, TextVariants, DataListItemRow, DataListItemCells, DataListCell, Chip } from '@patternfly/react-core';
|
||||
import { UserCheckIcon } from '@patternfly/react-icons';
|
||||
|
||||
import { AccountServiceClient } from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import { Msg } from '../../widgets/Msg';
|
||||
import { ContentAlert } from '../ContentAlert';
|
||||
import { Resource, Scope, Permission } from './MyResourcesPage';
|
||||
|
@ -55,13 +55,16 @@ export class PermissionRequest extends React.Component<PermissionRequestProps, P
|
|||
const id = this.props.resource._id
|
||||
this.handleToggleDialog();
|
||||
|
||||
const permissionsRequest = await AccountServiceClient.Instance.doGet(`/resources/${id}/permissions`);
|
||||
const userScopes = permissionsRequest.data.find((p: Permission) => p.username === username).scopes;
|
||||
const permissionsRequest: HttpResponse<Permission[]> = await AccountService.doGet(`/resources/${id}/permissions`);
|
||||
const permissions: Permission[] = permissionsRequest.data || [];
|
||||
|
||||
// Erik - I had to add the exclamation point. Can we be sure that the 'find' will not return undefined?
|
||||
const userScopes = permissions.find((p: Permission) => p.username === username)!.scopes;
|
||||
if (approve) {
|
||||
userScopes.push(...scopes);
|
||||
}
|
||||
try {
|
||||
await AccountServiceClient.Instance.doPut(`/resources/${id}/permissions`, { data: [{ username: username, scopes: userScopes }] })
|
||||
await AccountService.doPut(`/resources/${id}/permissions`, [{ username: username, scopes: userScopes }] )
|
||||
ContentAlert.success(Msg.localize('shareSuccess'));
|
||||
this.props.onClose();
|
||||
} catch (e) {
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import {AxiosResponse} from 'axios';
|
||||
|
||||
import {
|
||||
DataList,
|
||||
|
@ -34,7 +33,7 @@ import {
|
|||
|
||||
import { Remove2Icon } from '@patternfly/react-icons';
|
||||
|
||||
import {AccountServiceClient} from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import {PermissionRequest} from "./PermissionRequest";
|
||||
import {ShareTheResource} from "./ShareTheResource";
|
||||
import {Permission, Resource} from "./MyResourcesPage";
|
||||
|
@ -65,10 +64,10 @@ export class ResourcesTable extends AbstractResourcesTable<CollapsibleResourcesT
|
|||
};
|
||||
|
||||
private fetchPermissions(resource: Resource, row: number): void {
|
||||
AccountServiceClient.Instance.doGet('resources/' + resource._id + '/permissions')
|
||||
.then((response: AxiosResponse<Permission[]>) => {
|
||||
AccountService.doGet(`/resources/${resource._id}/permissions`)
|
||||
.then((response: HttpResponse<Permission[]>) => {
|
||||
const newPermissions: Map<number, Permission[]> = new Map(this.state.permissions);
|
||||
newPermissions.set(row, response.data);
|
||||
newPermissions.set(row, response.data || []);
|
||||
this.setState({permissions: newPermissions});
|
||||
}
|
||||
);
|
||||
|
@ -76,7 +75,7 @@ export class ResourcesTable extends AbstractResourcesTable<CollapsibleResourcesT
|
|||
|
||||
private removeShare(resource: Resource, row: number): void {
|
||||
const permissions = this.state.permissions.get(row)!.map(a => ({ username: a.username, scopes: [] }));
|
||||
AccountServiceClient.Instance.doPut(`/resources/${resource._id}/permissions`, { data: permissions })
|
||||
AccountService.doPut(`/resources/${resource._id}/permissions`, permissions)
|
||||
.then(() => {
|
||||
ContentAlert.success(Msg.localize('shareSuccess'));
|
||||
this.onToggle(row);
|
||||
|
@ -159,8 +158,8 @@ export class ResourcesTable extends AbstractResourcesTable<CollapsibleResourcesT
|
|||
<Level gutter='md'>
|
||||
<LevelItem><span/></LevelItem>
|
||||
<LevelItem>
|
||||
<ShareTheResource resource={resource}
|
||||
permissions={this.state.permissions.get(row)!}
|
||||
<ShareTheResource resource={resource}
|
||||
permissions={this.state.permissions.get(row)!}
|
||||
sharedWithUsersMsg={this.sharedWithUsersMessage(row)}
|
||||
onClose={this.fetchPermissions.bind(this)}
|
||||
row={row}/>
|
||||
|
|
|
@ -16,16 +16,16 @@
|
|||
|
||||
import * as React from 'react';
|
||||
|
||||
import {
|
||||
Button,
|
||||
import {
|
||||
Button,
|
||||
Chip,
|
||||
ChipGroup,
|
||||
ChipGroupToolbarItem,
|
||||
Form,
|
||||
FormGroup,
|
||||
Form,
|
||||
FormGroup,
|
||||
Gallery,
|
||||
GalleryItem,
|
||||
Modal,
|
||||
Modal,
|
||||
Stack,
|
||||
StackItem,
|
||||
TextInput
|
||||
|
@ -33,7 +33,7 @@ import {
|
|||
|
||||
import { ShareAltIcon } from '@patternfly/react-icons';
|
||||
|
||||
import {AccountServiceClient} from '../../account-service/account.service';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import { Resource, Permission, Scope } from './MyResourcesPage';
|
||||
import { Msg } from '../../widgets/Msg';
|
||||
import {ContentAlert} from '../ContentAlert';
|
||||
|
@ -63,7 +63,7 @@ export class ShareTheResource extends React.Component<ShareTheResourceProps, Sha
|
|||
public constructor(props: ShareTheResourceProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
permissionsSelected: [],
|
||||
permissionsUnSelected: this.props.resource.scopes,
|
||||
|
@ -83,23 +83,23 @@ export class ShareTheResource extends React.Component<ShareTheResourceProps, Sha
|
|||
|
||||
private handleAddPermission = () => {
|
||||
const rscId: string = this.props.resource._id;
|
||||
const newPermissions: string[] = [];
|
||||
|
||||
const newPermissions: string[] = [];
|
||||
|
||||
for (const permission of this.state.permissionsSelected) {
|
||||
newPermissions.push(permission.name);
|
||||
}
|
||||
|
||||
const permissions = [];
|
||||
|
||||
|
||||
for (const username of this.state.usernames) {
|
||||
permissions.push({username: username, scopes: newPermissions});
|
||||
}
|
||||
|
||||
this.handleToggleDialog();
|
||||
|
||||
AccountServiceClient.Instance.doPut('/resources/' + rscId + '/permissions', {data: permissions})
|
||||
AccountService.doPut(`/resources/${rscId}/permissions`, permissions)
|
||||
.then(() => {
|
||||
ContentAlert.success(Msg.localize('shareSuccess'));
|
||||
ContentAlert.success('shareSuccess');
|
||||
this.props.onClose(this.props.resource, this.props.row);
|
||||
})
|
||||
};
|
||||
|
@ -217,9 +217,9 @@ export class ShareTheResource extends React.Component<ShareTheResourceProps, Sha
|
|||
<Msg msgKey="add"/>
|
||||
</Button>
|
||||
</GalleryItem>
|
||||
|
||||
|
||||
</Gallery>
|
||||
<ChipGroup>
|
||||
<ChipGroup withToolbar>
|
||||
<ChipGroupToolbarItem key='users-selected' categoryName='Share with '>
|
||||
{this.state.usernames.map((currentChip: string) => (
|
||||
<Chip key={currentChip} onClick={() => this.handleDeleteUsername(currentChip)}>
|
||||
|
@ -234,7 +234,7 @@ export class ShareTheResource extends React.Component<ShareTheResourceProps, Sha
|
|||
fieldId="permissions-selected"
|
||||
>
|
||||
{this.state.permissionsSelected.length < 1 && <strong>Select permissions below:</strong>}
|
||||
<ChipGroup>
|
||||
<ChipGroup withToolbar>
|
||||
<ChipGroupToolbarItem key='permissions-selected' categoryName='Grant Permissions '>
|
||||
{this.state.permissionsSelected.map((currentChip: Scope) => (
|
||||
<Chip key={currentChip.toString()} onClick={() => this.handleSelectPermission(currentChip)}>
|
||||
|
@ -248,7 +248,7 @@ export class ShareTheResource extends React.Component<ShareTheResourceProps, Sha
|
|||
label=""
|
||||
fieldId="permissions-not-selected"
|
||||
>
|
||||
<ChipGroup>
|
||||
<ChipGroup withToolbar>
|
||||
<ChipGroupToolbarItem key='permissions-unselected' categoryName='Not Selected '>
|
||||
{this.state.permissionsUnSelected.map((currentChip: Scope) => (
|
||||
<Chip key={currentChip.toString()} onClick={() => this.handleSelectPermission(currentChip)}>
|
||||
|
@ -264,7 +264,7 @@ export class ShareTheResource extends React.Component<ShareTheResourceProps, Sha
|
|||
<StackItem isFilled>
|
||||
{this.props.sharedWithUsersMsg}
|
||||
</StackItem>
|
||||
|
||||
|
||||
</Stack>
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
|
|
|
@ -78,20 +78,22 @@ export class SharedResourcesTable extends AbstractResourcesTable<ResourcesTableS
|
|||
<a href={resource.client.baseUrl}>{this.getClientName(resource.client)}</a>
|
||||
</DataListCell>,
|
||||
<DataListCell key={'permissions-' + row} width={2}>
|
||||
<ChipGroup>
|
||||
{ resource.scopes.length > 0 &&
|
||||
<ChipGroup withToolbar>
|
||||
<ChipGroupToolbarItem key='permissions' categoryName={Msg.localize('permissions')}>
|
||||
{
|
||||
resource.scopes.length > 0 && resource.scopes.map(scope => (
|
||||
resource.scopes.map(scope => (
|
||||
<Chip key={scope.name} isReadOnly>
|
||||
{scope.displayName || scope.name}
|
||||
</Chip>
|
||||
))
|
||||
}
|
||||
</ChipGroupToolbarItem>
|
||||
</ChipGroup>
|
||||
</ChipGroup>}
|
||||
</DataListCell>,
|
||||
<DataListCell key={'pending-' + row} width={2}>
|
||||
{resource.shareRequests.length > 0 &&
|
||||
<ChipGroup withToolbar>
|
||||
<ChipGroupToolbarItem key='permissions' categoryName={Msg.localize('pending')}>
|
||||
{
|
||||
resource.shareRequests[0].scopes.map(scope => (
|
||||
|
@ -101,6 +103,7 @@ export class SharedResourcesTable extends AbstractResourcesTable<ResourcesTableS
|
|||
))
|
||||
}
|
||||
</ChipGroupToolbarItem>
|
||||
</ChipGroup>
|
||||
}
|
||||
</DataListCell>
|
||||
]}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
|
@ -10,11 +10,11 @@ import {EmptyState, EmptyStateBody, EmptyStateIcon, Title, TitleLevel} from '@pa
|
|||
import { WarningTriangleIcon } from '@patternfly/react-icons';
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom';
|
||||
import {Msg} from '../../widgets/Msg';
|
||||
|
||||
|
||||
export interface PageNotFoundProps extends RouteComponentProps {}
|
||||
|
||||
|
||||
class PgNotFound extends React.Component<PageNotFoundProps> {
|
||||
|
||||
|
||||
public constructor(props: PageNotFoundProps) {
|
||||
super(props);
|
||||
}
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as moment from 'moment';
|
||||
import {AxiosResponse} from 'axios';
|
||||
|
||||
import {AccountServiceClient} from '../../account-service/account.service';
|
||||
import {Msg} from '../../widgets/Msg';
|
||||
|
||||
export interface PasswordPageProps {
|
||||
}
|
||||
|
||||
interface FormFields {
|
||||
readonly currentPassword?: string;
|
||||
readonly newPassword?: string;
|
||||
readonly confirmation?: string;
|
||||
}
|
||||
|
||||
interface PasswordPageState {
|
||||
readonly canSubmit: boolean;
|
||||
readonly registered: boolean;
|
||||
readonly lastUpdate: number;
|
||||
readonly formFields: FormFields;
|
||||
}
|
||||
|
||||
export class PasswordPage extends React.Component<PasswordPageProps, PasswordPageState> {
|
||||
public state: PasswordPageState = {
|
||||
canSubmit: false,
|
||||
registered: false,
|
||||
lastUpdate: -1,
|
||||
formFields: {currentPassword: '',
|
||||
newPassword: '',
|
||||
confirmation: ''}
|
||||
}
|
||||
|
||||
public constructor(props: PasswordPageProps) {
|
||||
super(props);
|
||||
|
||||
AccountServiceClient.Instance.doGet("/credentials/password")
|
||||
.then((response: AxiosResponse<PasswordPageState>) => {
|
||||
this.setState({...response.data});
|
||||
console.log({response});
|
||||
});
|
||||
}
|
||||
|
||||
private handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const target: HTMLInputElement = event.target;
|
||||
const value: string = target.value;
|
||||
const name: string = target.name;
|
||||
this.setState({
|
||||
canSubmit: this.requiredFieldsHaveData(name, value),
|
||||
registered: this.state.registered,
|
||||
lastUpdate: this.state.lastUpdate,
|
||||
formFields: {...this.state.formFields, [name]: value}
|
||||
});
|
||||
}
|
||||
|
||||
private handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||
event.preventDefault();
|
||||
const reqData: FormFields = {...this.state.formFields};
|
||||
AccountServiceClient.Instance.doPost("/credentials/password", {data: reqData})
|
||||
.then((response: AxiosResponse<FormFields>) => {
|
||||
this.setState({canSubmit: false});
|
||||
alert('Data posted:' + response.statusText);
|
||||
});
|
||||
}
|
||||
|
||||
private requiredFieldsHaveData(fieldName: string, newValue: string): boolean {
|
||||
const fields: FormFields = {...this.state.formFields};
|
||||
fields[fieldName] = newValue;
|
||||
for (const field of Object.keys(fields)) {
|
||||
if (!fields[field]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const displayNone = {display: 'none'};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="page-header">
|
||||
<h1 id="pageTitle"><Msg msgKey="changePasswordHtmlTitle"/></h1>
|
||||
</div>
|
||||
|
||||
<div className="col-sm-12 card-pf">
|
||||
<div className="card-pf-body p-b" id="passwordLastUpdate">
|
||||
<span className="i pficon pficon-info"></span>
|
||||
<Msg msgKey="passwordLastUpdateMessage" /> <strong>{moment(this.state.lastUpdate).format('LLLL')}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-sm-12 card-pf">
|
||||
<div className="card-pf-body row">
|
||||
<div className="col-sm-4 col-md-4">
|
||||
<div className="card-pf-subtitle" id="updatePasswordSubTitle">
|
||||
<Msg msgKey="updatePasswordTitle"/>
|
||||
</div>
|
||||
<div className="introMessage" id="updatePasswordSubMessage">
|
||||
<strong><Msg msgKey="updatePasswordMessageTitle"/></strong>
|
||||
<p><Msg msgKey="updatePasswordMessage"/></p>
|
||||
</div>
|
||||
<div className="subtitle"><span className="required">*</span> <Msg msgKey="requiredFields"/></div>
|
||||
</div>
|
||||
<div className="col-sm-6 col-md-6">
|
||||
<form onSubmit={this.handleSubmit} className="form-horizontal">
|
||||
<input readOnly value="this is not a login form" style={displayNone} type="text"/>
|
||||
<input readOnly value="this is not a login form" style={displayNone} type="password"/>
|
||||
<div className="form-group">
|
||||
<label htmlFor="password" className="control-label"><Msg msgKey="currentPassword"/></label><span className="required">*</span>
|
||||
<input onChange={this.handleChange} className="form-control" name="currentPassword" autoFocus autoComplete="off" type="password"/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="password-new" className="control-label"><Msg msgKey="passwordNew"/></label><span className="required">*</span>
|
||||
<input onChange={this.handleChange} className="form-control" id="newPassword" name="newPassword" autoComplete="off" type="password"/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="password-confirm" className="control-label"><Msg msgKey="passwordConfirm"/></label><span className="required">*</span>
|
||||
<input onChange={this.handleChange} className="form-control" id="confirmation" name="confirmation" autoComplete="off" type="password"/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<div id="kc-form-buttons" className="submit">
|
||||
<div className="">
|
||||
<button disabled={!this.state.canSubmit}
|
||||
type="submit"
|
||||
className="btn btn-primary btn-lg"
|
||||
name="submitAction"><Msg msgKey="doSave"/></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as moment from 'moment';
|
||||
import {AxiosResponse} from 'axios';
|
||||
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom';
|
||||
import {
|
||||
|
@ -34,7 +32,8 @@ import {
|
|||
} from '@patternfly/react-core';
|
||||
|
||||
import {AIACommand} from '../../util/AIACommand';
|
||||
import {AccountServiceClient} from '../../account-service/account.service';
|
||||
import TimeUtil from '../../util/TimeUtil';
|
||||
import AccountService, {HttpResponse} from '../../account-service/account.service';
|
||||
import {ContinueCancelModal} from '../../widgets/ContinueCancelModal';
|
||||
import {Features} from '../../widgets/features';
|
||||
import {Msg} from '../../widgets/Msg';
|
||||
|
@ -96,11 +95,12 @@ class SigningInPage extends React.Component<SigningInPageProps, SigningInPageSta
|
|||
}
|
||||
|
||||
private getCredentialContainers(): void {
|
||||
AccountServiceClient.Instance.doGet("/credentials")
|
||||
.then((response: AxiosResponse<CredentialContainer[]>) => {
|
||||
AccountService.doGet("/credentials")
|
||||
.then((response: HttpResponse<CredentialContainer[]>) => {
|
||||
|
||||
const allContainers: CredContainerMap = new Map();
|
||||
response.data.forEach(container => {
|
||||
const containers: CredentialContainer[] = response.data || [];
|
||||
containers.forEach(container => {
|
||||
let categoryMap = allContainers.get(container.category);
|
||||
if (!categoryMap) {
|
||||
categoryMap = new Map();
|
||||
|
@ -115,7 +115,7 @@ class SigningInPage extends React.Component<SigningInPageProps, SigningInPageSta
|
|||
}
|
||||
|
||||
private handleRemove = (credentialId: string, userLabel: string) => {
|
||||
AccountServiceClient.Instance.doDelete("/credentials/" + credentialId)
|
||||
AccountService.doDelete("/credentials/" + credentialId)
|
||||
.then(() => {
|
||||
this.getCredentialContainers();
|
||||
ContentAlert.success('successRemovedMessage', [userLabel]);
|
||||
|
@ -200,7 +200,9 @@ class SigningInPage extends React.Component<SigningInPageProps, SigningInPageSta
|
|||
|
||||
userCredentials.forEach(credential => {
|
||||
if (!credential.userLabel) credential.userLabel = Msg.localize(credential.type);
|
||||
if (credential.hasOwnProperty('createdDate') && credential.createdDate! > 0) credential.strCreatedDate = moment(credential.createdDate).format('LLL');
|
||||
if (credential.hasOwnProperty('createdDate') && credential.createdDate && credential.createdDate! > 0) {
|
||||
credential.strCreatedDate = TimeUtil.format(credential.createdDate as number);
|
||||
}
|
||||
});
|
||||
|
||||
let updateAIA: AIACommand;
|
||||
|
|
|
@ -29,13 +29,13 @@ export class KeycloakService {
|
|||
private static instance: KeycloakService = new KeycloakService();
|
||||
|
||||
private constructor() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static get Instance(): KeycloakService {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure and initialize the Keycloak adapter.
|
||||
*
|
||||
|
@ -58,7 +58,7 @@ export class KeycloakService {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public authenticated(): boolean {
|
||||
return KeycloakService.keycloakAuth.authenticated ? KeycloakService.keycloakAuth.authenticated : false;
|
||||
}
|
||||
|
@ -74,12 +74,12 @@ export class KeycloakService {
|
|||
public account(): void {
|
||||
KeycloakService.keycloakAuth.accountManagement();
|
||||
}
|
||||
|
||||
|
||||
public authServerUrl(): string | undefined {
|
||||
const authServerUrl = KeycloakService.keycloakAuth.authServerUrl;
|
||||
return authServerUrl!.charAt(authServerUrl!.length - 1) === '/' ? authServerUrl : authServerUrl + '/';
|
||||
}
|
||||
|
||||
|
||||
public realm(): string | undefined {
|
||||
return KeycloakService.keycloakAuth.realm;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
declare const locale: string;
|
||||
|
||||
/**
|
||||
* @author Stan Silvert
|
||||
*/
|
||||
class TimeUtil {
|
||||
private options = { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' };
|
||||
private formatter: Intl.DateTimeFormat;
|
||||
|
||||
constructor() {
|
||||
try {
|
||||
this.formatter = new Intl.DateTimeFormat(locale, this.options);
|
||||
} catch(e) {
|
||||
// unknown locale falling back to English
|
||||
this.formatter = new Intl.DateTimeFormat('en', this.options);
|
||||
}
|
||||
}
|
||||
|
||||
format(time: number): string {
|
||||
return this.formatter.format(time);
|
||||
}
|
||||
}
|
||||
|
||||
const TimeUtilInstance: TimeUtil = new TimeUtil();
|
||||
export default TimeUtilInstance as TimeUtil;
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -17,7 +17,7 @@
|
|||
import * as React from 'react';
|
||||
import { Modal, Button, ButtonProps } from '@patternfly/react-core';
|
||||
import {Msg} from './Msg';
|
||||
|
||||
|
||||
/**
|
||||
* For any of these properties that are strings, you can
|
||||
* pass in a localization key instead of a static string.
|
||||
|
@ -41,7 +41,7 @@ interface ContinueCancelModalState {
|
|||
/**
|
||||
* This class renders a button that provides a continue/cancel modal dialog when clicked. If the user selects 'Continue'
|
||||
* then the onContinue function is executed.
|
||||
*
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc.
|
||||
*/
|
||||
export class ContinueCancelModal extends React.Component<ContinueCancelModalProps, ContinueCancelModalState> {
|
||||
|
@ -51,7 +51,7 @@ export class ContinueCancelModal extends React.Component<ContinueCancelModalProp
|
|||
modalCancelButtonLabel: 'doCancel',
|
||||
isDisabled: false
|
||||
};
|
||||
|
||||
|
||||
public constructor(props: ContinueCancelModalProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -23,15 +23,15 @@ import {
|
|||
import { Msg } from './Msg';
|
||||
|
||||
interface AvailableLocale {
|
||||
locale: string;
|
||||
locale: string;
|
||||
label: string;
|
||||
};
|
||||
declare const availableLocales: [AvailableLocale];
|
||||
|
||||
interface LocaleSelectorProps extends FormSelectProps { }
|
||||
interface LocaleSelectorProps extends Omit<FormSelectProps, 'children'> { }
|
||||
interface LocaleSelectorState { }
|
||||
export class LocaleSelector extends React.Component<LocaleSelectorProps, LocaleSelectorState> {
|
||||
|
||||
|
||||
constructor(props: LocaleSelectorProps) {
|
||||
super(props);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ export class LocaleSelector extends React.Component<LocaleSelectorProps, LocaleS
|
|||
onChange={(value, event) => { if (this.props.onChange) this.props.onChange(value, event) }}
|
||||
aria-label={Msg.localize('selectLocale')}
|
||||
>
|
||||
{availableLocales.map((locale, index) =>
|
||||
{availableLocales.map((locale, index) =>
|
||||
<FormSelectOption
|
||||
key={index}
|
||||
value={locale.locale}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -20,13 +20,13 @@ import {Msg} from './Msg';
|
|||
import {KeycloakService} from '../keycloak-service/keycloak.service';
|
||||
|
||||
import {Button, DropdownItem} from '@patternfly/react-core';
|
||||
|
||||
|
||||
declare const baseUrl: string;
|
||||
|
||||
function handleLogout(): void {
|
||||
KeycloakService.Instance.logout(baseUrl);
|
||||
}
|
||||
|
||||
|
||||
interface LogoutProps {}
|
||||
export class LogoutButton extends React.Component<LogoutProps> {
|
||||
public render(): React.ReactNode {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -15,20 +15,20 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
|
||||
declare const l18nMsg: {[key: string]: string};
|
||||
|
||||
export interface MsgProps {
|
||||
readonly msgKey: string;
|
||||
readonly params?: string[];
|
||||
}
|
||||
|
||||
|
||||
export class Msg extends React.Component<MsgProps> {
|
||||
|
||||
public constructor(props: MsgProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
|
||||
public render(): React.ReactNode {
|
||||
if (this.props.children) {
|
||||
return Msg.localizeWithChildren(this.props.msgKey, this.props.children);
|
||||
|
@ -46,11 +46,11 @@ export class Msg extends React.Component<MsgProps> {
|
|||
[parts[i], child, count === i + 1 ? parts[count] : '']
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static localize(msgKey: string, params?: string[]): string {
|
||||
let message: string = l18nMsg[this.processKey(msgKey)];
|
||||
if (message === undefined) message = msgKey;
|
||||
|
||||
|
||||
if ((params !== undefined) && (params.length > 0)) {
|
||||
params.forEach((value: string, index: number) => {
|
||||
value = this.processParam(value);
|
||||
|
@ -68,17 +68,17 @@ export class Msg extends React.Component<MsgProps> {
|
|||
// remove Freemarker syntax
|
||||
return msgKey.substring(2, msgKey.length - 1);
|
||||
}
|
||||
|
||||
|
||||
// if the param has Freemarker syntax, try to look up its value
|
||||
private static processParam(param: string): string {
|
||||
if (!(param.startsWith('${') && param.endsWith('}'))) return param;
|
||||
|
||||
// remove Freemarker syntax
|
||||
const key: string = param.substring(2, param.length - 1);
|
||||
|
||||
|
||||
let value: string = l18nMsg[key];
|
||||
if (value === undefined) return param;
|
||||
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -20,7 +20,7 @@ import {Msg} from '../widgets/Msg';
|
|||
|
||||
import {DropdownItem} from '@patternfly/react-core';
|
||||
import {ArrowIcon} from '@patternfly/react-icons';
|
||||
|
||||
|
||||
declare const referrerName: string;
|
||||
declare const referrerUri: string;
|
||||
|
||||
|
@ -31,13 +31,13 @@ export interface ReferrerDropdownItemProps {
|
|||
* @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.
|
||||
*/
|
||||
export class ReferrerDropdownItem extends React.Component<ReferrerDropdownItemProps> {
|
||||
|
||||
|
||||
public constructor(props: ReferrerDropdownItemProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
||||
|
||||
return (
|
||||
<DropdownItem id="referrerMobileLink" href={referrerUri}>
|
||||
<ArrowIcon /> {Msg.localize('backTo', [referrerName])}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
import * as React from 'react';
|
||||
|
||||
import {Msg} from '../widgets/Msg';
|
||||
import {Msg} from './Msg';
|
||||
|
||||
import {ArrowIcon} from '@patternfly/react-icons';
|
||||
|
||||
|
@ -30,7 +30,7 @@ export interface ReferrerLinkProps {
|
|||
* @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.
|
||||
*/
|
||||
export class ReferrerLink extends React.Component<ReferrerLinkProps> {
|
||||
|
||||
|
||||
public constructor(props: ReferrerLinkProps) {
|
||||
super(props);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ var content = [
|
|||
id: 'personal-info',
|
||||
path: 'personal-info',
|
||||
label: 'personalInfoHtmlTitle',
|
||||
modulePath: '/app/content/account-page/AccountPage',
|
||||
modulePath: '/app/content/account-page/AccountPage.js',
|
||||
componentName: 'AccountPage'
|
||||
},
|
||||
{
|
||||
|
@ -15,35 +15,21 @@ var content = [
|
|||
id: 'signingin',
|
||||
path: 'security/signingin',
|
||||
label: 'signingIn',
|
||||
modulePath: '/app/content/signingin-page/SigningInPage',
|
||||
modulePath: '/app/content/signingin-page/SigningInPage.js',
|
||||
componentName: 'SigningInPage',
|
||||
},
|
||||
/* {
|
||||
path: 'security/password',
|
||||
label: 'password',
|
||||
modulePath: '/app/content/aia-page/AppInitiatedActionPage',
|
||||
componentName: 'AppInitiatedActionPage',
|
||||
kcAction: 'UPDATE_PASSWORD'
|
||||
},
|
||||
{
|
||||
path: 'security/authenticator',
|
||||
label: 'authenticator',
|
||||
modulePath: '/app/content/aia-page/AppInitiatedActionPage',
|
||||
componentName: 'AppInitiatedActionPage',
|
||||
kcAction: 'CONFIGURE_TOTP'
|
||||
}, */
|
||||
{
|
||||
id: 'device-activity',
|
||||
path: 'security/device-activity',
|
||||
label: 'device-activity',
|
||||
modulePath: '/app/content/device-activity-page/DeviceActivityPage',
|
||||
modulePath: '/app/content/device-activity-page/DeviceActivityPage.js',
|
||||
componentName: 'DeviceActivityPage'
|
||||
},
|
||||
{
|
||||
id: 'linked-accounts',
|
||||
path: 'security/linked-accounts',
|
||||
label: 'linkedAccountsHtmlTitle',
|
||||
modulePath: '/app/content/linked-accounts-page/LinkedAccountsPage',
|
||||
modulePath: '/app/content/linked-accounts-page/LinkedAccountsPage.js',
|
||||
componentName: 'LinkedAccountsPage',
|
||||
hidden: !features.isLinkedAccountsEnabled
|
||||
}
|
||||
|
@ -53,14 +39,14 @@ var content = [
|
|||
id: 'applications',
|
||||
path: 'applications',
|
||||
label: 'applications',
|
||||
modulePath: '/app/content/applications-page/ApplicationsPage',
|
||||
modulePath: '/app/content/applications-page/ApplicationsPage.js',
|
||||
componentName: 'ApplicationsPage'
|
||||
},
|
||||
{
|
||||
id: 'resources',
|
||||
path: 'resources',
|
||||
label: 'resources',
|
||||
modulePath: '/app/content/my-resources-page/MyResourcesPage',
|
||||
modulePath: '/app/content/my-resources-page/MyResourcesPage.js',
|
||||
componentName: 'MyResourcesPage',
|
||||
hidden: !features.isMyResourcesEnabled
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,31 +3,34 @@
|
|||
"version": "1.0.0",
|
||||
"description": "keycloak-preview account management written in React",
|
||||
"scripts": {
|
||||
"build": "tsc --noImplicitAny --strictNullChecks --jsx react -p ./ && npm run lint",
|
||||
"build:watch": "tsc --noImplicitAny --strictNullChecks --jsx react -p ./ -w",
|
||||
"lint": "eslint --ignore-pattern *.d.ts ./**/*.ts*"
|
||||
"build": "snowpack && npm run check-types && npm run babel",
|
||||
"babel": "babel --source-maps --extensions \".js,.ts,.tsx\" app/ --out-dir app/",
|
||||
"babel:watch": "npm run babel -- --watch",
|
||||
"check-types": "tsc --noImplicitAny --strictNullChecks --jsx react -p ./",
|
||||
"check-types:watch": "npm run check-types -- -w",
|
||||
"lint": "eslint ./app/**/*.ts*"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Stan Silvert",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@patternfly/patternfly": "^2.26.5",
|
||||
"@patternfly/react-core": "^3.35.0",
|
||||
"@types/node": "^12.7.2",
|
||||
"axios": "^0.19.0",
|
||||
"moment": "^2.22.2",
|
||||
"querystring": "^0.2.0",
|
||||
"react": "^16.8.5",
|
||||
"react-dom": "^16.8.5",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"systemjs": "^0.20.17",
|
||||
"systemjs-plugin-babel": "0.0.25"
|
||||
"@patternfly/react-core": "^3.153.3",
|
||||
"@patternfly/react-icons": "^3.15.16",
|
||||
"react": "npm:@pika/react@^16.13.1",
|
||||
"react-dom": "npm:@pika/react-dom@^16.13.1",
|
||||
"react-router-dom": "^4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^16.8.8",
|
||||
"@types/react-dom": "^16.8.3",
|
||||
"@babel/cli": "^7.8.4",
|
||||
"@babel/core": "^7.8.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.7",
|
||||
"@babel/preset-react": "^7.8.3",
|
||||
"@babel/preset-typescript": "^7.8.3",
|
||||
"@types/node": "^13.9.8",
|
||||
"@types/react": "^16.9.23",
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"@types/react-router-dom": "^4.3.1",
|
||||
"@types/systemjs": "^0.20.6",
|
||||
"@typescript-eslint/eslint-plugin": "^1.4.2",
|
||||
"@typescript-eslint/parser": "^1.4.2",
|
||||
"babel-eslint": "^9.0.0",
|
||||
|
@ -37,7 +40,10 @@
|
|||
"eslint-plugin-import": "^2.16.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.1",
|
||||
"eslint-plugin-react": "^7.12.4",
|
||||
"typescript": "^3.3.3333"
|
||||
"rollup-plugin-copy": "^3.3.0",
|
||||
"rollup-plugin-postcss": "^2.5.0",
|
||||
"snowpack": "^1.7.0",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"repository": {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
const copy = require('rollup-plugin-copy');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
|
||||
module.exports = {
|
||||
rollup: {
|
||||
plugins: [
|
||||
postcss({
|
||||
extract: 'public/app.css'
|
||||
}),
|
||||
copy({
|
||||
targets: [
|
||||
{ src: 'node_modules/@patternfly/react-core/dist/styles/base.css', dest: 'public/' },
|
||||
{ src: 'node_modules/@patternfly/react-core/dist/styles/assets/fonts/overpass-webfont/overpass*.woff2', dest: 'public/assets/fonts/overpass-webfont/'},
|
||||
{ src: 'node_modules/@patternfly/react-core/dist/styles/assets/pficon/pficon.woff2', dest: 'public/assets/pficon/'},
|
||||
],
|
||||
})
|
||||
]
|
||||
}
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Add barrels and stuff
|
||||
* Adjust as necessary for your application needs.
|
||||
*/
|
||||
// (function (global) {
|
||||
// System.config({
|
||||
// packages: {
|
||||
// // add packages here
|
||||
// }
|
||||
// });
|
||||
// })(this);
|
File diff suppressed because it is too large
Load diff
|
@ -2,6 +2,7 @@
|
|||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"noEmit": true,
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
|
@ -13,7 +14,7 @@
|
|||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"include": [
|
||||
"./**/*.ts?"
|
||||
"./app/**/*.ts?"
|
||||
],
|
||||
"files": [
|
||||
"../../../../../../../../adapters/oidc/js/src/main/resources/keycloak.d.ts"
|
||||
|
|
Loading…
Reference in a new issue