Skip to content

Commit 3237ab5

Browse files
author
vikasrohit
authored
Merge pull request #4304 from appirio-tech/dev
Prod Release - 2.17.2
2 parents 64409b1 + 00a717b commit 3237ab5

File tree

17 files changed

+448
-44
lines changed

17 files changed

+448
-44
lines changed

docs/permissions.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,14 +1100,13 @@ <h2 class="anchor-container">
11001100
<div class="row border-top">
11011101
<div class="col py-2">
11021102
<div class="permission-title anchor-container">
1103-
<a href="#VIEW_PROJECT_DEFAULTS" name="VIEW_PROJECT_DEFAULTS" class="anchor"></a>View Project Defaults Tab
1103+
<a href="#VIEW_PROJECT_SETTINGS" name="VIEW_PROJECT_SETTINGS" class="anchor"></a>View Project Settings Tab
11041104
</div>
1105-
<div class="permission-variable"><small><code>VIEW_PROJECT_DEFAULTS</code></small></div>
1105+
<div class="permission-variable"><small><code>VIEW_PROJECT_SETTINGS</code></small></div>
11061106
<div class="text-black-50 small-text"></div>
11071107
</div>
11081108
<div class="col-9 py-2">
11091109
<div>
1110-
<span class="badge badge-primary" title="Allowed Project Role">customer</span>
11111110
<span class="badge badge-primary" title="Allowed Project Role">copilot</span>
11121111
<span class="badge badge-primary" title="Allowed Project Role">manager</span>
11131112
<span class="badge badge-primary" title="Allowed Project Role">account_manager</span>

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
},
8585
"dependencies": {
8686
"@contentful/rich-text-react-renderer": "^13.4.0",
87+
"@toast-ui/editor": "^2.5.1",
8788
"appirio-tech-react-components": "git+https://github.com/appirio-tech/react-components.git#feature/connectv2",
8889
"axios": "^0.19.2",
8990
"brace": "^0.11.1",

src/api/billingAccounts.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { axiosInstance as axios } from './requestInterceptor'
2+
import { TC_API_URL } from '../config/constants'
3+
4+
/**
5+
* Get billing accounts based on project id
6+
*
7+
* @param {String} projectId Id of the project
8+
*
9+
* @returns {Promise<Object>} Billing accounts data
10+
*/
11+
export function fetchBillingAccounts(projectId) {
12+
return axios.get(`${TC_API_URL}/v5/projects/${projectId}/billingAccounts`)
13+
}
14+
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
@import '~tc-ui/src/styles/tc-includes';
2+
3+
.editor {
4+
background: red;
5+
6+
> div {
7+
h1 {
8+
all: revert;
9+
font-size: 24px;
10+
}
11+
}
12+
13+
b,
14+
i,
15+
s,
16+
hr,
17+
blockquote,
18+
ul,
19+
li,
20+
ol,
21+
table,
22+
thead,
23+
tr,
24+
th,
25+
img,
26+
a,
27+
code,
28+
pre {
29+
all: revert;
30+
}
31+
32+
:global {
33+
// add style for heading list in headings selection popup, because 'all:revert' has been setted before
34+
.te-heading-add ul {
35+
list-style: none;
36+
}
37+
38+
// hide uplodd file
39+
.tui-editor-popup{
40+
box-shadow: 0px 0px 15px 5px rgba(0,0,0,0.26);
41+
}
42+
43+
.te-popup-add-image .te-tab button, .te-popup-add-image .te-file-type{
44+
display: none !important;
45+
}
46+
47+
.te-popup-add-image .te-url-type{
48+
display: block !important;
49+
}
50+
51+
}
52+
}

src/components/TuiEditor/index.jsx

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* TuiEditor
3+
* wrap toast-ui editor with react and support react 15
4+
*/
5+
6+
import React from 'react'
7+
import PropTypes from 'prop-types'
8+
import Editor from '@toast-ui/editor'
9+
import styles from './TuiEditor.scss'
10+
import cn from 'classnames'
11+
import 'codemirror/lib/codemirror.css'
12+
import '@toast-ui/editor/dist/toastui-editor.css'
13+
14+
class TuiEditor extends React.Component {
15+
constructor(props) {
16+
super(props)
17+
this.handleValueChange = this.handleValueChange.bind(this)
18+
}
19+
20+
getRootElement() {
21+
return this.refs.rootEl
22+
}
23+
24+
getInstance() {
25+
return this.editorInst
26+
}
27+
28+
bindEventHandlers(props) {
29+
Object.keys(props)
30+
.filter(key => /^on[A-Z][a-zA-Z]+/.test(key))
31+
.forEach(key => {
32+
const eventName = key[2].toLowerCase() + key.slice(3)
33+
this.editorInst.off(eventName)
34+
this.editorInst.on(eventName, props[key])
35+
})
36+
}
37+
38+
componentDidMount() {
39+
const props = {
40+
...this.props,
41+
onChange: this.handleValueChange
42+
}
43+
this.editorInst = new Editor({
44+
el: this.refs.rootEl,
45+
...props
46+
})
47+
this.bindEventHandlers(props)
48+
}
49+
50+
handleValueChange(){
51+
if (this.props.onChange) {
52+
this.props.onChange(this.getInstance().getMarkdown())
53+
}
54+
}
55+
56+
shouldComponentUpdate(nextProps) {
57+
const instance = this.getInstance()
58+
const { height, previewStyle, className } = nextProps
59+
60+
if (this.props.height !== height) {
61+
instance.height(height)
62+
}
63+
64+
if (this.props.previewStyle !== previewStyle) {
65+
instance.changePreviewStyle(previewStyle)
66+
}
67+
68+
if (this.props.className !== className) {
69+
return true
70+
}
71+
// this.bindEventHandlers(nextProps, this.props)
72+
73+
return false
74+
}
75+
76+
render() {
77+
return <div ref="rootEl" className={cn(styles.editor, this.props.className)} />
78+
}
79+
}
80+
81+
82+
TuiEditor.defaultProps = {
83+
height: '300px',
84+
minHeight: '300px',
85+
initialValue: '',
86+
previewStyle: '',
87+
initialEditType: 'wysiwyg',
88+
language: 'en-US',
89+
useCommandShortcut: true,
90+
customHTMLSanitizer: null,
91+
frontMatter: false,
92+
hideModeSwitch: false,
93+
referenceDefinition:false,
94+
usageStatistics: false,
95+
useDefaultHTMLSanitizer: true
96+
}
97+
98+
TuiEditor.propTypes = {
99+
className: PropTypes.string,
100+
// Markdown editor's preview style (tab, vertical)
101+
previewStyle: PropTypes.string.isRequired,
102+
// Editor's height style value. Height is applied as border-box ex) '300px', '100%', 'auto'
103+
height: PropTypes.string,
104+
// Initial editor type (markdown, wysiwyg)
105+
initialEditType: PropTypes.string,
106+
// Editor's initial value
107+
initialValue: PropTypes.string,
108+
// Editor's min-height style value in pixel ex) '300px'
109+
minHeight: PropTypes.string,
110+
// The placeholder text of the editable element.
111+
placeholder: PropTypes.string,
112+
// hide mode switch tab bar
113+
hideModeSwitch: PropTypes.bool,
114+
// language, 'en-US'
115+
language: PropTypes.string,
116+
// whether use keyboard shortcuts to perform commands
117+
useCommandShortcut: PropTypes.bool,
118+
// It would be emitted when editor fully load1
119+
onLoad: PropTypes.func,
120+
// It would be emitted when content changed
121+
onChange: PropTypes.func,
122+
// It would be emitted when format change by cursor position
123+
onStateChange: PropTypes.func,
124+
// It would be emitted when editor get focus
125+
onFocus: PropTypes.func,
126+
// It would be emitted when editor loose focus
127+
onBlur: PropTypes.func,
128+
// hooks
129+
hooks: PropTypes.arrayOf(PropTypes.object),
130+
// send hostname to google analytics
131+
usageStatistics: PropTypes.bool,
132+
// use default htmlSanitizer
133+
useDefaultHTMLSanitizer: PropTypes.bool,
134+
// toolbar items.
135+
toolbarItems: PropTypes.arrayOf(PropTypes.object),
136+
// Array of plugins. A plugin can be either a function or an array in the form of [function, options].
137+
plugins: PropTypes.arrayOf(PropTypes.object),
138+
// Using extended Autolinks specified in GFM spec
139+
extendedAutolinks: PropTypes.object,
140+
// convertor extention
141+
customConvertor: PropTypes.object,
142+
// Attributes of anchor element that should be rel, target, contenteditable, hreflang, type
143+
linkAttribute: PropTypes.object,
144+
// Object containing custom renderer functions correspond to markdown node
145+
customHTMLRenderer: PropTypes.object,
146+
// whether use the specification of link reference definition
147+
referenceDefinition: PropTypes.bool,
148+
// custom HTML sanitizer
149+
customHTMLSanitizer: PropTypes.func,
150+
// whether use the front matter
151+
frontMatter: PropTypes.bool
152+
}
153+
154+
export default TuiEditor

src/config/permissions.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -678,13 +678,13 @@ export const PERMISSIONS = {
678678
],
679679
},
680680

681-
VIEW_PROJECT_DEFAULTS: {
681+
VIEW_PROJECT_SETTINGS: {
682682
meta: {
683683
group: 'Project Details',
684-
title: 'View Project Defaults Tab',
684+
title: 'View Project Settings Tab',
685685
},
686686
projectRoles: [
687-
..._.difference(PROJECT_ALL, PROJECT_ROLE_CUSTOMER)
687+
..._.difference(PROJECT_ALL, [PROJECT_ROLE_CUSTOMER])
688688
],
689689
topcoderRoles: [
690690
...TOPCODER_ADMINS,

src/helpers/projectHelper.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,8 @@ export function getProjectNavLinks(project, projectId, renderFAQs) {
282282
navLinks.push(faqTab)
283283
}
284284

285-
const searchParams = new URLSearchParams(window.location.search)
286-
287-
if (searchParams.get('beta') === 'true' && hasPermission(PERMISSIONS.VIEW_PROJECT_DEFAULTS)) {
288-
navLinks.push({ label: 'Project Defaults', to: `/projects/${projectId}/settings`, Icon: AccountSecurityIcon, iconClassName: 'stroke' })
285+
if (hasPermission(PERMISSIONS.VIEW_PROJECT_SETTINGS)) {
286+
navLinks.push({ label: 'Project Settings', to: `/projects/${projectId}/settings`, Icon: AccountSecurityIcon, iconClassName: 'stroke' })
289287
}
290288

291289
return navLinks

src/helpers/protectComponent.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react'
2+
import CoderBroken from '../assets/icons/coder-broken.svg'
3+
import {hasPermission} from './permissions'
4+
5+
function protectComponent(Component, permission, pageName) {
6+
class ProtectedComponent extends React.Component {
7+
render() {
8+
if (!hasPermission(permission)) {
9+
return (
10+
<section className="content content-error">
11+
<div className="container">
12+
<div className="page-error">
13+
<CoderBroken className="icon-coder-broken" />
14+
<span>You don't have permission to access {pageName || 'this page'}</span>
15+
</div>
16+
</div>
17+
</section>
18+
)
19+
}
20+
return <Component {...this.props} />
21+
}
22+
}
23+
24+
return ProtectedComponent
25+
}
26+
27+
export default protectComponent

0 commit comments

Comments
 (0)