mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-12 13:24:52 +00:00
sysadmin reconstruct terms and conditions pages (#4231)
* sysadmin reconstruct terms and conditions pages * update seafile-js version * add term content dialog * optimized code struct * fix redirect logic after add term * optimized code * optimized code * update seafile-editor version
This commit is contained in:
154
frontend/package-lock.json
generated
154
frontend/package-lock.json
generated
@@ -137,9 +137,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@seafile/seafile-editor": {
|
"@seafile/seafile-editor": {
|
||||||
"version": "0.2.72",
|
"version": "0.2.76",
|
||||||
"resolved": "https://registry.npmjs.org/@seafile/seafile-editor/-/seafile-editor-0.2.72.tgz",
|
"resolved": "https://registry.npmjs.org/@seafile/seafile-editor/-/seafile-editor-0.2.76.tgz",
|
||||||
"integrity": "sha512-joCJtRfxRyxEMnIuLxv3Z2UaHOcaLqZ8zzhfKrpI0FCIFqdSvWxzHGLIGLKfD0q7kC+AG+Ut9ZJSLzTY0HAVcA==",
|
"integrity": "sha512-UDaVOtSeFMdDvCfHgjxXc1zoMf4dNOu3/z8BLLpYi0i1O4gz+BWT5cv8LkodJLg4QnDuGRH8/VyF3Ed6ns6J6g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@seafile/seafile-calendar": "^0.0.6",
|
"@seafile/seafile-calendar": "^0.0.6",
|
||||||
"@seafile/slate-react": "^0.1.8",
|
"@seafile/slate-react": "^0.1.8",
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
"slate": "0.44.13",
|
"slate": "0.44.13",
|
||||||
"slate-base64-serializer": "^0.2.72",
|
"slate-base64-serializer": "^0.2.72",
|
||||||
"slate-hotkeys": "0.2.3",
|
"slate-hotkeys": "0.2.3",
|
||||||
"slate-html-serializer": "0.7.2",
|
"slate-html-serializer": "^0.7.2",
|
||||||
"slate-schema-violations": "0.1.39",
|
"slate-schema-violations": "0.1.39",
|
||||||
"socket.io-client": "^2.1.1",
|
"socket.io-client": "^2.1.1",
|
||||||
"style-loader": "0.19.0",
|
"style-loader": "0.19.0",
|
||||||
@@ -328,9 +328,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "12.7.12",
|
"version": "12.12.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.7.tgz",
|
||||||
"integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ=="
|
"integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w=="
|
||||||
},
|
},
|
||||||
"@videojs/http-streaming": {
|
"@videojs/http-streaming": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
@@ -5470,7 +5470,7 @@
|
|||||||
},
|
},
|
||||||
"git-up": {
|
"git-up": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "http://registry.npmjs.org/git-up/-/git-up-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/git-up/-/git-up-1.2.1.tgz",
|
||||||
"integrity": "sha1-JkSAoAax2EJhrB/gmjpRacV+oZ0=",
|
"integrity": "sha1-JkSAoAax2EJhrB/gmjpRacV+oZ0=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-ssh": "^1.0.0",
|
"is-ssh": "^1.0.0",
|
||||||
@@ -5479,7 +5479,7 @@
|
|||||||
},
|
},
|
||||||
"git-url-parse": {
|
"git-url-parse": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/git-url-parse/-/git-url-parse-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-5.0.1.tgz",
|
||||||
"integrity": "sha1-/j15xnRq4FBIz6UIyB553du6OEM=",
|
"integrity": "sha1-/j15xnRq4FBIz6UIyB553du6OEM=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"git-up": "^1.0.0"
|
"git-up": "^1.0.0"
|
||||||
@@ -5862,9 +5862,9 @@
|
|||||||
"integrity": "sha512-C62CVn7jbjp89yOhhy7vrkSaB7Vk906Gtcw/Ihd+Iufnq+2pwOZjdPmpzpKLWJXPJBMDX3wXg4FqmdOayPcewA=="
|
"integrity": "sha512-C62CVn7jbjp89yOhhy7vrkSaB7Vk906Gtcw/Ihd+Iufnq+2pwOZjdPmpzpKLWJXPJBMDX3wXg4FqmdOayPcewA=="
|
||||||
},
|
},
|
||||||
"hast-util-parse-selector": {
|
"hast-util-parse-selector": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.3.tgz",
|
||||||
"integrity": "sha512-jIMtnzrLTjzqgVEQqPEmwEZV+ea4zHRFTP8Z2Utw0I5HuBOXHzUPPQWr6ouJdJqDKLbFU/OEiYwZ79LalZkmmw=="
|
"integrity": "sha512-nxbeqjQNxsvo/uYYAw9kij6td05YVUlf1qti09rVfbWSLT5H6wo3c+USIwX6nzXWk5kFZzXnEqO82856r0aM2Q=="
|
||||||
},
|
},
|
||||||
"hast-util-phrasing": {
|
"hast-util-phrasing": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
@@ -7614,11 +7614,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
||||||
},
|
},
|
||||||
"lodash._getnative": {
|
|
||||||
"version": "3.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
|
|
||||||
"integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
|
|
||||||
},
|
|
||||||
"lodash._reinterpolate": {
|
"lodash._reinterpolate": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
||||||
@@ -7650,16 +7645,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
|
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
|
||||||
},
|
},
|
||||||
"lodash.isarguments": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
|
||||||
"integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
|
|
||||||
},
|
|
||||||
"lodash.isarray": {
|
|
||||||
"version": "3.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
|
|
||||||
"integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
|
|
||||||
},
|
|
||||||
"lodash.isequal": {
|
"lodash.isequal": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
@@ -7675,16 +7660,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
|
||||||
"integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0="
|
"integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0="
|
||||||
},
|
},
|
||||||
"lodash.keys": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
|
|
||||||
"integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
|
|
||||||
"requires": {
|
|
||||||
"lodash._getnative": "^3.0.0",
|
|
||||||
"lodash.isarguments": "^3.0.0",
|
|
||||||
"lodash.isarray": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lodash.memoize": {
|
"lodash.memoize": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||||
@@ -7866,17 +7841,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mdast-util-compact": {
|
"mdast-util-compact": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz",
|
||||||
"integrity": "sha512-nRiU5GpNy62rZppDKbLwhhtw5DXoFMqw9UNZFmlPsNaQCZ//WLjGKUwWMdJrUH+Se7UvtO2gXtAMe0g/N+eI5w==",
|
"integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"unist-util-visit": "^1.1.0"
|
"unist-util-visit": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mdast-util-definitions": {
|
"mdast-util-definitions": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-1.2.5.tgz",
|
||||||
"integrity": "sha512-HfUArPog1j4Z78Xlzy9Q4aHLnrF/7fb57cooTHypyGoe2XFNbcx/kWZDoOz+ra8CkUzvg3+VHV434yqEd1DRmA==",
|
"integrity": "sha512-CJXEdoLfiISCDc2JB6QLb79pYfI6+GcIH+W2ox9nMc7od0Pz+bovcHsiq29xAQY6ayqe/9CsK2VzkSJdg1pFYA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"unist-util-visit": "^1.0.0"
|
"unist-util-visit": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -7900,9 +7875,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mdast-util-to-string": {
|
"mdast-util-to-string": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.0.7.tgz",
|
||||||
"integrity": "sha512-868pp48gUPmZIhfKrLbaDneuzGiw3OTDjHc5M1kAepR2CWBJ+HpEsm252K4aXdiP5coVZaJPOqGtVU6Po8xnXg=="
|
"integrity": "sha512-P+gdtssCoHOX+eJUrrC30Sixqao86ZPlVjR5NEAoy0U79Pfxb1Y0Gntei0+GrnQD4T04X9xA8tcugp90cSmNow=="
|
||||||
},
|
},
|
||||||
"mdurl": {
|
"mdurl": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@@ -8217,7 +8192,7 @@
|
|||||||
},
|
},
|
||||||
"node-status-codes": {
|
"node-status-codes": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "http://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
|
||||||
"integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8="
|
"integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8="
|
||||||
},
|
},
|
||||||
"noop6": {
|
"noop6": {
|
||||||
@@ -8524,7 +8499,7 @@
|
|||||||
},
|
},
|
||||||
"package.json": {
|
"package.json": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/package.json/-/package.json-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/package.json/-/package.json-2.0.1.tgz",
|
||||||
"integrity": "sha1-+IYFnSpJ7QduZIg2ldc7K0bSHW0=",
|
"integrity": "sha1-+IYFnSpJ7QduZIg2ldc7K0bSHW0=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"git-package-json": "^1.4.0",
|
"git-package-json": "^1.4.0",
|
||||||
@@ -8534,7 +8509,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"got": {
|
"got": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "http://registry.npmjs.org/got/-/got-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/got/-/got-5.7.1.tgz",
|
||||||
"integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=",
|
"integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"create-error-class": "^3.0.1",
|
"create-error-class": "^3.0.1",
|
||||||
@@ -8556,7 +8531,7 @@
|
|||||||
},
|
},
|
||||||
"package-json": {
|
"package-json": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "http://registry.npmjs.org/package-json/-/package-json-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/package-json/-/package-json-2.4.0.tgz",
|
||||||
"integrity": "sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=",
|
"integrity": "sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"got": "^5.0.0",
|
"got": "^5.0.0",
|
||||||
@@ -10236,16 +10211,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rc-animate": {
|
"rc-animate": {
|
||||||
"version": "2.10.1",
|
"version": "2.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.10.2.tgz",
|
||||||
"integrity": "sha512-yfP3g5fNf8wB5eh85nim2IGrqNu5u7TKrrSh710+1vlUqZvnI2R5YHK99IBCQNgkLCAWjT0sHtkcYdynjly39w==",
|
"integrity": "sha512-cE/A7piAzoWFSgUD69NmmMraqCeqVBa51UErod8NS3LUEqWfppSVagHfa0qHAlwPVPiIBg3emRONyny3eiH0Dg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"babel-runtime": "6.x",
|
"babel-runtime": "6.x",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"css-animation": "^1.3.2",
|
"css-animation": "^1.3.2",
|
||||||
"prop-types": "15.x",
|
"prop-types": "15.x",
|
||||||
"raf": "^3.4.0",
|
"raf": "^3.4.0",
|
||||||
"rc-util": "^4.8.0",
|
"rc-util": "^4.15.3",
|
||||||
"react-lifecycles-compat": "^3.0.4"
|
"react-lifecycles-compat": "^3.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -10264,15 +10239,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rc-util": {
|
"rc-util": {
|
||||||
"version": "4.13.0",
|
"version": "4.15.4",
|
||||||
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.15.4.tgz",
|
||||||
"integrity": "sha512-rjfPy+afc2n40APHp6GYScXfgwHuUnYLz/4SCEWRaF8CHXKR8xw598LtPA36J3fEXENuMm6liO/CoKBoSrYCDw==",
|
"integrity": "sha512-jy2Ej+5N0u9iRoZ/n9gYhVlZkgPV5h8Fu4zNBUsDQNQRCPJMfE6aI8h7KFZEeEZQfFq5abxBgyQyq7TGYyvARQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"add-dom-event-listener": "^1.1.0",
|
"add-dom-event-listener": "^1.1.0",
|
||||||
"babel-runtime": "6.x",
|
"babel-runtime": "6.x",
|
||||||
"prop-types": "^15.5.10",
|
"prop-types": "^15.5.10",
|
||||||
"react-lifecycles-compat": "^3.0.4",
|
"react-lifecycles-compat": "^3.0.4",
|
||||||
"shallowequal": "^0.2.2"
|
"shallowequal": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react": {
|
"react": {
|
||||||
@@ -11386,9 +11361,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"seafile-js": {
|
"seafile-js": {
|
||||||
"version": "0.2.138",
|
"version": "0.2.139",
|
||||||
"resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.138.tgz",
|
"resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.139.tgz",
|
||||||
"integrity": "sha512-glPINgDUw2a5q1qBX3hJPKlT2iNltvt3hQXkC6f2pQqLRdh3s8faNHP0ftD+7QnmEmXZpr1LX/6RjtdwP6U57g==",
|
"integrity": "sha512-/KNI7N59iOh6zyEW4lMvSiHE0uHgEmm9hdnthp0hVvEfIVKX8K4dxQBj1zqDxuGIQnF8FXxiR/6Pzs21jlkhZg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"form-data": "^2.3.2",
|
"form-data": "^2.3.2",
|
||||||
@@ -11535,12 +11510,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shallowequal": {
|
"shallowequal": {
|
||||||
"version": "0.2.2",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||||
"integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=",
|
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
|
||||||
"requires": {
|
|
||||||
"lodash.keys": "^3.1.2"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"shebang-command": {
|
"shebang-command": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -11612,9 +11584,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"slate-base64-serializer": {
|
"slate-base64-serializer": {
|
||||||
"version": "0.2.111",
|
"version": "0.2.112",
|
||||||
"resolved": "https://registry.npmjs.org/slate-base64-serializer/-/slate-base64-serializer-0.2.111.tgz",
|
"resolved": "https://registry.npmjs.org/slate-base64-serializer/-/slate-base64-serializer-0.2.112.tgz",
|
||||||
"integrity": "sha512-pEsbxz4msVSCCCkn7rX+lHXxUj/oddcR4VsIYwWeQQLm9Uw7Ovxja4rQ/hVFcQqoU2DIjITRwBR9pv3RyS+PZQ==",
|
"integrity": "sha512-Vo94bkCq8cbFj7Lutdh2RaM9S4WlLxnnMqZPKGUyefklUN4q2EzM/WUH7s9CIlLUH1qRfC/b0V25VJZr5XXTzA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"isomorphic-base64": "^1.0.2"
|
"isomorphic-base64": "^1.0.2"
|
||||||
}
|
}
|
||||||
@@ -11637,9 +11609,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"slate-html-serializer": {
|
"slate-html-serializer": {
|
||||||
"version": "0.7.2",
|
"version": "0.7.39",
|
||||||
"resolved": "https://registry.npmjs.org/slate-html-serializer/-/slate-html-serializer-0.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/slate-html-serializer/-/slate-html-serializer-0.7.39.tgz",
|
||||||
"integrity": "sha512-UpF3tnEEzdvQKQWvRPqnkKftoBG7efDkNCjaoa7p4yCPav/RstCAm9AwhdINGsKDcYgPt9RXvhpe6r7iu/KQQQ==",
|
"integrity": "sha512-ZNyVjqCasSa0M80+4W1bFXMhW4KJM7EE6dkyBOhQmIcuRX529xOahcz+6ZYK7fQn0Cyrye899OtX26LulAh/Ew==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"type-of": "^2.0.1"
|
"type-of": "^2.0.1"
|
||||||
}
|
}
|
||||||
@@ -11650,9 +11622,9 @@
|
|||||||
"integrity": "sha512-EGl+Y+9Fw9IULtPg8sttydaeiAoaibJolMXNfqI79+5GWTQwJFIbg24keKvsTw+3f2RieaPu8fcrKyujKtZ7ZQ=="
|
"integrity": "sha512-EGl+Y+9Fw9IULtPg8sttydaeiAoaibJolMXNfqI79+5GWTQwJFIbg24keKvsTw+3f2RieaPu8fcrKyujKtZ7ZQ=="
|
||||||
},
|
},
|
||||||
"slate-prop-types": {
|
"slate-prop-types": {
|
||||||
"version": "0.5.41",
|
"version": "0.5.42",
|
||||||
"resolved": "https://registry.npmjs.org/slate-prop-types/-/slate-prop-types-0.5.41.tgz",
|
"resolved": "https://registry.npmjs.org/slate-prop-types/-/slate-prop-types-0.5.42.tgz",
|
||||||
"integrity": "sha512-fLcXlugO9btF5b/by+dA+n8fn2mET75VGWltqFNxGdl6ncyBtrGspWA7mLVRFSqQWOS/Ig4A3URCRumOBBCUfQ=="
|
"integrity": "sha512-3n3556FDs9/cyhRdDMryVB1PJvWeu+p3dx9TvHtONybud4tfulWk4r175JoVWcFZCUFGFQK7IbObUbz1MWNKCg=="
|
||||||
},
|
},
|
||||||
"slate-react-placeholder": {
|
"slate-react-placeholder": {
|
||||||
"version": "0.1.20",
|
"version": "0.1.20",
|
||||||
@@ -12562,9 +12534,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"unist-util-generated": {
|
"unist-util-generated": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.5.tgz",
|
||||||
"integrity": "sha512-SA7Sys3h3X4AlVnxHdvN/qYdr4R38HzihoEVY2Q2BZu8NHWDnw5OGcC/tXWjQfd4iG+M6qRFNIRGqJmp2ez4Ww=="
|
"integrity": "sha512-1TC+NxQa4N9pNdayCYA1EGUOCAO0Le3fVp7Jzns6lnua/mYgwHo0tz5WUAfrdpNch1RZLHc61VZ1SDgrtNXLSw=="
|
||||||
},
|
},
|
||||||
"unist-util-is": {
|
"unist-util-is": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@@ -12572,22 +12544,22 @@
|
|||||||
"integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A=="
|
"integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A=="
|
||||||
},
|
},
|
||||||
"unist-util-modify-children": {
|
"unist-util-modify-children": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-1.1.5.tgz",
|
||||||
"integrity": "sha512-8iey9wkoB62C7Vi/8zcRUmi4b1f5AYKTwMkyEgLduo2D8+OY65RoSvbn6k9tVNri6qumXxAwXDVlXWQi0sENTw==",
|
"integrity": "sha512-XeL5qqyoS3TEueCKEzHusWXE9JBDJPE4rl6LmcLOwlzv0RIZrcMNqKx02GSK3Ms4v45ldu+ltPxG42FBMVdPZw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"array-iterate": "^1.0.0"
|
"array-iterate": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"unist-util-position": {
|
"unist-util-position": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.4.tgz",
|
||||||
"integrity": "sha512-28EpCBYFvnMeq9y/4w6pbnFmCUfzlsc41NJui5c51hOFjBA1fejcwc+5W4z2+0ECVbScG3dURS3JTVqwenzqZw=="
|
"integrity": "sha512-tWvIbV8goayTjobxDIr4zVTyG+Q7ragMSMeKC3xnPl9xzIc0+she8mxXLM3JVNDDsfARPbCd3XdzkyLdo7fF3g=="
|
||||||
},
|
},
|
||||||
"unist-util-remove-position": {
|
"unist-util-remove-position": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
|
||||||
"integrity": "sha512-CtszTlOjP2sBGYc2zcKA/CvNdTdEs3ozbiJ63IPBxh8iZg42SCCb8m04f8z2+V1aSk5a7BxbZKEdoDjadmBkWA==",
|
"integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"unist-util-visit": "^1.1.0"
|
"unist-util-visit": "^1.1.0"
|
||||||
}
|
}
|
||||||
@@ -12826,9 +12798,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vfile-location": {
|
"vfile-location": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
|
||||||
"integrity": "sha512-Pa1ey0OzYBkLPxPZI3d9E+S4BmvfVwNAAXrrqGbwTVXWaX2p9kM1zZ+n35UtVM06shmWKH4RPRN8KI80qE3wNQ=="
|
"integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA=="
|
||||||
},
|
},
|
||||||
"vfile-message": {
|
"vfile-message": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reach/router": "^1.2.0",
|
"@reach/router": "^1.2.0",
|
||||||
"@seafile/resumablejs": "^1.1.15",
|
"@seafile/resumablejs": "^1.1.15",
|
||||||
"@seafile/seafile-editor": "^0.2.72",
|
"@seafile/seafile-editor": "^0.2.76",
|
||||||
"MD5": "^1.3.0",
|
"MD5": "^1.3.0",
|
||||||
"autoprefixer": "7.1.6",
|
"autoprefixer": "7.1.6",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
"react-responsive": "^6.1.2",
|
"react-responsive": "^6.1.2",
|
||||||
"react-select": "^2.4.1",
|
"react-select": "^2.4.1",
|
||||||
"reactstrap": "^6.4.0",
|
"reactstrap": "^6.4.0",
|
||||||
"seafile-js": "^0.2.138",
|
"seafile-js": "^0.2.139",
|
||||||
"socket.io-client": "^2.2.0",
|
"socket.io-client": "^2.2.0",
|
||||||
"sw-precache-webpack-plugin": "0.11.4",
|
"sw-precache-webpack-plugin": "0.11.4",
|
||||||
"unified": "^7.0.0",
|
"unified": "^7.0.0",
|
||||||
|
@@ -0,0 +1,156 @@
|
|||||||
|
import React, {Fragment} from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Input, Alert, FormGroup, Label } from 'reactstrap';
|
||||||
|
import { gettext } from '../../../utils/constants';
|
||||||
|
import TermsPreviewWidget from '../terms-preview-widget';
|
||||||
|
import TermsEditorDialog from '../terms-editor-dialog';
|
||||||
|
|
||||||
|
import '../../../css/terms-conditions-editor.css';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
isUpdate: PropTypes.bool,
|
||||||
|
oldTermObj: PropTypes.object,
|
||||||
|
addTerm: PropTypes.func,
|
||||||
|
updateTerm: PropTypes.func,
|
||||||
|
toggle: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddOrUpdateTermDialog extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
name: '',
|
||||||
|
versionNumber: '',
|
||||||
|
text: {text: '', perview: ''},
|
||||||
|
isActive: true,
|
||||||
|
errorMsg: '',
|
||||||
|
isConditionsEditorDialogShow: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
let oldTermObj = this.props.oldTermObj;
|
||||||
|
if (oldTermObj) {
|
||||||
|
this.setState({
|
||||||
|
name: oldTermObj.name,
|
||||||
|
versionNumber: oldTermObj.version_number,
|
||||||
|
text: JSON.parse(oldTermObj.text),
|
||||||
|
isActive: !(oldTermObj.activate_time === ''),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleNameChange = (e) => {
|
||||||
|
this.setState({name: e.target.value.trim()});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleVersionNumberChange = (e) => {
|
||||||
|
this.setState({versionNumber: e.target.value.trim()});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTextChange = (e) => {
|
||||||
|
this.setState({text: e.target.value.trim()});
|
||||||
|
}
|
||||||
|
|
||||||
|
setActive = () => {
|
||||||
|
this.setState({isActive: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
setInActive = () => {
|
||||||
|
this.setState({isActive: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
addTerm = () => {
|
||||||
|
let { name, versionNumber, text, isActive } = this.state;
|
||||||
|
if (name === '') {
|
||||||
|
this.setState({errMsg: gettext('Name is required.')});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (versionNumber === '') {
|
||||||
|
this.setState({errMsg: gettext('Version Number is required.')});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNaN(versionNumber)) {
|
||||||
|
this.setState({errMsg: gettext('Version Number must be a number.')});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
text = JSON.stringify(text);
|
||||||
|
if (text === '') {
|
||||||
|
this.setState({errMsg: gettext('Text is required.')});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.props.isUpdate) {
|
||||||
|
this.props.updateTerm(name, versionNumber, text, isActive);
|
||||||
|
} else {
|
||||||
|
this.props.addTerm(name, versionNumber, text, isActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onContentClick = () => {
|
||||||
|
this.setState({isConditionsEditorDialogShow: !this.state.isConditionsEditorDialogShow});
|
||||||
|
}
|
||||||
|
|
||||||
|
onCloseEditorDialog = () => {
|
||||||
|
this.setState({isConditionsEditorDialogShow: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdateContent = (content) => {
|
||||||
|
this.setState({ text: content });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let title = this.props.isUpdate ? gettext('Update Terms and Conditions') : gettext('Add Terms and Conditions');
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Modal isOpen={true} toggle={this.props.toggle}>
|
||||||
|
<ModalHeader toggle={this.props.toggle}>{title}</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<FormGroup>
|
||||||
|
<Label for="name">{gettext('Name')}</Label>
|
||||||
|
<Input id="name" value={this.state.name} onChange={this.handleNameChange}/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup>
|
||||||
|
<Label>{gettext('Version Number')}</Label>
|
||||||
|
<Input value={this.state.versionNumber} onChange={this.handleVersionNumberChange}/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup className="form-content">
|
||||||
|
<Label>{gettext('Text')}</Label>
|
||||||
|
<TermsPreviewWidget content={this.state.text} onContentClick={this.onContentClick}/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup tag="fieldset">
|
||||||
|
<Label>{gettext('Activated')}</Label>
|
||||||
|
<FormGroup check>
|
||||||
|
<Label check>
|
||||||
|
<Input type="radio" checked={this.state.isActive} onChange={this.setActive} />
|
||||||
|
{' '}{gettext('On')}
|
||||||
|
</Label>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup check>
|
||||||
|
<Label check>
|
||||||
|
<Input type="radio" checked={!this.state.isActive} onChange={this.setInActive} />
|
||||||
|
{' '}{gettext('Off')}
|
||||||
|
</Label>
|
||||||
|
</FormGroup>
|
||||||
|
</FormGroup>
|
||||||
|
{this.state.errMsg && <Alert color="danger">{this.state.errMsg}</Alert>}
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button color="primary" onClick={this.addTerm}>{gettext('Submit')}</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
{this.state.isConditionsEditorDialogShow && (
|
||||||
|
<TermsEditorDialog
|
||||||
|
content={this.state.text}
|
||||||
|
onCommit={this.onUpdateContent}
|
||||||
|
onCloseEditorDialog={this.onCloseEditorDialog}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddOrUpdateTermDialog.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default AddOrUpdateTermDialog;
|
76
frontend/src/components/dialog/terms-editor-dialog.js
Normal file
76
frontend/src/components/dialog/terms-editor-dialog.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
|
||||||
|
import getPreviewContent from '../../utils/markdown-utils';
|
||||||
|
import { SimpleEditor } from '@seafile/seafile-editor';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
content: PropTypes.object,
|
||||||
|
onCommit: PropTypes.func.isRequired,
|
||||||
|
onCloseEditorDialog: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TermsEditorDialog extends React.Component {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
title: gettext('Terms'),
|
||||||
|
content: {text: '', preview: ''}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown = (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle = () => {
|
||||||
|
if (this.isContentChanged()) {
|
||||||
|
let currentContent = this.getCurrentContent();
|
||||||
|
this.props.onCommit(currentContent);
|
||||||
|
}
|
||||||
|
this.props.onCloseEditorDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
isContentChanged = () => {
|
||||||
|
return this.simpleEditor.hasContentChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentContent = () => {
|
||||||
|
let markdownContent = this.simpleEditor.getMarkdown();
|
||||||
|
let { previewText , images, links } = getPreviewContent(markdownContent);
|
||||||
|
let content = Object.assign({}, this.value, { text: markdownContent, preview: previewText, images: images, links: links });
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSimpleEditorRef = (editor) => {
|
||||||
|
this.simpleEditor = editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { content, title } = this.props;
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={true}
|
||||||
|
toggle={this.toggle}
|
||||||
|
onKeyDown={this.onKeyDown}
|
||||||
|
wrapClassName={'conditions-editor-dialog-wrapper'}
|
||||||
|
className={'conditions-editor-dialog'}
|
||||||
|
contentClassName={'conditions-editor-dialog-content'}
|
||||||
|
size={'lg'}
|
||||||
|
style={{width: 770}}
|
||||||
|
>
|
||||||
|
<ModalHeader className="conditions-editor-dialog-title" toggle={this.toggle}>{title}</ModalHeader>
|
||||||
|
<ModalBody className={'conditions-editor-dialog-main'}>
|
||||||
|
<SimpleEditor
|
||||||
|
onRef={this.setSimpleEditorRef.bind(this)}
|
||||||
|
value={content.text || ''}
|
||||||
|
/>
|
||||||
|
</ModalBody>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TermsEditorDialog.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default TermsEditorDialog;
|
46
frontend/src/components/dialog/terms-preview-dialog.js
Normal file
46
frontend/src/components/dialog/terms-preview-dialog.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
|
||||||
|
import ConditionsPreviewWidget from './terms-preview-widget';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
content: PropTypes.string,
|
||||||
|
onClosePreviewDialog: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TermsPreviewDialog extends React.Component {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
title: gettext('Terms'),
|
||||||
|
content: {text: '', perview: ''}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
toggle = () => {
|
||||||
|
this.props.onClosePreviewDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { title, content } = this.props;
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={true}
|
||||||
|
size={'lg'}
|
||||||
|
style={{width: 600}}
|
||||||
|
wrapClassName={'conditions-perview-wrapper'}
|
||||||
|
toggle={this.toggle}
|
||||||
|
>
|
||||||
|
<ModalHeader toggle={this.toggle}>{title}</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<ConditionsPreviewWidget content={content} />
|
||||||
|
</ModalBody>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TermsPreviewDialog.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default TermsPreviewDialog;
|
69
frontend/src/components/dialog/terms-preview-widget.js
Normal file
69
frontend/src/components/dialog/terms-preview-widget.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { processor } from '@seafile/seafile-editor/dist/utils/seafile-markdown2html';
|
||||||
|
import Loading from '../loading';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
content: PropTypes.object,
|
||||||
|
onContentClick: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TermsPreviewWidget extends React.Component {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
content: {text: '', perview: ''}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
innerHtml: null,
|
||||||
|
isFormatValue: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
let content = this.props.content;
|
||||||
|
let mdFile = content ? content.text : '';
|
||||||
|
if (mdFile) {
|
||||||
|
this.formatterLongTextValue(mdFile);
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
isFormatValue: false,
|
||||||
|
innerHtml: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
let mdFile = nextProps.content.text;
|
||||||
|
this.formatterLongTextValue(mdFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatterLongTextValue = (mdFile) => {
|
||||||
|
processor.process(mdFile).then((result) => {
|
||||||
|
let innerHtml = String(result);
|
||||||
|
this.setState({
|
||||||
|
isFormatValue: false,
|
||||||
|
innerHtml: innerHtml
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.isFormatValue) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="conditions-preview-container" onClick={this.props.onContentClick}>
|
||||||
|
<div dangerouslySetInnerHTML={{__html: this.state.innerHtml}}></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TermsPreviewWidget.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default TermsPreviewWidget;
|
26
frontend/src/css/terms-conditions-editor.css
Normal file
26
frontend/src/css/terms-conditions-editor.css
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
.form-content .conditions-preview-container {
|
||||||
|
padding: 10px;
|
||||||
|
min-height: 38px;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conditions-preview-wrapper .conditions-preview-container {
|
||||||
|
padding: 10px;
|
||||||
|
min-height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conditions-preview-container ol,
|
||||||
|
.conditions-preview-container ul {
|
||||||
|
padding-inline-start: 40px;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conditions-editor-dialog-main {
|
||||||
|
padding: 0;
|
||||||
|
height: 600px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
@@ -59,6 +59,8 @@ import SharePermissionLogs from './logs-page/share-permission-logs';
|
|||||||
import AdminOperationLogs from './admin-logs/operation-logs';
|
import AdminOperationLogs from './admin-logs/operation-logs';
|
||||||
import AdminLoginLogs from './admin-logs/login-logs';
|
import AdminLoginLogs from './admin-logs/login-logs';
|
||||||
|
|
||||||
|
import TermsAndConditions from './terms-and-conditions/terms-and-conditions';
|
||||||
|
|
||||||
import WebSettings from './web-settings/web-settings';
|
import WebSettings from './web-settings/web-settings';
|
||||||
import Notifications from './notifications/notifications';
|
import Notifications from './notifications/notifications';
|
||||||
import FileScanRecords from './file-scan-records';
|
import FileScanRecords from './file-scan-records';
|
||||||
@@ -197,6 +199,7 @@ class SysAdmin extends React.Component {
|
|||||||
<UserGroups path={siteRoot + 'sys/users/:email/groups'} />
|
<UserGroups path={siteRoot + 'sys/users/:email/groups'} />
|
||||||
|
|
||||||
<Invitations path={siteRoot + 'sys/invitations'} />
|
<Invitations path={siteRoot + 'sys/invitations'} />
|
||||||
|
<TermsAndConditions path={siteRoot + 'sys/terms-and-conditions/'} />
|
||||||
|
|
||||||
<FileScanRecords
|
<FileScanRecords
|
||||||
path={siteRoot + 'sys/file-scan-records'}
|
path={siteRoot + 'sys/file-scan-records'}
|
||||||
|
@@ -222,10 +222,14 @@ class SidePanel extends React.Component {
|
|||||||
}
|
}
|
||||||
{isDefaultAdmin && enableTermsAndConditions &&
|
{isDefaultAdmin && enableTermsAndConditions &&
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<a className='nav-link ellipsis' href={siteRoot + 'sys/termsadmin/'}>
|
<Link
|
||||||
|
className={`nav-link ellipsis ${this.getActiveClass('termsandconditions')}`}
|
||||||
|
to={siteRoot + 'sys/terms-and-conditions/'}
|
||||||
|
onClick={() => this.props.tabItemClick('termsandconditions')}
|
||||||
|
>
|
||||||
<span className="sf2-icon-wiki" aria-hidden="true"></span>
|
<span className="sf2-icon-wiki" aria-hidden="true"></span>
|
||||||
<span className="nav-text">{gettext('Terms and Conditions')}</span>
|
<span className="nav-text">{gettext('Terms and Conditions')}</span>
|
||||||
</a>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
{isPro && canViewAdminLog &&
|
{isPro && canViewAdminLog &&
|
||||||
|
84
frontend/src/pages/sys-admin/terms-and-conditions/content.js
Normal file
84
frontend/src/pages/sys-admin/terms-and-conditions/content.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { gettext } from '../../../utils/constants';
|
||||||
|
import EmptyTip from '../../../components/empty-tip';
|
||||||
|
import Loading from '../../../components/loading';
|
||||||
|
import Item from './item';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
loading: PropTypes.bool.isRequired,
|
||||||
|
items: PropTypes.array.isRequired,
|
||||||
|
errorMsg: PropTypes.string,
|
||||||
|
deleteTerm: PropTypes.func.isRequired,
|
||||||
|
updateTerm: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Content extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isItemFreezed: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onFreezedItem = () => {
|
||||||
|
this.setState({isItemFreezed: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnfreezedItem = () => {
|
||||||
|
this.setState({isItemFreezed: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { loading, errorMsg, items } = this.props;
|
||||||
|
if (loading) {
|
||||||
|
return <Loading />;
|
||||||
|
} else if (errorMsg) {
|
||||||
|
return <p className="error text-center">{errorMsg}</p>;
|
||||||
|
} else {
|
||||||
|
const emptyTip = (
|
||||||
|
<EmptyTip>
|
||||||
|
<h2>{gettext('No Terms and Conditions.')}</h2>
|
||||||
|
</EmptyTip>
|
||||||
|
);
|
||||||
|
const table = (
|
||||||
|
<Fragment>
|
||||||
|
<table className="table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="20%">{gettext('Name')}</th>
|
||||||
|
<th width="10%">{gettext('Version')}</th>
|
||||||
|
<th width="25%">{gettext('Text')}</th>
|
||||||
|
<th width="20%">{gettext('Created')}</th>
|
||||||
|
<th width="20%">{gettext('Activated')}</th>
|
||||||
|
<th width="5%">{/* operation */}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{items &&
|
||||||
|
<tbody>
|
||||||
|
{items.map((item, index) => {
|
||||||
|
return (<Item
|
||||||
|
key={index}
|
||||||
|
item={item}
|
||||||
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
|
onFreezedItem={this.onFreezedItem}
|
||||||
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
deleteTerm={this.props.deleteTerm}
|
||||||
|
updateTerm={this.props.updateTerm}
|
||||||
|
/>);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
return items.length ? table : emptyTip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Content.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default Content;
|
||||||
|
|
153
frontend/src/pages/sys-admin/terms-and-conditions/item.js
Normal file
153
frontend/src/pages/sys-admin/terms-and-conditions/item.js
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { gettext } from '../../../utils/constants';
|
||||||
|
import { Utils } from '../../../utils/utils';
|
||||||
|
import moment from 'moment';
|
||||||
|
import AddOrUpdateTermDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-or-update-term-dialog';
|
||||||
|
import TermsPerviewDialog from '../../../components/dialog/terms-preview-dialog';
|
||||||
|
import ModalPortal from '../../../components/modal-portal';
|
||||||
|
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
||||||
|
import OpMenu from './op-menu';
|
||||||
|
|
||||||
|
const propsTypes = {
|
||||||
|
item: PropTypes.object.isRequired,
|
||||||
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
|
onFreezedItem: PropTypes.func.isRequired,
|
||||||
|
onUnfreezedItem: PropTypes.func.isRequired,
|
||||||
|
deleteTerm: PropTypes.func.isRequired,
|
||||||
|
updateTerm: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
class Item extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isOpIconShown: false,
|
||||||
|
isUpdateDialogOpen: false,
|
||||||
|
isDeleteDialogOpen: false,
|
||||||
|
isTermsPerviewDialogOpen: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseEnter = () => {
|
||||||
|
if (!this.props.isItemFreezed) {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: true,
|
||||||
|
highlight: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseLeave = () => {
|
||||||
|
if (!this.props.isItemFreezed) {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: false,
|
||||||
|
highlight: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleUpdateDialog = (e) => {
|
||||||
|
this.setState({isUpdateDialogOpen: !this.state.isUpdateDialogOpen});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleDeleteDialog = (e) => {
|
||||||
|
this.setState({isDeleteDialogOpen: !this.state.isDeleteDialogOpen});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTermsContentDialog = (e) => {
|
||||||
|
this.setState({isTermsPerviewDialogOpen: !this.state.isTermsPerviewDialogOpen})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuItemClick = (operation) => {
|
||||||
|
switch(operation) {
|
||||||
|
case 'Update':
|
||||||
|
this.toggleUpdateDialog();
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
this.toggleDeleteDialog();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnfreezedItem = () => {
|
||||||
|
this.setState({
|
||||||
|
highlight: false,
|
||||||
|
isOpIconShow: false
|
||||||
|
});
|
||||||
|
this.props.onUnfreezedItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTerm = () => {
|
||||||
|
this.props.deleteTerm(this.props.item.id);
|
||||||
|
this.toggleDeleteDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTerm = (name, versionNumber, text, isActive) => {
|
||||||
|
this.props.updateTerm(this.props.item.id, name, versionNumber, text, isActive);
|
||||||
|
this.toggleUpdateDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { item } = this.props;
|
||||||
|
let { isDeleteDialogOpen, isUpdateDialogOpen, isTermsPerviewDialogOpen } = this.state;
|
||||||
|
let termContent = item.text ? JSON.parse(item.text) : {};
|
||||||
|
let itemName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>';
|
||||||
|
let deleteDialogMsg = gettext('Are you sure you want to delete {placeholder} ?').replace('{placeholder}', itemName);
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<tr onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||||
|
<td>{item.name}</td>
|
||||||
|
<td>{item.version_number}</td>
|
||||||
|
<td className="ellipsis"><a href='#' onClick={this.toggleTermsContentDialog}>{termContent.text}</a></td>
|
||||||
|
<td>{moment(item.ctime).fromNow()}</td>
|
||||||
|
<td>{item.activate_time ? moment(item.activate_time).fromNow() : '--'}</td>
|
||||||
|
<td>
|
||||||
|
{this.state.isOpIconShown &&
|
||||||
|
<OpMenu
|
||||||
|
item={item}
|
||||||
|
onMenuItemClick={this.onMenuItemClick}
|
||||||
|
onFreezedItem={this.props.onFreezedItem}
|
||||||
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{isDeleteDialogOpen &&
|
||||||
|
<ModalPortal>
|
||||||
|
<CommonOperationConfirmationDialog
|
||||||
|
title={gettext('Delete T&C')}
|
||||||
|
message={deleteDialogMsg}
|
||||||
|
toggleDialog={this.toggleDeleteDialog}
|
||||||
|
executeOperation={this.deleteTerm}
|
||||||
|
confirmBtnText={gettext('Delete')}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
}
|
||||||
|
{isUpdateDialogOpen &&
|
||||||
|
<ModalPortal>
|
||||||
|
<AddOrUpdateTermDialog
|
||||||
|
updateTerm={this.updateTerm}
|
||||||
|
toggle={this.toggleUpdateDialog}
|
||||||
|
isUpdate={true}
|
||||||
|
oldTermObj={item}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
}
|
||||||
|
{isTermsPerviewDialogOpen &&
|
||||||
|
<ModalPortal>
|
||||||
|
<TermsPerviewDialog
|
||||||
|
content={termContent}
|
||||||
|
onClosePreviewDialog={this.toggleTermsContentDialog}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item.propTypes = propsTypes;
|
||||||
|
|
||||||
|
export default Item;
|
85
frontend/src/pages/sys-admin/terms-and-conditions/op-menu.js
Normal file
85
frontend/src/pages/sys-admin/terms-and-conditions/op-menu.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
|
||||||
|
import { gettext } from '../../../utils/constants';
|
||||||
|
import { Utils } from '../../../utils/utils';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
item: PropTypes.object.isRequired,
|
||||||
|
onFreezedItem: PropTypes.func.isRequired,
|
||||||
|
onUnfreezedItem: PropTypes.func.isRequired,
|
||||||
|
onMenuItemClick: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpMenu extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isItemMenuShow: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuItemClick = (e) => {
|
||||||
|
let operation = Utils.getEventData(e, 'op');
|
||||||
|
this.props.onMenuItemClick(operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDropdownToggleClick = (e) => {
|
||||||
|
this.toggleOperationMenu(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleOperationMenu = (e) => {
|
||||||
|
this.setState(
|
||||||
|
{isItemMenuShow: !this.state.isItemMenuShow},
|
||||||
|
() => {
|
||||||
|
if (this.state.isItemMenuShow) {
|
||||||
|
this.props.onFreezedItem();
|
||||||
|
} else {
|
||||||
|
this.props.onUnfreezedItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
translateOperations = (item) => {
|
||||||
|
let translateResult = '';
|
||||||
|
switch(item) {
|
||||||
|
case 'Update':
|
||||||
|
translateResult = gettext('Update');
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
translateResult = gettext('Delete');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return translateResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let operations = ['Update', 'Delete'];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleOperationMenu}>
|
||||||
|
<DropdownToggle
|
||||||
|
tag="i"
|
||||||
|
className="sf-dropdown-toggle fa fa-ellipsis-v"
|
||||||
|
title={gettext('More Operations')}
|
||||||
|
data-toggle="dropdown"
|
||||||
|
aria-expanded={this.state.isItemMenuShow}
|
||||||
|
/>
|
||||||
|
<DropdownMenu className="mt-2 mr-2">
|
||||||
|
{operations.map((item, index )=> {
|
||||||
|
return (<DropdownItem key={index} data-op={item} onClick={this.onMenuItemClick}>{this.translateOperations(item)}</DropdownItem>);
|
||||||
|
})}
|
||||||
|
</DropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpMenu.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default OpMenu;
|
@@ -0,0 +1,132 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import { Button } from 'reactstrap';
|
||||||
|
import { Utils } from '../../../utils/utils';
|
||||||
|
import { seafileAPI } from '../../../utils/seafile-api';
|
||||||
|
import { gettext, loginUrl } from '../../../utils/constants';
|
||||||
|
import AddOrUpdateTermDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-or-update-term-dialog';
|
||||||
|
import ModalPortal from '../../../components/modal-portal';
|
||||||
|
import toaster from '../../../components/toast';
|
||||||
|
import MainPanelTopbar from '../main-panel-topbar';
|
||||||
|
import Content from './content';
|
||||||
|
|
||||||
|
class TermsAndConditions extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
errorMsg: '',
|
||||||
|
termList: [],
|
||||||
|
isAddTermDialogOpen: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleAddTermDialog = () => {
|
||||||
|
this.setState({isAddTermDialogOpen: !this.state.isAddTermDialogOpen});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
seafileAPI.sysAdminListTermsAndConditions().then((res) => {
|
||||||
|
this.setState({
|
||||||
|
termList: res.data.term_and_condition_list,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.response) {
|
||||||
|
if (error.response.status == 403) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
errorMsg: gettext('Permission denied')
|
||||||
|
});
|
||||||
|
location.href = `${loginUrl}?next=${encodeURIComponent(location.href)}`;
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
errorMsg: gettext('Error')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
errorMsg: gettext('Please check the network.')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addTerm = (name, versionNumber, text, isActive) => {
|
||||||
|
seafileAPI.sysAdminAddTermAndCondition(name, versionNumber, text, isActive).then(res => {
|
||||||
|
// After adding the terms, you need to refresh the page.
|
||||||
|
location.reload();
|
||||||
|
}).catch((error) => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTerm = (termID, name, versionNumber, text, isActive) => {
|
||||||
|
seafileAPI.sysAdminUpdateTermAndCondition(termID, name, versionNumber, text, isActive).then(res => {
|
||||||
|
let termList = this.state.termList.map(item => {
|
||||||
|
if (item.id == termID) {
|
||||||
|
return res.data;
|
||||||
|
} else {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setState({termList: termList});
|
||||||
|
toaster.success(gettext('Successfully update.'));
|
||||||
|
}).catch((error) => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTerm = (termID) => {
|
||||||
|
seafileAPI.sysAdminDeleteTermAndCondition(termID).then(res => {
|
||||||
|
let termList = this.state.termList.filter(item => item.id != termID);
|
||||||
|
this.setState({termList: termList});
|
||||||
|
toaster.success(gettext('Successfully deleted.'));
|
||||||
|
}).catch((error) => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { termList, isAddTermDialogOpen } = this.state;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<MainPanelTopbar>
|
||||||
|
<Button className="btn btn-secondary operation-item" onClick={this.toggleAddTermDialog}>{gettext('Add')}</Button>
|
||||||
|
</MainPanelTopbar>
|
||||||
|
<div className="main-panel-center flex-row">
|
||||||
|
<div className="cur-view-container">
|
||||||
|
<div className="cur-view-path">
|
||||||
|
<h3 className="sf-heading">{gettext('Terms and Conditions')}</h3>
|
||||||
|
</div>
|
||||||
|
<div className="cur-view-content">
|
||||||
|
<Content
|
||||||
|
loading={this.state.loading}
|
||||||
|
errorMsg={this.state.errorMsg}
|
||||||
|
items={termList}
|
||||||
|
deleteTerm={this.deleteTerm}
|
||||||
|
updateTerm={this.updateTerm}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{isAddTermDialogOpen &&
|
||||||
|
<ModalPortal>
|
||||||
|
<AddOrUpdateTermDialog
|
||||||
|
isUpdate={false}
|
||||||
|
addTerm={this.addTerm}
|
||||||
|
toggle={this.toggleAddTermDialog}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TermsAndConditions;
|
54
frontend/src/utils/markdown-utils.js
Normal file
54
frontend/src/utils/markdown-utils.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
const hrefReg = /\[.+\]\(\S+\)|<img src=(\S+).+\/>|!\[\]\(\S+\)|<\S+>/g,
|
||||||
|
imageReg1 = /^<img src="(\S+)" .+\/>/,
|
||||||
|
imageReg2 = /^!\[\]\((\S+)\)/,
|
||||||
|
linkReg1 = /^\[.+\]\(\S+\)/,
|
||||||
|
linkReg2 = /^<\S+>$/;
|
||||||
|
|
||||||
|
const getLinks = (hrefs) => {
|
||||||
|
const hrefObj = {
|
||||||
|
links: [],
|
||||||
|
images: []
|
||||||
|
};
|
||||||
|
hrefs.forEach((href) => {
|
||||||
|
if (href.search(linkReg1) >= 0 || href.search(linkReg2) >= 0) {
|
||||||
|
hrefObj.links.push(href);
|
||||||
|
} else {
|
||||||
|
let imageSrcs = href.match(imageReg1);
|
||||||
|
let imageSrcs1 = href.match(imageReg2);
|
||||||
|
if (imageSrcs) {
|
||||||
|
hrefObj.images.push(imageSrcs[1]);
|
||||||
|
} else if (imageSrcs1) {
|
||||||
|
hrefObj.images.push(imageSrcs1[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return hrefObj;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const getPreviewContent = (markdownContent) => {
|
||||||
|
let previewText = '';
|
||||||
|
let newMarkdownContent = markdownContent.replace(hrefReg, '');
|
||||||
|
for (let index = 0; index < newMarkdownContent.length; index++) {
|
||||||
|
if (newMarkdownContent[index] === '#') {
|
||||||
|
continue;
|
||||||
|
} else if (newMarkdownContent[index] === '\n') {
|
||||||
|
previewText += ' ';
|
||||||
|
} else {
|
||||||
|
previewText += newMarkdownContent[index];
|
||||||
|
}
|
||||||
|
if (previewText.length === 30) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hrefs = markdownContent.match(hrefReg);
|
||||||
|
if (hrefs) {
|
||||||
|
const { images, links } = getLinks(hrefs);
|
||||||
|
return { previewText, images, links };
|
||||||
|
}
|
||||||
|
return { previewText, images: [], links: [] };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default getPreviewContent;
|
@@ -733,6 +733,7 @@ urlpatterns = [
|
|||||||
url(r'^sys/institutions/(?P<inst_id>\d+)/info/$', sysadmin_react_fake_view, name="sys_institution_info"),
|
url(r'^sys/institutions/(?P<inst_id>\d+)/info/$', sysadmin_react_fake_view, name="sys_institution_info"),
|
||||||
url(r'^sys/institutions/(?P<inst_id>\d+)/members/$', sysadmin_react_fake_view, name="sys_institution_members"),
|
url(r'^sys/institutions/(?P<inst_id>\d+)/members/$', sysadmin_react_fake_view, name="sys_institution_members"),
|
||||||
url(r'^sys/institutions/(?P<inst_id>\d+)/admins/$', sysadmin_react_fake_view, name="sys_institution_admins"),
|
url(r'^sys/institutions/(?P<inst_id>\d+)/admins/$', sysadmin_react_fake_view, name="sys_institution_admins"),
|
||||||
|
url(r'^sys/terms-and-conditions/$', sysadmin_react_fake_view, name="terms_and_conditions"),
|
||||||
url(r'^sys/share-links/$', sysadmin_react_fake_view, name="sys_share_links"),
|
url(r'^sys/share-links/$', sysadmin_react_fake_view, name="sys_share_links"),
|
||||||
url(r'^sys/upload-links/$', sysadmin_react_fake_view, name="sys_upload_links"),
|
url(r'^sys/upload-links/$', sysadmin_react_fake_view, name="sys_upload_links"),
|
||||||
url(r'^sys/work-weixin/$', sysadmin_react_fake_view, name="sys_work_weixin"),
|
url(r'^sys/work-weixin/$', sysadmin_react_fake_view, name="sys_work_weixin"),
|
||||||
|
Reference in New Issue
Block a user