replace custom hook implementation for permissions

pull/1344/head
joseph izang 3 years ago
parent d72b8526a2
commit b51c8c1fa4
  1. 49
      libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx
  2. 123
      libs/remix-ui/plugin-manager/src/lib/custom-hooks/useLocalStorage.ts
  3. 3
      libs/remix-ui/plugin-manager/tsconfig.json
  4. 4
      libs/remix-ui/plugin-manager/tsconfig.lib.json
  5. 15
      libs/remix-ui/plugin-manager/tsconfig.spec.json

@ -2,7 +2,8 @@
import React, { Fragment, useEffect, useState } from 'react' import React, { Fragment, useEffect, useState } from 'react'
/* eslint-disable-line */ /* eslint-disable-line */
import { ModalDialog } from '@remix-ui/modal-dialog' import { ModalDialog } from '@remix-ui/modal-dialog'
import { useLocalStorage } from '../custom-hooks/useLocalStorage' import useLocalStorage from '../custom-hooks/useLocalStorage'
import { PluginPermissions } from '../../types'
// import { PluginManagerSettings, PluginPermissions } from '../../types' // import { PluginManagerSettings, PluginPermissions } from '../../types'
interface PermissionSettingsProps { interface PermissionSettingsProps {
@ -14,7 +15,7 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
* Declare component local state * Declare component local state
*/ */
const [modalVisibility, setModalVisibility] = useState<boolean>(true) const [modalVisibility, setModalVisibility] = useState<boolean>(true)
const [permissions, setPermissions] = useLocalStorage('plugins/permissions', '{}') const [permissions, setPermissions] = useLocalStorage<PluginPermissions>('plugins/permissions', {} as PluginPermissions)
const closeModal = () => setModalVisibility(true) const closeModal = () => setModalVisibility(true)
function ShowPluginHeading ({ headingName }) { function ShowPluginHeading ({ headingName }) {
@ -23,7 +24,6 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
<h3>{headingName} permissions:</h3> <h3>{headingName} permissions:</h3>
<i <i
onClick={() => { onClick={() => {
console.log(`${headingName}`)
clearPersmission(headingName) clearPersmission(headingName)
}} }}
className="far fa-trash-alt" className="far fa-trash-alt"
@ -41,28 +41,32 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
topLevelPluginName: string topLevelPluginName: string
}) { }) {
const [checkBoxState, setCheckBoxState] = useState(allow) const [checkBoxState, setCheckBoxState] = useState(allow)
const [showPermissions, setShowPermissions] = useLocalStorage<PluginPermissions>('plugins/permissions', {} as PluginPermissions)
useEffect(() => { useEffect(() => {
window.addEventListener('storage', () => setPermissions(showPermissions))
return () => window.removeEventListener('storage', () => setPermissions(showPermissions))
}, [checkBoxState]) }, [checkBoxState])
const handleCheckboxClick = () => { const handleCheckboxClick = () => {
const copyPermissions = permissions const copyPermissions = showPermissions
copyPermissions[pluginName][functionName][topLevelPluginName].allow = !checkBoxState copyPermissions[pluginName][functionName][topLevelPluginName].allow = !checkBoxState
setCheckBoxState(!checkBoxState) setCheckBoxState(!checkBoxState)
setPermissions(copyPermissions) setShowPermissions(copyPermissions)
} }
console.log('showPermissions', showPermissions)
return ( return (
<div className="form-group remixui_permissionKey"> <div className="form-group remixui_permissionKey">
<div className="remixui_checkbox"> { showPermissions && Object.keys(showPermissions).length > 0
? (
<><div className="remixui_checkbox">
<span className="mr-2"> <span className="mr-2">
<input <input
type="checkbox" type="checkbox"
onChange={handleCheckboxClick} onChange={handleCheckboxClick}
checked={checkBoxState} checked={checkBoxState}
id={`permission-checkbox-${topLevelPluginName}-${functionName}-${pluginName}`} id={`permission-checkbox-${topLevelPluginName}-${functionName}-${pluginName}`}
aria-describedby={`module ${pluginName} asks permission for ${functionName}`} aria-describedby={`module ${pluginName} asks permission for ${functionName}`} />
/>
<label <label
className="ml-4" className="ml-4"
htmlFor={`permission-checkbox-${topLevelPluginName}-${functionName}-${topLevelPluginName}`} htmlFor={`permission-checkbox-${topLevelPluginName}-${functionName}-${topLevelPluginName}`}
@ -71,15 +75,14 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
Allow <u>{pluginName}</u> to call <u>{functionName}</u> Allow <u>{pluginName}</u> to call <u>{functionName}</u>
</label> </label>
</span> </span>
</div> </div><i
<i
onClick={() => { onClick={() => {
console.log(`${pluginName}'s trash icon was clicked!`)
clearAllPersmissions(pluginName, topLevelPluginName, functionName) clearAllPersmissions(pluginName, topLevelPluginName, functionName)
} } } }
className="fa fa-trash-alt" className="fa fa-trash-alt"
data-id={`pluginManagerSettingsRemovePermission-${topLevelPluginName}-${functionName}-${topLevelPluginName}`} data-id={`pluginManagerSettingsRemovePermission-${topLevelPluginName}-${functionName}-${topLevelPluginName}`} /></>
/> ) : null
}
</div> </div>
) )
} }
@ -95,9 +98,7 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
delete permissionsCopy[topLevelPluginName] delete permissionsCopy[topLevelPluginName]
} }
} }
// eslint-disable-next-line no-debugger setPermissions(permissionsCopy)
debugger
setPermissions({ ...permissionsCopy })
} }
function clearPersmission (topLevelPluginName: string) { function clearPersmission (topLevelPluginName: string) {
@ -105,7 +106,7 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
if (permissionsCopy[topLevelPluginName]) { if (permissionsCopy[topLevelPluginName]) {
delete permissionsCopy[topLevelPluginName] delete permissionsCopy[topLevelPluginName]
} }
setPermissions({}) setPermissions({} as PluginPermissions)
} }
return ( return (
@ -117,23 +118,23 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
okLabel="OK" okLabel="OK"
cancelLabel="Cancel" cancelLabel="Cancel"
> >
{JSON.parse(localStorage.getItem('plugins/permissions')) && Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))).length > 0 {permissions && Object.keys(permissions).length > 0
? (<h4 className="text-center">Current Permission Settings</h4>) ? (<h4 className="text-center">Current Permission Settings</h4>)
: (<h4 className="text-center">No Permission requested yet.</h4>) : (<h4 className="text-center">No Permission requested yet.</h4>)
} }
<form className="remixui_permissionForm" data-id="pluginManagerSettingsPermissionForm"> <form className="remixui_permissionForm" data-id="pluginManagerSettingsPermissionForm">
<div className="p-2"> <div className="p-2">
{ {
Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))).map(toplevelName => ( Object.keys(permissions).map(toplevelName => (
<ShowPluginHeading key={toplevelName} headingName={toplevelName} /> <ShowPluginHeading key={toplevelName} headingName={toplevelName} />
)) ))
} }
{ {
Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))).map(topName => { Object.keys(permissions).map(topName => {
return Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))[topName]).map(funcName => { return Object.keys(permissions[topName]).map(funcName => {
return Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))[topName][funcName]).map(pluginName => ( return Object.keys(permissions[topName][funcName]).map(pluginName => (
<ShowCheckBox <ShowCheckBox
allow={JSON.parse(localStorage.getItem('plugins/permissions'))[topName][funcName][pluginName].allow} allow={permissions[topName][funcName][pluginName].allow}
functionName={funcName} functionName={funcName}
pluginName={pluginName} pluginName={pluginName}
topLevelPluginName={topName} topLevelPluginName={topName}

@ -1,36 +1,115 @@
import { useState } from 'react' // import { useState } from 'react'
// // Hook
// export const useLocalStorage = (key: string, initialValue: any) => {
// // State to store our value
// // Pass initial state function to useState so logic is only executed once
// const [storedValue, setStoredValue] = useState<any>(() => {
// try {
// // Get from local storage by key
// const item = window.localStorage.getItem(key)
// // Parse stored json or if none return initialValue
// return item ? JSON.parse(item) : initialValue
// } catch (error) {
// // If error also return initialValue
// console.log(error)
// return initialValue
// }
// })
// // Return a wrapped version of useState's setter function that ...
// // ... persists the new value to localStorage.
// const setValue = (value: any | ((val: any) => any)) => {
// try {
// // Allow value to be a function so we have same API as useState
// const valueToStore =
// value instanceof Function ? value(storedValue) : value
// // Save state
// setStoredValue(valueToStore)
// // Save to local storage
// window.localStorage.setItem(key, JSON.stringify(valueToStore))
// } catch (error) {
// // A more advanced implementation would handle the error case
// console.log(error)
// }
// }
// return [storedValue, setValue] as const
// }
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
type SetValue<T> = Dispatch<SetStateAction<T>>
function useLocalStorage<T> (key: string, initialValue: T): [T, SetValue<T>] {
// Get from local storage then
// parse stored json or return initialValue
const readValue = (): T => {
// Prevent build error "window is undefined" but keep keep working
if (typeof window === 'undefined') {
return initialValue
}
// Hook
export const useLocalStorage = (key: string, initialValue: any) => {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState<any>(() => {
try { try {
// Get from local storage by key
const item = window.localStorage.getItem(key) const item = window.localStorage.getItem(key)
// Parse stored json or if none return initialValue return item ? (JSON.parse(item) as T) : initialValue
return item ? JSON.parse(item) : initialValue
} catch (error) { } catch (error) {
// If error also return initialValue console.warn(`Error reading localStorage key “${key}”:`, error)
console.log(error)
return initialValue return initialValue
} }
}) }
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState<T>(readValue)
// Return a wrapped version of useState's setter function that ... // Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage. // ... persists the new value to localStorage.
const setValue = (value: any | ((val: any) => any)) => { const setValue: SetValue<T> = value => {
// Prevent build error "window is undefined" but keeps working
if (typeof window === 'undefined') {
console.warn(
`Tried setting localStorage key “${key}” even though environment is not a client`
)
}
try { try {
// Allow value to be a function so we have same API as useState // Allow value to be a function so we have the same API as useState
const valueToStore = const newValue = value instanceof Function ? value(storedValue) : value
value instanceof Function ? value(storedValue) : value
// Save state
setStoredValue(valueToStore)
// Save to local storage // Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore)) window.localStorage.setItem(key, JSON.stringify(newValue))
// Save state
setStoredValue(newValue)
// We dispatch a custom event so every useLocalStorage hook are notified
window.dispatchEvent(new Event('local-storage'))
} catch (error) { } catch (error) {
// A more advanced implementation would handle the error case console.warn(`Error setting localStorage key “${key}”:`, error)
console.log(error) }
}
useEffect(() => {
setStoredValue(readValue())
}, [])
useEffect(() => {
const handleStorageChange = () => {
setStoredValue(readValue())
} }
// this only works for other documents, not the current one
window.addEventListener('storage', handleStorageChange)
// this is a custom event, triggered in writeValueToLocalStorage
window.addEventListener('local-storage', handleStorageChange)
return () => {
window.removeEventListener('storage', handleStorageChange)
window.removeEventListener('local-storage', handleStorageChange)
} }
return [storedValue, setValue] as const }, [])
return [storedValue, setValue]
} }
export default useLocalStorage

@ -12,9 +12,6 @@
"references": [ "references": [
{ {
"path": "./tsconfig.lib.json" "path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
} }
] ]
} }

@ -5,8 +5,8 @@
"types": ["node"] "types": ["node"]
}, },
"files": [ "files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts", "../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../node_modules/@nrwl/react/typings/image.d.ts" "../../../node_modules/@nrwl/react/typings/image.d.ts"
], ],
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"], "exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]

@ -1,15 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*.spec.js",
"**/*.spec.jsx",
"**/*.d.ts"
]
}
Loading…
Cancel
Save