Added ability to change auth level IO-550
This commit is contained in:
@@ -4089,6 +4089,32 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>users</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>editaccess</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<concept_node>
|
||||
@@ -26240,9 +26266,56 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>errors</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>updating</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>fields</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>authlevel</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>displayname</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -26264,6 +26337,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>email</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>photourl</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -26287,6 +26381,32 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>labels</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>actions</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
|
||||
@@ -21,6 +21,7 @@ const ret = {
|
||||
"jobs:intake": 1,
|
||||
"jobs:close": 5,
|
||||
"jobs:detail": 1,
|
||||
"jobs:partsqueue": 4,
|
||||
|
||||
"bills:enter": 2,
|
||||
"bills:view": 2,
|
||||
@@ -49,5 +50,8 @@ const ret = {
|
||||
|
||||
"timetickets:enter": 3,
|
||||
"timetickets:list": 3,
|
||||
"timetickets:edit": 4,
|
||||
|
||||
"users:editaccess": 4,
|
||||
};
|
||||
export default ret;
|
||||
|
||||
@@ -476,6 +476,18 @@ export default function ShopInfoRbacComponent({ form }) {
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.users.editaccess")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
name={["md_rbac", "users:editaccess"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { InputNumber, notification } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useMutation } from "react-apollo";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_ASSOCIATION } from "../../graphql/user.queries";
|
||||
|
||||
export default function ShopUsersAuthEdit({ association }) {
|
||||
const { t } = useTranslation();
|
||||
const [updateAssociation] = useMutation(UPDATE_ASSOCIATION);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [value, setValue] = useState(association.authlevel);
|
||||
|
||||
const handleSave = async () => {
|
||||
setVisible(false);
|
||||
const result = await updateAssociation({
|
||||
variables: {
|
||||
assocId: association.id,
|
||||
assoc: { authlevel: value },
|
||||
},
|
||||
});
|
||||
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("user.errors.updating", {
|
||||
message: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{visible && (
|
||||
<div>
|
||||
<InputNumber
|
||||
min={0}
|
||||
value={value}
|
||||
onChange={(val) => setValue(val)}
|
||||
defaultValue={association.authlevel}
|
||||
onBlur={handleSave}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!visible && (
|
||||
<div style={{ cursor: "pointer" }} onClick={() => setVisible(true)}>
|
||||
{association.authlevel || t("general.labels.na")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
59
client/src/components/shop-users/shop-users.component.jsx
Normal file
59
client/src/components/shop-users/shop-users.component.jsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { Button, Table } from "antd";
|
||||
import React from "react";
|
||||
import { useQuery } from "react-apollo";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { QUERY_SHOP_ASSOCIATIONS } from "../../graphql/user.queries";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||
import ShopUsersAuthEdit from "../shop-users-auth-edit/shop-users-auth-edit.component";
|
||||
|
||||
export default function ShopInfoUsersComponent() {
|
||||
const { t } = useTranslation();
|
||||
const { loading, error, data } = useQuery(QUERY_SHOP_ASSOCIATIONS);
|
||||
const columns = [
|
||||
{
|
||||
title: t("user.fields.email"),
|
||||
dataIndex: "email",
|
||||
key: "email",
|
||||
render: (text, record) => record.user.email,
|
||||
},
|
||||
{
|
||||
title: t("user.fields.authlevel"),
|
||||
dataIndex: "authlevel",
|
||||
key: "authlevel",
|
||||
render: (text, record) => (
|
||||
<RbacWrapper action="users:editaccess">
|
||||
<ShopUsersAuthEdit association={record} />
|
||||
</RbacWrapper>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("user.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<div>
|
||||
<Button disabled onClick={() => {}}>
|
||||
{t("general.actions.delete")}
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
if (error) {
|
||||
return <AlertComponent type="error" message={JSON.stringify(error)} />;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
loading={loading}
|
||||
size="small"
|
||||
pagination={{ position: "top" }}
|
||||
columns={columns.map((item) => ({ ...item }))}
|
||||
rowKey="id"
|
||||
dataSource={data && data.associations}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,36 @@
|
||||
import gql from "graphql-tag";
|
||||
|
||||
export const QUERY_SHOP_ASSOCIATIONS = gql`
|
||||
query QUERY_SHOP_ASSOCIATIONS {
|
||||
associations {
|
||||
id
|
||||
authlevel
|
||||
shopid
|
||||
user {
|
||||
email
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UPDATE_ASSOCIATION = gql`
|
||||
mutation UPDATE_ASSOCIATION(
|
||||
$assocId: uuid!
|
||||
$assoc: associations_set_input!
|
||||
) {
|
||||
update_associations(where: { id: { _eq: $assocId } }, _set: $assoc) {
|
||||
returning {
|
||||
id
|
||||
authlevel
|
||||
shopid
|
||||
user {
|
||||
email
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UPSERT_USER = gql`
|
||||
mutation UPSERT_USER($authEmail: String!, $authToken: String!) {
|
||||
insert_users(
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
setBreadcrumbs,
|
||||
} from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ShopInfoUsersComponent from "../../components/shop-users/shop-users.component";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -42,7 +43,7 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
|
||||
<ShopEmployeesContainer />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={t("bodyshop.labels.licensing")} key="licensing">
|
||||
Licensing
|
||||
<ShopInfoUsersComponent />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={t("bodyshop.labels.csiq")} key="csiq">
|
||||
<ShopCsiConfig />
|
||||
|
||||
@@ -280,6 +280,9 @@
|
||||
"edit": "Time Tickets -> Edit",
|
||||
"enter": "Time Tickets -> Enter",
|
||||
"list": "Time Tickets -> List"
|
||||
},
|
||||
"users": {
|
||||
"editaccess": "Users -> Edit access"
|
||||
}
|
||||
},
|
||||
"responsibilitycenter": "Responsibility Center",
|
||||
@@ -1616,9 +1619,17 @@
|
||||
"signout": "Sign Out",
|
||||
"updateprofile": "Update Profile"
|
||||
},
|
||||
"errors": {
|
||||
"updating": "Error updating user or association {{message}}"
|
||||
},
|
||||
"fields": {
|
||||
"authlevel": "Authorization Level",
|
||||
"displayname": "Display Name",
|
||||
"email": "Email",
|
||||
"photourl": "Avatar URL"
|
||||
},
|
||||
"labels": {
|
||||
"actions": "Actions"
|
||||
}
|
||||
},
|
||||
"vehicles": {
|
||||
|
||||
@@ -280,6 +280,9 @@
|
||||
"edit": "",
|
||||
"enter": "",
|
||||
"list": ""
|
||||
},
|
||||
"users": {
|
||||
"editaccess": ""
|
||||
}
|
||||
},
|
||||
"responsibilitycenter": "",
|
||||
@@ -1616,9 +1619,17 @@
|
||||
"signout": "desconectar",
|
||||
"updateprofile": "Actualización del perfil"
|
||||
},
|
||||
"errors": {
|
||||
"updating": ""
|
||||
},
|
||||
"fields": {
|
||||
"authlevel": "",
|
||||
"displayname": "Nombre para mostrar",
|
||||
"email": "",
|
||||
"photourl": "URL de avatar"
|
||||
},
|
||||
"labels": {
|
||||
"actions": ""
|
||||
}
|
||||
},
|
||||
"vehicles": {
|
||||
|
||||
@@ -280,6 +280,9 @@
|
||||
"edit": "",
|
||||
"enter": "",
|
||||
"list": ""
|
||||
},
|
||||
"users": {
|
||||
"editaccess": ""
|
||||
}
|
||||
},
|
||||
"responsibilitycenter": "",
|
||||
@@ -1616,9 +1619,17 @@
|
||||
"signout": "Déconnexion",
|
||||
"updateprofile": "Mettre à jour le profil"
|
||||
},
|
||||
"errors": {
|
||||
"updating": ""
|
||||
},
|
||||
"fields": {
|
||||
"authlevel": "",
|
||||
"displayname": "Afficher un nom",
|
||||
"email": "",
|
||||
"photourl": "URL de l'avatar"
|
||||
},
|
||||
"labels": {
|
||||
"actions": ""
|
||||
}
|
||||
},
|
||||
"vehicles": {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- active
|
||||
- authlevel
|
||||
- id
|
||||
- shopid
|
||||
- useremail
|
||||
computed_fields: []
|
||||
filter:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,30 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- active
|
||||
- authlevel
|
||||
- id
|
||||
- shopid
|
||||
- useremail
|
||||
computed_fields: []
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,20 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
- args:
|
||||
permission:
|
||||
columns:
|
||||
- active
|
||||
filter:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -0,0 +1,21 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
- args:
|
||||
permission:
|
||||
columns:
|
||||
- active
|
||||
- authlevel
|
||||
filter:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -204,14 +204,20 @@ tables:
|
||||
- shopid
|
||||
- useremail
|
||||
filter:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- active
|
||||
- authlevel
|
||||
filter:
|
||||
user:
|
||||
authid:
|
||||
|
||||
Reference in New Issue
Block a user