@ant-design/icons#LinkOutlined JavaScript Examples
The following examples show how to use
@ant-design/icons#LinkOutlined.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Event.js From website with MIT License | 5 votes |
EventItem = ({
city = 'Em todo o estado',
status = 'F',
title,
description,
event,
hideAuthor = false
}) => {
const { author } = event;
const statusMessages = messages(status);
return (
<Timeline.Item
className={status}
dot={statusMessages.icon}
color={statusMessages.color}
>
<div className='city'>
{city}
{event?.region?.initial && ` - ${event?.region?.initial}`}
{author && !hideAuthor && author?.name && (
<Popover
content={
<div style={{ textAlign: 'center' }}>
Evento criado por {author?.name}. <br />
<a>Clique aqui</a> para fazer parte de nossa equipe de
colaboradores.
</div>
}
>
<span className='info'>
<NotificationOutlined />
<span>{author.name}</span>
</span>
</Popover>
)}
</div>
<div className='meta'>
<Popover content={<span style={{ textAlign: 'center' }}>{title}</span>}>
<span className='label'>{title} - </span>
</Popover>
<span className='status'>{statusMessages.message} - </span>
{(event.from_date !== null || event.to_date !== null) && (
<Popover
content={<span>Período de vigência do evento em questão.</span>}
>
<span className='info'>
<ClockCircleOutlined />
<span>
{event.undefined_ends_date && 'A partir de '}
{event.from_date && formatDate(event.from_date)}
{event.to_date && ` - ${formatDate(event.to_date)}`}
</span>
</span>
</Popover>
)}
{event?.source?.source && (
<span className='info'>
<LinkOutlined />
<span>Fonte: {event.source.source}</span>
</span>
)}
</div>
<Text>{description}</Text>
{event.source?.link && (
<a href={event.source.link} target='__blank' alt={event.source.source}>
Ver mais
</a>
)}
</Timeline.Item>
);
}
Example #2
Source File: switch-mode.jsx From virtuoso-design-system with MIT License | 5 votes |
Demo = () => {
const [mode, setMode] = React.useState('inline');
const [theme, setTheme] = React.useState('light');
const changeMode = value => {
setMode(value ? 'vertical' : 'inline');
};
const changeTheme = value => {
setTheme(value ? 'dark' : 'light');
};
return (
<>
<Switch onChange={changeMode} /> Change Mode
<Divider type="vertical" />
<Switch onChange={changeTheme} /> Change Style
<br />
<br />
<Menu
style={{ width: 256 }}
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
mode={mode}
theme={theme}
>
<Menu.Item key="1" icon={<MailOutlined />}>
Navigation One
</Menu.Item>
<Menu.Item key="2" icon={<CalendarOutlined />}>
Navigation Two
</Menu.Item>
<SubMenu key="sub1" icon={<AppstoreOutlined />} title="Navigation Two">
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
<SubMenu key="sub1-2" title="Submenu">
<Menu.Item key="5">Option 5</Menu.Item>
<Menu.Item key="6">Option 6</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub2" icon={<SettingOutlined />} title="Navigation Three">
<Menu.Item key="7">Option 7</Menu.Item>
<Menu.Item key="8">Option 8</Menu.Item>
<Menu.Item key="9">Option 9</Menu.Item>
<Menu.Item key="10">Option 10</Menu.Item>
</SubMenu>
<Menu.Item key="link" icon={<LinkOutlined />}>
<a href="https://ant.design" target="_blank" rel="noopener noreferrer">
Ant Design
</a>
</Menu.Item>
</Menu>
</>
);
}
Example #3
Source File: challengesTagSort.js From ctf_platform with MIT License | 4 votes |
render() {
return (
<Layout className="pageTransition" style={{ height: "100%", width: "100%", backgroundColor: "rgba(0, 0, 0, 0)" }}>
<Modal
title="Hint"
visible={this.state.hintModal}
onCancel={() => { this.setState({ hintModal: false }) }}
footer={null}
>
<p>{this.state.hintContent}</p>
</Modal>
<Modal
title={null}
visible={this.state.challengeModal}
footer={null}
bodyStyle={{ textAlign: "center" }}
onCancel={() => { this.setState({ challengeModal: false }); this.props.history.push("/Challenges/" + this.props.category); }}
>
<Tabs defaultActiveKey="challenge">
<TabPane
tab={<span><ProfileOutlined /> Challenge</span>}
key="challenge"
>
{this.state.challengeWriteup !== "" && this.state.challengeWriteup !== "CompleteFirst" && (
<Tooltip title="View writeups for this challenge">
<Button shape="circle" size="large" style={{ position: "absolute", right: "2ch" }} type="primary" icon={<SolutionOutlined />} onClick={() => { window.open(this.state.challengeWriteup) }} />
</Tooltip>
)}
{this.state.challengeWriteup === "" && (
<Tooltip title="Writeups are not available for this challenge">
<Button disabled shape="circle" size="large" style={{ position: "absolute", right: "2ch" }} type="primary" icon={<SolutionOutlined />} />
</Tooltip>
)}
{this.state.challengeWriteup === "CompleteFirst" && (
<Tooltip title="Writeups are available for this challenge but you must complete the challenge first to view it.">
<Button shape="circle" size="large" style={{ position: "absolute", right: "2ch", color: "#13a8a8" }} icon={<SolutionOutlined />} />
</Tooltip>
)}
<Suspense fallback={<div style={{ height: "100%", width: "100%", display: "flex", justifyContent: "center", alignItems: "center", zIndex: 15 }}>
<Ellipsis color="#177ddc" size={120} ></Ellipsis>
</div>}>
<div style={{ display: "flex", justifyContent: "center" }}>
<h1 style={{ fontSize: "150%", maxWidth: "35ch", whiteSpace: "initial" }}>{this.state.viewingChallengeDetails.name}
<Tooltip title="Copy challenge link to clipboard.">
<LinkOutlined style={{ color: "#1890ff", marginLeft: "0.5ch" }} onClick={
async () => {
await navigator.clipboard.writeText(window.location.href);
message.success("Challenge link copied to clipboard.")
}} /></Tooltip>
</h1>
</div>
<div>
{this.state.challengeTags}
</div>
<h2 style={{ color: "#1765ad", marginTop: "2vh", marginBottom: "6vh", fontSize: "200%" }}>{this.state.viewingChallengeDetails.points}</h2>
<div className="challengeModal">
<MarkdownRender >{this.state.viewingChallengeDetails.description}</MarkdownRender>
</div>
<div style={{ marginTop: "6vh", display: "flex", flexDirection: "column" }}>
{this.state.challengeHints}
</div>
</Suspense>
<div style={{ display: "flex" }}>
<SubmitFlagForm submitFlag={this.submitFlag.bind(this)} currentChallengeStatus={this.state.currentChallengeStatus} currentChallengeSolved={this.state.currentChallengeSolved}></SubmitFlagForm>
</div>
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", marginTop: "-1vh" }}>
<p>Challenge Author: <em>{this.state.viewingChallengeDetails.author}</em></p>
<p style={{ color: "#d87a16", fontWeight: 500 }}>Attempts Remaining: {this.state.viewingChallengeDetails.max_attempts}</p>
</div>
</TabPane>
<TabPane
tab={<span><UnlockOutlined /> Solves ({this.state.viewingChallengeDetails.solves.length}) </span>}
key="solves"
>
<List
itemLayout="horizontal"
dataSource={this.state.viewingChallengeDetails.solves}
locale={{
emptyText: (
<div>
<SmileOutlined style={{ fontSize: "500%" }} />
<br />
<br />
<p style={{ fontSize: "150%" }}>No solves yet. Maybe you can be the first!</p>
</div>
)
}}
renderItem={item => {
return (
<List.Item key={item}>
<List.Item.Meta
avatar={<Avatar src={"/static/profile/" + item + ".webp"} />}
title={<Link to={"/Profile/" + item}><a style={{ fontSize: "110%", fontWeight: 700 }} onClick={() => { this.setState({ challengeModal: false }) }}>{item}</a></Link>}
/>
</List.Item>
)
}
} />
</TabPane>
</Tabs>
</Modal>
<Divider style={{ marginTop: "0px" }}>Select Tags</Divider>
<span className="tag-holder" >
{Object.keys(this.state.tag).map((tag) => {
return (
<CheckableTag className="tag-select-style" key={tag} checked={this.state.selectedTags.indexOf(tag) !== -1}
onChange={(checked) => {
let selectedTags = this.state.selectedTags
if (!checked) selectedTags.splice(selectedTags.indexOf(tag), 1)
else selectedTags.push(tag)
if (selectedTags.length === 0) this.sortCats(this.state.sortType, true)
this.setState({ selectedTags: selectedTags })
}}>{tag} <span style={{ color: "#d89614" }}>({this.state.tag[tag].length})</span></CheckableTag>
)
})}
</span>
<Divider />
{this.state.tag && this.state.selectedTags.length > 0 ? (
<ChallengesTagSortList tag={this.state.tag} selectedTags={this.state.selectedTags} permissions={this.props.permissions} loadChallengeDetails={this.loadChallengeDetails.bind(this)} loadingChallenge={this.state.loadingChallenge} currentChallenge={this.state.currentChallenge} />
) : (
<List
grid={{
xs: 1,
sm: 2,
md: 2,
lg: 3,
xl: 4,
xxl: 5,
gutter: 20
}}
dataSource={this.state.challenges}
locale={{
emptyText: (
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", marginTop: "10vh" }}>
<FileUnknownTwoTone style={{ color: "#177ddc", fontSize: "400%", zIndex: 1 }} />
<h1 style={{ fontSize: "200%" }}>No challenges have been released yet</h1>
</div>
)
}}
renderItem={item => {
if (item.solves.length === 0) item.firstBlood = "No First Blood Yet!"
else {
if (this.props.disableNonCatFB) {
item.firstBlood = "No First blood Yet"
for (let i = 0; i < item.solves.length; i++) {
if (this.props.userCategories[item.solves[i]] !== "none") {
item.firstBlood = item.solves[i]
break
}
}
}
else item.firstBlood = item.solves[0]
}
if (item.requires && !item.requiresSolved && this.props.permissions < 2) {
return (
<List.Item key={item._id}>
<Tooltip title={<span>Please solve "<b><u>{item.requiresName}</u></b>" to unlock this challenge.</span>}>
<div id={item._id}>
<Card
type="inner"
bordered={true}
className="card-design"
>
<Meta
description={
<div className="card-design-body" >
<LockOutlined className="disabled-style" />
<h1 className="card-design-name" >{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.state.loadingChallenge && this.state.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</Tooltip>
</List.Item>
)
}
else if (!item.solved) {
return (
<List.Item key={item._id}>
<div id={item._id} onClick={() => { this.loadChallengeDetails(item._id, item.solved, item.firstBlood) }}>
<Card
hoverable
type="inner"
bordered={true}
className="card-design hover"
>
<Meta
description={
<div className="card-design-body">
<h1 className="card-design-name">{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.state.loadingChallenge && this.state.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</List.Item>
)
}
else {
return (
<List.Item key={item._id}>
<div id={item._id} onClick={() => { this.loadChallengeDetails(item._id, item.solved) }}>
<Card
hoverable
type="inner"
bordered={true}
className="card-design solved hover"
>
<Meta
description={
<div className="card-design-body">
<CheckOutlined className="correct-style" />
<h1 className="card-design-name">{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.state.loadingChallenge && this.state.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</List.Item>
)
}
}
}
/>)}
</Layout>
);
}
Example #4
Source File: Teams.js From ctf_platform with MIT License | 4 votes |
render() {
return (
<Layout className="layout-style">
<Modal
title={<span>Create New Team <UsergroupAddOutlined /></span>}
visible={this.state.createTeamModal}
footer={null}
onCancel={() => { this.setState({ createTeamModal: false }) }}
>
<CreateTeamForm setState={this.setState.bind(this)} obtainScore={this.props.obtainScore.bind(this)} loadTeamDetails={this.loadTeamDetails.bind(this)} setTeam={this.props.setTeam.bind(this)} />
</Modal>
{this.state.loading ? (
<div style={{ position: "absolute", left: "55%", transform: "translate(-55%, 0%)", zIndex: 10 }}>
<Ellipsis color="#177ddc" size={120} ></Ellipsis>
</div>
) : (
<div>
{this.props.team === "teams-disabled" ? (
<div style={{ display: "flex", placeContent: "center center", textAlign: "center", fontSize: "130%", width: "100%", height: "100%" }}>
<div>
<TeamOutlined style={{ fontSize: "600%", color: "#177ddc" }} />
<div>
<h1>It seem's like teams are disabled.</h1>
<p>If you believe this is an error, please contact the admins.</p>
</div>
</div>
</div>
) : (
<div>
{this.state.notFound ? (
<div style={{ display: "flex", placeContent: "center center", textAlign: "center", fontSize: "130%", width: "100%", height: "100%" }}>
<div>
<TeamOutlined style={{ fontSize: "600%", color: "#177ddc" }} />
<div>
<h1>We were unable to find this team.</h1>
</div>
</div>
</div>
) : (
<div>
{this.state.teamName ?
(
<Layout style={{ height: "100%", width: "100%", padding: "3%", backgroundColor: "rgba(0, 0, 0, 0)" }}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "2ch" }}>
<div style={{ display: "flex" }}>
<div style={{ display: "flex", marginRight: "5ch", alignItems: "center", justifyItems: "center" }}>
<Avatar.Group
maxCount={3}
>
{this.state.members.map((member) => {
return (
<Avatar style={{ backgroundColor: "transparent", marginRight: "3ch", width: "10ch", height: "10ch" }} size='large' src={"/static/profile/" + member + ".webp"} />
)
})}
</ Avatar.Group>
<h1 style={{ fontSize: "5ch" }}>{this.state.teamName}</h1>
</div>
<div>
<h1 style={{ fontSize: "5ch", color: "#faad14" }}><span style={{ color: "#d48806", fontSize: "1.5ch" }}><u>Team Score:</u> </span>{this.state.teamScore}</h1>
</div>
</div>
</div>
{this.state.teamName === this.props.team && (
<div style={{ backgroundColor: "rgba(0, 0, 0, 0.3)", border: "5px solid transparent", borderRadius: "20px", width: "fit-content", padding: "20px" }}>
<h4 style={{ fontSize: "2ch", color: "#49aa19" }}>You are part of this team</h4>
<div style={{ marginTop: "2ch" }}>
<div style={{ display: "flex", marginBottom: "2ch" }}>
<Input value={window.location.origin + "/Team/Join/" + this.state.code} />
<Button type="primary" style={{ marginLeft: "1ch" }} icon={<LinkOutlined />} onClick={async () => {
await navigator.clipboard.writeText(window.location.origin + "/Team/Join/" + this.state.code);
message.success("Invite link copied to clipboard.")
}}>Copy Invite Link</Button>
</div>
<Button style={{ marginRight: "1ch" }} danger type="primary" onClick={() => {
confirm({
title: "Leave Team?",
content: <span>Are you sure you want to leave: <b><u>{this.state.teamName}</u></b>?</span>,
icon: <WarningOutlined />,
maskClosable: true,
okText: "Leave Team",
confirmLoading: this.state.joinLoading,
onOk: (close) => { this.leaveTeam(close) },
onCancel: () => { },
});
}}>Leave Team</Button>
</div>
</div>
)}
<Divider />
<h1 style={{ fontSize: "3ch" }}>Individual Member's Scoring</h1>
<Table style={{ marginTop: "2vh" }} dataSource={this.state.userScores} pagination={{ pageSize: 10 }} locale={{
emptyText: (
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", marginTop: "10vh" }}>
<FileUnknownTwoTone style={{ color: "#177ddc", fontSize: "400%", zIndex: 1 }} />
<h1 style={{ fontSize: "200%" }}>{this.state.teamName} has not completed any challenges/bought any hints</h1>
</div>
)
}}>
<Column width={30} title="Username" dataIndex="username" key="username"
render={(text, row, index) => {
return <Link to={"/Profile/" + text}><a style={{ fontWeight: 700 }}>{text}</a></Link>;
}}
/>
<Column width={30} title="Total Score" dataIndex="score" key="score" />
</Table>
<Divider />
<h1 style={{ fontSize: "3ch" }}>Team Score History</h1>
<div style={{ height: 375, width: "100%", backgroundColor: "rgba(0, 0, 0, 0.3)", border: "5px solid transparent", borderRadius: "20px", padding: "10px", margin: "10px" }}>
<ResponsiveContainer width="90%" height={350}>
<AreaChart height={350} data={this.state.graphData}
margin={{ top: 10, right: 15, left: 15, bottom: 15 }}>
<defs>
<linearGradient id="color1" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#791a1f" stopOpacity={0.3} />
<stop offset="95%" stopColor="#f89f9a" stopOpacity={0.1} />
</linearGradient>
</defs>
<XAxis dataKey="Time">
<Label offset={-5} position="insideBottom" style={{ fill: 'rgba(207, 207, 207, 1)' }}>
Time
</Label>
</XAxis>
<YAxis >
<Label offset={-10} position='insideLeft' style={{ fill: 'rgba(207, 207, 207, 1)' }}>
Score
</Label>
</YAxis>
<CartesianGrid strokeDasharray="3 3" />
<Tooltip labelStyle={{ backgroundColor: "#1c2b3e" }} contentStyle={{ backgroundColor: "#1c2b3e" }} wrapperStyle={{ backgroundColor: "#1c2b3e" }} />
<Area isAnimationActive={false} type="monotone" dataKey="Score" stroke="#d32029" fillOpacity={1} fill="url(#color1)" />
</AreaChart>
</ResponsiveContainer>
</div>
<Table style={{ marginTop: "2vh" }} dataSource={this.state.scores} pagination={{ pageSize: 10 }} locale={{
emptyText: (
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", marginTop: "10vh" }}>
<FileUnknownTwoTone style={{ color: "#177ddc", fontSize: "400%", zIndex: 1 }} />
<h1 style={{ fontSize: "200%" }}>{this.state.teamName} has not completed any challenges/bought any hints</h1>
</div>
)
}}>
<Column width={30} title="Username" dataIndex="username" key="username"
render={(text, row, index) => {
return <Link to={"/Profile/" + text}><a style={{ fontWeight: 700 }}>{text}</a></Link>;
}}
/>
<Column width={1} title="Challenge/Hint" dataIndex="challenge" key="challenge"
render={(text, row, index) => {
if (row.challengeID !== "") return <Link to={"/Challenges/" + row.challengeID}><a style={{ fontWeight: 700 }}>{text}</a></Link>;
else return (<span>{text}</span>);
}} />
<Column width={30} title="Score Change" dataIndex="score" key="score" />
<Column width={30} title="Solved Timestamp" dataIndex="time" key="time" />
</Table>
</Layout>
) :
(
<div style={{ display: "flex", placeContent: "center center", textAlign: "center", fontSize: "130%", width: "100%", height: "100%" }}>
<div>
<TeamOutlined style={{ fontSize: "600%", color: "#177ddc" }} />
<div>
<h1>The world's a dangerous place</h1> <h2>Don't go alone, join/create a team today!</h2>
</div>
<Button icon={<UsergroupAddOutlined />} type="primary" size="large" onClick={() => { this.setState({ createTeamModal: true }) }}>Create a Team</Button>
<div style={{ marginTop: "3ch" }}>
<span>Got an <b>invite link <LinkOutlined />?</b></span>
<div>
<Button style={{ marginTop: "1ch" }} size="large" type="primary" icon={<LinkOutlined />} onClick={() => {
navigator.clipboard.readText().then(text => {
if (!(/^.*\/Team\/Join\/[0-9a-fA-F]{32}$/.test(text))) message.error("Invalid link. Please check that you have copied the link correctly.", 3)
else {
const code = text.split("/Team/Join/")
this.getCodeDetails(code[1])
}
}).catch(err => {
console.log(err)
message.error("Failed to read link from your clipboard.", 5)
message.info("Please ensure that you have allowed permissions for reading of clipboard text.", 5)
})
}}>Paste & Use Link</Button>
</div>
</div>
</div>
</div>
)
}
</div>
)}
</div>
)}
</div>
)}
</Layout>
)
}
Example #5
Source File: index.jsx From juno with Apache License 2.0 | 4 votes |
render() {
const {
app_service_tree,
use_cases,
editor,
selected_user_case,
node_addr_list,
selected_service,
right_menu_visible,
right_menu_position,
right_menu,
dispatch,
response,
active_tab,
selected_history_id,
public_cases,
settings,
setting_dialog_visible,
service_bind_dialog_visible,
proto_list,
appList,
use_case_loading,
} = this.props;
let addrOptions = node_addr_list?.hosts
? node_addr_list.hosts
.filter((i) => i.env !== 'prod' && i.env !== 'gray')
.map((item) => {
return (
<AutoComplete.Option key={item.addr} value={item.addr + ':' + node_addr_list.port}>
<Tag>{item.env}</Tag>
<span>
{item.addr}:{node_addr_list.port}
</span>
</AutoComplete.Option>
);
})
: [];
if (settings && settings.localhost) {
addrOptions.push(
<AutoComplete.Option
key={settings.localhost}
value={settings.localhost + ':' + node_addr_list.port}
>
<Tag>local</Tag>
<span>
{settings.localhost}:{node_addr_list.port}
</span>
</AutoComplete.Option>,
);
}
let metadata = editor.form.metadata || [];
if (!(metadata instanceof Array)) {
try {
metadata = JSON.parse(metadata);
} catch (e) {
metadata = [];
}
}
return (
<div className={styles.debugPage}>
<div className={styles.layoutHeader}>
<Cascader
showSearch
value={selected_service}
className={styles.serviceCascader}
displayRender={(labels) => {
return labels.join('/');
}}
placeholder="切换服务"
options={(app_service_tree || []).map((app) => {
return {
label: app.app_name,
value: app.app_name,
children: (app.services || []).map((service) => {
return {
value: '' + service.id,
label: service.name,
};
}),
};
})}
onChange={this.onChangeService}
/>
<Button
shape="circle"
icon={<SettingOutlined />}
className={styles.settingButton}
onClick={this.onShowSettingDialog}
/>
<Button
shape="circle"
icon={<LinkOutlined />}
className={styles.bindServiceButton}
onClick={this.onShowServiceBindDialog}
/>
</div>
<div className={styles.main}>
<div className={styles.layoutSider}>
<Tabs
type={'card'}
className={styles.leftTabs}
activeKey={active_tab}
onChange={this.onTabChange}
renderTabBar={(props, DefaultTabBar) => {
return (
<DefaultTabBar
{...props}
style={{
backgroundColor: 'rgb(250,250,250)',
padding: '10px 0 0 10px',
margin: '0',
flex: '0 0 50px',
}}
/>
);
}}
>
<Tabs.TabPane key="history" tab="History">
{active_tab === 'history' ? (
<History
selectedService={selected_service}
onChange={(id) => {
dispatch({ type: 'grpcDebugModel/loadHistoryItem', payload: id }).then(
(res) => {
if (res.code === 0) {
this.form.current.setFieldsValue({
case_name: editor.form.case_name,
address: res.data.addr,
});
}
},
);
}}
activeId={selected_history_id}
/>
) : null}
</Tabs.TabPane>
<Tabs.TabPane key="api" tab="API">
<ScrollArea style={{ height: '830px' }}>
<DirectoryTree
onRightClick={this.onUserCaseTreeRightClicked}
defaultExpandAll
onSelect={this.onSelectUserCaseTree}
selectedKeys={[selected_user_case]}
style={{ marginTop: '10px' }}
>
{(use_cases || []).map((method, id) => {
return (
<TreeNode
title={
method.description ? (
<Popover content={method.description}>{method.name}</Popover>
) : (
method.name
)
}
key={`method:${method.id}`}
>
<TreeNode
icon={<PlusOutlined />}
key={`new:${method.id}`}
title="New"
isLeaf
/>
{method.use_cases
? method.use_cases.map((tc, id) => {
return <TreeNode title={tc.name} key={`case:${tc.id}`} isLeaf />;
})
: null}
</TreeNode>
);
})}
</DirectoryTree>
</ScrollArea>
</Tabs.TabPane>
</Tabs>
</div>
{editor.form.method_id ? (
<Spin spinning={use_case_loading} wrapperClassName={styles.formSpin}>
{this.renderForm(editor, addrOptions, metadata, response)}
</Spin>
) : (
<div style={{ flex: '1 1 auto', padding: '100px' }}>
<Empty desciption={'请选择用例'} />
</div>
)}
</div>
<SettingDialog
onCancel={() => {
dispatch({
type: 'grpcDebugModel/showSettings',
payload: false,
});
}}
settings={settings}
onSave={this.onSaveSettings}
visible={setting_dialog_visible}
/>
<ServiceBindDialog
visible={service_bind_dialog_visible}
protoList={proto_list}
appList={appList}
onSubmit={this.onBindAppService}
onCancel={() => {
dispatch({
type: 'grpcDebugModel/showServiceBindDialog',
payload: false,
});
}}
/>
</div>
);
}
Example #6
Source File: App.js From next-terminal with GNU Affero General Public License v3.0 | 4 votes |
render() {
const menu = (
<Menu>
<Menu.Item>
<Link to={'/info'}>
<SolutionOutlined/> 个人中心
</Link>
</Menu.Item>
<Menu.Divider/>
<Menu.Item>
<Popconfirm
key='login-btn-pop'
title="您确定要退出登录吗?"
onConfirm={this.confirm}
okText="确定"
cancelText="取消"
placement="left"
>
<LogoutOutlined/> 退出登录
</Popconfirm>
</Menu.Item>
</Menu>
);
return (
<Switch>
<Route path="/access" component={Access}/>
<Route path="/term" component={Term}/>
<Route path="/login"><Login updateUser={this.updateUser}/></Route>
<Route path="/">
<Layout className="layout" style={{minHeight: '100vh'}}>
{
isAdmin() ?
<>
<Sider collapsible collapsed={this.state.collapsed} trigger={null}>
<div className="logo">
<img src={this.state.logo} alt='logo' width={this.state.logoWidth}/>
</div>
<Menu
onClick={(e) => this.setCurrent(e.key)}
selectedKeys={[this.state.current]}
onOpenChange={this.subMenuChange}
defaultOpenKeys={this.state.openKeys}
theme="dark" mode="inline" defaultSelectedKeys={['dashboard']}
inlineCollapsed={this.state.collapsed}
style={{lineHeight: '64px'}}>
<Menu.Item key="dashboard" icon={<DashboardOutlined/>}>
<Link to={'/'}>
控制面板
</Link>
</Menu.Item>
<SubMenu key='resource' title='资源管理' icon={<CloudServerOutlined/>}>
<Menu.Item key="asset" icon={<DesktopOutlined/>}>
<Link to={'/asset'}>
资产列表
</Link>
</Menu.Item>
<Menu.Item key="credential" icon={<IdcardOutlined/>}>
<Link to={'/credential'}>
授权凭证
</Link>
</Menu.Item>
<Menu.Item key="dynamic-command" icon={<CodeOutlined/>}>
<Link to={'/dynamic-command'}>
动态指令
</Link>
</Menu.Item>
<Menu.Item key="access-gateway" icon={<ApiOutlined/>}>
<Link to={'/access-gateway'}>
接入网关
</Link>
</Menu.Item>
</SubMenu>
<SubMenu key='audit' title='会话审计' icon={<AuditOutlined/>}>
<Menu.Item key="online-session" icon={<LinkOutlined/>}>
<Link to={'/online-session'}>
在线会话
</Link>
</Menu.Item>
<Menu.Item key="offline-session" icon={<DisconnectOutlined/>}>
<Link to={'/offline-session'}>
历史会话
</Link>
</Menu.Item>
</SubMenu>
<SubMenu key='ops' title='系统运维' icon={<ControlOutlined/>}>
<Menu.Item key="login-log" icon={<LoginOutlined/>}>
<Link to={'/login-log'}>
登录日志
</Link>
</Menu.Item>
<Menu.Item key="job" icon={<BlockOutlined/>}>
<Link to={'/job'}>
计划任务
</Link>
</Menu.Item>
<Menu.Item key="access-security" icon={<SafetyCertificateOutlined/>}>
<Link to={'/access-security'}>
访问安全
</Link>
</Menu.Item>
<Menu.Item key="storage" icon={<HddOutlined/>}>
<Link to={'/storage'}>
磁盘空间
</Link>
</Menu.Item>
</SubMenu>
<SubMenu key='user-manage' title='用户管理' icon={<UserSwitchOutlined/>}>
<Menu.Item key="user" icon={<UserOutlined/>}>
<Link to={'/user'}>
用户管理
</Link>
</Menu.Item>
<Menu.Item key="user-group" icon={<TeamOutlined/>}>
<Link to={'/user-group'}>
用户组管理
</Link>
</Menu.Item>
<Menu.Item key="strategy" icon={<InsuranceOutlined/>}>
<Link to={'/strategy'}>
授权策略
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="my-file" icon={<FolderOutlined/>}>
<Link to={'/my-file'}>
我的文件
</Link>
</Menu.Item>
<Menu.Item key="info" icon={<SolutionOutlined/>}>
<Link to={'/info'}>
个人中心
</Link>
</Menu.Item>
<Menu.Item key="setting" icon={<SettingOutlined/>}>
<Link to={'/setting'}>
系统设置
</Link>
</Menu.Item>
</Menu>
</Sider>
<Layout className="site-layout">
<Header className="site-layout-background"
style={{padding: 0, height: headerHeight, zIndex: 20}}>
<div className='layout-header'>
<div className='layout-header-left'>
{React.createElement(this.state.collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
className: 'trigger',
onClick: this.onCollapse,
})}
</div>
<div className='layout-header-right'>
<div className={'layout-header-right-item'}>
<a style={{color: 'black'}} target='_blank'
href='https://github.com/dushixiang/next-terminal'
rel='noreferrer noopener'>
<GithubOutlined/>
</a>
</div>
</div>
<div className='layout-header-right'>
<Dropdown overlay={menu}>
<div className='nickname layout-header-right-item'>
{getCurrentUser()['nickname']} <DownOutlined/>
</div>
</Dropdown>
</div>
</div>
</Header>
<Route path="/" exact component={Dashboard}/>
<Route path="/user" component={User}/>
<Route path="/user-group" component={UserGroup}/>
<Route path="/asset" component={Asset}/>
<Route path="/credential" component={Credential}/>
<Route path="/dynamic-command" component={DynamicCommand}/>
<Route path="/batch-command" component={BatchCommand}/>
<Route path="/online-session" component={OnlineSession}/>
<Route path="/offline-session" component={OfflineSession}/>
<Route path="/login-log" component={LoginLog}/>
<Route path="/info" component={Info}/>
<Route path="/setting" component={Setting}/>
<Route path="/job" component={Job}/>
<Route path="/access-security" component={Security}/>
<Route path="/access-gateway" component={AccessGateway}/>
<Route path="/my-file" component={MyFile}/>
<Route path="/storage" component={Storage}/>
<Route path="/strategy" component={Strategy}/>
<Footer style={{textAlign: 'center'}}>
Copyright © 2020-2022 dushixiang, All Rights Reserved.
Version:{this.state.package['version']}
</Footer>
</Layout>
</> :
<>
<Header style={{padding: 0}}>
<div className='km-header'>
<div style={{flex: '1 1 0%'}}>
<Link to={'/'}>
<img src={this.state.logo} alt='logo' width={120}/>
</Link>
<Link to={'/my-file'}>
<Button type="text" style={{color: 'white'}}
icon={<FolderOutlined/>}>
文件
</Button>
</Link>
<Link to={'/dynamic-command'}>
<Button type="text" style={{color: 'white'}}
icon={<CodeOutlined/>}>
指令
</Button>
</Link>
</div>
<div className='km-header-right'>
<Dropdown overlay={menu}>
<span className={'km-header-right-item'}>
{getCurrentUser()['nickname']}
</span>
</Dropdown>
</div>
</div>
</Header>
<Content className='km-container'>
<Layout>
<Route path="/" exact component={MyAsset}/>
<Content className={'kd-content'}>
<Route path="/info" component={Info}/>
<Route path="/my-file" component={MyFile}/>
<Route path="/dynamic-command" component={DynamicCommand}/>
</Content>
</Layout>
</Content>
<Footer style={{textAlign: 'center'}}>
Copyright © 2020-2022 dushixiang, All Rights Reserved.
Version:{this.state.package['version']}
</Footer>
</>
}
</Layout>
</Route>
</Switch>
);
}
Example #7
Source File: Dashboard.js From next-terminal with GNU Affero General Public License v3.0 | 4 votes |
render() {
const data = [
{
type: 'RDP',
value: this.state.asset['rdp'],
},
{
type: 'SSH',
value: this.state.asset['ssh'],
},
{
type: 'TELNET',
value: this.state.asset['telnet'],
},
{
type: 'VNC',
value: this.state.asset['vnc'],
},
{
type: 'Kubernetes',
value: this.state.asset['kubernetes'],
}
];
const config = {
appendPadding: 10,
data: data,
angleField: 'value',
colorField: 'type',
radius: 1,
innerRadius: 0.6,
label: {
type: 'inner',
offset: '-50%',
content: '{value}',
style: {
textAlign: 'center',
fontSize: 14,
},
},
interactions: [{type: 'element-selected'}, {type: 'element-active'}],
statistic: {
title: false,
content: {
formatter: () => {
return '资产类型';
},
},
},
};
let accessData = this.state.access.map(item=>{
return {
title: `${item['username']}@${item['ip']}:${item['port']}`,
// title: `${item['assetId']}`,
value: item['accessCount'],
protocol: item['protocol']
}
});
const accessConfig = {
data: accessData,
xField: 'value',
yField: 'title',
seriesField: 'protocol',
legend: { position: 'top-left' },
}
return (
<>
<div style={{margin: 16, marginBottom: 0}}>
<Row gutter={16}>
<Col span={6}>
<Card bordered={true} hoverable>
<Link to={'/user'}>
<Statistic title="在线用户" value={this.state.counter['user']}
prefix={<UserOutlined/>}/>
</Link>
</Card>
</Col>
<Col span={6}>
<Card bordered={true} hoverable>
<Link to={'/asset'}>
<Statistic title="资产数量" value={this.state.counter['asset']}
prefix={<DesktopOutlined/>}/>
</Link>
</Card>
</Col>
<Col span={6}>
<Card bordered={true} hoverable>
<Link to={'/credential'} hoverable>
<Statistic title="授权凭证" value={this.state.counter['credential']}
prefix={<IdcardOutlined/>}/>
</Link>
</Card>
</Col>
<Col span={6}>
<Card bordered={true} hoverable>
<Link to={'/online-session'}>
<Statistic title="在线会话" value={this.state.counter['onlineSession']}
prefix={<LinkOutlined/>}/>
</Link>
</Card>
</Col>
</Row>
</div>
<div className="page-card">
<Row gutter={16}>
<Col span={12}>
<Card bordered={true} title="资产类型">
<Pie {...config} />
</Card>
</Col>
<Col span={12}>
<Card bordered={true} title="使用次数Top10 资产">
<Bar {...accessConfig} />
</Card>
</Col>
</Row>
</div>
</>
);
}
Example #8
Source File: FileSystem.js From next-terminal with GNU Affero General Public License v3.0 | 4 votes |
render() {
const columns = [
{
title: '名称',
dataIndex: 'name',
key: 'name',
render: (value, item) => {
let icon;
if (item['isDir']) {
icon = <FolderTwoTone/>;
} else {
if (item['isLink']) {
icon = <LinkOutlined/>;
} else {
const fileExtension = item['name'].split('.').pop().toLowerCase();
switch (fileExtension) {
case "doc":
case "docx":
icon = <FileWordOutlined/>;
break;
case "xls":
case "xlsx":
icon = <FileExcelOutlined/>;
break;
case "bmp":
case "jpg":
case "jpeg":
case "png":
case "tif":
case "gif":
case "pcx":
case "tga":
case "exif":
case "svg":
case "psd":
case "ai":
case "webp":
icon = <FileImageOutlined/>;
break;
case "md":
icon = <FileMarkdownOutlined/>;
break;
case "pdf":
icon = <FilePdfOutlined/>;
break;
case "txt":
icon = <FileTextOutlined/>;
break;
case "zip":
case "gz":
case "tar":
case "tgz":
icon = <FileZipOutlined/>;
break;
default:
icon = <FileOutlined/>;
break;
}
}
}
return <span className={'dode'}>{icon} {item['name']}</span>;
},
sorter: (a, b) => {
if (a['key'] === '..') {
return 0;
}
if (b['key'] === '..') {
return 0;
}
return a.name.localeCompare(b.name);
},
sortDirections: ['descend', 'ascend'],
},
{
title: '大小',
dataIndex: 'size',
key: 'size',
render: (value, item) => {
if (!item['isDir'] && !item['isLink']) {
return <span className={'dode'}>{renderSize(value)}</span>;
}
return <span className={'dode'}/>;
},
sorter: (a, b) => {
if (a['key'] === '..') {
return 0;
}
if (b['key'] === '..') {
return 0;
}
return a.size - b.size;
},
}, {
title: '修改日期',
dataIndex: 'modTime',
key: 'modTime',
sorter: (a, b) => {
if (a['key'] === '..') {
return 0;
}
if (b['key'] === '..') {
return 0;
}
return a.modTime.localeCompare(b.modTime);
},
sortDirections: ['descend', 'ascend'],
render: (value, item) => {
return <span className={'dode'}>{value}</span>;
},
}, {
title: '属性',
dataIndex: 'mode',
key: 'mode',
render: (value, item) => {
return <span className={'dode'}>{value}</span>;
},
}, {
title: '操作',
dataIndex: 'action',
key: 'action',
width: 210,
render: (value, item) => {
if (item['key'] === '..') {
return undefined;
}
let disableDownload = !this.state.download;
let disableEdit = !this.state.edit;
if (item['isDir'] || item['isLink']) {
disableDownload = true;
disableEdit = true
}
return (
<>
<Button type="link" size='small' disabled={disableEdit}
onClick={() => this.showEditor(item['name'], item['key'])}>
编辑
</Button>
<Button type="link" size='small' disabled={disableDownload} onClick={async () => {
download(`${server}/${this.state.storageType}/${this.state.storageId}/download?file=${window.encodeURIComponent(item['key'])}&X-Auth-Token=${getToken()}&t=${new Date().getTime()}`);
}}>
下载
</Button>
<Button type={'link'} size={'small'} disabled={!this.state.rename} onClick={() => {
this.setState({
renameVisible: true,
currentFileKey: item['key']
})
}}>重命名</Button>
<Popconfirm
title="您确认要删除此文件吗?"
onConfirm={async () => {
await this.delete(item['key']);
await this.refresh();
}}
okText="是"
cancelText="否"
>
<Button type={'link'} size={'small'} disabled={!this.state.delete} danger>删除</Button>
</Popconfirm>
</>
);
},
}
];
const {selectedRowKeys} = this.state;
const rowSelection = {
selectedRowKeys,
onChange: (selectedRowKeys) => {
this.setState({selectedRowKeys});
},
getCheckboxProps: (record) => ({
disabled: record['disabled'],
}),
};
let hasSelected = selectedRowKeys.length > 0;
if (hasSelected) {
if (!this.state.delete) {
hasSelected = false;
}
}
const title = (
<div className='fs-header'>
<div className='fs-header-left'>
<Input value={this.state.currentDirectoryInput} onChange={this.handleCurrentDirectoryInputChange}
onPressEnter={this.handleCurrentDirectoryInputPressEnter}/>
</div>
<div className='fs-header-right'>
<Space>
<div className='fs-header-right-item'>
<Tooltip title="创建文件夹">
<Button type="primary" size="small"
disabled={!this.state.upload}
icon={<FolderAddOutlined/>}
onClick={() => {
this.setState({
mkdirVisible: true
})
}} ghost/>
</Tooltip>
</div>
<div className='fs-header-right-item'>
<Tooltip title="上传文件">
<Button type="primary" size="small"
icon={<CloudUploadOutlined/>}
disabled={!this.state.upload}
onClick={() => {
window.document.getElementById('file-upload').click();
}} ghost/>
<input type="file" id="file-upload" style={{display: 'none'}}
onChange={this.handleUploadFile} multiple/>
</Tooltip>
</div>
<div className='fs-header-right-item'>
<Tooltip title="上传文件夹">
<Button type="primary" size="small"
icon={<UploadOutlined/>}
disabled={!this.state.upload}
onClick={() => {
window.document.getElementById('dir-upload').click();
}} ghost/>
<input type="file" id="dir-upload" style={{display: 'none'}}
onChange={this.handleUploadDir} webkitdirectory='' multiple/>
</Tooltip>
</div>
<div className='fs-header-right-item'>
<Tooltip title="刷新">
<Button type="primary" size="small"
icon={<ReloadOutlined/>}
onClick={this.refresh}
ghost/>
</Tooltip>
</div>
<div className='fs-header-right-item'>
<Tooltip title="批量删除">
<Button type="primary" size="small" ghost danger disabled={!hasSelected}
icon={<DeleteOutlined/>}
loading={this.state.delBtnLoading}
onClick={() => {
let rowKeys = this.state.selectedRowKeys;
const content = <div>
您确定要删除选中的<Text style={{color: '#1890FF'}}
strong>{rowKeys.length}</Text>条记录吗?
</div>;
confirm({
icon: <ExclamationCircleOutlined/>,
content: content,
onOk: async () => {
for (let i = 0; i < rowKeys.length; i++) {
if (rowKeys[i] === '..') {
continue;
}
await this.delete(rowKeys[i]);
}
this.refresh();
},
onCancel() {
},
});
}}>
</Button>
</Tooltip>
</div>
</Space>
</div>
</div>
);
return (
<div>
<Card title={title} bordered={true} size="small" style={{minHeight: this.state.minHeight}}>
<Table columns={columns}
rowSelection={rowSelection}
dataSource={this.state.files}
size={'small'}
pagination={false}
loading={this.state.loading}
onRow={record => {
return {
onDoubleClick: event => {
if (record['isDir'] || record['isLink']) {
if (record['path'] === '..') {
// 获取当前目录的上级目录
let currentDirectory = this.state.currentDirectory;
let parentDirectory = currentDirectory.substring(0, currentDirectory.lastIndexOf('/'));
this.loadFiles(parentDirectory);
} else {
this.loadFiles(record['path']);
}
} else {
}
},
};
}}
/>
</Card>
{
this.state.mkdirVisible ?
<Modal
title="创建文件夹"
visible={this.state.mkdirVisible}
okButtonProps={{form: 'mkdir-form', key: 'submit', htmlType: 'submit'}}
onOk={() => {
this.mkdirFormRef.current
.validateFields()
.then(async values => {
this.mkdirFormRef.current.resetFields();
let params = {
'dir': this.state.currentDirectory + '/' + values['dir']
}
let paramStr = qs.stringify(params);
this.setState({
confirmLoading: true
})
let result = await request.post(`/${this.state.storageType}/${this.state.storageId}/mkdir?${paramStr}`);
if (result.code === 1) {
message.success('创建成功');
this.loadFiles(this.state.currentDirectory);
} else {
message.error(result.message);
}
this.setState({
confirmLoading: false,
mkdirVisible: false
})
})
.catch(info => {
});
}}
confirmLoading={this.state.confirmLoading}
onCancel={() => {
this.setState({
mkdirVisible: false
})
}}
>
<Form ref={this.mkdirFormRef} id={'mkdir-form'}>
<Form.Item name='dir' rules={[{required: true, message: '请输入文件夹名称'}]}>
<Input autoComplete="off" placeholder="请输入文件夹名称"/>
</Form.Item>
</Form>
</Modal> : undefined
}
{
this.state.renameVisible ?
<Modal
title="重命名"
visible={this.state.renameVisible}
okButtonProps={{form: 'rename-form', key: 'submit', htmlType: 'submit'}}
onOk={() => {
this.renameFormRef.current
.validateFields()
.then(async values => {
this.renameFormRef.current.resetFields();
try {
let currentDirectory = this.state.currentDirectory;
if (!currentDirectory.endsWith("/")) {
currentDirectory += '/';
}
let params = {
'oldName': this.state.currentFileKey,
'newName': currentDirectory + values['newName'],
}
if (params['oldName'] === params['newName']) {
message.success('重命名成功');
return;
}
let paramStr = qs.stringify(params);
this.setState({
confirmLoading: true
})
let result = await request.post(`/${this.state.storageType}/${this.state.storageId}/rename?${paramStr}`);
if (result['code'] === 1) {
message.success('重命名成功');
this.refresh();
} else {
message.error(result.message);
}
} finally {
this.setState({
confirmLoading: false,
renameVisible: false
})
}
})
.catch(info => {
});
}}
confirmLoading={this.state.confirmLoading}
onCancel={() => {
this.setState({
renameVisible: false
})
}}
>
<Form id={'rename-form'}
ref={this.renameFormRef}
initialValues={{newName: getFileName(this.state.currentFileKey)}}>
<Form.Item name='newName' rules={[{required: true, message: '请输入新的名称'}]}>
<Input autoComplete="off" placeholder="新的名称"/>
</Form.Item>
</Form>
</Modal> : undefined
}
<Modal
title={"编辑 " + this.state.fileName}
className='modal-no-padding'
visible={this.state.editorVisible}
destroyOnClose={true}
width={window.innerWidth * 0.8}
centered={true}
okButtonProps={{form: 'rename-form', key: 'submit', htmlType: 'submit'}}
onOk={this.edit}
confirmLoading={this.state.confirmLoading}
onCancel={this.hideEditor}
>
<MonacoEditor
language="javascript"
height={window.innerHeight * 0.8}
theme="vs-dark"
value={this.state.fileContent}
options={{
selectOnLineNumbers: true
}}
editorDidMount={(editor, monaco) => {
console.log('editorDidMount', editor);
editor.focus();
}}
onChange={(newValue, e) => {
console.log('onChange', newValue, e);
this.setState(
{
fileContent: newValue
}
)
}}
/>
</Modal>
</div>
);
}
Example #9
Source File: index.js From getlink-next with MIT License | 4 votes |
App = ({ user, isAdmin, isDev }) => {
const [type, setType] = useState('image');
const handleTypeChange = useCallback((e) => {
setType(e.key);
}, []);
return (
<Context.Provider value={{ user, isAdmin, isDev }}>
<Layout style={{ height: '100%', flexDirection: 'row' }}>
<HTMLHead />
<Sider
breakpoint="lg"
collapsedWidth={0}
>
<a className="logo" href="https://github.com/int64ago/getlink-next" target="_blank">
Get Link!
</a>
<Menu
theme="dark"
mode="inline"
selectedKeys={[type]}
onClick={handleTypeChange}
>
<Menu.Item key="image">
<FileImageOutlined />IMAGE
</Menu.Item>
<Menu.Item key="video">
<VideoCameraOutlined />VIDEO
</Menu.Item>
<Menu.Item key="file">
<FileOutlined />FILE
</Menu.Item>
<Menu.Item key="placeholder">
<ContainerOutlined />Placeholder
</Menu.Item>
<Menu.Item key="qrcode">
<QrcodeOutlined />QR Code
</Menu.Item>
<Menu.Item key="urlshorten">
<LinkOutlined />URL Shortener
</Menu.Item>
</Menu>
</Sider>
<Layout style={{ background: '#fff', overflow: 'hidden' }}>
<Header>
{user ? (
<Dropdown overlay={(
<Menu>
<Menu.Item>
<a href="/api/logout">Logout</a>
</Menu.Item>
</Menu>
)}>
<Avatar src={user.picture} />
</Dropdown>
) : (
<div>
<Button type="link" href="/api/login">Login</Button>
</div>
)}
</Header>
<Content
style={{
padding: 24,
height: '100%',
background: '#fff',
overflow: 'auto',
}}
>
{type === 'image' && <Uploader type="image" />}
{type === 'video' && <Uploader type="video" />}
{type === 'file' && <Uploader type="file" />}
{type === 'qrcode' && <QRCode />}
{type === 'urlshorten' && <ShortUrl />}
{type === 'placeholder' && <Placeholder />}
</Content>
</Layout>
</Layout>
</Context.Provider>
);
}
Example #10
Source File: Status.js From network-rc with Apache License 2.0 | 4 votes |
export default function Status({
statusInfo,
piPowerOff,
wsConnected,
delay = 0,
isFullscreen,
setting,
isLogin,
session,
changeEditabled,
channelStatus,
changeChannel,
serverConfig,
version,
connectType,
onCarMicphoneChange,
locked,
onControllerMicphoneChange = () => {},
enabledControllerMicphone = true,
}) {
const isWebRTC = connectType === "webrtc";
const { sharedEndTime } = serverConfig;
const gamepadPress = ({ detail: { index, value } }) => {
if (index === 3 && value > 0.5) {
onControllerMicphoneChange(!enabledControllerMicphone);
}
};
useKeyPress(
"t",
() => onControllerMicphoneChange(!enabledControllerMicphone),
{
events: ["keyup"],
}
);
useEventListener("gamepadpress", gamepadPress);
return (
<Form layout="inline" className="app-status" size="small">
<Form.Item>
<Link to={`${process.env.PUBLIC_URL}/controller`}>
<img className="logo" src="/logo-256.png" alt="N-RC" />
</Link>
<span>N RC</span>
</Form.Item>
<Form.Item>
<Tag
style={{
width: "7em",
}}
icon={
locked ? (
<StopOutlined />
) : wsConnected ? (
<LinkOutlined />
) : (
<DisconnectOutlined />
)
}
color={locked || delay > 80 || !wsConnected ? "red" : "green"}
size="xs"
>
{isWebRTC ? "直连" : "中转"}:{delay.toFixed(0)}
</Tag>
</Form.Item>
{(serverConfig.channelList || [])
.filter(({ enabled, type }) => enabled && type === "switch")
.map(({ pin, name }) => (
<Form.Item key={pin}>
<Switch
checked={channelStatus[pin] || false}
checkedChildren={name}
unCheckedChildren={name}
onChange={(value) => changeChannel({ pin, value })}
/>
</Form.Item>
))}
{isLogin && isWebRTC && (
<Form.Item>
<Switch
checked={enabledControllerMicphone}
onChange={onControllerMicphoneChange}
checkedChildren={
<>
<DesktopOutlined /> <AudioOutlined />
</>
}
unCheckedChildren={
<>
<DesktopOutlined /> <AudioMutedOutlined />
</>
}
/>
</Form.Item>
)}
{isLogin && (
<Form.Item>
<AudioPlayer
session={session}
connectType={connectType}
onMicphoneChange={onCarMicphoneChange}
url={`${
window.location.protocol === "https:" ? "wss://" : "ws://"
}${setting.host}/microphone`}
/>
</Form.Item>
)}
<Form.Item>
<Switch
checkedChildren={<FormOutlined />}
unCheckedChildren={<FormOutlined />}
onChange={changeEditabled}
></Switch>
</Form.Item>
<Form.Item>
<Link to={`${process.env.PUBLIC_URL}/setting`}>
<Button
size="small"
icon={<SettingOutlined />}
shape="circle"
></Button>
</Link>
</Form.Item>
{document.body.requestFullscreen && (
<Form.Item>
<Button
type="primary"
shape="circle"
icon={
isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />
}
onClick={() => {
if (isFullscreen) {
document.exitFullscreen();
} else {
document.body.requestFullscreen();
}
}}
></Button>
</Form.Item>
)}
{wsConnected && isLogin && (
<Form.Item>
<Button
type="danger"
shape="circle"
icon={<PoweroffOutlined />}
onClick={piPowerOff}
></Button>
</Form.Item>
)}
{wsConnected &&
isLogin &&
Object.keys(statusInfo).map((key) => {
const { color, label, value } = statusInfo[key];
return !["gps"].includes(label) ? (
<Form.Item key={key}>
<Tag color={color}>
{label}:{value}
</Tag>
</Form.Item>
) : undefined;
})}
{wsConnected && sharedEndTime && (
<Form.Item>
<Tag
icon={<HourglassOutlined />}
color={session && session.endTime && "orange"}
>
{((sharedEndTime - new Date().getTime()) / 1000).toFixed(0)}s
</Tag>
</Form.Item>
)}
{version && (
<Form.Item>
<Tag>v{version}</Tag>
</Form.Item>
)}
</Form>
);
}
Example #11
Source File: build_record_table.js From art-dashboard-ui with Apache License 2.0 | 4 votes |
render() {
const table_column = [
{
title: 'Brew Build',
dataIndex: "build_id",
key: "build_id",
render: (text, record) => (
<div>
<a href={process.env.REACT_APP_BREW_BUILD_LINK+record["build_id"]}
target="_blank" rel="noopener noreferrer">
{record["build_id"]}
</a>
</div>
)
},
{
title: "Build Status",
dataIndex: "fault_code",
key: "fault_code",
render: (text, record) =>{
if(record["fault_code"] === "0"){
return(
<div>
<CheckOutlined style = {{color: "#52c41a"}}/>
</div>
)
}
else{
return(
<div>
<Tooltip title={"Fault Code is " + record["fault_code"]}>
<CloseOutlined style = {{color: "#f55d42"}}/>
</Tooltip>
</div>
)
}
}
},
{
title: "Brew Task",
dataIndex: "task_id",
key: "task_id",
render: (data, record) => {
return(
<div>
<a href={process.env.REACT_APP_BREW_TASK_LINK+record["task_id"]}
target="_blank" rel="noopener noreferrer">{record["task_id"]}</a>
</div>
)
}
},
{
title: "Jenkins Build URL",
dataIndex: "jenkins_build_url",
key: "jenkins_build_url",
render: (data, record) =>{
return (
<div>
<p><a href={record["jenkins_build_url"]}>{<LinkOutlined/>}</a></p>
</div>
)
}
},
{
title: "DistGit Name",
dataIndex: "label_name",
key: "label_name",
filters: this.state.label_name_filter,
onFilter: (value, record) => record.label_name === value,
width: "20%",
sorter: (a, b) => a.label_name.length - b.label_name.length
},
{
title: "OpenShift Group",
dataIndex: "group",
key: "group",
filters: this.state.group_filter,
onFilter: (value, record) => record.group === value,
width: "20%",
sorter: (a, b) => parseFloat(a.group.split("-")[1]) - parseFloat(b.group.split("-")[1])
},
{
title: "Build Time",
dataIndex: "iso_time",
key: "iso_time",
render: (data, record) => {
let date = new Date(record["iso_time"])
return (
<p>{date.getFullYear()+'-' + this.render_single_digit_to_double_datetime((date.getMonth()+1)) + '-'+this.render_single_digit_to_double_datetime(date.getDate()) + ' ' + this.render_single_digit_to_double_datetime(date.getHours()) + ':' + this.render_single_digit_to_double_datetime(date.getMinutes()) + ":" + this.render_single_digit_to_double_datetime(date.getSeconds())}</p>
)
}
}
]
return (
<div>
<Table dataSource={this.state.data} columns={table_column} style={{padding: "30px"}} loading={this.state.loading}/>
</div>
);
}
Example #12
Source File: whatsnew_carousel.js From art-dashboard-ui with Apache License 2.0 | 4 votes |
parse_based_on_section_request(){
const data_july_30_2020 = [
"Release Page: The page now has previous advisories as well for an OpenShift version."
]
const data_july_29_2020 = [
"Build History: Build status icon has link to brew task.",
"Build History: Source commit shows commit id instead of link icon.",
"Release: No github developer api stats on release home page."
]
const data_july_27_2020 = [
"Build History: Data source migrated from SimpleDB to MySQL. Faster results. Now can support even more advanced filters.",
"Build History: Support for link with query parameters to support link sharing for filtered results.",
"Build History: Export history data to csv.",
"Build History: Aesthetic UI changes. Cleaner \"More Details\" popup."
]
const data_july_15_2020 = [
"Release: Release status page for each openshift version. Sample Endpoint: /release/status/?type=branch&branch=openshift-4.6"
]
const data_july_09_2020 = [
"Build History: Advanced Filters has option to sort results based on columns.",
"Build History: Semantically correct icons in the table.",
"Build History: Quick Search over table headers.",
"Build Health: Build History for the date available.",
"Build Health: Build History for a particular package under health section.",
"Build Health: All the tables under health have required sort and filter over columns.",
"What's New: And the what's new section :)"
]
const data_july_13_2020 = [
"Release: Home Page for all the openshift versions. Endpoint : /release/status/?type=all",
"Release: Status for specific openshift versions with all the advisories. Sample Endpoint : /release/status/?type=branch&branch=openshift-4.6",
"Release: overview for specific advisory. Sample Endpoint : /release/advisory/overview/54579"
]
const data_july_21_2020 = [
"Release: Revamped openshift branch page. Sample Endpoint : /release/status/?type=branch&branch=openshift-4.6",
"Release: Dropdown to select openshift branch to get advisory details."
]
const navigating_table_data = [
{
'section': 'Release',
'url': 'http://art-dash-ui-aos-art-web.apps.ocp4.prod.psi.redhat.com/release/status/?type=all',
'desc': 'This is where you can find all the major OpenShift versions. The current status of each release. You also find the current and the previous advisories ' +
'associated with each version with information about approval status, reviewer details, release date and current status.',
'children': [
{
'section': 'Release Advisories',
'url': 'http://art-dash-ui-aos-art-web.apps.ocp4.prod.psi.redhat.com/release/status/detail/openshift-4.6',
'desc': 'This page has current and previous advisors (rpm, image, metadata, extras) details per OpenShift release version.'
},
{
'section': 'Advisory Details',
'url': 'http://art-dash-ui-aos-art-web.apps.ocp4.prod.psi.redhat.com/release/advisory/overview/54579',
'desc': 'This pages displays details for a particular advisory. The details include bugs, release date, status of release.'
}
]
},
{
'section': 'Build',
'url': undefined,
'desc': 'This sections has data for all the builds for OpenShift builds attempted by ART team. The two major type of information' +
'is the build history and the build health.',
children: [
{
'section': 'Build History',
'url': 'http://art-dash-ui-aos-art-web.apps.ocp4.prod.psi.redhat.com/build/history',
'desc': 'This page shows the complete history of all the build attempts made by ART team. The history can be filtered with ' +
'multiple parameters.'
},
{
'section': 'Build Health',
'url': undefined,
'desc': 'This sections has various pages to help understand the build history using daily reports and aggregated stats with options ' +
'to filter.',
children: [
{
'section': 'Daily Build Health',
'url': 'http://art-dash-ui-aos-art-web.apps.ocp4.prod.psi.redhat.com/health/daily/overview',
'desc': 'This page contains the daily overview and health of builds including success rate, failures.'
},
{
'section': 'Detail Daily Health',
'url': 'http://art-dash-ui-aos-art-web.apps.ocp4.prod.psi.redhat.com/health/daily/detail/2020-08-04',
'desc': 'This page is the expansion of health for a particular date. The page is easy to navigate and intuitive.'
}
]
}
]
}
]
const features_table_data = [
{
'feature': 'Release',
'desc': "OpenShift release version details.",
'date': "July 13th 2020",
children: [
{
'feature': 'Release Home',
'desc': 'Access to all the OpenShift version.',
'date': '13th July 2020'
},
{
'feature': 'Release Version',
'desc': 'Detailed view of a particular OpenShift version. The details include release status, dates, approval statuses, reviewers for attached advisories.',
'date': '13th July 2020',
children: [
{
'feature': 'Change OpenShift Version',
'desc': 'Change the OpenShift version in the detail page to load data for the selected version. Helpful in quickly navigating through different versions.',
'date': 'July 21st 2020'
},
{
'feature': 'Detailed Release Version',
'desc': 'Detailed data for a particular version. Includes bug history, statuses, dates, approvals and reviewers.',
'date': 'July 15th 2020'
},
{
'feature': 'Current Advisories',
'desc': 'The release version page has current advisories attached to the release version.',
'date': 'July 15th 2020'
},
{
'feature': 'Previous Advisories',
'desc': 'The release version page has previous advisories that were attached to the release version.',
'date': 'July 30th 2020'
}
]
},
]
},
{
'feature': 'Build',
'desc': 'Attempted ART build data.',
'date': 'July 1st 2020',
children: [
{
'feature': 'Build History',
'desc': 'Displays all the builds attempted by ART.',
'date': 'July 1st 2020',
children: [
{
'feature': 'Quick Filters',
'desc': 'The history table has quick filters over the table header.',
'date': 'July 9th 2020',
},
{
'feature': 'Advanced Filters',
'desc': 'The history page has advanced filters to include multiple parameters to do search on.',
'date': 'July 1st 2020',
},
{
'feature': 'Export Build History',
'desc': 'The history page has option to export the filtered data into a csv.',
'date': 'July 27th 2020',
}
]
},
{
'feature': 'Build Health',
'desc': 'Aggregated data for ART builds.',
'date': 'July 9th 2020',
children: [
{
'feature': 'Daily Overview',
'desc': 'Date wise overview of the builds.',
'date': 'July 9th 2020',
},
{
'feature': 'Expanded Daily Overview',
'desc': 'Detailed overview of builds for a date',
'date': 'July 9th 2020',
},
{
'feature': 'Quick Search',
'desc': 'All the tables in build history have quick search options on table header.',
'date': 'July 9th 2020',
}
]
}
]
}
]
const features_table_column = [
{
title: 'Feature',
key: 'feature',
dataIndex: 'feature'
},
{
title: 'Feature Description',
key: 'desc',
dataIndex: 'desc'
},
{
title: 'Date on Inclusion',
key: 'date',
dataIndex: 'date'
}
]
const navigating_table_column = [
{
title: 'Section',
key: 'section',
dataIndex: 'section',
width: "15%"
},
{
title: 'Description',
key: 'desc',
dataIndex: 'desc',
width: "75%"
},
{
title: "URL",
key: 'url',
dataIndex: 'url',
render: (data, record) => {
if(data !== undefined)
return(
<a href={data}><LinkOutlined/>
</a>
)
else{
return(
<p></p>
)
}
},
width: "10%"
}
]
return (
<Collapse defaultActiveKey={"Portal Navigation"} accordion bordered={false}>
<Panel key={"Portal Navigation"} header={"Portal Navigation"}>
<div style={{marginLeft: "50px", marginTop: "30px"}}>
<h5>
Sections
</h5>
<ul>
<li style={{margin: "10px", listStyleType: "circle"}}>
The OpenShift Release Portal can be used to access various information about the release process and release status of OpenShift.
</li>
<li style={{margin: "10px", listStyleType: "circle"}}>
All the information is segregated into sections for ease of use.
</li>
<li style={{margin: "10px", listStyleType: "circle"}}>
The different sections can be access through navigation menu available on the left of the page.
</li>
</ul>
<Table dataSource={navigating_table_data} columns={navigating_table_column} pagination={false}/>
</div>
</Panel>
<Panel key={"Features"} header={"Features"}>
<Table dataSource={features_table_data} columns={features_table_column} pagination={false}/>
</Panel>
<Panel key={"Feature History"} header={"Feature History"} >
<div style={{ padding: "30px"}}>
<Collapse accordion defaultActiveKey={['1']} >
<Panel key={"1"} header={"July 30th 2020"}>
<List
size="large"
style={{backgroundColor: "white"}}
header={<div>New Features: July 30th 2020</div>}
footer={<div>Try them out!</div>}
bordered
dataSource={data_july_30_2020}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</Panel>
<Panel key={"2"} header={"July 29th 2020"}>
<List
size="large"
style={{backgroundColor: "white"}}
header={<div>New Features: July 29th 2020</div>}
footer={<div>Try them out!</div>}
bordered
dataSource={data_july_29_2020}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</Panel>
<Panel key={"3"} header={"July 27th 2020"}>
<List
size="large"
style={{backgroundColor: "white"}}
header={<div>New Features: July 27th 2020</div>}
footer={<div>Try them out!</div>}
bordered
dataSource={data_july_27_2020}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</Panel>
<Panel key={"4"} header={"July 21st 2020"}>
<List
size="large"
style={{backgroundColor: "white"}}
header={<div>New Features: July 21st 2020</div>}
footer={<div>Try them out!</div>}
bordered
dataSource={data_july_21_2020}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</Panel>
<Panel key={"5"} header={"July 15th 2020"}>
<List
size="large"
style={{backgroundColor: "white"}}
header={<div>New Features: July 15th 2020</div>}
footer={<div>Try them out!</div>}
bordered
dataSource={data_july_15_2020}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</Panel>
<Panel key={"6"} header={"July 13th 2020"}>
<List
size="large"
style={{backgroundColor: "white"}}
header={<div>New Features: July 13th 2020</div>}
footer={<div>Try them out!</div>}
bordered
dataSource={data_july_13_2020}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</Panel>
<Panel key={"7"} header={"July 9th 2020"}>
<List
size="large"
style={{backgroundColor: "white"}}
header={<div>New Features: July 9th 2020</div>}
footer={<div>Try them out!</div>}
bordered
dataSource={data_july_27_2020}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</Panel>
</Collapse>
</div>
</Panel>
</Collapse>
)
}