diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 1c103c695..749267367 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -66,6 +66,10 @@ action.custom-entity-attributes=Custom Entity Attributes action.enable=Enable action.disable=Disable +action.add-new-role=Add new role +action.roles=Roles +action.source-role=Role + value.enabled=Enabled value.disabled=Disabled value.current=Current @@ -483,6 +487,16 @@ label.by=By label.source=Metadata Source label.provider=Metadata Provider +label.roles-management=Role Management +label.new-role=New Role +label.role-name=Role Name +label.role-description=Role Description +label.role=Role + +message.delete-role-title=Delete Role? + +message.delete-role-body=You are requesting to delete a role. If you complete this process the role will be removed. This cannot be undone. Do you wish to continue? + message.delete-user-title=Delete User? message.delete-user-body=You are requesting to delete a user. If you complete this process the user will be removed. This cannot be undone. Do you wish to continue? @@ -669,4 +683,7 @@ tooltip.match=A regular expression against which the entityID is evaluated. tooltip.remove-existing-formats=Whether to remove any existing formats from a role if any are added by the filter (unmodified roles will be untouched regardless of this setting) tooltip.nameid-formats-format=Format tooltip.nameid-formats-value=Value -tooltip.nameid-formats-type=Type \ No newline at end of file +tooltip.nameid-formats-type=Type + +tooltip.role-name=Role Name +tooltip.role-description=Role Description \ No newline at end of file diff --git a/ui/public/assets/schema/roles/role.json b/ui/public/assets/schema/roles/role.json new file mode 100644 index 000000000..8145fae88 --- /dev/null +++ b/ui/public/assets/schema/roles/role.json @@ -0,0 +1,15 @@ +{ + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "title": "label.role-name", + "description": "tooltip.role-name", + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } +} \ No newline at end of file diff --git a/ui/src/app/App.js b/ui/src/app/App.js index 5d0c4e1e4..c65324bb9 100644 --- a/ui/src/app/App.js +++ b/ui/src/app/App.js @@ -26,6 +26,7 @@ import { NewProvider } from './metadata/new/NewProvider'; import { Filter } from './metadata/Filter'; import { Contention } from './metadata/contention/ContentionContext'; import { SessionModal } from './core/user/SessionModal'; +import { Roles } from './admin/Roles'; import Button from 'react-bootstrap/Button'; @@ -79,6 +80,7 @@ function App() { + diff --git a/ui/src/app/admin/Roles.js b/ui/src/app/admin/Roles.js new file mode 100644 index 000000000..08daed90d --- /dev/null +++ b/ui/src/app/admin/Roles.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { Switch, Route, useRouteMatch, Redirect } from 'react-router-dom'; +import { RolesProvider } from './hoc/RolesProvider'; +import { NewRole } from './container/NewRole'; +import { EditRole } from './container/EditRole'; +import { RoleList } from './container/RoleList'; + +export function Roles() { + + let { path } = useRouteMatch(); + + return ( + <> + + + + {(roles, onDelete) => + + } + + } /> + + + } /> + + + } /> + + + + ); +} \ No newline at end of file diff --git a/ui/src/app/admin/component/RoleForm.js b/ui/src/app/admin/component/RoleForm.js new file mode 100644 index 000000000..074cb5b09 --- /dev/null +++ b/ui/src/app/admin/component/RoleForm.js @@ -0,0 +1,68 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import Form from '@rjsf/bootstrap-4'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSpinner, faSave } from '@fortawesome/free-solid-svg-icons'; +import Translate from '../../i18n/components/translate'; + +import { useRoleUiSchema } from '../hooks'; +import { fields, widgets } from '../../form/component'; +import { templates } from '../../form/component'; +import { FormContext, setFormDataAction, setFormErrorAction } from '../../form/FormManager'; + +function ErrorListTemplate() { + return (<>); +} + +export function RoleForm({ role = {}, errors = [], loading = false, schema, onSave, onCancel }) { + + const { dispatch } = React.useContext(FormContext); + const onChange = ({ formData, errors }) => { + dispatch(setFormDataAction(formData)); + dispatch(setFormErrorAction(errors)); + }; + + const uiSchema = useRoleUiSchema(); + + return (<> +
+
+ + + + +
+
+
+
+
onChange(form)} + schema={schema} + uiSchema={uiSchema} + FieldTemplate={templates.FieldTemplate} + ObjectFieldTemplate={templates.ObjectFieldTemplate} + ArrayFieldTemplate={templates.ArrayFieldTemplate} + fields={fields} + widgets={widgets} + liveValidate={true} + ErrorList={ErrorListTemplate}> + <> +
+
+
+
+ ) +} +/**/ \ No newline at end of file diff --git a/ui/src/app/admin/container/EditRole.js b/ui/src/app/admin/container/EditRole.js new file mode 100644 index 000000000..cc8d802ed --- /dev/null +++ b/ui/src/app/admin/container/EditRole.js @@ -0,0 +1,91 @@ +import React from 'react'; + +import { Prompt, useHistory } from 'react-router'; +import { useParams } from 'react-router-dom'; +import Translate from '../../i18n/components/translate'; +import { useRoles } from '../hooks'; +import { Schema } from '../../form/Schema'; +import { FormManager } from '../../form/FormManager'; + +import { RoleForm } from '../component/RoleForm'; +import { RoleProvider } from '../hoc/RoleProvider'; +import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications'; +import { useTranslator } from '../../i18n/hooks'; + +export function EditRole() { + + const { id } = useParams(); + + const notifier = useNotificationDispatcher(); + const translator = useTranslator(); + + const history = useHistory(); + + const { put, response, loading } = useRoles(); + + const [blocking, setBlocking] = React.useState(false); + + async function save(role) { + let toast; + const resp = await put(``, role); + if (response.ok) { + gotoDetail({ refresh: true }); + toast = createNotificationAction(`Updated role successfully.`, NotificationTypes.SUCCESS); + } else { + toast = createNotificationAction(`${resp.errorCode} - ${translator(resp.errorMessage)}`, NotificationTypes.ERROR); + } + if (toast) { + notifier(toast); + } + }; + + const cancel = () => { + gotoDetail(); + }; + + const gotoDetail = (state = null) => { + setBlocking(false); + history.push(`/roles`, state); + }; + + return ( +
+ + `message.unsaved-editor` + } + /> +
+
+
+
+ Edit role +
+
+
+
+ + {(role) => + + {(schema) => + <>{role && + + {(data, errors) => + save(data)} + onCancel={() => cancel()} />} + + }} + + } + +
+
+
+ ); +} \ No newline at end of file diff --git a/ui/src/app/admin/container/MetadataActions.js b/ui/src/app/admin/container/MetadataActions.js index 80f43d56a..4500354f4 100644 --- a/ui/src/app/admin/container/MetadataActions.js +++ b/ui/src/app/admin/container/MetadataActions.js @@ -1,5 +1,5 @@ import React from 'react'; -import { DeleteConfirmation } from '../../metadata/component/DeleteConfirmation'; +import { DeleteConfirmation } from '../../core/components/DeleteConfirmation'; import { useMetadataEntity } from '../../metadata/hooks/api'; import { NotificationContext, createNotificationAction } from '../../notifications/hoc/Notifications'; diff --git a/ui/src/app/admin/container/NewRole.js b/ui/src/app/admin/container/NewRole.js new file mode 100644 index 000000000..6d1abfc56 --- /dev/null +++ b/ui/src/app/admin/container/NewRole.js @@ -0,0 +1,79 @@ +import React from 'react'; + +import { Prompt, useHistory } from 'react-router'; +import Translate from '../../i18n/components/translate'; +import { useRoles } from '../hooks'; +import { Schema } from '../../form/Schema'; +import { FormManager } from '../../form/FormManager'; +import { RoleForm } from '../component/RoleForm'; + +import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications'; +import { useTranslator } from '../../i18n/hooks'; + +export function NewRole() { + const history = useHistory(); + const notifier = useNotificationDispatcher(); + const translator = useTranslator(); + + const { post, response, loading } = useRoles({}); + + const [blocking, setBlocking] = React.useState(false); + + async function save(role) { + let toast; + const resp = await post(``, role); + if (response.ok) { + gotoDetail({ refresh: true }); + toast = createNotificationAction(`Added role successfully.`, NotificationTypes.SUCCESS); + } else { + toast = createNotificationAction(`${resp.errorCode} - ${translator(resp.errorMessage)}`, NotificationTypes.ERROR); + } + if (toast) { + notifier(toast); + } + }; + + const cancel = () => { + gotoDetail(); + }; + + const gotoDetail = (state = null) => { + setBlocking(false); + history.push(`/roles`, state); + }; + + return ( +
+ + `message.unsaved-editor` + } + /> +
+
+
+
+ Add a new role +
+
+
+
+ + {(schema) => + + {(data, errors) => + save(data)} + onCancel={() => cancel()} />} + } + +
+
+
+ ); +} \ No newline at end of file diff --git a/ui/src/app/admin/container/RoleList.js b/ui/src/app/admin/container/RoleList.js new file mode 100644 index 000000000..e48851f90 --- /dev/null +++ b/ui/src/app/admin/container/RoleList.js @@ -0,0 +1,78 @@ +import React from 'react'; +import { faEdit, faPlusCircle, faTrash } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import Button from 'react-bootstrap/Button'; +import { Link } from 'react-router-dom'; + +import { Translate } from '../../i18n/components/translate'; + +import { DeleteConfirmation } from '../../core/components/DeleteConfirmation'; + +export function RoleList({ roles, onDelete }) { + + const remove = (id) => { + onDelete(id); + } + + return ( + + {(block) => +
+
+
+
+ + Roles Management + +
+
+
+ +   + Add new role + +
+
+ + + + + + + + + {(roles?.length > 0) ? roles.map((role, i) => + + + + + ) : + + } + +
+ Role Name + Actions
{role.name} + + + + Edit + + + +
No roles defined.
+
+
+
+
+
+ } +
+ ); +} \ No newline at end of file diff --git a/ui/src/app/admin/hoc/RoleProvider.js b/ui/src/app/admin/hoc/RoleProvider.js new file mode 100644 index 000000000..091ac1bd6 --- /dev/null +++ b/ui/src/app/admin/hoc/RoleProvider.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { useRole } from '../hooks'; + +export function RoleProvider({ id, children }) { + + const [role, setRole] = React.useState({id: 'foo'}); + const { get, response } = useRole(id); + + async function loadRole() { + const role = await get(``); + if (response.ok) { + setRole(role); + } + } + + /*eslint-disable react-hooks/exhaustive-deps*/ + React.useEffect(() => { loadRole() }, []); + + return (<>{children(role)}); +} \ No newline at end of file diff --git a/ui/src/app/admin/hoc/RoleProvider.test.js b/ui/src/app/admin/hoc/RoleProvider.test.js new file mode 100644 index 000000000..9c063a41a --- /dev/null +++ b/ui/src/app/admin/hoc/RoleProvider.test.js @@ -0,0 +1,35 @@ +import { render, screen } from "@testing-library/react"; +import { act } from 'react-dom/test-utils'; +import React from 'react'; +import {RoleProvider} from './RoleProvider'; + +import {useRole} from '../hooks'; + +jest.mock('../hooks'); + +describe('RoleProvider component', () => { + + beforeEach(() => { + useRole.mockImplementation(() => { + return { + get: jest.fn().mockResolvedValue({ id: 'foo' }), + response: { + ok: false, + status: 200 + } + }; + }); + }) + + test('should provide the role context', async () => { + act(() => { + render( + {(role) =>
{role?.id}
} +
); + }); + + expect(useRole).toHaveBeenCalled(); + expect(screen.getByText('foo')).toBeInTheDocument(); + }); + +}) \ No newline at end of file diff --git a/ui/src/app/admin/hoc/RolesProvider.js b/ui/src/app/admin/hoc/RolesProvider.js new file mode 100644 index 000000000..e87d96539 --- /dev/null +++ b/ui/src/app/admin/hoc/RolesProvider.js @@ -0,0 +1,42 @@ +import React from 'react'; +import { useRoles } from '../hooks'; +import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications'; +import { useTranslator } from '../../i18n/hooks'; + +export function RolesProvider({ children, cache = 'no-cache' }) { + + const [roles, setRoles] = React.useState([]); + + const notifier = useNotificationDispatcher(); + const translator = useTranslator(); + + const { get, del, response, loading } = useRoles({ + cachePolicy: cache + }); + + async function loadRoles() { + const list = await get(``); + if (response.ok) { + setRoles(list); + } + } + + async function removeRole(id) { + let toast; + const resp = await del(`/${id}`); + if (response.ok) { + loadRoles(); + toast = createNotificationAction(`Deleted role successfully.`, NotificationTypes.SUCCESS); + } else { + toast = createNotificationAction(`${resp.errorCode} - ${translator(resp.errorMessage)}`, NotificationTypes.ERROR); + } + if (toast) { + notifier(toast); + } + } + + /*eslint-disable react-hooks/exhaustive-deps*/ + React.useEffect(() => { loadRoles() }, []); + + return (<>{children(roles, removeRole, loading)}); +} \ No newline at end of file diff --git a/ui/src/app/admin/hoc/RolesProvider.test.js b/ui/src/app/admin/hoc/RolesProvider.test.js new file mode 100644 index 000000000..11c01481e --- /dev/null +++ b/ui/src/app/admin/hoc/RolesProvider.test.js @@ -0,0 +1,43 @@ +import { render, screen } from "@testing-library/react"; +import { act } from 'react-dom/test-utils'; +import React from 'react'; +import { RolesProvider } from './RolesProvider'; + +import { useRoles } from '../hooks'; +import { useNotificationDispatcher } from "../../notifications/hoc/Notifications"; + +jest.mock('../hooks'); + +jest.mock('../../notifications/hoc/Notifications'); + +describe('RolesProvider component', () => { + + beforeEach(() => { + + useNotificationDispatcher.mockImplementation(() => { + return {}; + }); + + useRoles.mockImplementation(() => { + return { + get: jest.fn().mockResolvedValue([]), + response: { + ok: false, + status: 200 + } + }; + }); + }) + + test('should provide the roles context', async () => { + act(() => { + render( + {(roles) =>
{roles.length}
} +
); + }); + + expect(useRoles).toHaveBeenCalled(); + expect(screen.getByText('0')).toBeInTheDocument(); + }); + +}) \ No newline at end of file diff --git a/ui/src/app/admin/hooks.js b/ui/src/app/admin/hooks.js new file mode 100644 index 000000000..30e840dc8 --- /dev/null +++ b/ui/src/app/admin/hooks.js @@ -0,0 +1,16 @@ +import useFetch from 'use-http'; +import API_BASE_PATH from '../App.constant'; + +export function useRoles(opts = { cachePolicy: 'no-cache' }) { + return useFetch(`${API_BASE_PATH}/admin/roles`, opts); +} + +export function useRole(id) { + return useFetch(`${API_BASE_PATH}/admin/roles/${id}`, { + cachePolicy: 'no-cache' + }); +} + +export function useRoleUiSchema() { + return {}; +} \ No newline at end of file diff --git a/ui/src/app/admin/hooks.test.js b/ui/src/app/admin/hooks.test.js new file mode 100644 index 000000000..d739c9aa1 --- /dev/null +++ b/ui/src/app/admin/hooks.test.js @@ -0,0 +1,55 @@ +import { + useRoles, + useRole, +} from './hooks'; + +import useFetch from 'use-http'; +import API_BASE_PATH from '../App.constant'; + +jest.mock('use-http'); + +describe('api hooks', () => { + + let mockPut; + let mockGet; + + beforeEach(() => { + + mockPut = jest.fn().mockResolvedValue({ response: { ok: true } }); + mockGet = jest.fn().mockResolvedValue({ response: { ok: true } }); + + useFetch.mockImplementation(() => { + return { + request: { + ok: true + }, + put: mockPut, + get: mockGet, + error: null, + response: { + status: 409 + } + }; + }); + }) + + describe('useRoles', () => { + it('should call useFetch', () => { + const opts = {}; + const roles = useRoles(opts); + + expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}/admin/roles`, opts) + }); + }); + + describe('useRole', () => { + it('should call useFetch', () => { + const opts = { + cachePolicy: 'no-cache' + }; + const role = useRole('foo'); + + expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}/admin/roles/foo`, opts) + }); + }); +}); \ No newline at end of file diff --git a/ui/src/app/metadata/component/DeleteConfirmation.js b/ui/src/app/core/components/DeleteConfirmation.js similarity index 93% rename from ui/src/app/metadata/component/DeleteConfirmation.js rename to ui/src/app/core/components/DeleteConfirmation.js index a0f2f8c09..ac699063e 100644 --- a/ui/src/app/metadata/component/DeleteConfirmation.js +++ b/ui/src/app/core/components/DeleteConfirmation.js @@ -37,7 +37,7 @@ export function DeleteConfirmation({ children, body, title }) {

- You are deleting an entity. This cannot be undone. Continue? + You are deleting an entity. This cannot be undone. Continue?

diff --git a/ui/src/app/metadata/component/DeleteConfirmation.test.js b/ui/src/app/core/components/DeleteConfirmation.test.js similarity index 97% rename from ui/src/app/metadata/component/DeleteConfirmation.test.js rename to ui/src/app/core/components/DeleteConfirmation.test.js index 8aa4a57ee..76abf8dd6 100644 --- a/ui/src/app/metadata/component/DeleteConfirmation.test.js +++ b/ui/src/app/core/components/DeleteConfirmation.test.js @@ -28,7 +28,7 @@ test('Delete confirmation', () => { {(block) => } , - container); + container); }); const initiator = container.querySelector('button'); diff --git a/ui/src/app/core/components/Header.js b/ui/src/app/core/components/Header.js index 54d0c402c..b464dffe6 100644 --- a/ui/src/app/core/components/Header.js +++ b/ui/src/app/core/components/Header.js @@ -6,7 +6,7 @@ import Navbar from 'react-bootstrap/Navbar'; import Dropdown from 'react-bootstrap/Dropdown'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faTh, faSignOutAlt, faPlusCircle, faCube, faCubes } from '@fortawesome/free-solid-svg-icons'; +import { faTh, faSignOutAlt, faPlusCircle, faCube, faCubes, faUserTag } from '@fortawesome/free-solid-svg-icons'; import Translate from '../../i18n/components/translate'; import { useTranslator } from '../../i18n/hooks'; @@ -41,6 +41,10 @@ export function Header () { + + + + } diff --git a/ui/src/app/core/components/UserConfirmation.test.js b/ui/src/app/core/components/UserConfirmation.test.js index 9c2835d9b..58f73c3b8 100644 --- a/ui/src/app/core/components/UserConfirmation.test.js +++ b/ui/src/app/core/components/UserConfirmation.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { act, render, fireEvent, waitFor, screen } from '@testing-library/react'; +import { render, fireEvent, screen } from '@testing-library/react'; import { UserConfirmation, ConfirmWindow } from './UserConfirmation'; jest.mock('../../i18n/hooks', () => ({ diff --git a/ui/src/app/form/FormManager.js b/ui/src/app/form/FormManager.js new file mode 100644 index 000000000..41b39d520 --- /dev/null +++ b/ui/src/app/form/FormManager.js @@ -0,0 +1,105 @@ +import React from 'react'; + +const initialState = { + data: {}, + errors: [] +}; + +const FormContext = React.createContext(); + +const { Provider, Consumer } = FormContext; + +export const FormActions = { + SET_FORM_ERROR: 'set form error', + SET_FORM_DATA: 'set form data' +}; + +export const setFormDataAction = (payload) => { + return { + type: FormActions.SET_FORM_DATA, + payload + } +} + +export const setFormErrorAction = (errors) => { + return { + type: FormActions.SET_FORM_ERROR, + payload: errors + } +} + +function reducer(state, action) { + switch (action.type) { + + case FormActions.SET_FORM_ERROR: + return { + ...state, + errors: action.payload + }; + case FormActions.SET_FORM_DATA: + return { + ...state, + data: action.payload + }; + default: + return state; + } +} + +/*eslint-disable react-hooks/exhaustive-deps*/ +function FormManager({ children, initial = {} }) { + + const data = { + ...initial + }; + + const [state, dispatch] = React.useReducer(reducer, { + ...initialState, + data + }); + const contextValue = React.useMemo(() => ({ state, dispatch }), [state, dispatch]); + + return ( + + {children(state.data, state.errors)} + + ); +} + +function useFormErrors() { + const { state } = React.useContext(FormContext); + const { errors } = state; + + return errors; +} + +function useFormContext() { + return React.useContext(FormContext); +} + +function useFormDispatcher() { + const { dispatch } = useFormContext(); + return dispatch; +} + +function useFormState() { + const { state } = useFormContext(); + return state; +} + +function useFormData() { + const { data } = useFormContext(); + return data; +} + +export { + useFormErrors, + useFormContext, + useFormDispatcher, + useFormState, + useFormData, + FormManager, + FormContext, + Provider as FormProvider, + Consumer as FormConsumer +}; \ No newline at end of file diff --git a/ui/src/app/form/Schema.js b/ui/src/app/form/Schema.js new file mode 100644 index 000000000..92aefe325 --- /dev/null +++ b/ui/src/app/form/Schema.js @@ -0,0 +1,24 @@ +import React from 'react'; +import useFetch from 'use-http'; + +export function Schema({ path, children }) { + + const [schema, setSchema] = React.useState({}); + + + const { get, response } = useFetch(path, { + cachePolicy: 'no-cache' + }); + + async function loadSchema() { + const list = await get(``); + if (response.ok) { + setSchema(list); + } + } + + /*eslint-disable react-hooks/exhaustive-deps*/ + React.useEffect(() => { loadSchema() }, []); + + return (<>{children(schema)}); +} \ No newline at end of file diff --git a/ui/src/app/metadata/domain/filter/component/MetadataFilters.js b/ui/src/app/metadata/domain/filter/component/MetadataFilters.js index d38c97013..26c63f131 100644 --- a/ui/src/app/metadata/domain/filter/component/MetadataFilters.js +++ b/ui/src/app/metadata/domain/filter/component/MetadataFilters.js @@ -1,6 +1,6 @@ import React from 'react'; import { useMetadataFilters } from '../../../hooks/api'; -import { DeleteConfirmation } from '../../../component/DeleteConfirmation'; +import { DeleteConfirmation } from '../../../../core/components/DeleteConfirmation'; import { NotificationContext, createNotificationAction } from '../../../../notifications/hoc/Notifications'; export const MetadataFiltersContext = React.createContext(); diff --git a/ui/src/app/metadata/hooks/schema.js b/ui/src/app/metadata/hooks/schema.js index ecde47f05..5083559b1 100644 --- a/ui/src/app/metadata/hooks/schema.js +++ b/ui/src/app/metadata/hooks/schema.js @@ -1,5 +1,4 @@ import React from 'react'; -import { useIsAdmin } from '../../core/user/UserContext'; export const fillInRootProperties = (keys, ui) => keys.reduce((sch, key, idx) => { if (!sch.hasOwnProperty(key)) { @@ -31,21 +30,7 @@ export function useUiSchema(definition, schema, current, locked = true) { } ), [mapped, step.locked, locked]); - const isAdmin = useIsAdmin(); - - const hideEnableFromNonAdmins = React.useMemo(() => { - if (!isAdmin) { - return { - ...isLocked, - serviceEnabled: { - 'ui:widget': 'hidden' - } - }; - } - return isLocked; - }, [isAdmin, isLocked]); - - return { uiSchema: hideEnableFromNonAdmins, step}; + return { uiSchema: isLocked, step}; } diff --git a/ui/src/app/metadata/view/MetadataAttributeList.js b/ui/src/app/metadata/view/MetadataAttributeList.js index f585f805f..69e6754f6 100644 --- a/ui/src/app/metadata/view/MetadataAttributeList.js +++ b/ui/src/app/metadata/view/MetadataAttributeList.js @@ -8,7 +8,7 @@ import { Link } from 'react-router-dom'; import { Translate } from '../../i18n/components/translate'; import { useTranslator } from '../../i18n/hooks'; -import { DeleteConfirmation } from '../component/DeleteConfirmation'; +import { DeleteConfirmation } from '../../core/components/DeleteConfirmation'; export function MetadataAttributeList ({entities, onDelete}) { diff --git a/ui/src/testing/sourceSchema.js b/ui/src/testing/sourceSchema.js index 93262c5f4..c723fd548 100644 --- a/ui/src/testing/sourceSchema.js +++ b/ui/src/testing/sourceSchema.js @@ -1,3 +1,3 @@ -const SCHEMA = { "type": "object", "required": ["serviceProviderName", "entityId"], "properties": { "serviceProviderName": { "title": "label.service-provider-name", "description": "tooltip.service-provider-name", "type": "string", "minLength": 1, "maxLength": 255 }, "entityId": { "title": "label.entity-id", "description": "tooltip.entity-id", "type": "string", "minLength": 1, "maxLength": 255 }, "serviceEnabled": { "title": "label.enable-this-service", "description": "tooltip.enable-this-service-upon-saving", "type": "boolean", "default": false }, "organization": { "$ref": "#/definitions/Organization" }, "contacts": { "title": "label.contact-information", "description": "tooltip.contact-information", "type": "array", "items": { "$ref": "#/definitions/Contact" } }, "mdui": { "$ref": "#/definitions/MDUI" }, "securityInfo": { "type": "object", "widget": { "id": "fieldset" }, "dependencies": { "authenticationRequestsSigned": { "oneOf": [{ "properties": { "authenticationRequestsSigned": { "enum": [true] }, "x509Certificates": { "minItems": 1 } } }, { "properties": { "authenticationRequestsSigned": { "enum": [false] }, "x509Certificates": { "minItems": 0 } } }] } }, "properties": { "x509CertificateAvailable": { "type": "boolean", "default": true }, "authenticationRequestsSigned": { "title": "label.authentication-requests-signed", "description": "tooltip.authentication-requests-signed", "type": "boolean", "enumNames": ["value.true", "value.false"] }, "wantAssertionsSigned": { "title": "label.want-assertions-signed", "description": "tooltip.want-assertions-signed", "type": "boolean", "enumNames": ["value.true", "value.false"] }, "x509Certificates": { "title": "label.x509-certificates", "type": "array", "items": { "$ref": "#/definitions/Certificate" } } } }, "assertionConsumerServices": { "title": "label.assertion-consumer-service-endpoints", "description": "", "type": "array", "items": { "$ref": "#/definitions/AssertionConsumerService" } }, "serviceProviderSsoDescriptor": { "type": "object", "properties": { "protocolSupportEnum": { "title": "label.protocol-support-enumeration", "description": "tooltip.protocol-support-enumeration", "type": "string", "widget": { "id": "select" }, "oneOf": [{ "enum": ["SAML 2"], "description": "SAML 2" }, { "enum": ["SAML 1.1"], "description": "SAML 1.1" }] }, "nameIdFormats": { "$ref": "#/definitions/nameIdFormats" } }, "dependencies": { "nameIdFormats": ["protocolSupportEnum"] } }, "logoutEndpoints": { "title": "label.logout-endpoints", "description": "tooltip.logout-endpoints", "type": "array", "items": { "$ref": "#/definitions/LogoutEndpoint" } }, "relyingPartyOverrides": { "type": "object", "properties": { "signAssertion": { "title": "label.sign-the-assertion", "description": "tooltip.sign-assertion", "type": "boolean", "default": false }, "dontSignResponse": { "title": "label.dont-sign-the-response", "description": "tooltip.dont-sign-response", "type": "boolean", "default": false }, "turnOffEncryption": { "title": "label.turn-off-encryption-of-response", "description": "tooltip.turn-off-encryption", "type": "boolean", "default": false }, "useSha": { "title": "label.use-sha1-signing-algorithm", "description": "tooltip.usa-sha-algorithm", "type": "boolean", "default": false }, "ignoreAuthenticationMethod": { "title": "label.ignore-any-sp-requested-authentication-method", "description": "tooltip.ignore-auth-method", "type": "boolean", "default": false }, "omitNotBefore": { "title": "label.omit-not-before-condition", "description": "tooltip.omit-not-before-condition", "type": "boolean", "default": false }, "responderId": { "title": "label.responder-id", "description": "tooltip.responder-id", "type": "string", "default": "" }, "nameIdFormats": { "$ref": "#/definitions/nameIdFormats" }, "authenticationMethods": { "$ref": "#/definitions/authenticationMethods" }, "forceAuthn": { "title": "label.force-authn", "description": "tooltip.force-authn", "type": "boolean", "default": false } } }, "attributeRelease": { "type": "array", "title": "label.attribute-release", "description": "Attribute release table - select the attributes you want to release (default unchecked)", "items": { "type": "string", "enum": ["eduPersonPrincipalName", "uid", "mail", "surname", "givenName", "eduPersonAffiliation", "eduPersonScopedAffiliation", "eduPersonPrimaryAffiliation", "eduPersonEntitlement", "eduPersonAssurance", "eduPersonUniqueId", "employeeNumber"] }, "uniqueItems": true } }, "definitions": { "Contact": { "type": "object", "required": ["name", "type", "emailAddress"], "properties": { "name": { "title": "label.contact-name", "description": "tooltip.contact-name", "type": "string", "minLength": 1, "maxLength": 255 }, "type": { "title": "label.contact-type", "description": "tooltip.contact-type", "type": "string", "widget": "select", "minLength": 1, "oneOf": [{ "enum": ["support"], "description": "value.support" }, { "enum": ["technical"], "description": "value.technical" }, { "enum": ["administrative"], "description": "value.administrative" }, { "enum": ["other"], "description": "value.other" }] }, "emailAddress": { "title": "label.contact-email-address", "description": "tooltip.contact-email", "type": "string", "pattern": "^(mailto:)?(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$", "minLength": 1, "maxLength": 255 } } }, "Certificate": { "type": "object", "required": ["type", "value"], "properties": { "name": { "title": "label.certificate-name-display-only", "description": "tooltip.certificate-name", "type": "string", "maxLength": 255 }, "type": { "title": "label.certificate-type", "type": "string", "widget": { "id": "radio", "class": "form-check-inline" }, "oneOf": [{ "enum": ["signing"], "description": "value.signing" }, { "enum": ["encryption"], "description": "value.encryption" }, { "enum": ["both"], "description": "value.both" }] }, "value": { "title": "label.certificate", "description": "tooltip.certificate", "type": "string", "widget": "textarea", "minLength": 1 } } }, "AssertionConsumerService": { "type": "object", "required": ["locationUrl", "binding"], "properties": { "locationUrl": { "title": "label.assertion-consumer-service-location", "description": "tooltip.assertion-consumer-service-location", "type": "string", "widget": { "id": "string", "help": "message.valid-url" }, "minLength": 1, "maxLength": 255 }, "binding": { "title": "label.assertion-consumer-service-location-binding", "description": "tooltip.assertion-consumer-service-location-binding", "type": "string", "widget": "select", "oneOf": [{ "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:PAOS"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:PAOS" }, { "enum": ["urn:oasis:names:tc:SAML:1.0:profiles:browser-post"], "description": "urn:oasis:names:tc:SAML:1.0:profiles:browser-post" }, { "enum": ["urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"], "description": "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01" }] }, "makeDefault": { "title": "label.mark-as-default", "description": "tooltip.mark-as-default", "type": "boolean" } } }, "LogoutEndpoint": { "description": "tooltip.new-endpoint", "type": "object", "fieldsets": [{ "fields": ["url", "bindingType"] }], "required": ["url", "bindingType"], "properties": { "url": { "title": "label.url", "description": "tooltip.url", "type": "string", "minLength": 1, "maxLength": 255 }, "bindingType": { "title": "label.binding-type", "description": "tooltip.binding-type", "type": "string", "widget": "select", "oneOf": [{ "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:SOAP"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" }] } } }, "MDUI": { "type": "object", "widget": { "id": "fieldset" }, "fieldsets": [{ "type": "group", "fields": ["displayName", "informationUrl", "description"] }, { "type": "group", "fields": ["privacyStatementUrl", "logoUrl", "logoWidth", "logoHeight"] }], "properties": { "displayName": { "title": "label.display-name", "description": "tooltip.mdui-display-name", "type": "string", "minLength": 1, "maxLength": 255 }, "informationUrl": { "title": "label.information-url", "description": "tooltip.mdui-information-url", "type": "string", "minLength": 1, "maxLength": 255 }, "privacyStatementUrl": { "title": "label.privacy-statement-url", "description": "tooltip.mdui-privacy-statement-url", "type": "string", "minLength": 1, "maxLength": 255 }, "description": { "title": "label.description", "description": "tooltip.mdui-description", "type": "string", "widget": { "id": "textarea" }, "minLength": 1, "maxLength": 255 }, "logoUrl": { "title": "label.logo-url", "description": "tooltip.mdui-logo-url", "type": "string", "minLength": 1, "maxLength": 255 }, "logoHeight": { "title": "label.logo-height", "description": "tooltip.mdui-logo-height", "minimum": 0, "type": "integer" }, "logoWidth": { "title": "label.logo-width", "description": "tooltip.mdui-logo-width", "minimum": 0, "type": "integer" } } }, "Organization": { "type": "object", "properties": { "name": { "title": "label.organization-name", "description": "tooltip.organization-name", "type": "string", "minLength": 1, "maxLength": 255 }, "displayName": { "title": "label.organization-display-name", "description": "tooltip.organization-display-name", "type": "string", "minLength": 1, "maxLength": 255 }, "url": { "title": "label.organization-url", "description": "tooltip.organization-url", "type": "string", "minLength": 1, "maxLength": 255 } }, "dependencies": { "name": { "required": ["displayName", "url"] }, "displayName": { "required": ["name", "url"] }, "url": { "required": ["name", "displayName"] } } }, "nameIdFormats": { "title": "label.nameid-format-to-send", "description": "tooltip.nameid-format", "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 255, "examples": ["urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"] } }, "authenticationMethods": { "title": "label.authentication-methods-to-use", "description": "tooltip.authentication-methods-to-use", "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 255, "examples": ["https://refeds.org/profile/mfa", "urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken", "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"] } } } }; +const SCHEMA = { "type": "object", "required": ["serviceProviderName", "entityId"], "properties": { "serviceProviderName": { "title": "label.service-provider-name", "description": "tooltip.service-provider-name", "type": "string", "minLength": 1, "maxLength": 255 }, "entityId": { "title": "label.entity-id", "description": "tooltip.entity-id", "type": "string", "minLength": 1, "maxLength": 255 }, "organization": { "$ref": "#/definitions/Organization" }, "contacts": { "title": "label.contact-information", "description": "tooltip.contact-information", "type": "array", "items": { "$ref": "#/definitions/Contact" } }, "mdui": { "$ref": "#/definitions/MDUI" }, "securityInfo": { "type": "object", "widget": { "id": "fieldset" }, "dependencies": { "authenticationRequestsSigned": { "oneOf": [{ "properties": { "authenticationRequestsSigned": { "enum": [true] }, "x509Certificates": { "minItems": 1 } } }, { "properties": { "authenticationRequestsSigned": { "enum": [false] }, "x509Certificates": { "minItems": 0 } } }] } }, "properties": { "x509CertificateAvailable": { "type": "boolean", "default": true }, "authenticationRequestsSigned": { "title": "label.authentication-requests-signed", "description": "tooltip.authentication-requests-signed", "type": "boolean", "enumNames": ["value.true", "value.false"] }, "wantAssertionsSigned": { "title": "label.want-assertions-signed", "description": "tooltip.want-assertions-signed", "type": "boolean", "enumNames": ["value.true", "value.false"] }, "x509Certificates": { "title": "label.x509-certificates", "type": "array", "items": { "$ref": "#/definitions/Certificate" } } } }, "assertionConsumerServices": { "title": "label.assertion-consumer-service-endpoints", "description": "", "type": "array", "items": { "$ref": "#/definitions/AssertionConsumerService" } }, "serviceProviderSsoDescriptor": { "type": "object", "properties": { "protocolSupportEnum": { "title": "label.protocol-support-enumeration", "description": "tooltip.protocol-support-enumeration", "type": "string", "widget": { "id": "select" }, "oneOf": [{ "enum": ["SAML 2"], "description": "SAML 2" }, { "enum": ["SAML 1.1"], "description": "SAML 1.1" }] }, "nameIdFormats": { "$ref": "#/definitions/nameIdFormats" } }, "dependencies": { "nameIdFormats": ["protocolSupportEnum"] } }, "logoutEndpoints": { "title": "label.logout-endpoints", "description": "tooltip.logout-endpoints", "type": "array", "items": { "$ref": "#/definitions/LogoutEndpoint" } }, "relyingPartyOverrides": { "type": "object", "properties": { "signAssertion": { "title": "label.sign-the-assertion", "description": "tooltip.sign-assertion", "type": "boolean", "default": false }, "dontSignResponse": { "title": "label.dont-sign-the-response", "description": "tooltip.dont-sign-response", "type": "boolean", "default": false }, "turnOffEncryption": { "title": "label.turn-off-encryption-of-response", "description": "tooltip.turn-off-encryption", "type": "boolean", "default": false }, "useSha": { "title": "label.use-sha1-signing-algorithm", "description": "tooltip.usa-sha-algorithm", "type": "boolean", "default": false }, "ignoreAuthenticationMethod": { "title": "label.ignore-any-sp-requested-authentication-method", "description": "tooltip.ignore-auth-method", "type": "boolean", "default": false }, "omitNotBefore": { "title": "label.omit-not-before-condition", "description": "tooltip.omit-not-before-condition", "type": "boolean", "default": false }, "responderId": { "title": "label.responder-id", "description": "tooltip.responder-id", "type": "string", "default": "" }, "nameIdFormats": { "$ref": "#/definitions/nameIdFormats" }, "authenticationMethods": { "$ref": "#/definitions/authenticationMethods" }, "forceAuthn": { "title": "label.force-authn", "description": "tooltip.force-authn", "type": "boolean", "default": false } } }, "attributeRelease": { "type": "array", "title": "label.attribute-release", "description": "Attribute release table - select the attributes you want to release (default unchecked)", "items": { "type": "string", "enum": ["eduPersonPrincipalName", "uid", "mail", "surname", "givenName", "eduPersonAffiliation", "eduPersonScopedAffiliation", "eduPersonPrimaryAffiliation", "eduPersonEntitlement", "eduPersonAssurance", "eduPersonUniqueId", "employeeNumber"] }, "uniqueItems": true } }, "definitions": { "Contact": { "type": "object", "required": ["name", "type", "emailAddress"], "properties": { "name": { "title": "label.contact-name", "description": "tooltip.contact-name", "type": "string", "minLength": 1, "maxLength": 255 }, "type": { "title": "label.contact-type", "description": "tooltip.contact-type", "type": "string", "widget": "select", "minLength": 1, "oneOf": [{ "enum": ["support"], "description": "value.support" }, { "enum": ["technical"], "description": "value.technical" }, { "enum": ["administrative"], "description": "value.administrative" }, { "enum": ["other"], "description": "value.other" }] }, "emailAddress": { "title": "label.contact-email-address", "description": "tooltip.contact-email", "type": "string", "pattern": "^(mailto:)?(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$", "minLength": 1, "maxLength": 255 } } }, "Certificate": { "type": "object", "required": ["type", "value"], "properties": { "name": { "title": "label.certificate-name-display-only", "description": "tooltip.certificate-name", "type": "string", "maxLength": 255 }, "type": { "title": "label.certificate-type", "type": "string", "widget": { "id": "radio", "class": "form-check-inline" }, "oneOf": [{ "enum": ["signing"], "description": "value.signing" }, { "enum": ["encryption"], "description": "value.encryption" }, { "enum": ["both"], "description": "value.both" }] }, "value": { "title": "label.certificate", "description": "tooltip.certificate", "type": "string", "widget": "textarea", "minLength": 1 } } }, "AssertionConsumerService": { "type": "object", "required": ["locationUrl", "binding"], "properties": { "locationUrl": { "title": "label.assertion-consumer-service-location", "description": "tooltip.assertion-consumer-service-location", "type": "string", "widget": { "id": "string", "help": "message.valid-url" }, "minLength": 1, "maxLength": 255 }, "binding": { "title": "label.assertion-consumer-service-location-binding", "description": "tooltip.assertion-consumer-service-location-binding", "type": "string", "widget": "select", "oneOf": [{ "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:PAOS"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:PAOS" }, { "enum": ["urn:oasis:names:tc:SAML:1.0:profiles:browser-post"], "description": "urn:oasis:names:tc:SAML:1.0:profiles:browser-post" }, { "enum": ["urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"], "description": "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01" }] }, "makeDefault": { "title": "label.mark-as-default", "description": "tooltip.mark-as-default", "type": "boolean" } } }, "LogoutEndpoint": { "description": "tooltip.new-endpoint", "type": "object", "fieldsets": [{ "fields": ["url", "bindingType"] }], "required": ["url", "bindingType"], "properties": { "url": { "title": "label.url", "description": "tooltip.url", "type": "string", "minLength": 1, "maxLength": 255 }, "bindingType": { "title": "label.binding-type", "description": "tooltip.binding-type", "type": "string", "widget": "select", "oneOf": [{ "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:SOAP"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" }] } } }, "MDUI": { "type": "object", "widget": { "id": "fieldset" }, "fieldsets": [{ "type": "group", "fields": ["displayName", "informationUrl", "description"] }, { "type": "group", "fields": ["privacyStatementUrl", "logoUrl", "logoWidth", "logoHeight"] }], "properties": { "displayName": { "title": "label.display-name", "description": "tooltip.mdui-display-name", "type": "string", "minLength": 1, "maxLength": 255 }, "informationUrl": { "title": "label.information-url", "description": "tooltip.mdui-information-url", "type": "string", "minLength": 1, "maxLength": 255 }, "privacyStatementUrl": { "title": "label.privacy-statement-url", "description": "tooltip.mdui-privacy-statement-url", "type": "string", "minLength": 1, "maxLength": 255 }, "description": { "title": "label.description", "description": "tooltip.mdui-description", "type": "string", "widget": { "id": "textarea" }, "minLength": 1, "maxLength": 255 }, "logoUrl": { "title": "label.logo-url", "description": "tooltip.mdui-logo-url", "type": "string", "minLength": 1, "maxLength": 255 }, "logoHeight": { "title": "label.logo-height", "description": "tooltip.mdui-logo-height", "minimum": 0, "type": "integer" }, "logoWidth": { "title": "label.logo-width", "description": "tooltip.mdui-logo-width", "minimum": 0, "type": "integer" } } }, "Organization": { "type": "object", "properties": { "name": { "title": "label.organization-name", "description": "tooltip.organization-name", "type": "string", "minLength": 1, "maxLength": 255 }, "displayName": { "title": "label.organization-display-name", "description": "tooltip.organization-display-name", "type": "string", "minLength": 1, "maxLength": 255 }, "url": { "title": "label.organization-url", "description": "tooltip.organization-url", "type": "string", "minLength": 1, "maxLength": 255 } }, "dependencies": { "name": { "required": ["displayName", "url"] }, "displayName": { "required": ["name", "url"] }, "url": { "required": ["name", "displayName"] } } }, "nameIdFormats": { "title": "label.nameid-format-to-send", "description": "tooltip.nameid-format", "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 255, "examples": ["urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"] } }, "authenticationMethods": { "title": "label.authentication-methods-to-use", "description": "tooltip.authentication-methods-to-use", "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 255, "examples": ["https://refeds.org/profile/mfa", "urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken", "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"] } } } }; export default SCHEMA; \ No newline at end of file diff --git a/ui/src/testing/uiSchema.js b/ui/src/testing/uiSchema.js index eb557bcf2..c1af6f4fa 100644 --- a/ui/src/testing/uiSchema.js +++ b/ui/src/testing/uiSchema.js @@ -11,7 +11,6 @@ const schema = { "fields": [ "serviceProviderName", "entityId", - "serviceEnabled", "organization" ] }, @@ -208,7 +207,6 @@ const schema = { }, "serviceProviderName": {}, "entityId": {}, - "serviceEnabled": {}, "organization": {}, "ui:disabled": false };