perf(memory): add 16 bit texture via configuration - reduces memory by half (#3662)
Co-authored-by: Ouwen Huang <ouwen.huang@duke.edu>
This commit is contained in:
parent
034a6d7696
commit
2bd3b26a6a
@ -44,9 +44,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^1.13.2",
|
||||
"@cornerstonejs/core": "^1.13.2",
|
||||
"@cornerstonejs/tools": "^1.13.2",
|
||||
"@cornerstonejs/adapters": "^1.16.5",
|
||||
"@cornerstonejs/core": "^1.16.5",
|
||||
"@cornerstonejs/tools": "^1.16.5",
|
||||
"classnames": "^2.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.13.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.16.5",
|
||||
"@ohif/core": "3.7.0-beta.78",
|
||||
"@ohif/ui": "3.7.0-beta.78",
|
||||
"dcmjs": "^0.29.6",
|
||||
@ -52,10 +52,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^1.13.2",
|
||||
"@cornerstonejs/core": "^1.13.2",
|
||||
"@cornerstonejs/streaming-image-volume-loader": "^1.13.2",
|
||||
"@cornerstonejs/tools": "^1.13.2",
|
||||
"@cornerstonejs/adapters": "^1.16.5",
|
||||
"@cornerstonejs/core": "^1.16.5",
|
||||
"@cornerstonejs/streaming-image-volume-loader": "^1.16.5",
|
||||
"@cornerstonejs/tools": "^1.16.5",
|
||||
"@kitware/vtk.js": "27.3.1",
|
||||
"html2canvas": "^1.4.1",
|
||||
"lodash.debounce": "4.0.8",
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
imageLoadPoolManager,
|
||||
Settings,
|
||||
utilities as csUtilities,
|
||||
Enums as csEnums,
|
||||
} from '@cornerstonejs/core';
|
||||
import { Enums, utilities, ReferenceLinesTool } from '@cornerstonejs/tools';
|
||||
import { cornerstoneStreamingImageVolumeLoader } from '@cornerstonejs/streaming-image-volume-loader';
|
||||
@ -41,10 +42,28 @@ export default async function init({
|
||||
configuration,
|
||||
appConfig,
|
||||
}: Types.Extensions.ExtensionParams): Promise<void> {
|
||||
await cs3DInit();
|
||||
|
||||
await cs3DInit({
|
||||
rendering: {
|
||||
preferSizeOverAccuracy: Boolean(appConfig.use16BitDataType),
|
||||
useNorm16Texture: Boolean(appConfig.use16BitDataType),
|
||||
},
|
||||
});
|
||||
|
||||
// For debugging e2e tests that are failing on CI
|
||||
cornerstone.setUseCPURendering(Boolean(appConfig.useCPURendering));
|
||||
|
||||
switch (appConfig.useSharedArrayBuffer) {
|
||||
case 'AUTO':
|
||||
cornerstone.setUseSharedArrayBuffer(csEnums.SharedArrayBufferModes.AUTO);
|
||||
break;
|
||||
case 'FALSE':
|
||||
cornerstone.setUseSharedArrayBuffer(csEnums.SharedArrayBufferModes.FALSE);
|
||||
break;
|
||||
default:
|
||||
cornerstone.setUseSharedArrayBuffer(csEnums.SharedArrayBufferModes.TRUE);
|
||||
}
|
||||
|
||||
cornerstone.setConfiguration({
|
||||
...cornerstone.getConfiguration(),
|
||||
rendering: {
|
||||
|
||||
@ -49,6 +49,7 @@ export default function initWADOImageLoader(
|
||||
// Until the default is set to true (which is the case for cornerstone3D),
|
||||
// we should set this flag to false.
|
||||
convertFloatPixelDataToInt: false,
|
||||
use16BitDataType: Boolean(appConfig.use16BitDataType),
|
||||
},
|
||||
beforeSend: function (xhr) {
|
||||
//TODO should be removed in the future and request emitted by DicomWebDataSource
|
||||
|
||||
@ -30,8 +30,8 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cornerstonejs/core": "^1.13.2",
|
||||
"@cornerstonejs/tools": "^1.13.2",
|
||||
"@cornerstonejs/core": "^1.16.5",
|
||||
"@cornerstonejs/tools": "^1.16.5",
|
||||
"@ohif/core": "3.7.0-beta.78",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.78",
|
||||
"@ohif/ui": "3.7.0-beta.78",
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.13.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.16.5",
|
||||
"@ohif/core": "3.7.0-beta.78",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.78",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.78",
|
||||
|
||||
189
platform/app/public/config/default_16bit.js
Normal file
189
platform/app/public/config/default_16bit.js
Normal file
@ -0,0 +1,189 @@
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
// whiteLabeling: {},
|
||||
extensions: [],
|
||||
modes: [],
|
||||
customizationService: {
|
||||
// Shows a custom route -access via http://localhost:3000/custom
|
||||
// helloPage: '@ohif/extension-default.customizationModule.helloPage',
|
||||
},
|
||||
showStudyList: true,
|
||||
// some windows systems have issues with more than 3 web workers
|
||||
maxNumberOfWebWorkers: 3,
|
||||
// below flag is for performance reasons, but it might not work for all servers
|
||||
omitQuotationForMultipartRequest: true,
|
||||
showWarningMessageForCrossOrigin: false,
|
||||
showCPUFallbackMessage: true,
|
||||
showLoadingIndicator: true,
|
||||
use16BitDataType: true,
|
||||
useSharedArrayBuffer: 'AUTO',
|
||||
maxNumRequests: {
|
||||
interaction: 100,
|
||||
thumbnail: 75,
|
||||
// Prefetch number is dependent on the http protocol. For http 2 or
|
||||
// above, the number of requests can be go a lot higher.
|
||||
prefetch: 25,
|
||||
},
|
||||
// filterQueryParam: false,
|
||||
dataSources: [
|
||||
{
|
||||
friendlyName: 'dcmjs DICOMWeb Server',
|
||||
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
|
||||
sourceName: 'dicomweb',
|
||||
configuration: {
|
||||
name: 'aws',
|
||||
// old server
|
||||
// wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
|
||||
// qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
// wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
// new server
|
||||
wadoUriRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
|
||||
qidoRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
|
||||
wadoRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
|
||||
qidoSupportsIncludeField: false,
|
||||
supportsReject: false,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
enableStudyLazyLoad: true,
|
||||
supportsFuzzyMatching: false,
|
||||
supportsWildcard: true,
|
||||
staticWado: true,
|
||||
singlepart: 'bulkdata,video,pdf',
|
||||
},
|
||||
},
|
||||
{
|
||||
friendlyName: 'dicom json',
|
||||
namespace: '@ohif/extension-default.dataSourcesModule.dicomjson',
|
||||
sourceName: 'dicomjson',
|
||||
configuration: {
|
||||
name: 'json',
|
||||
},
|
||||
},
|
||||
{
|
||||
friendlyName: 'dicom local',
|
||||
namespace: '@ohif/extension-default.dataSourcesModule.dicomlocal',
|
||||
sourceName: 'dicomlocal',
|
||||
configuration: {},
|
||||
},
|
||||
],
|
||||
httpErrorHandler: error => {
|
||||
// This is 429 when rejected from the public idc sandbox too often.
|
||||
console.warn(error.status);
|
||||
|
||||
// Could use services manager here to bring up a dialog/modal if needed.
|
||||
console.warn('test, navigate to https://ohif.org/');
|
||||
},
|
||||
// whiteLabeling: {
|
||||
// /* Optional: Should return a React component to be rendered in the "Logo" section of the application's Top Navigation bar */
|
||||
// createLogoComponentFn: function (React) {
|
||||
// return React.createElement(
|
||||
// 'a',
|
||||
// {
|
||||
// target: '_self',
|
||||
// rel: 'noopener noreferrer',
|
||||
// className: 'text-purple-600 line-through',
|
||||
// href: '/',
|
||||
// },
|
||||
// React.createElement('img',
|
||||
// {
|
||||
// src: './customLogo.svg',
|
||||
// className: 'w-8 h-8',
|
||||
// }
|
||||
// ))
|
||||
// },
|
||||
// },
|
||||
defaultDataSourceName: 'dicomweb',
|
||||
hotkeys: [
|
||||
{
|
||||
commandName: 'incrementActiveViewport',
|
||||
label: 'Next Viewport',
|
||||
keys: ['right'],
|
||||
},
|
||||
{
|
||||
commandName: 'decrementActiveViewport',
|
||||
label: 'Previous Viewport',
|
||||
keys: ['left'],
|
||||
},
|
||||
{ commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] },
|
||||
{ commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] },
|
||||
{ commandName: 'invertViewport', label: 'Invert', keys: ['i'] },
|
||||
{
|
||||
commandName: 'flipViewportHorizontal',
|
||||
label: 'Flip Horizontally',
|
||||
keys: ['h'],
|
||||
},
|
||||
{
|
||||
commandName: 'flipViewportVertical',
|
||||
label: 'Flip Vertically',
|
||||
keys: ['v'],
|
||||
},
|
||||
{ commandName: 'scaleUpViewport', label: 'Zoom In', keys: ['+'] },
|
||||
{ commandName: 'scaleDownViewport', label: 'Zoom Out', keys: ['-'] },
|
||||
{ commandName: 'fitViewportToWindow', label: 'Zoom to Fit', keys: ['='] },
|
||||
{ commandName: 'resetViewport', label: 'Reset', keys: ['space'] },
|
||||
{ commandName: 'nextImage', label: 'Next Image', keys: ['down'] },
|
||||
{ commandName: 'previousImage', label: 'Previous Image', keys: ['up'] },
|
||||
// {
|
||||
// commandName: 'previousViewportDisplaySet',
|
||||
// label: 'Previous Series',
|
||||
// keys: ['pagedown'],
|
||||
// },
|
||||
// {
|
||||
// commandName: 'nextViewportDisplaySet',
|
||||
// label: 'Next Series',
|
||||
// keys: ['pageup'],
|
||||
// },
|
||||
{
|
||||
commandName: 'setToolActive',
|
||||
commandOptions: { toolName: 'Zoom' },
|
||||
label: 'Zoom',
|
||||
keys: ['z'],
|
||||
},
|
||||
// ~ Window level presets
|
||||
{
|
||||
commandName: 'windowLevelPreset1',
|
||||
label: 'W/L Preset 1',
|
||||
keys: ['1'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset2',
|
||||
label: 'W/L Preset 2',
|
||||
keys: ['2'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset3',
|
||||
label: 'W/L Preset 3',
|
||||
keys: ['3'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset4',
|
||||
label: 'W/L Preset 4',
|
||||
keys: ['4'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset5',
|
||||
label: 'W/L Preset 5',
|
||||
keys: ['5'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset6',
|
||||
label: 'W/L Preset 6',
|
||||
keys: ['6'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset7',
|
||||
label: 'W/L Preset 7',
|
||||
keys: ['7'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset8',
|
||||
label: 'W/L Preset 8',
|
||||
keys: ['8'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset9',
|
||||
label: 'W/L Preset 9',
|
||||
keys: ['9'],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -35,7 +35,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.13.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.16.5",
|
||||
"@ohif/ui": "3.7.0-beta.78",
|
||||
"cornerstone-math": "0.1.9",
|
||||
"dicom-parser": "^1.8.21"
|
||||
|
||||
@ -108,8 +108,13 @@ window.config = ({ servicesManager } = {}) => {
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Configuration Options
|
||||
|
||||
|
||||
Here are a list of some options available:
|
||||
- `disableEditing`: If true, it disables editing in OHIF, hiding edit buttons in segmentation
|
||||
panel and locking already stored measurements.
|
||||
@ -174,6 +179,10 @@ if auth headers are used, a preflight request is required.
|
||||
}
|
||||
```
|
||||
- `showLoadingIndicator`: (default to true), if set to false, the loading indicator will not be shown when navigating between studies.
|
||||
- `use16BitDataType`: (default to false), if set to true, it will use 16 bit data type for the image data wherever possible which has
|
||||
significant impact on reducing the memory usage. However, the 16Bit textures require EXT_texture_norm16 extension in webGL 2.0 (you can check if you have it here https://webglreport.com/?v=2). In addition to the extension, there are reported problems for Intel Macs that might cause the viewer to crash. In summary, it is great a configuration if you have support for it.
|
||||
- `useSharedArrayBuffer` (default to true), for volume loading we use sharedArrayBuffer to be able to
|
||||
load the volume progressively as the data arrives (each webworker has the shared buffer and can write to it). However, there might be certain environments that do not support sharedArrayBuffer. In that case, you can set this flag to false and the viewer will use the regular arrayBuffer which might be slower for large volume loading.
|
||||
- `supportsWildcard`: (default to false), if set to true, the datasource will support wildcard matching for patient name and patient id.
|
||||
- `dangerouslyUseDynamicConfig`: Dynamic config allows user to pass `configUrl` query string. This allows to load config without recompiling application. If the `configUrl` query string is passed, the worklist and modes will load from the referenced json rather than the default .env config. If there is no `configUrl` path provided, the default behaviour is used and there should not be any deviation from current user experience.<br/>
|
||||
Points to consider while using `dangerouslyUseDynamicConfig`:<br/>
|
||||
|
||||
46
yarn.lock
46
yarn.lock
@ -1376,10 +1376,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||
|
||||
"@cornerstonejs/adapters@^1.13.2":
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.13.2.tgz#4c7a40b652a6c6c9572186852f0c87a8121479bf"
|
||||
integrity sha512-YpMBWLIGbLIVwzQ8gtOE0fE0KW5gH8DGEdXUV0gvKGjsygsKFIdTw3xDC6RJr5n/cpVT0pJHXNhk2bbpiZmfkQ==
|
||||
"@cornerstonejs/adapters@^1.16.5":
|
||||
version "1.16.5"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.16.5.tgz#cb50044ff7a3c26bdf98bda9c13dadbde4580018"
|
||||
integrity sha512-wHDpCwWvo70kzAzxR6zGLUv55D3D52QDmLOAZLHMbeMSVHnKCepefU8mF1z7D2MLnOeyzB9rXGAZyqnK/1VVXA==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs2" "^7.17.8"
|
||||
buffer "^6.0.3"
|
||||
@ -1428,43 +1428,43 @@
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.2.tgz#e96721d56f6ec96f7f95c16321d88cc8467d8d81"
|
||||
integrity sha512-lgdvBvvNezleY+4pIe2ceUsJzlZe/0PipdeubQ3vZZOz3xxtHHMR1XFCl4fgd8gosR8COHuD7h6q+MwgrwBsng==
|
||||
|
||||
"@cornerstonejs/core@^1.13.2":
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.13.2.tgz#15c144ca4da9db257e96fe9f95643b4eb8f707d1"
|
||||
integrity sha512-w2ZonXmOoE8GcDQ0/mY1m/P9CYORH51kh9e26sTQ3CmrvHmAtHI7se4oqcDcUKvSdsA0luw1XKR+TqBR0VcAqQ==
|
||||
"@cornerstonejs/core@^1.16.5":
|
||||
version "1.16.5"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.16.5.tgz#c83a49c5c63ea384f71fe45a977fb9c47c5d7445"
|
||||
integrity sha512-uW+wKsdEDshVCo0A4XcYR4G3zxrGQf2xPuTL4G7jpRmASQGAMYgKQJ/0xOlgyJjlKgvkiXb6qrwbfZH0U9S0vA==
|
||||
dependencies:
|
||||
"@kitware/vtk.js" "27.3.1"
|
||||
detect-gpu "^5.0.22"
|
||||
gl-matrix "^3.4.3"
|
||||
lodash.clonedeep "4.5.0"
|
||||
|
||||
"@cornerstonejs/dicom-image-loader@^1.13.2":
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.13.2.tgz#8f525d246efc1188c15eb1630969524e2002deac"
|
||||
integrity sha512-FyAY7AGU7iQocmmRGYZdoyhSGyNlonpM1qMwhUjA5OoA6hJcWilVW05R0SFrHAbV9DulASaXWsf1Ue0giS0xog==
|
||||
"@cornerstonejs/dicom-image-loader@^1.16.5":
|
||||
version "1.16.5"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.16.5.tgz#23ca3e27e29b88cd05840c777578b37de60e5b87"
|
||||
integrity sha512-PfYU9LujMeyr3rnAjJsgbMU77x/BDAVDR/8XDFLRPbxoeCvdfGLeIR0bbiO6ajvgTutjr9sbYQwtdmQiGnqmCg==
|
||||
dependencies:
|
||||
"@cornerstonejs/codec-charls" "^1.2.3"
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
|
||||
"@cornerstonejs/codec-openjpeg" "^1.2.2"
|
||||
"@cornerstonejs/codec-openjph" "^2.4.2"
|
||||
"@cornerstonejs/core" "^1.13.2"
|
||||
"@cornerstonejs/core" "^1.16.5"
|
||||
dicom-parser "^1.8.9"
|
||||
pako "^2.0.4"
|
||||
uuid "^9.0.0"
|
||||
|
||||
"@cornerstonejs/streaming-image-volume-loader@^1.13.2":
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-1.13.2.tgz#4b4ba637d79bfd194367a88697e6d3dc2440505d"
|
||||
integrity sha512-V+2nQmIXQZQvHL6wYMHuW6NsIWi/sDmsJRyXvWKUSJvrCmj7JIxfeECr1+Mn11yizy3bYeA6eDWWGyapFh/2iw==
|
||||
"@cornerstonejs/streaming-image-volume-loader@^1.16.5":
|
||||
version "1.16.5"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-1.16.5.tgz#9af370be2409e932caf1ff47fba9cfcf1b671065"
|
||||
integrity sha512-98NsgeBPaEPMJnCsYKLDvGydREBh4Gue62o4AwcMyMOmH3tVC1neeMPzRNh0YTHHkQJJfjT5vD18+vYP86hnUw==
|
||||
dependencies:
|
||||
"@cornerstonejs/core" "^1.13.2"
|
||||
"@cornerstonejs/core" "^1.16.5"
|
||||
|
||||
"@cornerstonejs/tools@^1.13.2":
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-1.13.2.tgz#2074d0d7f1dba61295fcb81616bf48ea530d747f"
|
||||
integrity sha512-DI8GpbygBWG5ha9mawk0gSUfT+xBn/NE6gwo9jjjN2MTpiI1N8AcsNktLG2mlmq89wRMZhu4xvmo9QQDlf2dPQ==
|
||||
"@cornerstonejs/tools@^1.16.5":
|
||||
version "1.16.5"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-1.16.5.tgz#79948216521c591a02f395e2130d72e0b9347eca"
|
||||
integrity sha512-zUDBB6P13O1HZDiEyIGCORmAN1Ih9Z8QpjE0iM3hATdWUmHFs/2mBvHre/Wjh+BkNdtNTJ6s9pmbmz0CRVScUQ==
|
||||
dependencies:
|
||||
"@cornerstonejs/core" "^1.13.2"
|
||||
"@cornerstonejs/core" "^1.16.5"
|
||||
lodash.clonedeep "4.5.0"
|
||||
lodash.get "^4.4.2"
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user