Merge pull request #207 from authorizerdev/feat/email-template-ui
feat: email template UI + subject
This commit is contained in:
commit
8f69d5746e
480
dashboard/package-lock.json
generated
480
dashboard/package-lock.json
generated
|
@ -17,6 +17,9 @@
|
|||
"@types/react-dom": "^17.0.11",
|
||||
"@types/react-router-dom": "^5.3.2",
|
||||
"dayjs": "^1.10.7",
|
||||
"draft-js": "^0.11.7",
|
||||
"draft-js-import-html": "^1.4.1",
|
||||
"draftjs-to-html": "^0.9.1",
|
||||
"esbuild": "^0.14.9",
|
||||
"focus-visible": "^5.2.0",
|
||||
"framer-motion": "^5.5.5",
|
||||
|
@ -24,11 +27,16 @@
|
|||
"lodash": "^4.17.21",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-draft-wysiwyg": "^1.15.0",
|
||||
"react-dropzone": "^12.0.4",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-router-dom": "^6.2.1",
|
||||
"typescript": "^4.5.4",
|
||||
"urql": "^2.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/draftjs-to-html": "^0.8.1",
|
||||
"@types/react-draft-wysiwyg": "^1.13.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
|
@ -1145,6 +1153,25 @@
|
|||
"react-dom": "^16.8.0 || 17.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/draft-js": {
|
||||
"version": "0.11.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/draft-js/-/draft-js-0.11.9.tgz",
|
||||
"integrity": "sha512-cQJBZjjIlGaPA1tOY+wGz2KhlPtAAZOIXpUvGPxPRw5uzZ2tcj8m6Yu1QDV9YgP36+cqE3cUvgkARBzgUiuI/Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"immutable": "~3.7.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/draftjs-to-html": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/draftjs-to-html/-/draftjs-to-html-0.8.1.tgz",
|
||||
"integrity": "sha512-NBkphQs+qZ/sAz/j1pCUaxkPAOx00LTsE88aMSSfcvK+UfCpjHJDqIMCkm6wKotuJvY5w0BtdRazQ0sAaXzPdg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/draft-js": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/history": {
|
||||
"version": "4.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz",
|
||||
|
@ -1191,6 +1218,16 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-draft-wysiwyg": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-draft-wysiwyg/-/react-draft-wysiwyg-1.13.4.tgz",
|
||||
"integrity": "sha512-wasD1t78JDmQvdPDRPf/mf5FSHMlncunW0F6KMOKB3awzi3Wi21yHMGsRAUOkfTr3R8F+yceG8fSLz0kYWu/QA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/draft-js": "*",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router": {
|
||||
"version": "5.1.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz",
|
||||
|
@ -1259,6 +1296,11 @@
|
|||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
|
||||
},
|
||||
"node_modules/attr-accept": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz",
|
||||
|
@ -1306,6 +1348,11 @@
|
|||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
|
||||
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
|
@ -1340,6 +1387,16 @@
|
|||
"toggle-selection": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.24.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.24.1.tgz",
|
||||
"integrity": "sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==",
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
|
||||
|
@ -1355,6 +1412,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
|
||||
"integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
|
||||
"dependencies": {
|
||||
"node-fetch": "2.6.7"
|
||||
}
|
||||
},
|
||||
"node_modules/css-box-model": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
|
||||
|
@ -1383,6 +1448,68 @@
|
|||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
|
||||
},
|
||||
"node_modules/draft-js": {
|
||||
"version": "0.11.7",
|
||||
"resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz",
|
||||
"integrity": "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==",
|
||||
"dependencies": {
|
||||
"fbjs": "^2.0.0",
|
||||
"immutable": "~3.7.4",
|
||||
"object-assign": "^4.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=0.14.0",
|
||||
"react-dom": ">=0.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/draft-js-import-element": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/draft-js-import-element/-/draft-js-import-element-1.4.0.tgz",
|
||||
"integrity": "sha512-WmYT5PrCm47lGL5FkH6sRO3TTAcn7qNHsD3igiPqLG/RXrqyKrqN4+wBgbcT2lhna/yfWTRtgzAbQsSJoS1Meg==",
|
||||
"dependencies": {
|
||||
"draft-js-utils": "^1.4.0",
|
||||
"synthetic-dom": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"draft-js": ">=0.10.0",
|
||||
"immutable": "3.x.x"
|
||||
}
|
||||
},
|
||||
"node_modules/draft-js-import-html": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/draft-js-import-html/-/draft-js-import-html-1.4.1.tgz",
|
||||
"integrity": "sha512-KOZmtgxZriCDgg5Smr3Y09TjubvXe7rHPy/2fuLSsL+aSzwUDwH/aHDA/k47U+WfpmL4qgyg4oZhqx9TYJV0tg==",
|
||||
"dependencies": {
|
||||
"draft-js-import-element": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"draft-js": ">=0.10.0",
|
||||
"immutable": "3.x.x"
|
||||
}
|
||||
},
|
||||
"node_modules/draft-js-utils": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/draft-js-utils/-/draft-js-utils-1.4.1.tgz",
|
||||
"integrity": "sha512-xE81Y+z/muC5D5z9qWmKfxEW1XyXfsBzSbSBk2JRsoD0yzMGGHQm/0MtuqHl/EUDkaBJJLjJ2EACycoDMY/OOg==",
|
||||
"peerDependencies": {
|
||||
"draft-js": ">=0.10.0",
|
||||
"immutable": "3.x.x"
|
||||
}
|
||||
},
|
||||
"node_modules/draftjs-to-html": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/draftjs-to-html/-/draftjs-to-html-0.9.1.tgz",
|
||||
"integrity": "sha512-fFstE6+IayaVFBEvaFt/wN8vdj8FsTRzij7dy7LI9QIwf5LgfHFi9zSpvCg+feJ2tbYVqHxUkjcibwpsTpgFVQ=="
|
||||
},
|
||||
"node_modules/draftjs-utils": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz",
|
||||
"integrity": "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==",
|
||||
"peerDependencies": {
|
||||
"draft-js": "^0.11.x",
|
||||
"immutable": "3.x.x || 4.x.x"
|
||||
}
|
||||
},
|
||||
"node_modules/error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
|
@ -1647,6 +1774,26 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/fbjs": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz",
|
||||
"integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==",
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.4",
|
||||
"cross-fetch": "^3.0.4",
|
||||
"fbjs-css-vars": "^1.0.0",
|
||||
"loose-envify": "^1.0.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"promise": "^7.1.1",
|
||||
"setimmediate": "^1.0.5",
|
||||
"ua-parser-js": "^0.7.18"
|
||||
}
|
||||
},
|
||||
"node_modules/fbjs-css-vars": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
|
||||
"integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="
|
||||
},
|
||||
"node_modules/file-selector": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz",
|
||||
|
@ -1802,6 +1949,23 @@
|
|||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-to-draftjs": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz",
|
||||
"integrity": "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ==",
|
||||
"peerDependencies": {
|
||||
"draft-js": "^0.10.x || ^0.11.x",
|
||||
"immutable": "3.x.x || 4.x.x"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "3.7.6",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz",
|
||||
"integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
|
@ -1856,6 +2020,14 @@
|
|||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
|
||||
"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
|
||||
"dependencies": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
|
@ -1877,6 +2049,25 @@
|
|||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
|
@ -1945,6 +2136,14 @@
|
|||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"dependencies": {
|
||||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
|
@ -1991,6 +2190,24 @@
|
|||
"react": "17.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-draft-wysiwyg": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/react-draft-wysiwyg/-/react-draft-wysiwyg-1.15.0.tgz",
|
||||
"integrity": "sha512-p1cYZcWc6/ALFBVksbFoCM3b29fGQDlZLIMrXng0TU/UElxIOF2/AWWo4L5auIYVhmqKTZ0NkNjnXOzGGuxyeA==",
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.6",
|
||||
"draftjs-utils": "^0.10.2",
|
||||
"html-to-draftjs": "^1.5.0",
|
||||
"linkify-it": "^2.2.0",
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"draft-js": "^0.10.x || ^0.11.x",
|
||||
"immutable": "3.x.x || 4.x.x",
|
||||
"react": "0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x",
|
||||
"react-dom": "0.13.x || 0.14.x || ^15.0.0-0 || 15.x.x || ^16.0.0-0 || ^16.x.x || ^17.x.x || ^18.x.x"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dropzone": {
|
||||
"version": "12.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-12.0.4.tgz",
|
||||
|
@ -2207,6 +2424,11 @@
|
|||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
|
@ -2240,6 +2462,11 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/synthetic-dom": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/synthetic-dom/-/synthetic-dom-1.4.0.tgz",
|
||||
"integrity": "sha512-mHv51ZsmZ+ShT/4s5kg+MGUIhY7Ltq4v03xpN1c8T1Krb5pScsh/lzEjyhrVD0soVDbThbd2e+4dD9vnDG4rhg=="
|
||||
},
|
||||
"node_modules/tiny-invariant": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz",
|
||||
|
@ -2258,6 +2485,11 @@
|
|||
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
|
||||
"integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
|
@ -2275,6 +2507,29 @@
|
|||
"node": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ua-parser-js": {
|
||||
"version": "0.7.31",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
|
||||
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ua-parser-js"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/faisalman"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
|
||||
},
|
||||
"node_modules/urql": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz",
|
||||
|
@ -2333,6 +2588,20 @@
|
|||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wonka": {
|
||||
"version": "4.0.15",
|
||||
"resolved": "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz",
|
||||
|
@ -2529,8 +2798,7 @@
|
|||
"@chakra-ui/css-reset": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz",
|
||||
"integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg=="
|
||||
},
|
||||
"@chakra-ui/descendant": {
|
||||
"version": "2.1.1",
|
||||
|
@ -3134,8 +3402,7 @@
|
|||
"@graphql-typed-document-node/core": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
|
||||
"integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg=="
|
||||
},
|
||||
"@popperjs/core": {
|
||||
"version": "2.11.0",
|
||||
|
@ -3172,6 +3439,25 @@
|
|||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"@types/draft-js": {
|
||||
"version": "0.11.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/draft-js/-/draft-js-0.11.9.tgz",
|
||||
"integrity": "sha512-cQJBZjjIlGaPA1tOY+wGz2KhlPtAAZOIXpUvGPxPRw5uzZ2tcj8m6Yu1QDV9YgP36+cqE3cUvgkARBzgUiuI/Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"immutable": "~3.7.4"
|
||||
}
|
||||
},
|
||||
"@types/draftjs-to-html": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/draftjs-to-html/-/draftjs-to-html-0.8.1.tgz",
|
||||
"integrity": "sha512-NBkphQs+qZ/sAz/j1pCUaxkPAOx00LTsE88aMSSfcvK+UfCpjHJDqIMCkm6wKotuJvY5w0BtdRazQ0sAaXzPdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/draft-js": "*"
|
||||
}
|
||||
},
|
||||
"@types/history": {
|
||||
"version": "4.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz",
|
||||
|
@ -3218,6 +3504,16 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-draft-wysiwyg": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-draft-wysiwyg/-/react-draft-wysiwyg-1.13.4.tgz",
|
||||
"integrity": "sha512-wasD1t78JDmQvdPDRPf/mf5FSHMlncunW0F6KMOKB3awzi3Wi21yHMGsRAUOkfTr3R8F+yceG8fSLz0kYWu/QA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/draft-js": "*",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "5.1.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz",
|
||||
|
@ -3279,6 +3575,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
|
||||
},
|
||||
"attr-accept": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz",
|
||||
|
@ -3316,6 +3617,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
|
||||
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
|
@ -3350,6 +3656,11 @@
|
|||
"toggle-selection": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.24.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.24.1.tgz",
|
||||
"integrity": "sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg=="
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
|
||||
|
@ -3362,6 +3673,14 @@
|
|||
"yaml": "^1.7.2"
|
||||
}
|
||||
},
|
||||
"cross-fetch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
|
||||
"integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
|
||||
"requires": {
|
||||
"node-fetch": "2.6.7"
|
||||
}
|
||||
},
|
||||
"css-box-model": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
|
||||
|
@ -3390,6 +3709,48 @@
|
|||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
|
||||
},
|
||||
"draft-js": {
|
||||
"version": "0.11.7",
|
||||
"resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz",
|
||||
"integrity": "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==",
|
||||
"requires": {
|
||||
"fbjs": "^2.0.0",
|
||||
"immutable": "~3.7.4",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"draft-js-import-element": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/draft-js-import-element/-/draft-js-import-element-1.4.0.tgz",
|
||||
"integrity": "sha512-WmYT5PrCm47lGL5FkH6sRO3TTAcn7qNHsD3igiPqLG/RXrqyKrqN4+wBgbcT2lhna/yfWTRtgzAbQsSJoS1Meg==",
|
||||
"requires": {
|
||||
"draft-js-utils": "^1.4.0",
|
||||
"synthetic-dom": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"draft-js-import-html": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/draft-js-import-html/-/draft-js-import-html-1.4.1.tgz",
|
||||
"integrity": "sha512-KOZmtgxZriCDgg5Smr3Y09TjubvXe7rHPy/2fuLSsL+aSzwUDwH/aHDA/k47U+WfpmL4qgyg4oZhqx9TYJV0tg==",
|
||||
"requires": {
|
||||
"draft-js-import-element": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"draft-js-utils": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/draft-js-utils/-/draft-js-utils-1.4.1.tgz",
|
||||
"integrity": "sha512-xE81Y+z/muC5D5z9qWmKfxEW1XyXfsBzSbSBk2JRsoD0yzMGGHQm/0MtuqHl/EUDkaBJJLjJ2EACycoDMY/OOg=="
|
||||
},
|
||||
"draftjs-to-html": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/draftjs-to-html/-/draftjs-to-html-0.9.1.tgz",
|
||||
"integrity": "sha512-fFstE6+IayaVFBEvaFt/wN8vdj8FsTRzij7dy7LI9QIwf5LgfHFi9zSpvCg+feJ2tbYVqHxUkjcibwpsTpgFVQ=="
|
||||
},
|
||||
"draftjs-utils": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz",
|
||||
"integrity": "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg=="
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
|
@ -3536,6 +3897,26 @@
|
|||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
|
||||
},
|
||||
"fbjs": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz",
|
||||
"integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==",
|
||||
"requires": {
|
||||
"core-js": "^3.6.4",
|
||||
"cross-fetch": "^3.0.4",
|
||||
"fbjs-css-vars": "^1.0.0",
|
||||
"loose-envify": "^1.0.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"promise": "^7.1.1",
|
||||
"setimmediate": "^1.0.5",
|
||||
"ua-parser-js": "^0.7.18"
|
||||
}
|
||||
},
|
||||
"fbjs-css-vars": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
|
||||
"integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="
|
||||
},
|
||||
"file-selector": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz",
|
||||
|
@ -3659,6 +4040,16 @@
|
|||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"html-to-draftjs": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz",
|
||||
"integrity": "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ=="
|
||||
},
|
||||
"immutable": {
|
||||
"version": "3.7.6",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz",
|
||||
"integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw=="
|
||||
},
|
||||
"import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
|
@ -3704,6 +4095,14 @@
|
|||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||
},
|
||||
"linkify-it": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
|
||||
"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
|
||||
"requires": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
|
@ -3722,6 +4121,14 @@
|
|||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
|
@ -3777,6 +4184,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"requires": {
|
||||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
|
@ -3814,6 +4229,18 @@
|
|||
"scheduler": "^0.20.2"
|
||||
}
|
||||
},
|
||||
"react-draft-wysiwyg": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/react-draft-wysiwyg/-/react-draft-wysiwyg-1.15.0.tgz",
|
||||
"integrity": "sha512-p1cYZcWc6/ALFBVksbFoCM3b29fGQDlZLIMrXng0TU/UElxIOF2/AWWo4L5auIYVhmqKTZ0NkNjnXOzGGuxyeA==",
|
||||
"requires": {
|
||||
"classnames": "^2.2.6",
|
||||
"draftjs-utils": "^0.10.2",
|
||||
"html-to-draftjs": "^1.5.0",
|
||||
"linkify-it": "^2.2.0",
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"react-dropzone": {
|
||||
"version": "12.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-12.0.4.tgz",
|
||||
|
@ -3845,8 +4272,7 @@
|
|||
"react-icons": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
|
||||
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ=="
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
|
@ -3968,6 +4394,11 @@
|
|||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
|
@ -3995,6 +4426,11 @@
|
|||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"synthetic-dom": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/synthetic-dom/-/synthetic-dom-1.4.0.tgz",
|
||||
"integrity": "sha512-mHv51ZsmZ+ShT/4s5kg+MGUIhY7Ltq4v03xpN1c8T1Krb5pScsh/lzEjyhrVD0soVDbThbd2e+4dD9vnDG4rhg=="
|
||||
},
|
||||
"tiny-invariant": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz",
|
||||
|
@ -4010,6 +4446,11 @@
|
|||
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
|
||||
"integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
|
@ -4020,6 +4461,16 @@
|
|||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz",
|
||||
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.31",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
|
||||
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ=="
|
||||
},
|
||||
"uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
|
||||
},
|
||||
"urql": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz",
|
||||
|
@ -4032,8 +4483,7 @@
|
|||
"use-callback-ref": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz",
|
||||
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg=="
|
||||
},
|
||||
"use-sidecar": {
|
||||
"version": "1.0.5",
|
||||
|
@ -4059,6 +4509,20 @@
|
|||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"wonka": {
|
||||
"version": "4.0.15",
|
||||
"resolved": "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz",
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"@types/react-dom": "^17.0.11",
|
||||
"@types/react-router-dom": "^5.3.2",
|
||||
"dayjs": "^1.10.7",
|
||||
"draft-js": "^0.11.7",
|
||||
"draft-js-import-html": "^1.4.1",
|
||||
"draftjs-to-html": "^0.9.1",
|
||||
"esbuild": "^0.14.9",
|
||||
"focus-visible": "^5.2.0",
|
||||
"framer-motion": "^5.5.5",
|
||||
|
@ -26,10 +29,15 @@
|
|||
"lodash": "^4.17.21",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-draft-wysiwyg": "^1.15.0",
|
||||
"react-dropzone": "^12.0.4",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-router-dom": "^6.2.1",
|
||||
"typescript": "^4.5.4",
|
||||
"urql": "^2.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/draftjs-to-html": "^0.8.1",
|
||||
"@types/react-draft-wysiwyg": "^1.13.4"
|
||||
}
|
||||
}
|
||||
|
|
106
dashboard/src/components/DeleteEmailTemplateModal.tsx
Normal file
106
dashboard/src/components/DeleteEmailTemplateModal.tsx
Normal file
|
@ -0,0 +1,106 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
useDisclosure,
|
||||
Text,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { useClient } from 'urql';
|
||||
import { FaRegTrashAlt } from 'react-icons/fa';
|
||||
import { DeleteEmailTemplate } from '../graphql/mutation';
|
||||
import { capitalizeFirstLetter } from '../utils';
|
||||
|
||||
interface deleteEmailTemplateModalInputPropTypes {
|
||||
emailTemplateId: string;
|
||||
eventName: string;
|
||||
fetchEmailTemplatesData: Function;
|
||||
}
|
||||
|
||||
const DeleteEmailTemplateModal = ({
|
||||
emailTemplateId,
|
||||
eventName,
|
||||
fetchEmailTemplatesData,
|
||||
}: deleteEmailTemplateModalInputPropTypes) => {
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
const deleteHandler = async () => {
|
||||
const res = await client
|
||||
.mutation(DeleteEmailTemplate, { params: { id: emailTemplateId } })
|
||||
.toPromise();
|
||||
if (res.error) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(res.error.message),
|
||||
isClosable: true,
|
||||
status: 'error',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
|
||||
return;
|
||||
} else if (res.data?._delete_email_template) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(res.data?._delete_email_template.message),
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
}
|
||||
onClose();
|
||||
fetchEmailTemplatesData();
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={onOpen}>Delete</MenuItem>
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Delete Email Template</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Text fontSize="md">Are you sure?</Text>
|
||||
<Flex
|
||||
padding="5%"
|
||||
marginTop="5%"
|
||||
marginBottom="2%"
|
||||
border="1px solid #ff7875"
|
||||
borderRadius="5px"
|
||||
flexDirection="column"
|
||||
>
|
||||
<Text fontSize="sm">
|
||||
Email template for event <b>{eventName}</b> will be deleted
|
||||
permanently!
|
||||
</Text>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button
|
||||
leftIcon={<FaRegTrashAlt />}
|
||||
colorScheme="red"
|
||||
variant="solid"
|
||||
onClick={deleteHandler}
|
||||
isDisabled={false}
|
||||
>
|
||||
<Center h="100%" pt="5%">
|
||||
Delete
|
||||
</Center>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteEmailTemplateModal;
|
|
@ -12,7 +12,6 @@ import {
|
|||
Select,
|
||||
Textarea,
|
||||
Switch,
|
||||
Code,
|
||||
Text,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
FiUsers,
|
||||
FiChevronDown,
|
||||
FiLink,
|
||||
FiFileText,
|
||||
} from 'react-icons/fi';
|
||||
import { BiCustomize } from 'react-icons/bi';
|
||||
import { AiOutlineKey } from 'react-icons/ai';
|
||||
|
@ -113,6 +114,7 @@ const LinkItems: Array<LinkItemProps> = [
|
|||
},
|
||||
{ name: 'Users', icon: FiUsers, route: '/users' },
|
||||
{ name: 'Webhooks', icon: FiLink, route: '/webhooks' },
|
||||
{ name: 'Email Templates', icon: FiFileText, route: '/email-templates' },
|
||||
];
|
||||
|
||||
interface SidebarProps extends BoxProps {
|
||||
|
|
375
dashboard/src/components/UpdateEmailTemplateModal.tsx
Normal file
375
dashboard/src/components/UpdateEmailTemplateModal.tsx
Normal file
|
@ -0,0 +1,375 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
Input,
|
||||
InputGroup,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Select,
|
||||
Text,
|
||||
useDisclosure,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaPlus } from 'react-icons/fa';
|
||||
import { useClient } from 'urql';
|
||||
import { Editor } from 'react-draft-wysiwyg';
|
||||
import { EditorState, convertToRaw, Modifier } from 'draft-js';
|
||||
import draftToHtml from 'draftjs-to-html';
|
||||
import { stateFromHTML } from 'draft-js-import-html';
|
||||
import {
|
||||
UpdateModalViews,
|
||||
EmailTemplateInputDataFields,
|
||||
emailTemplateEventNames,
|
||||
emailTemplateVariables,
|
||||
} from '../constants';
|
||||
import { capitalizeFirstLetter } from '../utils';
|
||||
import { AddEmailTemplate, EditEmailTemplate } from '../graphql/mutation';
|
||||
|
||||
interface selectedEmailTemplateDataTypes {
|
||||
[EmailTemplateInputDataFields.ID]: string;
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]: string;
|
||||
[EmailTemplateInputDataFields.SUBJECT]: string;
|
||||
[EmailTemplateInputDataFields.CREATED_AT]: number;
|
||||
[EmailTemplateInputDataFields.TEMPLATE]: string;
|
||||
}
|
||||
|
||||
interface UpdateEmailTemplateInputPropTypes {
|
||||
view: UpdateModalViews;
|
||||
selectedTemplate?: selectedEmailTemplateDataTypes;
|
||||
fetchEmailTemplatesData: Function;
|
||||
}
|
||||
|
||||
interface templateVariableDataTypes {
|
||||
text: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface emailTemplateDataType {
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]: string;
|
||||
[EmailTemplateInputDataFields.SUBJECT]: string;
|
||||
}
|
||||
|
||||
interface validatorDataType {
|
||||
[EmailTemplateInputDataFields.SUBJECT]: boolean;
|
||||
}
|
||||
|
||||
const initTemplateData: emailTemplateDataType = {
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]:
|
||||
emailTemplateEventNames.BASIC_AUTH_SIGNUP,
|
||||
[EmailTemplateInputDataFields.SUBJECT]: '',
|
||||
};
|
||||
|
||||
const initTemplateValidatorData: validatorDataType = {
|
||||
[EmailTemplateInputDataFields.SUBJECT]: true,
|
||||
};
|
||||
|
||||
const UpdateEmailTemplate = ({
|
||||
view,
|
||||
selectedTemplate,
|
||||
fetchEmailTemplatesData,
|
||||
}: UpdateEmailTemplateInputPropTypes) => {
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [editorState, setEditorState] = React.useState<EditorState>(
|
||||
EditorState.createEmpty()
|
||||
);
|
||||
const [templateVariables, setTemplateVariables] = useState<
|
||||
templateVariableDataTypes[]
|
||||
>([]);
|
||||
const [templateData, setTemplateData] = useState<emailTemplateDataType>({
|
||||
...initTemplateData,
|
||||
});
|
||||
const [validator, setValidator] = useState<validatorDataType>({
|
||||
...initTemplateValidatorData,
|
||||
});
|
||||
const onEditorStateChange = (editorState: EditorState) => {
|
||||
setEditorState(editorState);
|
||||
};
|
||||
const inputChangehandler = (inputType: string, value: any) => {
|
||||
if (inputType !== EmailTemplateInputDataFields.EVENT_NAME) {
|
||||
setValidator({
|
||||
...validator,
|
||||
[inputType]: value?.trim().length,
|
||||
});
|
||||
}
|
||||
setTemplateData({ ...templateData, [inputType]: value });
|
||||
};
|
||||
|
||||
const validateData = () => {
|
||||
const rawData: string = draftToHtml(
|
||||
convertToRaw(editorState.getCurrentContent())
|
||||
).trim();
|
||||
return (
|
||||
!loading &&
|
||||
rawData &&
|
||||
rawData !== '<p></p>' &&
|
||||
rawData !== '<h1></h1>' &&
|
||||
templateData[EmailTemplateInputDataFields.EVENT_NAME].length > 0 &&
|
||||
templateData[EmailTemplateInputDataFields.SUBJECT].length > 0 &&
|
||||
validator[EmailTemplateInputDataFields.SUBJECT]
|
||||
);
|
||||
};
|
||||
|
||||
const saveData = async () => {
|
||||
if (!validateData()) return;
|
||||
setLoading(true);
|
||||
const params = {
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]:
|
||||
templateData[EmailTemplateInputDataFields.EVENT_NAME],
|
||||
[EmailTemplateInputDataFields.SUBJECT]:
|
||||
templateData[EmailTemplateInputDataFields.SUBJECT],
|
||||
[EmailTemplateInputDataFields.TEMPLATE]: draftToHtml(
|
||||
convertToRaw(editorState.getCurrentContent())
|
||||
).trim(),
|
||||
};
|
||||
let res: any = {};
|
||||
if (
|
||||
view === UpdateModalViews.Edit &&
|
||||
selectedTemplate?.[EmailTemplateInputDataFields.ID]
|
||||
) {
|
||||
res = await client
|
||||
.mutation(EditEmailTemplate, {
|
||||
params: {
|
||||
...params,
|
||||
id: selectedTemplate[EmailTemplateInputDataFields.ID],
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
} else {
|
||||
res = await client.mutation(AddEmailTemplate, { params }).toPromise();
|
||||
}
|
||||
setLoading(false);
|
||||
if (res.error) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(res.error.message),
|
||||
isClosable: true,
|
||||
status: 'error',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
} else if (
|
||||
res.data?._add_email_template ||
|
||||
res.data?._update_email_template
|
||||
) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(
|
||||
res.data?._add_email_template?.message ||
|
||||
res.data?._update_email_template?.message
|
||||
),
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
setTemplateData({
|
||||
...initTemplateData,
|
||||
});
|
||||
setValidator({ ...initTemplateValidatorData });
|
||||
fetchEmailTemplatesData();
|
||||
}
|
||||
view === UpdateModalViews.ADD && onClose();
|
||||
};
|
||||
const resetData = () => {
|
||||
if (selectedTemplate) {
|
||||
setTemplateData(selectedTemplate);
|
||||
setEditorState(
|
||||
EditorState.createWithContent(stateFromHTML(selectedTemplate.template))
|
||||
);
|
||||
} else {
|
||||
setTemplateData({ ...initTemplateData });
|
||||
setEditorState(EditorState.createEmpty());
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
view === UpdateModalViews.Edit &&
|
||||
selectedTemplate &&
|
||||
Object.keys(selectedTemplate || {}).length
|
||||
) {
|
||||
const { id, created_at, template, ...rest } = selectedTemplate;
|
||||
setTemplateData(rest);
|
||||
setEditorState(EditorState.createWithContent(stateFromHTML(template)));
|
||||
}
|
||||
}, [isOpen]);
|
||||
useEffect(() => {
|
||||
const updatedTemplateVariables = Object.entries(
|
||||
emailTemplateVariables
|
||||
).reduce((acc, varData): any => {
|
||||
if (
|
||||
(templateData[EmailTemplateInputDataFields.EVENT_NAME] !==
|
||||
emailTemplateEventNames.VERIFY_OTP &&
|
||||
varData[1] === emailTemplateVariables.otp) ||
|
||||
(templateData[EmailTemplateInputDataFields.EVENT_NAME] ===
|
||||
emailTemplateEventNames.VERIFY_OTP &&
|
||||
varData[1] === emailTemplateVariables.verification_url)
|
||||
) {
|
||||
return acc;
|
||||
}
|
||||
return [
|
||||
...acc,
|
||||
{
|
||||
text: varData[0],
|
||||
value: varData[1],
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
setTemplateVariables(updatedTemplateVariables);
|
||||
}, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]);
|
||||
return (
|
||||
<>
|
||||
{view === UpdateModalViews.ADD ? (
|
||||
<Button
|
||||
leftIcon={<FaPlus />}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={onOpen}
|
||||
isDisabled={false}
|
||||
size="sm"
|
||||
>
|
||||
<Center h="100%">Add Template</Center>{' '}
|
||||
</Button>
|
||||
) : (
|
||||
<MenuItem onClick={onOpen}>Edit</MenuItem>
|
||||
)}
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="3xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{view === UpdateModalViews.ADD
|
||||
? 'Add New Email Template'
|
||||
: 'Edit Email Template'}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
border="1px"
|
||||
borderRadius="md"
|
||||
borderColor="gray.200"
|
||||
p="5"
|
||||
>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
marginBottom="2%"
|
||||
>
|
||||
<Flex flex="1">Event Name</Flex>
|
||||
<Flex flex="3">
|
||||
<Select
|
||||
size="md"
|
||||
value={
|
||||
templateData[EmailTemplateInputDataFields.EVENT_NAME]
|
||||
}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
EmailTemplateInputDataFields.EVENT_NAME,
|
||||
e.currentTarget.value
|
||||
)
|
||||
}
|
||||
>
|
||||
{Object.entries(emailTemplateEventNames).map(
|
||||
([key, value]: any) => (
|
||||
<option value={value} key={key}>
|
||||
{key}
|
||||
</option>
|
||||
)
|
||||
)}
|
||||
</Select>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
marginBottom="5%"
|
||||
>
|
||||
<Flex flex="1">Subject</Flex>
|
||||
<Flex flex="3">
|
||||
<InputGroup size="md">
|
||||
<Input
|
||||
pr="4.5rem"
|
||||
type="text"
|
||||
placeholder="Subject Line"
|
||||
value={templateData[EmailTemplateInputDataFields.SUBJECT]}
|
||||
isInvalid={
|
||||
!validator[EmailTemplateInputDataFields.SUBJECT]
|
||||
}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
EmailTemplateInputDataFields.SUBJECT,
|
||||
e.currentTarget.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
marginBottom="2%"
|
||||
>
|
||||
<Flex>Template Body</Flex>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 14,
|
||||
}}
|
||||
color="gray.400"
|
||||
>{`To select dynamic variables open curly braces "{"`}</Text>
|
||||
</Flex>
|
||||
<Editor
|
||||
editorState={editorState}
|
||||
onEditorStateChange={onEditorStateChange}
|
||||
editorStyle={{
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: '5px',
|
||||
marginTop: '2%',
|
||||
height: '35vh',
|
||||
}}
|
||||
mention={{
|
||||
separator: ' ',
|
||||
trigger: '{',
|
||||
suggestions: templateVariables,
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={resetData}
|
||||
isDisabled={loading}
|
||||
marginRight="5"
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
isLoading={loading}
|
||||
onClick={saveData}
|
||||
isDisabled={!validateData()}
|
||||
>
|
||||
<Center h="100%" pt="5%">
|
||||
Save
|
||||
</Center>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateEmailTemplate;
|
|
@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react';
|
|||
import {
|
||||
Button,
|
||||
Center,
|
||||
Code,
|
||||
Collapse,
|
||||
Flex,
|
||||
Input,
|
||||
InputGroup,
|
||||
|
@ -20,19 +22,29 @@ import {
|
|||
useDisclosure,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaMinusCircle, FaPlus } from 'react-icons/fa';
|
||||
import {
|
||||
FaAngleDown,
|
||||
FaAngleUp,
|
||||
FaMinusCircle,
|
||||
FaPlus,
|
||||
FaRegClone,
|
||||
} from 'react-icons/fa';
|
||||
import { useClient } from 'urql';
|
||||
import {
|
||||
webhookEventNames,
|
||||
ArrayInputOperations,
|
||||
WebhookInputDataFields,
|
||||
WebhookInputHeaderFields,
|
||||
UpdateWebhookModalViews,
|
||||
UpdateModalViews,
|
||||
webhookVerifiedStatus,
|
||||
webhookPayloadExample,
|
||||
} from '../constants';
|
||||
import { capitalizeFirstLetter, validateURI } from '../utils';
|
||||
import {
|
||||
capitalizeFirstLetter,
|
||||
copyTextToClipboard,
|
||||
validateURI,
|
||||
} from '../utils';
|
||||
import { AddWebhook, EditWebhook, TestEndpoint } from '../graphql/mutation';
|
||||
import { rest } from 'lodash';
|
||||
import { BiCheckCircle, BiError, BiErrorCircle } from 'react-icons/bi';
|
||||
|
||||
interface headersDataType {
|
||||
|
@ -54,7 +66,7 @@ interface selecetdWebhookDataTypes {
|
|||
}
|
||||
|
||||
interface UpdateWebhookModalInputPropTypes {
|
||||
view: UpdateWebhookModalViews;
|
||||
view: UpdateModalViews;
|
||||
selectedWebhook?: selecetdWebhookDataTypes;
|
||||
fetchWebookData: Function;
|
||||
}
|
||||
|
@ -103,6 +115,7 @@ const UpdateWebhookModal = ({
|
|||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [verifyingEndpoint, setVerifyingEndpoint] = useState<boolean>(false);
|
||||
const [isShowingPayload, setIsShowingPayload] = useState<boolean>(false);
|
||||
const [webhook, setWebhook] = useState<webhookDataType>({
|
||||
...initWebhookData,
|
||||
});
|
||||
|
@ -254,7 +267,7 @@ const UpdateWebhookModal = ({
|
|||
const params = getParams();
|
||||
let res: any = {};
|
||||
if (
|
||||
view === UpdateWebhookModalViews.Edit &&
|
||||
view === UpdateModalViews.Edit &&
|
||||
selectedWebhook?.[WebhookInputDataFields.ID]
|
||||
) {
|
||||
res = await client
|
||||
|
@ -292,12 +305,12 @@ const UpdateWebhookModal = ({
|
|||
setValidator({ ...initWebhookValidatorData });
|
||||
fetchWebookData();
|
||||
}
|
||||
view === UpdateWebhookModalViews.ADD && onClose();
|
||||
view === UpdateModalViews.ADD && onClose();
|
||||
};
|
||||
useEffect(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
view === UpdateWebhookModalViews.Edit &&
|
||||
view === UpdateModalViews.Edit &&
|
||||
selectedWebhook &&
|
||||
Object.keys(selectedWebhook || {}).length
|
||||
) {
|
||||
|
@ -347,7 +360,7 @@ const UpdateWebhookModal = ({
|
|||
};
|
||||
return (
|
||||
<>
|
||||
{view === UpdateWebhookModalViews.ADD ? (
|
||||
{view === UpdateModalViews.ADD ? (
|
||||
<Button
|
||||
leftIcon={<FaPlus />}
|
||||
colorScheme="blue"
|
||||
|
@ -365,9 +378,7 @@ const UpdateWebhookModal = ({
|
|||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{view === UpdateWebhookModalViews.ADD
|
||||
? 'Add New Webhook'
|
||||
: 'Edit Webhook'}
|
||||
{view === UpdateModalViews.ADD ? 'Add New Webhook' : 'Edit Webhook'}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
|
@ -457,6 +468,63 @@ const UpdateWebhookModal = ({
|
|||
</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
marginBottom="5%"
|
||||
flexDirection="column"
|
||||
>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Flex>
|
||||
Payload
|
||||
<Text color="gray.500" ml={1}>
|
||||
(example)
|
||||
</Text>
|
||||
</Flex>
|
||||
<Button
|
||||
onClick={() => setIsShowingPayload(!isShowingPayload)}
|
||||
variant="ghost"
|
||||
>
|
||||
{isShowingPayload ? <FaAngleUp /> : <FaAngleDown />}
|
||||
</Button>
|
||||
</Flex>
|
||||
<Collapse
|
||||
style={{
|
||||
marginTop: 10,
|
||||
width: '100%',
|
||||
}}
|
||||
in={isShowingPayload}
|
||||
>
|
||||
<Code
|
||||
width="inherit"
|
||||
borderRadius={5}
|
||||
padding={2}
|
||||
position="relative"
|
||||
>
|
||||
<pre style={{ overflow: 'auto' }}>
|
||||
{webhookPayloadExample}
|
||||
</pre>
|
||||
{isShowingPayload && (
|
||||
<Flex
|
||||
position="absolute"
|
||||
top={4}
|
||||
right={4}
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
copyTextToClipboard(webhookPayloadExample)
|
||||
}
|
||||
>
|
||||
<FaRegClone color="#bfbfbf" />
|
||||
</Flex>
|
||||
)}
|
||||
</Code>
|
||||
</Collapse>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
|
|
|
@ -162,12 +162,20 @@ export enum WebhookInputDataFields {
|
|||
HEADERS = 'headers',
|
||||
}
|
||||
|
||||
export enum EmailTemplateInputDataFields {
|
||||
ID = 'id',
|
||||
EVENT_NAME = 'event_name',
|
||||
SUBJECT = 'subject',
|
||||
CREATED_AT = 'created_at',
|
||||
TEMPLATE = 'template',
|
||||
}
|
||||
|
||||
export enum WebhookInputHeaderFields {
|
||||
KEY = 'key',
|
||||
VALUE = 'value',
|
||||
}
|
||||
|
||||
export enum UpdateWebhookModalViews {
|
||||
export enum UpdateModalViews {
|
||||
ADD = 'add',
|
||||
Edit = 'edit',
|
||||
}
|
||||
|
@ -183,8 +191,67 @@ export const webhookEventNames = {
|
|||
USER_ACCESS_REVOKED: 'user.access_revoked',
|
||||
};
|
||||
|
||||
export const emailTemplateEventNames = {
|
||||
BASIC_AUTH_SIGNUP: 'basic_auth_signup',
|
||||
MAGIC_LINK_LOGIN: 'magic_link_login',
|
||||
UPDATE_EMAIL: 'update_email',
|
||||
FORGOT_PASSWORD: 'forgot_password',
|
||||
VERIFY_OTP: 'verify_otp',
|
||||
};
|
||||
|
||||
export enum webhookVerifiedStatus {
|
||||
VERIFIED = 'verified',
|
||||
NOT_VERIFIED = 'not_verified',
|
||||
PENDING = 'verification_pending',
|
||||
}
|
||||
|
||||
export const emailTemplateVariables = {
|
||||
'user.id': '{user.id}}',
|
||||
'user.email': '{user.email}}',
|
||||
'user.given_name': '{user.given_name}}',
|
||||
'user.family_name': '{user.family_name}}',
|
||||
'user.signup_methods': '{user.signup_methods}}',
|
||||
'user.email_verified': '{user.email_verified}}',
|
||||
'user.picture': '{user.picture}}',
|
||||
'user.roles': '{user.roles}}',
|
||||
'user.middle_name': '{user.middle_name}}',
|
||||
'user.nickname': '{user.nickname}}',
|
||||
'user.preferred_username': '{user.preferred_username}}',
|
||||
'user.gender': '{user.gender}}',
|
||||
'user.birthdate': '{user.birthdate}}',
|
||||
'user.phone_number': '{user.phone_number}}',
|
||||
'user.phone_number_verified': '{user.phone_number_verified}}',
|
||||
'user.created_at': '{user.created_at}}',
|
||||
'user.updated_at': '{user.updated_at}}',
|
||||
'organization.name': '{organization.name}}',
|
||||
'organization.logo': '{organization.logo}}',
|
||||
verification_url: '{verification_url}}',
|
||||
otp: '{otp}}',
|
||||
};
|
||||
|
||||
export const webhookPayloadExample: string = `{
|
||||
"event_name":"user.login",
|
||||
"user":{
|
||||
"birthdate":null,
|
||||
"created_at":1657524721,
|
||||
"email":"lakhan.m.samani@gmail.com",
|
||||
"email_verified":true,
|
||||
"family_name":"Samani",
|
||||
"gender":null,
|
||||
"given_name":"Lakhan",
|
||||
"id":"466d0b31-1b87-420e-bea5-09d05d79c586",
|
||||
"middle_name":null,
|
||||
"nickname":null,
|
||||
"phone_number":null,
|
||||
"phone_number_verified":false,
|
||||
"picture":"https://lh3.googleusercontent.com/a-/AFdZucppvU6a2zIDkX0wvhhapVjT0ZMKDlYCkQDi3NxcUg=s96-c",
|
||||
"preferred_username":"lakhan.m.samani@gmail.com",
|
||||
"revoked_timestamp":null,
|
||||
"roles":[
|
||||
"user"
|
||||
],
|
||||
"signup_methods":"google",
|
||||
"updated_at":1657526492
|
||||
},
|
||||
"auth_recipe":"google"
|
||||
}`;
|
||||
|
|
|
@ -112,3 +112,27 @@ export const TestEndpoint = `
|
|||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const AddEmailTemplate = `
|
||||
mutation addEmailTemplate($params: AddEmailTemplateRequest!) {
|
||||
_add_email_template(params: $params) {
|
||||
message
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const EditEmailTemplate = `
|
||||
mutation editEmailTemplate($params: UpdateEmailTemplateRequest!) {
|
||||
_update_email_template(params: $params) {
|
||||
message
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const DeleteEmailTemplate = `
|
||||
mutation deleteEmailTemplate($params: DeleteEmailTemplateRequest!) {
|
||||
_delete_email_template(params: $params) {
|
||||
message
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -122,6 +122,26 @@ export const WebhooksDataQuery = `
|
|||
}
|
||||
`;
|
||||
|
||||
export const EmailTemplatesQuery = `
|
||||
query getEmailTemplates($params: PaginatedInput!) {
|
||||
_email_templates(params: $params) {
|
||||
EmailTemplates {
|
||||
id
|
||||
event_name
|
||||
subject
|
||||
created_at
|
||||
template
|
||||
}
|
||||
pagination {
|
||||
limit
|
||||
page
|
||||
offset
|
||||
total
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const WebhookLogsQuery = `
|
||||
query getWebhookLogs($params: ListWebhookLogRequest!) {
|
||||
_webhook_logs(params: $params) {
|
||||
|
|
347
dashboard/src/pages/EmailTemplates.tsx
Normal file
347
dashboard/src/pages/EmailTemplates.tsx
Normal file
|
@ -0,0 +1,347 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { useClient } from 'urql';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuList,
|
||||
NumberDecrementStepper,
|
||||
NumberIncrementStepper,
|
||||
NumberInput,
|
||||
NumberInputField,
|
||||
NumberInputStepper,
|
||||
Select,
|
||||
Spinner,
|
||||
Table,
|
||||
TableCaption,
|
||||
Tbody,
|
||||
Td,
|
||||
Text,
|
||||
Th,
|
||||
Thead,
|
||||
Tooltip,
|
||||
Tr,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaAngleDoubleLeft,
|
||||
FaAngleDoubleRight,
|
||||
FaAngleDown,
|
||||
FaAngleLeft,
|
||||
FaAngleRight,
|
||||
FaExclamationCircle,
|
||||
} from 'react-icons/fa';
|
||||
import UpdateEmailTemplateModal from '../components/UpdateEmailTemplateModal';
|
||||
import {
|
||||
pageLimits,
|
||||
UpdateModalViews,
|
||||
EmailTemplateInputDataFields,
|
||||
} from '../constants';
|
||||
import { EmailTemplatesQuery, WebhooksDataQuery } from '../graphql/queries';
|
||||
import dayjs from 'dayjs';
|
||||
import DeleteEmailTemplateModal from '../components/DeleteEmailTemplateModal';
|
||||
|
||||
interface paginationPropTypes {
|
||||
limit: number;
|
||||
page: number;
|
||||
offset: number;
|
||||
total: number;
|
||||
maxPages: number;
|
||||
}
|
||||
|
||||
interface EmailTemplateDataType {
|
||||
[EmailTemplateInputDataFields.ID]: string;
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]: string;
|
||||
[EmailTemplateInputDataFields.SUBJECT]: string;
|
||||
[EmailTemplateInputDataFields.CREATED_AT]: number;
|
||||
[EmailTemplateInputDataFields.TEMPLATE]: string;
|
||||
}
|
||||
|
||||
const EmailTemplates = () => {
|
||||
const client = useClient();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [emailTemplatesData, setEmailTemplatesData] = useState<
|
||||
EmailTemplateDataType[]
|
||||
>([]);
|
||||
const [paginationProps, setPaginationProps] = useState<paginationPropTypes>({
|
||||
limit: 5,
|
||||
page: 1,
|
||||
offset: 0,
|
||||
total: 0,
|
||||
maxPages: 1,
|
||||
});
|
||||
const getMaxPages = (pagination: paginationPropTypes) => {
|
||||
const { limit, total } = pagination;
|
||||
if (total > 1) {
|
||||
return total % limit === 0
|
||||
? total / limit
|
||||
: parseInt(`${total / limit}`) + 1;
|
||||
} else return 1;
|
||||
};
|
||||
const fetchEmailTemplatesData = async () => {
|
||||
setLoading(true);
|
||||
const res = await client
|
||||
.query(EmailTemplatesQuery, {
|
||||
params: {
|
||||
pagination: {
|
||||
limit: paginationProps.limit,
|
||||
page: paginationProps.page,
|
||||
},
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
if (res.data?._email_templates) {
|
||||
const { pagination, EmailTemplates: emailTemplates } =
|
||||
res.data?._email_templates;
|
||||
const maxPages = getMaxPages(pagination);
|
||||
if (emailTemplates?.length) {
|
||||
setEmailTemplatesData(emailTemplates);
|
||||
setPaginationProps({ ...paginationProps, ...pagination, maxPages });
|
||||
} else {
|
||||
if (paginationProps.page !== 1) {
|
||||
setPaginationProps({
|
||||
...paginationProps,
|
||||
...pagination,
|
||||
maxPages,
|
||||
page: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
const paginationHandler = (value: Record<string, number>) => {
|
||||
setPaginationProps({ ...paginationProps, ...value });
|
||||
};
|
||||
useEffect(() => {
|
||||
fetchEmailTemplatesData();
|
||||
}, [paginationProps.page, paginationProps.limit]);
|
||||
return (
|
||||
<Box m="5" py="5" px="10" bg="white" rounded="md">
|
||||
<Flex margin="2% 0" justifyContent="space-between" alignItems="center">
|
||||
<Text fontSize="md" fontWeight="bold">
|
||||
Email Templates
|
||||
</Text>
|
||||
<UpdateEmailTemplateModal
|
||||
view={UpdateModalViews.ADD}
|
||||
fetchEmailTemplatesData={fetchEmailTemplatesData}
|
||||
/>
|
||||
</Flex>
|
||||
{!loading ? (
|
||||
emailTemplatesData.length ? (
|
||||
<Table variant="simple">
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>Event Name</Th>
|
||||
<Th>Subject</Th>
|
||||
<Th>Created At</Th>
|
||||
<Th>Actions</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{emailTemplatesData.map((templateData: EmailTemplateDataType) => (
|
||||
<Tr
|
||||
key={templateData[EmailTemplateInputDataFields.ID]}
|
||||
style={{ fontSize: 14 }}
|
||||
>
|
||||
<Td maxW="300">
|
||||
{templateData[EmailTemplateInputDataFields.EVENT_NAME]}
|
||||
</Td>
|
||||
<Td>{templateData[EmailTemplateInputDataFields.SUBJECT]}</Td>
|
||||
<Td>
|
||||
{dayjs(templateData.created_at * 1000).format(
|
||||
'MMM DD, YYYY'
|
||||
)}
|
||||
</Td>
|
||||
<Td>
|
||||
<Menu>
|
||||
<MenuButton as={Button} variant="unstyled" size="sm">
|
||||
<Flex
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm" fontWeight="light">
|
||||
Menu
|
||||
</Text>
|
||||
<FaAngleDown style={{ marginLeft: 10 }} />
|
||||
</Flex>
|
||||
</MenuButton>
|
||||
<MenuList>
|
||||
<UpdateEmailTemplateModal
|
||||
view={UpdateModalViews.Edit}
|
||||
selectedTemplate={templateData}
|
||||
fetchEmailTemplatesData={fetchEmailTemplatesData}
|
||||
/>
|
||||
<DeleteEmailTemplateModal
|
||||
emailTemplateId={
|
||||
templateData[EmailTemplateInputDataFields.ID]
|
||||
}
|
||||
eventName={
|
||||
templateData[
|
||||
EmailTemplateInputDataFields.EVENT_NAME
|
||||
]
|
||||
}
|
||||
fetchEmailTemplatesData={fetchEmailTemplatesData}
|
||||
/>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
{(paginationProps.maxPages > 1 || paginationProps.total >= 5) && (
|
||||
<TableCaption>
|
||||
<Flex
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
m="2% 0"
|
||||
>
|
||||
<Flex flex="1">
|
||||
<Tooltip label="First Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: 1,
|
||||
})
|
||||
}
|
||||
isDisabled={paginationProps.page <= 1}
|
||||
mr={4}
|
||||
icon={<FaAngleDoubleLeft />}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip label="Previous Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.page - 1,
|
||||
})
|
||||
}
|
||||
isDisabled={paginationProps.page <= 1}
|
||||
icon={<FaAngleLeft />}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
<Flex
|
||||
flex="8"
|
||||
justifyContent="space-evenly"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text mr={8}>
|
||||
Page{' '}
|
||||
<Text fontWeight="bold" as="span">
|
||||
{paginationProps.page}
|
||||
</Text>{' '}
|
||||
of{' '}
|
||||
<Text fontWeight="bold" as="span">
|
||||
{paginationProps.maxPages}
|
||||
</Text>
|
||||
</Text>
|
||||
<Flex alignItems="center">
|
||||
<Text flexShrink="0">Go to page:</Text>{' '}
|
||||
<NumberInput
|
||||
ml={2}
|
||||
mr={8}
|
||||
w={28}
|
||||
min={1}
|
||||
max={paginationProps.maxPages}
|
||||
onChange={(value) =>
|
||||
paginationHandler({
|
||||
page: parseInt(value),
|
||||
})
|
||||
}
|
||||
value={paginationProps.page}
|
||||
>
|
||||
<NumberInputField />
|
||||
<NumberInputStepper>
|
||||
<NumberIncrementStepper />
|
||||
<NumberDecrementStepper />
|
||||
</NumberInputStepper>
|
||||
</NumberInput>
|
||||
</Flex>
|
||||
<Select
|
||||
w={32}
|
||||
value={paginationProps.limit}
|
||||
onChange={(e) =>
|
||||
paginationHandler({
|
||||
page: 1,
|
||||
limit: parseInt(e.target.value),
|
||||
})
|
||||
}
|
||||
>
|
||||
{pageLimits.map((pageSize) => (
|
||||
<option key={pageSize} value={pageSize}>
|
||||
Show {pageSize}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Flex>
|
||||
<Flex flex="1">
|
||||
<Tooltip label="Next Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.page + 1,
|
||||
})
|
||||
}
|
||||
isDisabled={
|
||||
paginationProps.page >= paginationProps.maxPages
|
||||
}
|
||||
icon={<FaAngleRight />}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip label="Last Page">
|
||||
<IconButton
|
||||
aria-label="icon button"
|
||||
onClick={() =>
|
||||
paginationHandler({
|
||||
page: paginationProps.maxPages,
|
||||
})
|
||||
}
|
||||
isDisabled={
|
||||
paginationProps.page >= paginationProps.maxPages
|
||||
}
|
||||
ml={4}
|
||||
icon={<FaAngleDoubleRight />}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</TableCaption>
|
||||
)}
|
||||
</Table>
|
||||
) : (
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
minH="25vh"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<Center w="50px" marginRight="1.5%">
|
||||
<FaExclamationCircle style={{ color: '#f0f0f0', fontSize: 70 }} />
|
||||
</Center>
|
||||
<Text
|
||||
fontSize="2xl"
|
||||
paddingRight="1%"
|
||||
fontWeight="bold"
|
||||
color="#d9d9d9"
|
||||
>
|
||||
No Data
|
||||
</Text>
|
||||
</Flex>
|
||||
)
|
||||
) : (
|
||||
<Center minH="25vh">
|
||||
<Spinner />
|
||||
</Center>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmailTemplates;
|
|
@ -8,7 +8,6 @@ import {
|
|||
IconButton,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
NumberDecrementStepper,
|
||||
NumberIncrementStepper,
|
||||
|
@ -40,7 +39,7 @@ import UpdateWebhookModal from '../components/UpdateWebhookModal';
|
|||
import {
|
||||
pageLimits,
|
||||
WebhookInputDataFields,
|
||||
UpdateWebhookModalViews,
|
||||
UpdateModalViews,
|
||||
} from '../constants';
|
||||
import { WebhooksDataQuery } from '../graphql/queries';
|
||||
import DeleteWebhookModal from '../components/DeleteWebhookModal';
|
||||
|
@ -125,7 +124,7 @@ const Webhooks = () => {
|
|||
Webhooks
|
||||
</Text>
|
||||
<UpdateWebhookModal
|
||||
view={UpdateWebhookModalViews.ADD}
|
||||
view={UpdateModalViews.ADD}
|
||||
fetchWebookData={fetchWebookData}
|
||||
/>
|
||||
</Flex>
|
||||
|
@ -196,7 +195,7 @@ const Webhooks = () => {
|
|||
</MenuButton>
|
||||
<MenuList>
|
||||
<UpdateWebhookModal
|
||||
view={UpdateWebhookModalViews.Edit}
|
||||
view={UpdateModalViews.Edit}
|
||||
selectedWebhook={webhook}
|
||||
fetchWebookData={fetchWebookData}
|
||||
/>
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Outlet, Route, Routes } from 'react-router-dom';
|
|||
|
||||
import { useAuthContext } from '../contexts/AuthContext';
|
||||
import { DashboardLayout } from '../layouts/DashboardLayout';
|
||||
import EmailTemplates from '../pages/EmailTemplates';
|
||||
|
||||
const Auth = lazy(() => import('../pages/Auth'));
|
||||
const Environment = lazy(() => import('../pages/Environment'));
|
||||
|
@ -31,6 +32,7 @@ export const AppRoutes = () => {
|
|||
</Route>
|
||||
<Route path="users" element={<Users />} />
|
||||
<Route path="webhooks" element={<Webhooks />} />
|
||||
<Route path="email-templates" element={<EmailTemplates />} />
|
||||
<Route path="*" element={<Home />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
|
|
@ -12,6 +12,7 @@ type EmailTemplate struct {
|
|||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
|
||||
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"`
|
||||
Subject string `gorm:"type:text" json:"subject" bson:"subject" cql:"subject"`
|
||||
Template string `gorm:"type:text" json:"template" bson:"template" cql:"template"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
|
||||
|
@ -26,6 +27,7 @@ func (e *EmailTemplate) AsAPIEmailTemplate() *model.EmailTemplate {
|
|||
return &model.EmailTemplate{
|
||||
ID: id,
|
||||
EventName: e.EventName,
|
||||
Subject: e.Subject,
|
||||
Template: e.Template,
|
||||
CreatedAt: refs.NewInt64Ref(e.CreatedAt),
|
||||
UpdatedAt: refs.NewInt64Ref(e.UpdatedAt),
|
||||
|
|
|
@ -29,7 +29,7 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em
|
|||
return nil, fmt.Errorf("Email template with %s event_name already exists", emailTemplate.EventName)
|
||||
}
|
||||
|
||||
insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, template, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt)
|
||||
insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, subject, template, created_at, updated_at) VALUES ('%s', '%s', '%s','%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Subject, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt)
|
||||
err := p.db.Query(insertQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -103,14 +103,14 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
|||
// there is no offset in cassandra
|
||||
// so we fetch till limit + offset
|
||||
// and return the results from offset to limit
|
||||
query := fmt.Sprintf("SELECT id, event_name, template, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.EmailTemplate, pagination.Limit+pagination.Offset)
|
||||
query := fmt.Sprintf("SELECT id, event_name, subject, template, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.EmailTemplate, pagination.Limit+pagination.Offset)
|
||||
|
||||
scanner := p.db.Query(query).Iter().Scanner()
|
||||
counter := int64(0)
|
||||
for scanner.Next() {
|
||||
if counter >= pagination.Offset {
|
||||
var emailTemplate models.EmailTemplate
|
||||
err := scanner.Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
err := scanner.Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -128,8 +128,8 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
|||
// GetEmailTemplateByID to get EmailTemplate by id
|
||||
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
||||
var emailTemplate models.EmailTemplate
|
||||
query := fmt.Sprintf(`SELECT id, event_name, template, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.EmailTemplate, emailTemplateID)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
query := fmt.Sprintf(`SELECT id, event_name, subject, template, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.EmailTemplate, emailTemplateID)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -139,8 +139,8 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str
|
|||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||
var emailTemplate models.EmailTemplate
|
||||
query := fmt.Sprintf(`SELECT id, event_name, template, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.EmailTemplate, eventName)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
query := fmt.Sprintf(`SELECT id, event_name, subject, template, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.EmailTemplate, eventName)
|
||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -214,6 +214,12 @@ func NewProvider() (*provider, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// add subject on email_templates table
|
||||
emailTemplateAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD subject text;`, KeySpace, models.Collections.EmailTemplate)
|
||||
err = session.Query(emailTemplateAlterQuery).Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &provider{
|
||||
db: session,
|
||||
|
|
|
@ -56,6 +56,7 @@ type ComplexityRoot struct {
|
|||
CreatedAt func(childComplexity int) int
|
||||
EventName func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
Subject func(childComplexity int) int
|
||||
Template func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
}
|
||||
|
@ -403,6 +404,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.EmailTemplate.ID(childComplexity), true
|
||||
|
||||
case "EmailTemplate.subject":
|
||||
if e.complexity.EmailTemplate.Subject == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.EmailTemplate.Subject(childComplexity), true
|
||||
|
||||
case "EmailTemplate.template":
|
||||
if e.complexity.EmailTemplate.Template == nil {
|
||||
break
|
||||
|
@ -1978,6 +1986,7 @@ type EmailTemplate {
|
|||
id: ID!
|
||||
event_name: String!
|
||||
template: String!
|
||||
subject: String!
|
||||
created_at: Int64
|
||||
updated_at: Int64
|
||||
}
|
||||
|
@ -2193,6 +2202,7 @@ input TestEndpointRequest {
|
|||
|
||||
input AddEmailTemplateRequest {
|
||||
event_name: String!
|
||||
subject: String!
|
||||
template: String!
|
||||
}
|
||||
|
||||
|
@ -2200,6 +2210,7 @@ input UpdateEmailTemplateRequest {
|
|||
id: ID!
|
||||
event_name: String
|
||||
template: String
|
||||
subject: String
|
||||
}
|
||||
|
||||
input DeleteEmailTemplateRequest {
|
||||
|
@ -3108,6 +3119,41 @@ func (ec *executionContext) _EmailTemplate_template(ctx context.Context, field g
|
|||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _EmailTemplate_subject(ctx context.Context, field graphql.CollectedField, obj *model.EmailTemplate) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "EmailTemplate",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Subject, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(string)
|
||||
fc.Result = res
|
||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _EmailTemplate_created_at(ctx context.Context, field graphql.CollectedField, obj *model.EmailTemplate) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
@ -10087,6 +10133,14 @@ func (ec *executionContext) unmarshalInputAddEmailTemplateRequest(ctx context.Co
|
|||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "subject":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("subject"))
|
||||
it.Subject, err = ec.unmarshalNString2string(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "template":
|
||||
var err error
|
||||
|
||||
|
@ -10866,6 +10920,14 @@ func (ec *executionContext) unmarshalInputUpdateEmailTemplateRequest(ctx context
|
|||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "subject":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("subject"))
|
||||
it.Subject, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11632,6 +11694,11 @@ func (ec *executionContext) _EmailTemplate(ctx context.Context, sel ast.Selectio
|
|||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "subject":
|
||||
out.Values[i] = ec._EmailTemplate_subject(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "created_at":
|
||||
out.Values[i] = ec._EmailTemplate_created_at(ctx, field, obj)
|
||||
case "updated_at":
|
||||
|
|
|
@ -4,6 +4,7 @@ package model
|
|||
|
||||
type AddEmailTemplateRequest struct {
|
||||
EventName string `json:"event_name"`
|
||||
Subject string `json:"subject"`
|
||||
Template string `json:"template"`
|
||||
}
|
||||
|
||||
|
@ -43,6 +44,7 @@ type EmailTemplate struct {
|
|||
ID string `json:"id"`
|
||||
EventName string `json:"event_name"`
|
||||
Template string `json:"template"`
|
||||
Subject string `json:"subject"`
|
||||
CreatedAt *int64 `json:"created_at"`
|
||||
UpdatedAt *int64 `json:"updated_at"`
|
||||
}
|
||||
|
@ -240,6 +242,7 @@ type UpdateEmailTemplateRequest struct {
|
|||
ID string `json:"id"`
|
||||
EventName *string `json:"event_name"`
|
||||
Template *string `json:"template"`
|
||||
Subject *string `json:"subject"`
|
||||
}
|
||||
|
||||
type UpdateEnvInput struct {
|
||||
|
|
|
@ -189,6 +189,7 @@ type EmailTemplate {
|
|||
id: ID!
|
||||
event_name: String!
|
||||
template: String!
|
||||
subject: String!
|
||||
created_at: Int64
|
||||
updated_at: Int64
|
||||
}
|
||||
|
@ -404,6 +405,7 @@ input TestEndpointRequest {
|
|||
|
||||
input AddEmailTemplateRequest {
|
||||
event_name: String!
|
||||
subject: String!
|
||||
template: String!
|
||||
}
|
||||
|
||||
|
@ -411,6 +413,7 @@ input UpdateEmailTemplateRequest {
|
|||
id: ID!
|
||||
event_name: String
|
||||
template: String
|
||||
subject: String
|
||||
}
|
||||
|
||||
input DeleteEmailTemplateRequest {
|
||||
|
|
|
@ -34,6 +34,10 @@ func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplate
|
|||
return nil, fmt.Errorf("invalid event name %s", params.EventName)
|
||||
}
|
||||
|
||||
if strings.TrimSpace(params.Subject) == "" {
|
||||
return nil, fmt.Errorf("empty subject not allowed")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(params.Template) == "" {
|
||||
return nil, fmt.Errorf("empty template not allowed")
|
||||
}
|
||||
|
@ -41,6 +45,7 @@ func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplate
|
|||
_, err = db.Provider.AddEmailTemplate(ctx, models.EmailTemplate{
|
||||
EventName: params.EventName,
|
||||
Template: params.Template,
|
||||
Subject: params.Subject,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add email template: ", err)
|
||||
|
|
|
@ -51,6 +51,14 @@ func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTe
|
|||
emailTemplateDetails.EventName = refs.StringValue(params.EventName)
|
||||
}
|
||||
|
||||
if params.Subject != nil && emailTemplateDetails.Subject != refs.StringValue(params.Subject) {
|
||||
if strings.TrimSpace(refs.StringValue(params.Subject)) == "" {
|
||||
log.Debug("empty subject not allowed")
|
||||
return nil, fmt.Errorf("empty subject not allowed")
|
||||
}
|
||||
emailTemplateDetails.Subject = refs.StringValue(params.Subject)
|
||||
}
|
||||
|
||||
if params.Template != nil && emailTemplateDetails.Template != refs.StringValue(params.Template) {
|
||||
if strings.TrimSpace(refs.StringValue(params.Template)) == "" {
|
||||
log.Debug("empty template not allowed")
|
||||
|
|
|
@ -31,10 +31,21 @@ func addEmailTemplateTest(t *testing.T, s TestSetup) {
|
|||
assert.Nil(t, emailTemplate)
|
||||
})
|
||||
|
||||
t.Run("should not add email template for empty template", func(t *testing.T) {
|
||||
emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{
|
||||
EventName: s.TestInfo.TestEmailTemplateEventTypes[0],
|
||||
Template: " test ",
|
||||
Subject: " ",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, emailTemplate)
|
||||
})
|
||||
|
||||
t.Run("should not add email template for empty template", func(t *testing.T) {
|
||||
emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{
|
||||
EventName: s.TestInfo.TestEmailTemplateEventTypes[0],
|
||||
Template: " ",
|
||||
Subject: "test",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, emailTemplate)
|
||||
|
@ -43,7 +54,8 @@ func addEmailTemplateTest(t *testing.T, s TestSetup) {
|
|||
t.Run("should add email template for "+eventType, func(t *testing.T) {
|
||||
emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{
|
||||
EventName: eventType,
|
||||
Template: `Test email`,
|
||||
Template: "Test email",
|
||||
Subject: "Test email",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, emailTemplate)
|
||||
|
@ -52,6 +64,7 @@ func addEmailTemplateTest(t *testing.T, s TestSetup) {
|
|||
et, err := db.Provider.GetEmailTemplateByEventName(ctx, eventType)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, et.EventName, eventType)
|
||||
assert.Equal(t, "Test email", et.Subject)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -31,6 +31,7 @@ func updateEmailTemplateTest(t *testing.T, s TestSetup) {
|
|||
res, err := resolvers.UpdateEmailTemplateResolver(ctx, model.UpdateEmailTemplateRequest{
|
||||
ID: emailTemplate.ID,
|
||||
Template: refs.NewStringRef("Updated test template"),
|
||||
Subject: refs.NewStringRef("Updated subject"),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
@ -42,5 +43,6 @@ func updateEmailTemplateTest(t *testing.T, s TestSetup) {
|
|||
assert.NotNil(t, updatedEmailTemplate)
|
||||
assert.Equal(t, emailTemplate.ID, updatedEmailTemplate.ID)
|
||||
assert.Equal(t, updatedEmailTemplate.Template, "Updated test template")
|
||||
assert.Equal(t, updatedEmailTemplate.Subject, "Updated subject")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -12,9 +12,901 @@
|
|||
<script>
|
||||
window.__authorizer__ = {{.data}}
|
||||
</script>
|
||||
<style>
|
||||
.rdw-option-wrapper {
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 5px;
|
||||
min-width: 25px;
|
||||
height: 20px;
|
||||
border-radius: 2px;
|
||||
margin: 0 4px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.rdw-option-wrapper:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
}
|
||||
.rdw-option-wrapper:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-option-active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-option-disabled {
|
||||
opacity: 0.3;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.rdw-dropdown-wrapper {
|
||||
height: 30px;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
margin: 0 3px;
|
||||
text-transform: capitalize;
|
||||
background: white;
|
||||
}
|
||||
.rdw-dropdown-wrapper:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-dropdown-wrapper:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.rdw-dropdown-wrapper:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-dropdown-carettoopen {
|
||||
height: 0px;
|
||||
width: 0px;
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
right: 10%;
|
||||
border-top: 6px solid black;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
.rdw-dropdown-carettoclose {
|
||||
height: 0px;
|
||||
width: 0px;
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
right: 10%;
|
||||
border-bottom: 6px solid black;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
.rdw-dropdown-selectedtext {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-dropdown-optionwrapper {
|
||||
z-index: 100;
|
||||
position: relative;
|
||||
border: 1px solid #F1F1F1;
|
||||
width: 98%;
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: 250px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.rdw-dropdown-optionwrapper:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.rdw-dropdownoption-default {
|
||||
min-height: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-dropdownoption-highlighted {
|
||||
background: #F1F1F1;
|
||||
}
|
||||
.rdw-dropdownoption-active {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.rdw-dropdownoption-disabled {
|
||||
opacity: 0.3;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.rdw-inline-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-inline-dropdown {
|
||||
width: 50px;
|
||||
}
|
||||
.rdw-inline-dropdownoption {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.rdw-block-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-block-dropdown {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.rdw-fontsize-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-fontsize-dropdown {
|
||||
min-width: 40px;
|
||||
}
|
||||
.rdw-fontsize-option {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.rdw-fontfamily-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-fontfamily-dropdown {
|
||||
width: 115px;
|
||||
}
|
||||
.rdw-fontfamily-placeholder {
|
||||
white-space: nowrap;
|
||||
max-width: 90px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.rdw-fontfamily-optionwrapper {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.rdw-list-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-list-dropdown {
|
||||
width: 50px;
|
||||
z-index: 90;
|
||||
}
|
||||
.rdw-list-dropdownOption {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.rdw-text-align-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-text-align-dropdown {
|
||||
width: 50px;
|
||||
z-index: 90;
|
||||
}
|
||||
.rdw-text-align-dropdownOption {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-right-aligned-block {
|
||||
text-align: right;
|
||||
}
|
||||
.rdw-left-aligned-block {
|
||||
text-align: left !important;
|
||||
}
|
||||
.rdw-center-aligned-block {
|
||||
text-align: center !important;
|
||||
}
|
||||
.rdw-justify-aligned-block {
|
||||
text-align: justify !important;
|
||||
}
|
||||
.rdw-right-aligned-block > div {
|
||||
display: inline-block;
|
||||
}
|
||||
.rdw-left-aligned-block > div {
|
||||
display: inline-block;
|
||||
}
|
||||
.rdw-center-aligned-block > div {
|
||||
display: inline-block;
|
||||
}
|
||||
.rdw-justify-aligned-block > div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.rdw-colorpicker-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-colorpicker-modal {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 175px;
|
||||
height: 175px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-colorpicker-modal-header {
|
||||
display: flex;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.rdw-colorpicker-modal-style-label {
|
||||
font-size: 15px;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
padding: 0 10px 5px;
|
||||
}
|
||||
.rdw-colorpicker-modal-style-label-active {
|
||||
border-bottom: 2px solid #0a66b7;
|
||||
}
|
||||
.rdw-colorpicker-modal-options {
|
||||
margin: 5px auto;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-wrap: wrap;
|
||||
overflow: scroll;
|
||||
}
|
||||
.rdw-colorpicker-cube {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 1px solid #F1F1F1;
|
||||
}
|
||||
.rdw-colorpicker-option {
|
||||
margin: 3px;
|
||||
padding: 0;
|
||||
min-height: 20px;
|
||||
border: none;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
min-width: 22px;
|
||||
box-shadow: 1px 2px 1px #BFBDBD inset;
|
||||
}
|
||||
.rdw-colorpicker-option:hover {
|
||||
box-shadow: 1px 2px 1px #BFBDBD;
|
||||
}
|
||||
.rdw-colorpicker-option:active {
|
||||
box-shadow: -1px -2px 1px #BFBDBD;
|
||||
}
|
||||
.rdw-colorpicker-option-active {
|
||||
box-shadow: 0px 0px 2px 2px #BFBDBD;
|
||||
}
|
||||
|
||||
.rdw-link-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-link-dropdown {
|
||||
width: 50px;
|
||||
}
|
||||
.rdw-link-dropdownOption {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-link-dropdownPlaceholder {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.rdw-link-modal {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 235px;
|
||||
height: 205px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-link-modal-label {
|
||||
font-size: 15px;
|
||||
}
|
||||
.rdw-link-modal-input {
|
||||
margin-top: 5px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #F1F1F1;
|
||||
height: 25px;
|
||||
margin-bottom: 15px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-link-modal-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-link-modal-buttonsection {
|
||||
margin: 0 auto;
|
||||
}
|
||||
.rdw-link-modal-target-option {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.rdw-link-modal-target-option > span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.rdw-link-modal-btn {
|
||||
margin-left: 10px;
|
||||
width: 75px;
|
||||
height: 30px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.rdw-link-modal-btn:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
}
|
||||
.rdw-link-modal-btn:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-link-modal-btn:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.rdw-link-modal-btn:disabled {
|
||||
background: #ece9e9;
|
||||
}
|
||||
.rdw-link-dropdownoption {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-history-dropdown {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.rdw-embedded-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-embedded-modal {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 235px;
|
||||
height: 180px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
justify-content: space-between;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-embedded-modal-header {
|
||||
font-size: 15px;
|
||||
display: flex;
|
||||
}
|
||||
.rdw-embedded-modal-header-option {
|
||||
width: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rdw-embedded-modal-header-label {
|
||||
width: 95px;
|
||||
border: 1px solid #f1f1f1;
|
||||
margin-top: 5px;
|
||||
background: #6EB8D4;
|
||||
border-bottom: 2px solid #0a66b7;
|
||||
}
|
||||
.rdw-embedded-modal-link-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rdw-embedded-modal-link-input {
|
||||
width: 88%;
|
||||
height: 35px;
|
||||
margin: 10px 0;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
font-size: 15px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-embedded-modal-link-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.rdw-embedded-modal-link-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-embedded-modal-btn-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-embedded-modal-btn {
|
||||
margin: 0 3px;
|
||||
width: 75px;
|
||||
height: 30px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.rdw-embedded-modal-btn:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
}
|
||||
.rdw-embedded-modal-btn:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-embedded-modal-btn:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.rdw-embedded-modal-btn:disabled {
|
||||
background: #ece9e9;
|
||||
}
|
||||
.rdw-embedded-modal-size {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
margin: 8px 0;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.rdw-embedded-modal-size-input {
|
||||
width: 80%;
|
||||
height: 20px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rdw-embedded-modal-size-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.rdw-emoji-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-emoji-modal {
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 235px;
|
||||
height: 180px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-emoji-icon {
|
||||
margin: 2.5px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
cursor: pointer;
|
||||
font-size: 22px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rdw-spinner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.rdw-spinner > div {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: #333;
|
||||
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
}
|
||||
.rdw-spinner .rdw-bounce1 {
|
||||
-webkit-animation-delay: -0.32s;
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
.rdw-spinner .rdw-bounce2 {
|
||||
-webkit-animation-delay: -0.16s;
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
@-webkit-keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% { -webkit-transform: scale(0) }
|
||||
40% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
@keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
} 40% {
|
||||
-webkit-transform: scale(1.0);
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
.rdw-image-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-image-modal {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 235px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-image-modal-header {
|
||||
font-size: 15px;
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
}
|
||||
.rdw-image-modal-header-option {
|
||||
width: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rdw-image-modal-header-label {
|
||||
width: 80px;
|
||||
background: #f1f1f1;
|
||||
border: 1px solid #f1f1f1;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.rdw-image-modal-header-label-highlighted {
|
||||
background: #6EB8D4;
|
||||
border-bottom: 2px solid #0a66b7;
|
||||
}
|
||||
.rdw-image-modal-upload-option {
|
||||
width: 100%;
|
||||
color: gray;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f1f1f1;
|
||||
outline: 2px dashed gray;
|
||||
outline-offset: -10px;
|
||||
margin: 10px 0;
|
||||
padding: 9px 0;
|
||||
}
|
||||
.rdw-image-modal-upload-option-highlighted {
|
||||
outline: 2px dashed #0a66b7;
|
||||
}
|
||||
.rdw-image-modal-upload-option-label {
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
}
|
||||
.rdw-image-modal-upload-option-label span{
|
||||
padding: 0 20px;
|
||||
}
|
||||
.rdw-image-modal-upload-option-image-preview {
|
||||
max-width: 100%;
|
||||
max-height: 200px;
|
||||
}
|
||||
.rdw-image-modal-upload-option-input {
|
||||
width: 0.1px;
|
||||
height: 0.1px;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
.rdw-image-modal-url-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.rdw-image-modal-url-input {
|
||||
width: 90%;
|
||||
height: 35px;
|
||||
margin: 15px 0 12px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
font-size: 15px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-image-modal-btn-section {
|
||||
margin: 10px auto 0;
|
||||
}
|
||||
.rdw-image-modal-url-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-image-modal-btn {
|
||||
margin: 0 5px;
|
||||
width: 75px;
|
||||
height: 30px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.rdw-image-modal-btn:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
}
|
||||
.rdw-image-modal-btn:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-image-modal-btn:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.rdw-image-modal-btn:disabled {
|
||||
background: #ece9e9;
|
||||
}
|
||||
.rdw-image-modal-spinner {
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.rdw-image-modal-alt-input {
|
||||
width: 70%;
|
||||
height: 20px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.rdw-image-modal-alt-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-image-modal-alt-lbl {
|
||||
font-size: 12px;
|
||||
}
|
||||
.rdw-image-modal-size {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
margin: 8px 0;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.rdw-image-modal-size-input {
|
||||
width: 40%;
|
||||
height: 20px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rdw-image-modal-size-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-image-mandatory-sign {
|
||||
color: red;
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.rdw-remove-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
|
||||
.rdw-history-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
.rdw-history-dropdownoption {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-history-dropdown {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.rdw-link-decorator-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.rdw-link-decorator-icon {
|
||||
position: absolute;
|
||||
left: 40%;
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.rdw-mention-link {
|
||||
text-decoration: none;
|
||||
color: #1236ff;
|
||||
background-color: #f0fbff;
|
||||
padding: 1px 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.rdw-suggestion-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.rdw-suggestion-dropdown {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #F1F1F1;
|
||||
min-width: 100px;
|
||||
max-height: 150px;
|
||||
overflow: auto;
|
||||
background: white;
|
||||
z-index: 100;
|
||||
}
|
||||
.rdw-suggestion-option {
|
||||
padding: 7px 5px;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
}
|
||||
.rdw-suggestion-option-active {
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
.rdw-hashtag-link {
|
||||
text-decoration: none;
|
||||
color: #1236ff;
|
||||
background-color: #f0fbff;
|
||||
padding: 1px 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.rdw-image-alignment-options-popup {
|
||||
position: absolute;
|
||||
background: white;
|
||||
display: flex;
|
||||
padding: 5px 2px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #F1F1F1;
|
||||
width: 105px;
|
||||
cursor: pointer;
|
||||
z-index: 100;
|
||||
}
|
||||
.rdw-alignment-option-left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.rdw-image-alignment-option {
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
min-width: 15px;
|
||||
}
|
||||
.rdw-image-alignment {
|
||||
position: relative;
|
||||
}
|
||||
.rdw-image-imagewrapper {
|
||||
position: relative;
|
||||
}
|
||||
.rdw-image-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-image-left {
|
||||
display: flex;
|
||||
}
|
||||
.rdw-image-right {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.rdw-image-alignment-options-popup-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.rdw-editor-main {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.rdw-editor-toolbar {
|
||||
padding: 6px 5px 0;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #F1F1F1;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
background: white;
|
||||
flex-wrap: wrap;
|
||||
font-size: 15px;
|
||||
margin-bottom: 5px;
|
||||
user-select: none;
|
||||
}
|
||||
.public-DraftStyleDefault-block {
|
||||
margin: 1em 0;
|
||||
}
|
||||
.rdw-editor-wrapper:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-editor-wrapper {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.rdw-editor-main blockquote {
|
||||
border-left: 5px solid #f1f1f1;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.rdw-editor-main pre {
|
||||
background: #f1f1f1;
|
||||
border-radius: 3px;
|
||||
padding: 1px 10px;
|
||||
}
|
||||
/**
|
||||
* Draft v0.9.1
|
||||
*
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
.DraftEditor-editorContainer,.DraftEditor-root,.public-DraftEditor-content{height:inherit;text-align:initial}.public-DraftEditor-content[contenteditable=true]{-webkit-user-modify:read-write-plaintext-only}.DraftEditor-root{position:relative}.DraftEditor-editorContainer{background-color:rgba(255,255,255,0);border-left:.1px solid transparent;position:relative;z-index:1}.public-DraftEditor-block{position:relative}.DraftEditor-alignLeft .public-DraftStyleDefault-block{text-align:left}.DraftEditor-alignLeft .public-DraftEditorPlaceholder-root{left:0;text-align:left}.DraftEditor-alignCenter .public-DraftStyleDefault-block{text-align:center}.DraftEditor-alignCenter .public-DraftEditorPlaceholder-root{margin:0 auto;text-align:center;width:100%}.DraftEditor-alignRight .public-DraftStyleDefault-block{text-align:right}.DraftEditor-alignRight .public-DraftEditorPlaceholder-root{right:0;text-align:right}.public-DraftEditorPlaceholder-root{color:#9197a3;position:absolute;z-index:0}.public-DraftEditorPlaceholder-hasFocus{color:#bdc1c9}.DraftEditorPlaceholder-hidden{display:none}.public-DraftStyleDefault-block{position:relative;white-space:pre-wrap}.public-DraftStyleDefault-ltr{direction:ltr;text-align:left}.public-DraftStyleDefault-rtl{direction:rtl;text-align:right}.public-DraftStyleDefault-listLTR{direction:ltr}.public-DraftStyleDefault-listRTL{direction:rtl}.public-DraftStyleDefault-ol,.public-DraftStyleDefault-ul{margin:16px 0;padding:0}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-listLTR{margin-left:1.5em}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-listRTL{margin-right:1.5em}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-listLTR{margin-left:3em}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-listRTL{margin-right:3em}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-listLTR{margin-left:4.5em}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-listRTL{margin-right:4.5em}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-listLTR{margin-left:6em}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-listRTL{margin-right:6em}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-listLTR{margin-left:7.5em}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-listRTL{margin-right:7.5em}.public-DraftStyleDefault-unorderedListItem{list-style-type:square;position:relative}.public-DraftStyleDefault-unorderedListItem.public-DraftStyleDefault-depth0{list-style-type:disc}.public-DraftStyleDefault-unorderedListItem.public-DraftStyleDefault-depth1{list-style-type:circle}.public-DraftStyleDefault-orderedListItem{list-style-type:none;position:relative}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-listLTR:before{left:-36px;position:absolute;text-align:right;width:30px}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-listRTL:before{position:absolute;right:-36px;text-align:left;width:30px}.public-DraftStyleDefault-orderedListItem:before{content:counter(ol0) ". ";counter-increment:ol0}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth1:before{content:counter(ol1) ". ";counter-increment:ol1}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth2:before{content:counter(ol2) ". ";counter-increment:ol2}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth3:before{content:counter(ol3) ". ";counter-increment:ol3}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth4:before{content:counter(ol4) ". ";counter-increment:ol4}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-reset{counter-reset:ol0}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-reset{counter-reset:ol1}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-reset{counter-reset:ol2}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-reset{counter-reset:ol3}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-reset{counter-reset:ol4}
|
||||
|
||||
|
||||
/*# sourceMappingURL=react-draft-wysiwyg.css.map*/
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/dashboard/build/index.js"></script>
|
||||
<script>var global = global || window;</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue
Block a user