Use env vars
This commit is contained in:
9
.env.template
Normal file
9
.env.template
Normal file
@@ -0,0 +1,9 @@
|
||||
PORT = 3000
|
||||
ALLOWED_HOSTS =
|
||||
|
||||
VITE_SERVER_URL_DEFAULT = http://localhost:4567
|
||||
|
||||
CODEGEN_SERVER_URL_GQL = http://localhost:4567/api/graphql
|
||||
|
||||
GITHUB_TOKEN =
|
||||
WEBLATE_TOKEN =
|
||||
2
.github/workflows/update_i18n_languages.yml
vendored
2
.github/workflows/update_i18n_languages.yml
vendored
@@ -41,5 +41,5 @@ jobs:
|
||||
- name: Update i18n resources
|
||||
run: |
|
||||
cd master
|
||||
echo '{"weblateToken": "${{ secrets.WEBLATE_TOKEN }}"}' > tools/scripts/tokens.json
|
||||
echo "WEBLATE_TOKEN=${{ secrets.MY_SECRET }}" > .env
|
||||
yarn i18n:gen-resources
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,6 +6,4 @@ node_modules/
|
||||
|
||||
build/*
|
||||
|
||||
tools/scripts/tokens.json
|
||||
|
||||
src/lib/graphql/schema.json
|
||||
@@ -7,10 +7,12 @@
|
||||
*/
|
||||
|
||||
import type { CodegenConfig } from '@graphql-codegen/cli';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import 'dotenv/config';
|
||||
|
||||
const config: CodegenConfig = {
|
||||
overwrite: true,
|
||||
schema: 'http://localhost:4567/api/graphql',
|
||||
schema: process.env.CODEGEN_SERVER_URL_GQL,
|
||||
documents: [
|
||||
'src/lib/graphql/queries/**',
|
||||
'src/lib/graphql/mutations/**',
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
"@typescript-eslint/parser": "7.16.1",
|
||||
"@vitejs/plugin-legacy": "7.0.0",
|
||||
"@vitejs/plugin-react-swc": "3.10.2",
|
||||
"dotenv": "17.2.1",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-airbnb": "19.0.4",
|
||||
"eslint-config-airbnb-typescript": "18.0.0",
|
||||
|
||||
@@ -14,11 +14,7 @@ export abstract class BaseClient<Client, ClientConfig, Fetcher> {
|
||||
public abstract readonly fetcher: Fetcher;
|
||||
|
||||
public getBaseUrl(): string {
|
||||
const { hostname, port, protocol } = window.location;
|
||||
|
||||
// if port is 3000 it's probably running from webpack development server
|
||||
const inferredPort = import.meta.env.DEV && port === '3000' ? '4567' : port;
|
||||
return AppStorage.local.getItemParsed('serverBaseURL', `${protocol}//${hostname}:${inferredPort}`);
|
||||
return AppStorage.local.getItemParsed('serverBaseURL', import.meta.env.VITE_SERVER_URL_DEFAULT);
|
||||
}
|
||||
|
||||
public abstract updateConfig(config: Partial<ClientConfig>): void;
|
||||
|
||||
@@ -99,7 +99,10 @@ export const ServerSettings = () => {
|
||||
});
|
||||
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||
|
||||
const [serverAddress, setServerAddress] = useLocalStorage<string>('serverBaseURL', window.location.origin);
|
||||
const [serverAddress, setServerAddress] = useLocalStorage<string>(
|
||||
'serverBaseURL',
|
||||
import.meta.env.VITE_SERVER_URL_DEFAULT,
|
||||
);
|
||||
|
||||
const handleServerAddressChange = (address: string) => {
|
||||
const serverBaseUrl = address.replaceAll(/(\/)+$/g, '');
|
||||
|
||||
@@ -32,7 +32,7 @@ import { TTrackerSearch } from '@/modules/tracker/Tracker.types.ts';
|
||||
export const SettingsTrackerCard = ({ tracker }: { tracker: TTrackerSearch }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [serverAddress] = useLocalStorage('serverBaseURL', window.location.origin);
|
||||
const [serverAddress] = useLocalStorage('serverBaseURL', import.meta.env.VITE_SERVER_URL_DEFAULT);
|
||||
|
||||
const [loginTrackerCredentials, { loading: isCredentialLoginInProgress }] =
|
||||
requestManager.useLoginToTrackerCredentials();
|
||||
|
||||
15
src/vite-env.d.ts
vendored
15
src/vite-env.d.ts
vendored
@@ -7,3 +7,18 @@
|
||||
*/
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ViteTypeOptions {
|
||||
// By adding this line, you can make the type of ImportMetaEnv strict
|
||||
// to disallow unknown keys.
|
||||
strictImportMetaEnv: unknown;
|
||||
}
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_SERVER_URL_DEFAULT: string;
|
||||
// more env variables...
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import tokens from '../tokens.json';
|
||||
import 'dotenv/config';
|
||||
|
||||
type GithubAuthor = {
|
||||
name: string;
|
||||
@@ -115,7 +115,7 @@ const fetchCommits = async (
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${tokens.githubToken}`,
|
||||
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||
},
|
||||
body: JSON.stringify({ query, variables }),
|
||||
})
|
||||
|
||||
@@ -10,7 +10,6 @@ import path from 'path';
|
||||
import fs from 'fs';
|
||||
import readline from 'readline';
|
||||
import { ControlledPromise } from '@/lib/ControlledPromise.ts';
|
||||
import tokens from '../tokens.json';
|
||||
import {
|
||||
ActionByTranslationUrlByUserUrl,
|
||||
ContributionsByLanguage,
|
||||
@@ -74,25 +73,23 @@ const extractContributionInfoFromChanges = (
|
||||
|
||||
const getUsernameByUserUrlMap = async (
|
||||
userUrlsByTranslationUrl: UserUrlsByTranslationUrl,
|
||||
authToken: string,
|
||||
): Promise<Record<string, string>> =>
|
||||
Object.fromEntries(
|
||||
(await Promise.all(
|
||||
Object.values(userUrlsByTranslationUrl)
|
||||
.flat()
|
||||
.map(async (userUrl) => [userUrl, await getUsername(userUrl, authToken)]),
|
||||
.map(async (userUrl) => [userUrl, await getUsername(userUrl)]),
|
||||
)) satisfies [string, string][],
|
||||
);
|
||||
|
||||
const getLanguageNameByTranslationUrl = async (
|
||||
userUrlsByTranslationUrl: UserUrlsByTranslationUrl,
|
||||
authToken: string,
|
||||
): Promise<LanguageNameByTranslationUrl> =>
|
||||
Object.fromEntries(
|
||||
(await Promise.all(
|
||||
Object.keys(userUrlsByTranslationUrl)
|
||||
.flat()
|
||||
.map(async (translationUrl) => [translationUrl, await getLanguageName(translationUrl, authToken)]),
|
||||
.map(async (translationUrl) => [translationUrl, await getLanguageName(translationUrl)]),
|
||||
)) satisfies [string, string][],
|
||||
);
|
||||
|
||||
@@ -129,8 +126,8 @@ const doesLanguageOfChangeMeetTranslatePercentThreshold = (
|
||||
return meetsTranslatedPercentThreshold(langaugeStats.translated_percent);
|
||||
};
|
||||
|
||||
const getContributorsForRange = async (url: string, authToken: string): Promise<ContributionsByLanguage> => {
|
||||
const weblateChanges = await fetchWeblateChanges(url, authToken);
|
||||
const getContributorsForRange = async (url: string): Promise<ContributionsByLanguage> => {
|
||||
const weblateChanges = await fetchWeblateChanges(url);
|
||||
const weblateLanguageStats = await fetchWeblateLanguageStats();
|
||||
|
||||
const validWeblateChanges = weblateChanges.filter((change) =>
|
||||
@@ -147,8 +144,8 @@ const getContributorsForRange = async (url: string, authToken: string): Promise<
|
||||
const { userUrlsByTranslationUrl, actionsByTranslationUrlByUserUrl } =
|
||||
extractContributionInfoFromChanges(validWeblateChanges);
|
||||
|
||||
const usernameByUserUrl = await getUsernameByUserUrlMap(userUrlsByTranslationUrl, authToken);
|
||||
const languageNameByTranslationUrl = await getLanguageNameByTranslationUrl(userUrlsByTranslationUrl, authToken);
|
||||
const usernameByUserUrl = await getUsernameByUserUrlMap(userUrlsByTranslationUrl);
|
||||
const languageNameByTranslationUrl = await getLanguageNameByTranslationUrl(userUrlsByTranslationUrl);
|
||||
|
||||
return getUserContributionByLanguage(
|
||||
userUrlsByTranslationUrl,
|
||||
@@ -238,7 +235,7 @@ export const createTranslationChangelog = async (
|
||||
|
||||
const url = `https://hosted.weblate.org/api/components/suwayomi/suwayomi-webui/changes/?timestamp_after=${timestampAfter}×tamp_before=${timestampBefore}&${creditRelevantActions.map((action) => `action=${action}`).join('&')}`;
|
||||
|
||||
const contributorsForRange = await getContributorsForRange(url, tokens.weblateToken);
|
||||
const contributorsForRange = await getContributorsForRange(url);
|
||||
const knownContributorsByLanguage = await getKnownContributorsByLanguage();
|
||||
|
||||
const contributionInfo: { language: string; contributors: string[] }[] = Object.entries(contributorsForRange).map(
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"githubToken": "",
|
||||
"weblateToken": ""
|
||||
}
|
||||
@@ -13,14 +13,14 @@ import {
|
||||
WeblateLanguageStatistic,
|
||||
WeblateUserPayload,
|
||||
} from '@/../tools/scripts/weblate/Weblate.types.ts';
|
||||
import tokens from '../tokens.json';
|
||||
import 'dotenv/config';
|
||||
import { TRANSLATED_PERCENT_THRESHOLD } from '@/../tools/scripts/weblate/Weblate.constants.ts';
|
||||
|
||||
export const fetchData = async <T = any>(url: string, authToken: string): Promise<T> => {
|
||||
export const fetchData = async <T = any>(url: string): Promise<T> => {
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Token ${authToken}`,
|
||||
...(process.env.WEBLATE_TOKEN ? { Authorization: `Token ${process.env.WEBLATE_TOKEN}` } : {}),
|
||||
Accept: 'application/json',
|
||||
},
|
||||
});
|
||||
@@ -34,36 +34,29 @@ export const fetchData = async <T = any>(url: string, authToken: string): Promis
|
||||
|
||||
export const fetchWeblateChanges = async (
|
||||
url: string,
|
||||
authToken: string,
|
||||
weblateChangeResults: WeblateChangeResult[] = [],
|
||||
): Promise<WeblateChangeResult[]> => {
|
||||
const weblateChangePage = await fetchData<WeblateChangePayload>(url, authToken);
|
||||
const weblateChangePage = await fetchData<WeblateChangePayload>(url);
|
||||
|
||||
if (!weblateChangePage.next) {
|
||||
return [...weblateChangePage.results, ...weblateChangeResults];
|
||||
}
|
||||
|
||||
return fetchWeblateChanges(weblateChangePage.next, authToken, [
|
||||
...weblateChangePage.results,
|
||||
...weblateChangeResults,
|
||||
]);
|
||||
return fetchWeblateChanges(weblateChangePage.next, [...weblateChangePage.results, ...weblateChangeResults]);
|
||||
};
|
||||
|
||||
export const getUsername = async (url: string, authToken: string): Promise<string> => {
|
||||
const userPayload = await fetchData<WeblateUserPayload>(url, authToken);
|
||||
export const getUsername = async (url: string): Promise<string> => {
|
||||
const userPayload = await fetchData<WeblateUserPayload>(url);
|
||||
return userPayload.full_name;
|
||||
};
|
||||
|
||||
export const getLanguageName = async (url: string, authToken: string): Promise<string> => {
|
||||
const languagePayload = await fetchData<WeblateLanguagePayload>(url, authToken);
|
||||
export const getLanguageName = async (url: string): Promise<string> => {
|
||||
const languagePayload = await fetchData<WeblateLanguagePayload>(url);
|
||||
return languagePayload.language.name.replace(/\(([a-zA-Z]+) Han script\)/g, '($1)');
|
||||
};
|
||||
|
||||
export const fetchWeblateLanguageStats = async () =>
|
||||
fetchData(
|
||||
'https://hosted.weblate.org/api/components/suwayomi/suwayomi-webui/statistics/?format=json-flat',
|
||||
tokens.weblateToken,
|
||||
);
|
||||
fetchData('https://hosted.weblate.org/api/components/suwayomi/suwayomi-webui/statistics/?format=json-flat');
|
||||
|
||||
const dateRegex = /[0-9]{4}-[0-9]{2}-[0-9]{2}/g;
|
||||
const isValidIS08601Date = (date: string): boolean => !!date.match(dateRegex);
|
||||
|
||||
@@ -14,6 +14,7 @@ import react from '@vitejs/plugin-react-swc';
|
||||
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
||||
import legacy from '@vitejs/plugin-legacy';
|
||||
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||
import 'dotenv/config';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default defineConfig(() => ({
|
||||
@@ -21,7 +22,8 @@ export default defineConfig(() => ({
|
||||
outDir: 'build',
|
||||
},
|
||||
server: {
|
||||
port: 3000,
|
||||
port: Number(process.env.PORT),
|
||||
allowedHosts: process.env.ALLOWED_HOSTS.split(','),
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
@@ -4511,6 +4511,11 @@ dot-case@^3.0.4:
|
||||
no-case "^3.0.4"
|
||||
tslib "^2.0.3"
|
||||
|
||||
dotenv@17.2.1:
|
||||
version "17.2.1"
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.2.1.tgz#6f32e10faf014883515538dc922a0fb8765d9b32"
|
||||
integrity sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==
|
||||
|
||||
dotenv@^16.0.0:
|
||||
version "16.4.5"
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
|
||||
|
||||
Reference in New Issue
Block a user