diff --git a/web/web/public/icons/git-fork.svg b/web/web/public/icons/git-fork.svg
new file mode 100644
index 00000000000..0a1d7806591
--- /dev/null
+++ b/web/web/public/icons/git-fork.svg
@@ -0,0 +1,20 @@
+
+
+
diff --git a/web/web/public/icons/github-mark.svg b/web/web/public/icons/github-mark.svg
new file mode 100644
index 00000000000..13ad84ec591
--- /dev/null
+++ b/web/web/public/icons/github-mark.svg
@@ -0,0 +1,20 @@
+
+
+
diff --git a/web/web/src/app/rootLayout/AppBar.js b/web/web/src/app/rootLayout/AppBar.js
index c4917d58eee..1851b6bc405 100644
--- a/web/web/src/app/rootLayout/AppBar.js
+++ b/web/web/src/app/rootLayout/AppBar.js
@@ -41,6 +41,7 @@ import clsx from 'clsx'
import VersionView from './VersionView'
import LogoutButton from './Logout'
+import GitHubInfo from './GitHubInfo'
import { useSearchParams } from 'next/navigation'
import { useRouter } from 'next/navigation'
import { useAppSelector, useAppDispatch } from '@/lib/hooks/useStore'
@@ -94,6 +95,7 @@ const AppBar = () => {
>
Gravitino
+
@@ -135,7 +137,7 @@ const AppBar = () => {
) : null}
-
+
diff --git a/web/web/src/app/rootLayout/GitHubInfo.js b/web/web/src/app/rootLayout/GitHubInfo.js
new file mode 100644
index 00000000000..50744302b9d
--- /dev/null
+++ b/web/web/src/app/rootLayout/GitHubInfo.js
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Link from 'next/link'
+import Image from 'next/image'
+import { Box, Typography } from '@mui/material'
+import { Star } from '@mui/icons-material'
+import { useAppSelector } from '@/lib/hooks/useStore'
+
+const GitHubInfo = () => {
+ const githubUrl = 'https://github.com/apache/gravitino'
+ const githubForkUrl = 'https://github.com/apache/gravitino/fork'
+ const githubLogoUrl = (process.env.NEXT_PUBLIC_BASE_PATH ?? '') + '/icons/github-mark.svg'
+ const forkLogoUrl = (process.env.NEXT_PUBLIC_BASE_PATH ?? '') + '/icons/git-fork.svg'
+ const store = useAppSelector(state => state.sys)
+
+ return (
+
+
+
+
+
+
+
+
+ {store.forks} Forks
+
+
+
+
+
+ {store.stars} Stars
+
+
+
+
+ )
+}
+
+export default GitHubInfo
diff --git a/web/web/src/app/rootLayout/VersionView.js b/web/web/src/app/rootLayout/VersionView.js
index 70ba6990398..0f3d39b357d 100644
--- a/web/web/src/app/rootLayout/VersionView.js
+++ b/web/web/src/app/rootLayout/VersionView.js
@@ -26,7 +26,7 @@ const VersionView = () => {
const store = useAppSelector(state => state.sys)
return (
-
+
{store.version}
)
diff --git a/web/web/src/lib/api/github/index.js b/web/web/src/lib/api/github/index.js
new file mode 100644
index 00000000000..456316221d0
--- /dev/null
+++ b/web/web/src/lib/api/github/index.js
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { defHttp } from '@/lib/utils/axios'
+
+const githubApis = {
+ GET: 'https://api.github.com/repos/apache/gravitino'
+}
+
+export const getGitHubApi = () => {
+ return defHttp.get({
+ url: `${githubApis.GET}`,
+ headers: {
+ Accept: 'application/vnd.github+json'
+ }
+ })
+}
diff --git a/web/web/src/lib/provider/session.js b/web/web/src/lib/provider/session.js
index 1c9858f9965..5247987c24e 100644
--- a/web/web/src/lib/provider/session.js
+++ b/web/web/src/lib/provider/session.js
@@ -25,7 +25,7 @@ import { useRouter } from 'next/navigation'
import { useSearchParams } from 'next/navigation'
import { useAppDispatch } from '@/lib/hooks/useStore'
-import { initialVersion } from '@/lib/store/sys'
+import { initialVersion, fetchGitHubInfo } from '@/lib/store/sys'
import { to } from '../utils'
import { getAuthConfigs, setAuthToken } from '../store/auth'
@@ -78,11 +78,13 @@ const AuthProvider = ({ children }) => {
if (authType === 'simple') {
dispatch(initialVersion())
+ dispatch(fetchGitHubInfo())
goToMetalakeListPage()
} else if (authType === 'oauth') {
if (token) {
dispatch(setAuthToken(token))
dispatch(initialVersion())
+ dispatch(fetchGitHubInfo())
goToMetalakeListPage()
} else {
router.push('/login')
diff --git a/web/web/src/lib/store/sys/index.js b/web/web/src/lib/store/sys/index.js
index 475063f8a76..cb7eb605041 100644
--- a/web/web/src/lib/store/sys/index.js
+++ b/web/web/src/lib/store/sys/index.js
@@ -19,10 +19,12 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
-import { loggerVersion, to } from '@/lib/utils'
+import { loggerVersion, to, formatNumber, loggerGitHubInfo } from '@/lib/utils'
import { getVersionApi } from '@/lib/api/version'
+import { getGitHubApi } from '@/lib/api/github'
+
export const initialVersion = createAsyncThunk('sys/fetchVersion', async (params, { getState }) => {
let version = null
const [err, res] = await to(getVersionApi())
@@ -39,23 +41,54 @@ export const initialVersion = createAsyncThunk('sys/fetchVersion', async (params
return version
})
+export const fetchGitHubInfo = createAsyncThunk('sys/fetchGitHubInfo', async (params, { getState }) => {
+ let stars = 0
+ let forks = 0
+ const [err, res] = await to(getGitHubApi())
+ if (err || !res) {
+ console.error('Error fetching repository status : ', err)
+ }
+
+ stars = formatNumber(res.stargazers_count)
+ forks = formatNumber(res.forks_count)
+ loggerGitHubInfo(stars, forks)
+
+ return {
+ stars: stars,
+ forks: forks
+ }
+})
+
export const sysSlice = createSlice({
name: 'sys',
initialState: {
- version: ''
+ version: '',
+ stars: 0,
+ forks: 0
},
reducers: {
setVersion(state, action) {
state.version = action.payload
+ },
+ setStars(state, action) {
+ state.stars = action.payload
+ },
+ setForks(state, action) {
+ state.forks = action.payload
}
},
extraReducers: builder => {
- builder.addCase(initialVersion.fulfilled, (state, action) => {
- state.version = action.payload.version
- })
+ builder
+ .addCase(initialVersion.fulfilled, (state, action) => {
+ state.version = action.payload.version
+ })
+ .addCase(fetchGitHubInfo.fulfilled, (state, action) => {
+ state.stars = action.payload.stars
+ state.forks = action.payload.forks
+ })
}
})
-export const { setVersion } = sysSlice.actions
+export const { setVersion, setStars, setForks } = sysSlice.actions
export default sysSlice.reducer
diff --git a/web/web/src/lib/utils/index.js b/web/web/src/lib/utils/index.js
index 17444dfa80e..8b41db98a67 100644
--- a/web/web/src/lib/utils/index.js
+++ b/web/web/src/lib/utils/index.js
@@ -45,6 +45,13 @@ export const loggerVersion = version => {
)
}
+export const loggerGitHubInfo = (stars, forks) => {
+ console.log(
+ `Gravitino GitHubInfo: %c Stars ${stars}, Forks ${forks}`,
+ `color: white; background-color: #6062E0; padding: 2px; border-radius: 4px;`
+ )
+}
+
export const genUpdates = (originalData, newData) => {
const updates = []
@@ -227,3 +234,13 @@ export const findInTree = (tree, key, value) => {
return result
}
+
+export const formatNumber = num => {
+ if (num >= 1000000) {
+ return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'm'
+ } else if (num >= 1000) {
+ return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'k'
+ }
+
+ return num.toString()
+}