diff --git a/frontend/desktop/public/icons/inviter.svg b/frontend/desktop/public/icons/inviter.svg
new file mode 100644
index 00000000000..f7c0fee038e
--- /dev/null
+++ b/frontend/desktop/public/icons/inviter.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/desktop/public/locales/en/common.json b/frontend/desktop/public/locales/en/common.json
index 16cfb810c70..065f1ce0cd9 100644
--- a/frontend/desktop/public/locales/en/common.json
+++ b/frontend/desktop/public/locales/en/common.json
@@ -135,6 +135,7 @@
"invitation_reminder": "Invitation reminder",
"invite_member": "Invite Member",
"invite_members_to_workspace_": "Invite members to workspace {{workspace}}",
+ "inviter_id_tips": "Invitation code (optional)",
"irreversibleactiontips": "This action is irreversible, please proceed with caution.",
"jump_over": "Jump Over",
"laf_on_sealos": "Laf on Sealos",
@@ -302,4 +303,4 @@
"you_can_view_fees_through_the_fee_center": "You can view fees through the fee center",
"you_have_not_purchased_the_license": "You have not purchased the License",
"yuan": "Yuan"
-}
+}
\ No newline at end of file
diff --git a/frontend/desktop/public/locales/zh/common.json b/frontend/desktop/public/locales/zh/common.json
index 1e56f9d94f3..e901112dbb2 100644
--- a/frontend/desktop/public/locales/zh/common.json
+++ b/frontend/desktop/public/locales/zh/common.json
@@ -130,6 +130,7 @@
"invitation_reminder": "受邀提醒",
"invite_member": "邀请成员",
"invite_members_to_workspace": "邀请成员至工作空间 {{workspace}}",
+ "inviter_id_tips": "邀请码(选填)",
"irreversibleactiontips": "此操作不可逆转,请谨慎操作",
"jump_over": "跳过",
"language": "语言",
@@ -293,4 +294,4 @@
"you_can_view_fees_through_the_fee_center": "您可通过费用中心查看费用",
"you_have_not_purchased_the_license": "您还没有购买 License",
"yuan": "元"
-}
+}
\ No newline at end of file
diff --git a/frontend/desktop/src/components/signin/auth/useSms.tsx b/frontend/desktop/src/components/signin/auth/useSms.tsx
index 81a4c27fa96..aa63cc56ef6 100644
--- a/frontend/desktop/src/components/signin/auth/useSms.tsx
+++ b/frontend/desktop/src/components/signin/auth/useSms.tsx
@@ -34,6 +34,7 @@ export default function useSms({
const { register, handleSubmit, trigger, getValues, watch } = useForm<{
phoneNumber: string;
verifyCode: string;
+ inviterId?: string;
}>();
const login = async () => {
@@ -54,7 +55,7 @@ export default function useSms({
{
id: data.phoneNumber,
code: data.verifyCode,
- inviterId: getInviterId(),
+ inviterId: data?.inviterId || getInviterId(),
semData: getUserSemData(),
bdVid: getBaiduId()
}
@@ -225,6 +226,36 @@ export default function useSms({
)}
+ {!!authConfig?.invite.enabled && (
+
+
+
+
+
+
+ )}
>
);
};
diff --git a/frontend/providers/template/src/pages/api/getTemplateSource.ts b/frontend/providers/template/src/pages/api/getTemplateSource.ts
index 8343a8187c8..fa856619074 100644
--- a/frontend/providers/template/src/pages/api/getTemplateSource.ts
+++ b/frontend/providers/template/src/pages/api/getTemplateSource.ts
@@ -93,7 +93,18 @@ export async function GetTemplateByName({
if (cdnUrl) {
templateYaml.spec.readme = replaceRawWithCDN(templateYaml.spec.readme, cdnUrl);
templateYaml.spec.icon = replaceRawWithCDN(templateYaml.spec.icon, cdnUrl);
+ if (templateYaml?.spec?.i18n) {
+ Object.keys(templateYaml?.spec?.i18n || {}).forEach((lang) => {
+ const i18nLang = templateYaml?.spec?.i18n?.[lang];
+ ['readme', 'icon'].forEach((field) => {
+ if (i18nLang?.[field]) {
+ i18nLang[field] = replaceRawWithCDN(i18nLang[field], cdnUrl);
+ }
+ });
+ });
+ }
}
+
templateYaml = parseTemplateVariable(templateYaml, TemplateEnvs);
const dataSource = getTemplateDataSource(templateYaml);
diff --git a/frontend/providers/template/src/pages/deploy/index.tsx b/frontend/providers/template/src/pages/deploy/index.tsx
index b2e27c25bce..2c293d034dc 100644
--- a/frontend/providers/template/src/pages/deploy/index.tsx
+++ b/frontend/providers/template/src/pages/deploy/index.tsx
@@ -405,54 +405,91 @@ export default function EditApp({
);
}
+async function fetchReadmeContent(url: string): Promise {
+ let retryCount = 0;
+ const maxRetries = 3;
+
+ while (retryCount < maxRetries) {
+ try {
+ const response = await fetch(url, {
+ headers: {
+ Accept: 'text/markdown,text/plain,*/*',
+ 'Content-Type': 'text/markdown; charset=UTF-8',
+ 'Cache-Control': 'no-cache',
+ Pragma: 'no-cache',
+ 'User-Agent': 'Mozilla/5.0'
+ },
+ credentials: 'omit'
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ return await response.text();
+ } catch (err) {
+ retryCount++;
+
+ if (retryCount === maxRetries) {
+ return '';
+ }
+ await new Promise((resolve) => setTimeout(resolve, retryCount * 1000));
+ }
+ }
+ return '';
+}
+
export async function getServerSideProps(content: any) {
- const brandName = process.env.NEXT_PUBLIC_BRAND_NAME;
+ const brandName = process.env.NEXT_PUBLIC_BRAND_NAME || 'Sealos';
const local =
content?.req?.cookies?.NEXT_LOCALE ||
compareFirstLanguages(content?.req?.headers?.['accept-language'] || 'zh');
+ const appName = content?.query?.templateName || '';
+ const baseurl = `http://${process.env.HOSTNAME || 'localhost'}:${process.env.PORT || 3000}`;
content?.res.setHeader(
'Set-Cookie',
`NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`
);
- const appName = content?.query?.templateName || '';
-
- const baseurl = `http://${process.env.HOSTNAME || 'localhost'}:${process.env.PORT || 3000}`;
-
- let metaData = {
- title: `${appName}部署和安装教程 - Sealos`,
- keywords: '',
- description: ''
- };
- let readmeContent = '';
- let readUrl = '';
-
try {
- const templateSource: { data: TemplateSourceType } = await (
+ const { data: templateSource } = await (
await fetch(`${baseurl}/api/getTemplateSource?templateName=${appName}`)
).json();
- const templateDetail = templateSource?.data.templateYaml;
- metaData = {
- title: templateDetail?.spec?.title,
- keywords: templateDetail?.spec?.description,
- description: templateDetail?.spec?.description
+ const templateDetail = templateSource?.templateYaml;
+ const metaData = {
+ title: templateDetail?.spec?.title || '',
+ keywords: templateDetail?.spec?.description || '',
+ description: templateDetail?.spec?.description || ''
};
- const readme = templateDetail?.spec?.i18n?.[local]?.readme ?? templateDetail?.spec?.readme;
- readUrl = readme;
- readmeContent = await (await fetch(readme)).text();
- } catch (error) {}
-
- return {
- props: {
- appName,
- metaData,
- brandName,
- readmeContent,
- readUrl,
- ...(await serviceSideProps(content))
- }
- };
+ const readUrl =
+ templateDetail?.spec?.i18n?.[local]?.readme || templateDetail?.spec?.readme || '';
+ const readmeContent = readUrl ? await fetchReadmeContent(readUrl) : '';
+
+ return {
+ props: {
+ appName,
+ metaData,
+ brandName,
+ readmeContent,
+ readUrl,
+ ...(await serviceSideProps(content))
+ }
+ };
+ } catch (error) {
+ console.log('Error in getServerSideProps:', error);
+
+ return {
+ props: {
+ appName,
+ metaData: { title: appName, keywords: '', description: '' },
+ brandName,
+ readmeContent: '',
+ readUrl: '',
+ ...(await serviceSideProps(content))
+ }
+ };
+ }
}
diff --git a/frontend/providers/template/src/pages/index.tsx b/frontend/providers/template/src/pages/index.tsx
index 7484088f1d8..00c1f5b80c4 100644
--- a/frontend/providers/template/src/pages/index.tsx
+++ b/frontend/providers/template/src/pages/index.tsx
@@ -276,7 +276,7 @@ export default function AppList({
// https://nextjs.org/docs/pages/api-reference/functions/get-server-side-props#context-parameter
export async function getServerSideProps(content: any) {
const forcedLanguage = process.env.FORCED_LANGUAGE;
- const brandName = process.env.NEXT_PUBLIC_BRAND_NAME;
+ const brandName = process.env.NEXT_PUBLIC_BRAND_NAME || 'Sealos';
const local =
forcedLanguage ||
content?.req?.cookies?.NEXT_LOCALE ||