Skip to content

Commit

Permalink
Merge pull request #1433 from SenseNet/release/2022-08
Browse files Browse the repository at this point in the history
  • Loading branch information
Restobit authored Aug 26, 2022
2 parents f13669b + 3b7de17 commit 5426f5b
Show file tree
Hide file tree
Showing 105 changed files with 11,282 additions and 3,945 deletions.
50 changes: 25 additions & 25 deletions apps/sensenet/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@app/sensenet",
"version": "1.24.0",
"version": "1.25.1",
"main": "dist/index.js",
"files": [
"dist",
Expand Down Expand Up @@ -38,37 +38,37 @@
]
},
"devDependencies": {
"@cypress/code-coverage": "^3.9.10",
"@relative-ci/agent": "^2.0.0",
"@types/autosuggest-highlight": "^3.1.1",
"@cypress/code-coverage": "^3.10.0",
"@relative-ci/agent": "^4.0.0",
"@types/autosuggest-highlight": "^3.2.0",
"@types/react": "^17.0.15",
"@types/react-autosuggest": "^10.1.5",
"@types/react-dom": "^17.0.9",
"@types/react-responsive": "^8.0.3",
"@types/react-router": "^5.1.16",
"@types/react-router-dom": "^5.1.8",
"@types/react-virtualized": "^9.21.12",
"@types/uuid": "^8.3.1",
"@types/react-responsive": "^8.0.5",
"@types/react-router": "^5.1.18",
"@types/react-router-dom": "^5.3.3",
"@types/react-virtualized": "^9.21.21",
"@types/uuid": "^8.3.4",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"compression-webpack-plugin": "8.0.1",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "^6.2.0",
"css-minimizer-webpack-plugin": "^3.0.2",
"cypress": "7.5.0",
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^4.0.0",
"cypress": "10.4.0",
"cypress-file-upload": "^5.0.8",
"cypress-xpath": "^1.6.2",
"file-loader": "^6.1.1",
"fork-ts-checker-webpack-plugin": "^6.3.1",
"html-webpack-plugin": "^5.3.2",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.1.0",
"monaco-editor-webpack-plugin": "^4.1.1",
"nyc": "^15.1.0",
"nyc-config-tsx": "^0.1.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"source-map-support": "^0.5.19",
"style-loader": "^3.2.1",
"terser-webpack-plugin": "^5.1.4",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.3",
"ts-loader": "^9.2.4",
"ts-node": "^10.1.0",
"url-loader": "^4.1.1",
Expand All @@ -82,20 +82,20 @@
"@iconify-icons/logos": "^1.1.10",
"@iconify/react": "^1.1.4",
"@material-ui/core": "~4.11.4",
"@material-ui/icons": "^4.11.2",
"@material-ui/icons": "^4.11.3",
"@material-ui/lab": "4.0.0-alpha.58",
"@sensenet/authentication-oidc-react": "^2.3.1",
"@sensenet/client-core": "^4.0.1",
"@sensenet/client-utils": "^2.1.2",
"@sensenet/controls-react": "^8.0.3",
"@sensenet/client-core": "^4.0.2",
"@sensenet/client-utils": "^2.1.3",
"@sensenet/controls-react": "^8.0.4",
"@sensenet/default-content-types": "^5.0.0",
"@sensenet/document-viewer-react": "^4.2.1",
"@sensenet/hooks-react": "^1.6.2",
"@sensenet/document-viewer-react": "^4.2.2",
"@sensenet/hooks-react": "^1.6.3",
"@sensenet/list-controls-react": "^2.1.1",
"@sensenet/pickers-react": "^2.1.2",
"@sensenet/query": "^2.1.2",
"@sensenet/repository-events": "^2.1.2",
"autosuggest-highlight": "^3.1.1",
"@sensenet/pickers-react": "^2.1.3",
"@sensenet/query": "^2.1.3",
"@sensenet/repository-events": "^2.1.3",
"autosuggest-highlight": "^3.3.4",
"clsx": "^1.1.1",
"date-fns": "^2.23.0",
"filesize": "^8.0.0",
Expand Down
4 changes: 3 additions & 1 deletion apps/sensenet/src/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Button from '@material-ui/core/Button'
import Tooltip from '@material-ui/core/Tooltip'
import React, { MouseEvent, useState } from 'react'
import { ContentContextMenu } from './context-menu/content-context-menu'
import CopyPath from './CopyPath'
import { DropFileArea } from './DropFileArea'

export interface BreadcrumbItem<T extends GenericContent> {
Expand All @@ -27,7 +28,7 @@ export function Breadcrumbs<T extends GenericContent>(props: BreadcrumbProps<T>)
<>
<MUIBreadcrumbs maxItems={5} aria-label="breadcrumb">
{props.items.map((item) => (
<DropFileArea key={item.content.Id} parentContent={item.content} style={{ display: 'inline-block' }}>
<DropFileArea key={item.content.Id} parentContent={item.content} style={{ display: 'flex' }}>
<Tooltip title={item.title}>
<Button
data-test={`breadcrumb-item-${item.displayName.replace(/\s+/g, '-').toLowerCase()}`}
Expand All @@ -45,6 +46,7 @@ export function Breadcrumbs<T extends GenericContent>(props: BreadcrumbProps<T>)
</DropFileArea>
))}
</MUIBreadcrumbs>
<CopyPath copyText={props.items[props.items.length - 1].title} />
{contextMenuItem ? (
<ContentContextMenu
isOpened={isContextMenuOpened}
Expand Down
43 changes: 43 additions & 0 deletions apps/sensenet/src/components/CopyPath.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Button from '@material-ui/core/Button'
import CheckCircleOutlineOutlinedIcon from '@material-ui/icons/CheckCircleOutlineOutlined'
import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined'
import React, { useState } from 'react'

type Props = { copyText: string }

const CopyPath = ({ copyText }: Props) => {
const [isCopied, setIsCopied] = useState(false)

const copyTextToClipboard = async (text: string) => {
if ('clipboard' in navigator) {
return await navigator.clipboard.writeText(text)
} else {
return document.execCommand('copy', true, text)
}
}

const handleCopyClick = () => {
copyTextToClipboard(copyText)
.then(() => {
setIsCopied(true)
setTimeout(() => {
setIsCopied(false)
}, 1500)
})
.catch((err) => {
console.log(err)
})
}

return (
<div>
<Button onClick={handleCopyClick}>
<span>
{isCopied ? <CheckCircleOutlineOutlinedIcon style={{ color: 'lightgreen' }} /> : <FileCopyOutlinedIcon />}
</span>
</Button>
</div>
)
}

export default CopyPath
5 changes: 4 additions & 1 deletion apps/sensenet/src/components/appbar/desktop-nav-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ export const DesktopNavMenu: FunctionComponent = () => {
path: PATHS.usersAndGroups.appPath,
params: { browseType: 'explorer', action: 'edit' },
}),
newParams: { content: `${currentUser.Path.replace(PATHS.usersAndGroups.snPath, '')}` },
newParams: {
content: currentUser.Path,
needRoot: 'false',
},
})}>
{localization.topMenu.accountSettings}
</Link>
Expand Down
1 change: 1 addition & 0 deletions apps/sensenet/src/components/content-list/content-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ export const ContentList = <T extends GenericContent = GenericContent>(props: Co
return (
<ContextMenuWrapper onContextMenu={(ev) => openContext(ev, fieldOptions.rowData)}>
<RolesField
user={fieldOptions.rowData}
roles={fieldOptions.rowData[fieldOptions.dataKey] as GenericContent[]}
directRoles={fieldOptions.rowData.DirectRoles}
/>
Expand Down
128 changes: 72 additions & 56 deletions apps/sensenet/src/components/content-list/roles-field.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { GenericContent, Group, User } from '@sensenet/default-content-types'
import { useRepository } from '@sensenet/hooks-react'
import { Button, createStyles, makeStyles, Menu, MenuItem, TableCell, Tooltip } from '@material-ui/core'
import SettingsIcon from '@material-ui/icons/Settings'
import SwapHorizIcon from '@material-ui/icons/SwapHoriz'
import clsx from 'clsx'
import React, { FunctionComponent, useState } from 'react'
import { useGlobalStyles } from '../../globalStyles'
import { useLocalization } from '../../hooks'
import { useDialog } from '../dialogs'

const useStyles = makeStyles(() => {
Expand All @@ -19,28 +21,31 @@ const useStyles = makeStyles(() => {
})

interface RolesFieldProps {
user: GenericContent
roles: GenericContent[]
directRoles?: GenericContent[]
}

export const RolesField: FunctionComponent<RolesFieldProps> = ({ roles, directRoles }) => {
export const RolesField: FunctionComponent<RolesFieldProps> = ({ user, roles, directRoles }) => {
const classes = useStyles()
const globalClasses = useGlobalStyles()
const repository = useRepository()
const localization = useLocalization()
const { openDialog } = useDialog()
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null)

const openGroupDialog = async (event: React.MouseEvent, group: Group) => {
event.stopPropagation()
const actions = await repository.getActions({ idOrPath: group.Path })

const canEdit = await canUserEditContent(group)

const content = await repository.load<Group>({
idOrPath: group.Path,
oDataOptions: {
select: ['Members'],
expand: ['Members'],
},
})
const canEdit = actions.d.results.some((action) => action.Name === 'Edit')

openDialog({
name: 'reference-content-list',
Expand All @@ -49,6 +54,18 @@ export const RolesField: FunctionComponent<RolesFieldProps> = ({ roles, directRo
})
}

const openAddToGroupDialog = async (event: React.MouseEvent) => {
event.stopPropagation()

const canEdit = await canUserEditContent(user)

openDialog({
name: 'add-delete-user-groups',
props: { user, directGroups: directRoles ?? [], canEdit },
dialogProps: { maxWidth: 'sm', classes: { container: globalClasses.centeredRight } },
})
}

const isIndirect = (role: GenericContent) => {
if (!directRoles) {
return false
Expand All @@ -57,61 +74,60 @@ export const RolesField: FunctionComponent<RolesFieldProps> = ({ roles, directRo
return !directRoles.some((directRole) => directRole.Id === role.Id)
}

const canUserEditContent = async (content: GenericContent): Promise<boolean> => {
const actions = await repository.getActions({ idOrPath: content.Path })
return actions.d.results.some((action) => action.Name === 'Edit')
}

return (
<TableCell className={clsx(globalClasses.centeredLeft, globalClasses.virtualizedCellStyle)} component="div">
{roles.length === 1 ? (
<Tooltip className={globalClasses.centered} title={roles[0].DisplayName!} placement="top">
<Button
classes={{
label: classes.label,
}}
variant="contained"
color="primary"
size="small"
style={{ marginRight: '0.5rem' }}
endIcon={isIndirect(roles[0]) ? <SwapHorizIcon /> : undefined}
onClick={async (event) => openGroupDialog(event, roles[0])}>
{roles[0].DisplayName}
</Button>
</Tooltip>
) : (
<>
<Tooltip className={globalClasses.centered} title={`${roles.length} roles`} placement="top">
<Button
classes={{
label: classes.label,
}}
aria-controls="more-roles"
aria-haspopup="true"
variant="contained"
color="primary"
size="small"
onClick={(event) => {
event.stopPropagation()
roles.length && setAnchorEl(event.currentTarget)
}}>
{roles.length} roles
</Button>
</Tooltip>
<Menu id="simple-roles" keepMounted anchorEl={anchorEl} open={!!anchorEl} onClose={() => setAnchorEl(null)}>
{roles.map((role) => (
<MenuItem
key={role.Id}
onClick={async (event) => {
openGroupDialog(event, role)
setAnchorEl(null)
}}>
{role.DisplayName}
{isIndirect(role) && (
<div style={{ display: 'flex', paddingLeft: '6px' }}>
<SwapHorizIcon />
</div>
)}
</MenuItem>
))}
</Menu>
</>
)}
<Tooltip
className={globalClasses.centered}
title={roles.length === 1 ? roles[0].DisplayName! : `${roles.length} roles`}
placement="top">
<Button
classes={{
label: classes.label,
}}
aria-controls="more-roles"
aria-haspopup="true"
variant="contained"
color="primary"
size="small"
onClick={(event) => {
event.stopPropagation()
setAnchorEl(event.currentTarget)
}}>
{roles.length === 1 ? roles[0].DisplayName! : `${roles.length} roles`}
</Button>
</Tooltip>
<Menu id="simple-roles" keepMounted anchorEl={anchorEl} open={!!anchorEl} onClose={() => setAnchorEl(null)}>
{roles.map((role) => (
<MenuItem
key={role.Id}
onClick={async (event) => {
openGroupDialog(event, role)
setAnchorEl(null)
}}>
{role.DisplayName}
{isIndirect(role) && (
<div style={{ display: 'flex', paddingLeft: '6px' }}>
<SwapHorizIcon />
</div>
)}
</MenuItem>
))}
<MenuItem
onClick={async (event) => {
openAddToGroupDialog(event)
setAnchorEl(null)
}}>
{localization.addDeleteUserGroups.manageGroups}
<div style={{ display: 'flex', paddingLeft: '6px' }}>
<SettingsIcon fontSize="small" />
</div>
</MenuItem>
</Menu>
</TableCell>
)
}
5 changes: 3 additions & 2 deletions apps/sensenet/src/components/content/Explore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const useStyles = makeStyles((theme: Theme) => {
boxSizing: 'border-box',
borderBottom: theme.palette.type === 'light' ? '1px solid #DBDBDB' : '1px solid rgba(255, 255, 255, 0.11)',
paddingLeft: '15px',
justifyContent: 'space-between',
justifyContent: 'start',
},
treeAndDatagridWrapper: {
display: 'flex',
Expand Down Expand Up @@ -87,6 +87,7 @@ export function Explore({
const history = useHistory()
const uiSettings = useContext(ResponsivePersonalSettings)
const activeContent = useQuery().get('content') ?? ''
const needRoot = useQuery().get('needRoot') !== 'false'
const contentTypeName = useQuery().get('content-type')
const pathFromUrl = useQuery().get('path')
const snRoute = useSnRoute()
Expand Down Expand Up @@ -117,7 +118,7 @@ export function Explore({
<EditView
key={activeContent}
actionName={activeAction}
contentPath={`${rootPath}${activeContent}`}
contentPath={`${needRoot ? rootPath : ''}${activeContent}`}
submitCallback={(savedContent) => {
const contentNameBeforeEdit = PathHelper.getSegments(activeContent).pop()
if (contentNameBeforeEdit && contentNameBeforeEdit !== savedContent.Name && pathFromUrl) {
Expand Down
Loading

0 comments on commit 5426f5b

Please sign in to comment.