Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions packages/app-card-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@serverless-cd/app-card-ui",
"version": "0.0.8",
"version": "0.0.13",
"scripts": {
"start": "dumi dev",
"docs:build": "dumi build",
Expand All @@ -19,7 +19,7 @@
"typings": "dist/esm/index.d.ts",
"dependencies": {
"@alicloud/console-components-slide-panel": "^2.2.14",
"@serverless-cd/ui-help": "^0.0.2",
"@serverless-cd/ui-help": "^0.0.9",
"axios": "^1.2.2",
"qs": "^6.11.0",
"react-markdown": "^8.0.4",
Expand All @@ -38,9 +38,13 @@
"access": "public"
},
"devDependencies": {
"@alicloud/console-components": ">=1.0.0",
"@types/jest": "^29.5.6",
"@types/qs": "^6.9.7",
"dumi": "^1.1.0",
"father": "^4.0.0-rc.2"
"father": "^4.0.0-rc.2",
"moment": "^2.29.4",
"styled-components": "^6.1.0"
},
"repository": "[email protected]:g-fengchen/ui.git"
}
}
14 changes: 11 additions & 3 deletions packages/app-card-ui/src/components/readme/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum NavKey {
codepre = 'codepre',
appdetail = 'appdetail',
usedetail = 'usedetail',
matters = 'matters',
local_experience = 'local_experience',
disclaimers = 'disclaimers',
}
Expand All @@ -27,9 +28,13 @@ const navs = [
title: i18n('ui.application.usage.document'),
},
{
key: NavKey.local_experience,
title: i18n('ui.local_experience'),
key: NavKey.matters,
title: i18n('ui.application.matters.document'),
},
// {
// key: NavKey.local_experience,
// title: i18n('ui.local_experience'),
// },
{
key: NavKey.disclaimers,
title: i18n('ui.project.disclaimer'),
Expand Down Expand Up @@ -68,6 +73,7 @@ const Nav: FC<Props> = (props) => {
const scrollBottom = scrollHeight - scrollTop - clientHeight;
const appdetail = document.getElementById(NavKey.appdetail);
const usedetail = document.getElementById(NavKey.usedetail);
const matters = document.getElementById(NavKey.matters);
const local_experience = document.getElementById(NavKey.local_experience);
const disclaimers = document.getElementById(NavKey.disclaimers);

Expand All @@ -81,6 +87,8 @@ const Nav: FC<Props> = (props) => {
setActiveKey(NavKey.usedetail);
} else if (scrollTop < disclaimers.offsetTop - FIX_HEIGHT) {
setActiveKey(NavKey.local_experience);
} else if (scrollTop < matters.offsetTop - FIX_HEIGHT) {
setActiveKey(NavKey.matters);
}
}, 300);

Expand All @@ -90,7 +98,7 @@ const Nav: FC<Props> = (props) => {
const scrollElement = document.getElementsByClassName('panel-body')[0];
const anchorElement = document.getElementById(id);
scrollElement.scrollTo({
top: anchorElement.offsetTop - 90,
top: anchorElement?.offsetTop - 90,
});
setTimeout(() => {
scrollRef.current.listen = true;
Expand Down
159 changes: 132 additions & 27 deletions packages/app-card-ui/src/components/readme/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import React, { FC, useState, PropsWithChildren } from 'react';
import {
Balloon,
Button,
Icon,
Loading,
Message,
} from '@alicloud/console-components';
import { SlidePanel } from '@alicloud/console-components-slide-panel';
import { Loading, Balloon, Message, Button, Icon } from '@alicloud/console-components';
import Nav, { NavKey } from './Nav';
import ExternalLink from './ExternalLink';
import ReactMarkdown from './ReactMarkdown';
import GithubIcon from './GithubIcon';
import { parseReadme } from '@serverless-cd/ui-help';
import { i18n, copyText, lang } from '../../utils';
import axios from 'axios';
import { find, get, isEmpty, isFunction, map, isNumber } from 'lodash';
import qs from 'qs';
import { get, isEmpty, map, find, isFunction } from 'lodash';
import { IApiTypeVal, IApiType } from '../../types';
import React, { FC, PropsWithChildren, useState } from 'react';
import { IApiType, IApiTypeVal } from '../../types';
import { copyText, i18n, lang } from '../../utils';
import ExternalLink from './ExternalLink';
import GithubIcon from './GithubIcon';
import Nav, { NavKey } from './Nav';
import ReactMarkdown from './ReactMarkdown';

function copy(val) {
copyText(val);
Expand All @@ -32,6 +38,7 @@ export type Props = PropsWithChildren & {
visible?: boolean;
env?: 'vscode' | 'web';
fetchReadme?: () => Promise<string>;
isV3?: boolean;
};

const AliReadme: FC<Props> = (props) => {
Expand All @@ -46,11 +53,13 @@ const AliReadme: FC<Props> = (props) => {
activeTab,
fetchReadme,
visible: readmeVisible = false,
isV3 = false,
} = props;
const [visible, setVisible] = useState(readmeVisible);
const [loading, setLoading] = useState(false);
const [readmeInfo, setReadmeInfo] = useState<any>({});


const fetchApps = async () => {
try {
const result = await axios({
Expand Down Expand Up @@ -85,9 +94,17 @@ const AliReadme: FC<Props> = (props) => {

const fetchData = async () => {
setLoading(true);
const [app, content] = await Promise.all([fetchApps(), fetchContent()]);
const appInfo = find(app, (item) => item.package === name);
if (content.match(/(?=<appdetai)[\s\S]+(?=<\/appdetail>)/)) {
const [content, appInfo] = await getTemplateInfo(name);
if (isNumber(name)) {
const data = parseReadme(content);
setReadmeInfo({
...data,
logo: get(appInfo, 'logo'),
description: get(appInfo, 'description'),
codeUrl: get(appInfo, 'codeUrl'),
previewUrl: get(appInfo, 'previewUrl'),
});
} else if (content.match(/(?=<appdetai)[\s\S]+(?=<\/appdetail>)/)) {
const data = parseReadme(content);
setReadmeInfo({
...data,
Expand All @@ -102,6 +119,55 @@ const AliReadme: FC<Props> = (props) => {
setLoading(false);
};

const getTemplateInfo = async (name) => {
const v3Info = await fetchV3(name);
if (isEmpty(v3Info)) {
const v2Info = await fetchV2(name);
return v2Info
} else {
return v3Info
}
}

const fetchV3 = async (name) => {
const { version = {}, package: app = {} } = await getAppV3(name);
if (!isEmpty(version)) return [version.readme, app];
else []
};

const fetchV2 = async (name) => {
const [app, content] = await Promise.all([fetchApps(), fetchContent()]);
const appInfo = find(app, (item) => item.package === name);
return [content, appInfo]
};

const getAppV3 = async (projectName) => {
try {
const result = await axios({
method: 'get',
url: `https://api.devsapp.cn/v3/console/project/${projectName}?lang=${lang()}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
const Response = get(result, 'data.body', {});

return {
...Response,
package: {
...get(Response, 'package', {}),
package: get(Response, 'package.name'),
codeUrl: get(Response, 'repo'),
previewUrl: get(Response, 'demo'),
logo: get(Response, 'logo'),
title: Response.name,
},
};
} catch (e) {
return {};
}
};

const doFetchReadme = async () => {
setLoading(true);
try {
Expand Down Expand Up @@ -199,7 +265,9 @@ const AliReadme: FC<Props> = (props) => {
};
const renderBody = () => {
if (loading) {
return <Loading visible={loading} inline={false} style={{ minHeight: 400 }} />;
return (
<Loading visible={loading} inline={false} style={{ minHeight: 400 }} />
);
}
// 兼容旧模版
if (typeof readmeInfo === 'string') {
Expand All @@ -208,8 +276,14 @@ const AliReadme: FC<Props> = (props) => {
return (
<div className="serverless-cd__alireadme-wrapper">
<Nav activeTab={activeTab} />
<div className={readmeInfo.logo || readmeInfo.description ? 'pt-24' : 'pt-1'}>
{readmeInfo.logo && <img src={readmeInfo.logo} style={{ height: 30 }} />}
<div
className={
readmeInfo.logo || readmeInfo.description ? 'pt-24' : 'pt-1'
}
>
{readmeInfo.logo && (
<img src={readmeInfo.logo} style={{ height: 30 }} />
)}
{readmeInfo.description && <div>{readmeInfo.description}</div>}
<h1 className="mt-20" id={NavKey.codepre}>
{i18n('ui.codepre.title')}
Expand All @@ -220,7 +294,11 @@ const AliReadme: FC<Props> = (props) => {
<ul style={{ listStyle: 'unset' }} className="pl-16">
{map(readmeInfo.service, (item) => (
<li key={item.label}>
<a className="color-link cursor-pointer" href={item.url} target="_blank">
<a
className="color-link cursor-pointer"
href={item.url}
target="_blank"
>
{item.name}:
</a>
<span className="ml-8">{item.description}</span>
Expand Down Expand Up @@ -280,14 +358,21 @@ const AliReadme: FC<Props> = (props) => {
</>
)}
<h1 className="mt-20" id={NavKey.appdetail}>
{i18n('ui.application.introduction.document')}
{readmeInfo.appdetail ? i18n('ui.application.introduction.document') : null}
</h1>
<ReactMarkdown text={readmeInfo.appdetail} />

<h1 className="mt-20" id={NavKey.usedetail}>
{i18n('ui.application.usage.document')}
{readmeInfo.usedetail ? i18n('ui.application.usage.document') : null}
</h1>
<ReactMarkdown text={readmeInfo.usedetail} />
<h1 className="mt-20" id={NavKey.local_experience}>

<h1 className="mt-20" id={NavKey.matters}>
{readmeInfo.matters ? i18n('ui.application.matters.document') : null}
</h1>
<ReactMarkdown text={readmeInfo.matters} />

{/* <h1 className="mt-20" id={NavKey.local_experience}>
{i18n('ui.local_experience')}
</h1>
<ul className="ml-0">
Expand Down Expand Up @@ -317,7 +402,10 @@ const AliReadme: FC<Props> = (props) => {
label={i18n('ui.s.doc')}
/>
</li>
<li className="align-start mt-8" style={{ background: '#f8f8f9' }}>
<li
className="align-start mt-8"
style={{ background: '#f8f8f9' }}
>
<div
style={{ height: 100, width: 100, background: '#000' }}
className="align-center"
Expand All @@ -328,7 +416,14 @@ const AliReadme: FC<Props> = (props) => {
style={{ width: 60 }}
/>
</div>
<div style={{ flex: 1, height: '100%', padding: 16, border: '1px solid #eee' }}>
<div
style={{
flex: 1,
height: '100%',
padding: 16,
border: '1px solid #eee',
}}
>
<div
dangerouslySetInnerHTML={{
__html: i18n('ui.s.intro'),
Expand Down Expand Up @@ -400,7 +495,10 @@ const AliReadme: FC<Props> = (props) => {
align="t"
closable={false}
trigger={
<code className="cursor-pointer" onClick={() => copy('s config add')}>
<code
className="cursor-pointer"
onClick={() => copy('s config add')}
>
s config add
</code>
}
Expand Down Expand Up @@ -443,7 +541,10 @@ const AliReadme: FC<Props> = (props) => {
align="t"
closable={false}
trigger={
<code className="cursor-pointer" onClick={() => copy(`cd ${name} && s deploy`)}>
<code
className="cursor-pointer"
onClick={() => copy(`cd ${name} && s deploy`)}
>
{`cd ${name} && s deploy`}
</code>
}
Expand All @@ -461,16 +562,20 @@ const AliReadme: FC<Props> = (props) => {
</li>
</ul>
</li>
</ul>
</ul> */}
<h1 className="mt-20" id={NavKey.disclaimers}>
{i18n('ui.application.center.disclaimer')}
</h1>
<div
dangerouslySetInnerHTML={{ __html: i18n('ui.application.center.disclaimer.content') }}
dangerouslySetInnerHTML={{
__html: i18n('ui.application.center.disclaimer.content'),
}}
/>
{readmeInfo.disclaimers && (
<>
<h1 className="mt-20">{i18n('ui.disclaimer.for.current.application')}</h1>
<h1 className="mt-20">
{i18n('ui.disclaimer.for.current.application')}
</h1>
<ReactMarkdown text={readmeInfo.disclaimers} />
</>
)}
Expand All @@ -486,7 +591,7 @@ const AliReadme: FC<Props> = (props) => {
title={title}
isShowing={visible}
onClose={onClose}
customFooter={env==='web' && renderFooter()}
customFooter={env === 'web' && renderFooter()}
>
{renderBody()}
</SlidePanel>
Expand Down
4 changes: 2 additions & 2 deletions packages/app-card-ui/src/utils/i18n/en.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default {
'ui.review': 'Preview',
'ui.source.code': 'Source',
'ui.codepre.title': 'Preparations',
'ui.application.introduction.document': 'Application introduction document',
'ui.application.introduction.document': 'Help documentation',
'ui.application.usage.document': 'Application usage document',
'ui.local_experience': 'Local deployment scheme',
'ui.project.disclaimer': 'Project Disclaimer',
Expand All @@ -31,7 +31,7 @@ export default {
'ui.remark.document': 'Component command documentation of Function Compute',
'ui.application.center.disclaimer': 'Application Center Disclaimer',
'ui.disclaimer.for.current.application': 'Disclaimer for Current Application',
'ui.application.center.disclaimer.content': `<div>1. The application center only provides you with the logical relationship of the application and does not host any resources for you. If there is a certain resource charging phenomenon in the application you deploy, please refer to the charging standard of the corresponding product. If some products or services used by your application are incompatible and changed due to product planning and other reasons, it is recommended that you directly consult the corresponding products or services. </div><div class = "mt-4">2. The default pipeline function provided by the application center is free of charge. If you need to switch to the custom pipeline manually, the resource usage cost may be involved. The specific charging standard needs to refer to the charging document calculated by the function. </div><div class = "mt-4">3. Some applications deployed by the application center will assign you a test domain name of "devsapp.cn". This test domain name is not the official domain name of Aliyun, but the test domain name provided by the CNCF Sandbox project Serverless Devs. We do not guarantee the effectiveness of using this domain name and promote you to use it only during testing. If the custom domain name function recommends you to use your own domain name for binding;</div><div class = "mt-4">4. During the application deployment process, if the message "The current application Template is contributed by the community and is not officially provided by Aliyun, it is recommended that you carefully read the application details before using the current application template to ensure the safety and stability of the application", it means that the application is not officially provided by Aliyun and is only included and displayed. If you continue to deploy the application, we recommend that you contact the author of the application, and negotiate with the author the relevant protocols used in the application, etc.;</div>'`,
'ui.application.center.disclaimer.content': `<div>1. The Serverless development platform only provides you with the logical relationship of the application and does not host any resources for you. If there are certain resource charges in the application you deploy, please refer to the charging standard of the corresponding product; if some products or services used by your application have been incompatible changes due to product planning and other reasons, it is recommended that you directly consult the corresponding product Products or services; </div><div class="mt-4">2. The default pipeline function provided by the Serverless development platform is free. If you need to manually switch to a custom pipeline, resource usage fees may be involved. For specific charging standards, please refer to the billing document of Function Compute;</div><div class="mt-4">3. Some applications deployed by the Serverless development platform will assign you the test domain name of "devsapp.cn". This The test domain name is not the official domain name of Alibaba Cloud. It is a test domain name provided by the CNCF Sandbox project Serverless Devs. We do not guarantee the effectiveness of the use of this domain name. We encourage you to use it only during testing. If you customize the domain name function, we recommend that you use your own domain name. Binding; </div><div class="mt-4">4. During the application deployment process, if it prompts "The current application template is contributed by the community and is not officially provided by Alibaba Cloud, it is recommended that you carefully check the current application template before using it. "Read the application details to ensure the security and stability of the application" means that the application is not officially provided by Alibaba Cloud. We only include and display it. If you continue to deploy the application, we recommend that you contact the author of the application and contact the author. Negotiate relevant protocols used by the application, etc.;</div>'`,
'ui.cancel': 'Cancel',
'ui.share': 'Share',
'ui.share.copy.sucess': 'The link for sharing is copied.',
Expand Down
Loading