forked from cerc-io/snowballtools-base
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c433ce0e27 |
@@ -21,4 +21,3 @@ yarn build --ignore frontend
|
|||||||
### Environment variables, running the development server, and deployment
|
### Environment variables, running the development server, and deployment
|
||||||
|
|
||||||
Follow the instructions in the README.md files of the [backend](packages/backend/README.md) and [frontend](packages/frontend/README.md) packages.
|
Follow the instructions in the README.md files of the [backend](packages/backend/README.md) and [frontend](packages/frontend/README.md) packages.
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ yarn start
|
|||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Clone the [deployer repository](https://git.vdb.to/cerc-io/snowballtools-base-api-deployments):
|
Clone the deployer repository:
|
||||||
|
|
||||||
```zsh
|
```zsh
|
||||||
git clone git@git.vdb.to:cerc-io/snowballtools-base-api-deployments.git
|
git clone git@git.vdb.to:cerc-io/snowballtools-base-api-deployments.git
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
port = 8000
|
port = 8000
|
||||||
gqlPath = "/graphql"
|
gqlPath = "/graphql"
|
||||||
[server.session]
|
[server.session]
|
||||||
secret = ""
|
secret = "p4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi"
|
||||||
appOriginUrl = "http://localhost:3000"
|
appOriginUrl = "http://localhost:3000"
|
||||||
trustProxy = false
|
trustProxy = false
|
||||||
domain = "localhost"
|
domain = "localhost"
|
||||||
@@ -17,16 +17,6 @@
|
|||||||
clientId = ""
|
clientId = ""
|
||||||
clientSecret = ""
|
clientSecret = ""
|
||||||
|
|
||||||
[google]
|
|
||||||
clientId = ""
|
|
||||||
clientSecret = ""
|
|
||||||
|
|
||||||
[turnkey]
|
|
||||||
apiBaseUrl = "https://api.turnkey.com"
|
|
||||||
apiPrivateKey = ""
|
|
||||||
apiPublicKey = ""
|
|
||||||
defaultOrganizationId = ""
|
|
||||||
|
|
||||||
[registryConfig]
|
[registryConfig]
|
||||||
fetchDeploymentRecordDelay = 5000
|
fetchDeploymentRecordDelay = 5000
|
||||||
restEndpoint = "http://localhost:1317"
|
restEndpoint = "http://localhost:1317"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Router } from 'express';
|
|||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get('/version', async (req, res) => {
|
router.get('/version', async (req, res) => {
|
||||||
return res.send({ version: '0.0.9' });
|
return res.send({ version: '0.0.8' });
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ record:
|
|||||||
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com
|
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com
|
||||||
LACONIC_HOSTED_CONFIG_turnkey_organization_id: 5049ae99-5bca-40b3-8317-504384d4e591
|
LACONIC_HOSTED_CONFIG_turnkey_organization_id: 5049ae99-5bca-40b3-8317-504384d4e591
|
||||||
meta:
|
meta:
|
||||||
note: Added by Snowball @ Mon Jun 24 23:51:48 UTC 2024
|
note: Added by Snowball @ Sat Jun 22 02:49:45 UTC 2024
|
||||||
repository: "https://git.vdb.to/cerc-io/snowballtools-base"
|
repository: "https://git.vdb.to/cerc-io/snowballtools-base"
|
||||||
repository_ref: 61e3e88a6c9d57e95441059369ee5a46f5c07601
|
repository_ref: 61e3e88a6c9d57e95441059369ee5a46f5c07601
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ yarn dev
|
|||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
From the root of the project,
|
From the root of the project, run:
|
||||||
|
|
||||||
- check if the [gittea repository mirror](https://git.vdb.to/cerc-io/snowballtools-base) is up to date
|
|
||||||
|
|
||||||
### Staging
|
### Staging
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-dropdown": "^1.11.0",
|
"react-dropdown": "^1.11.0",
|
||||||
"react-hook-form": "^7.49.0",
|
"react-hook-form": "^7.49.0",
|
||||||
|
"react-hot-toast": "^2.4.1",
|
||||||
"react-oauth-popup": "^1.0.5",
|
"react-oauth-popup": "^1.0.5",
|
||||||
"react-router-dom": "^6.20.1",
|
"react-router-dom": "^6.20.1",
|
||||||
"react-timer-hook": "^3.0.7",
|
"react-timer-hook": "^3.0.7",
|
||||||
|
|||||||
+16
-18
@@ -100,24 +100,22 @@ export const ProjectSearchBarDialog = ({
|
|||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{items.length > 0 ? (
|
{items.length > 0
|
||||||
<>
|
? items.map((item, index) => (
|
||||||
<div className="px-2 py-2">
|
<>
|
||||||
<p className="text-elements-mid-em text-xs font-medium">
|
<div className="px-2 py-2">
|
||||||
Suggestions
|
<p className="text-elements-mid-em text-xs font-medium">
|
||||||
</p>
|
Suggestions
|
||||||
</div>
|
</p>
|
||||||
{items.map((item, index) => (
|
</div>
|
||||||
<ProjectSearchBarItem
|
<ProjectSearchBarItem
|
||||||
key={item.id}
|
key={item.id}
|
||||||
item={item}
|
item={item}
|
||||||
{...getItemProps({ item, index })}
|
{...getItemProps({ item, index })}
|
||||||
/>
|
/>
|
||||||
))}
|
</>
|
||||||
</>
|
))
|
||||||
) : (
|
: inputValue && <ProjectSearchBarEmpty />}
|
||||||
inputValue && <ProjectSearchBarEmpty />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog.Content>
|
</Dialog.Content>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
|||||||
import { Domain, DomainStatus, Project } from 'gql-client';
|
import { Domain, DomainStatus, Project } from 'gql-client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
Chip,
|
||||||
Typography,
|
Typography,
|
||||||
Menu,
|
Menu,
|
||||||
MenuHandler,
|
MenuHandler,
|
||||||
@@ -14,15 +15,6 @@ import EditDomainDialog from './EditDomainDialog';
|
|||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from 'context/GQLClientContext';
|
||||||
import { DeleteDomainDialog } from 'components/projects/Dialog/DeleteDomainDialog';
|
import { DeleteDomainDialog } from 'components/projects/Dialog/DeleteDomainDialog';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
import { Tag } from 'components/shared/Tag';
|
|
||||||
import {
|
|
||||||
CheckIcon,
|
|
||||||
CrossIcon,
|
|
||||||
GearIcon,
|
|
||||||
LoadingIcon,
|
|
||||||
} from 'components/shared/CustomIcon';
|
|
||||||
import { Heading } from 'components/shared/Heading';
|
|
||||||
import { Button } from 'components/shared/Button';
|
|
||||||
|
|
||||||
enum RefreshStatus {
|
enum RefreshStatus {
|
||||||
IDLE,
|
IDLE,
|
||||||
@@ -87,29 +79,22 @@ const DomainCard = ({
|
|||||||
<>
|
<>
|
||||||
<div className="flex justify-between py-3">
|
<div className="flex justify-between py-3">
|
||||||
<div className="flex justify-start gap-1">
|
<div className="flex justify-start gap-1">
|
||||||
<Heading as="h6" className="flex-col">
|
<Typography variant="h6">
|
||||||
{domain.name}{' '}
|
<i>^</i> {domain.name}
|
||||||
<Tag
|
</Typography>
|
||||||
type={
|
<Chip
|
||||||
domain.status === DomainStatus.Live ? 'positive' : 'negative'
|
className="w-fit capitalize"
|
||||||
}
|
value={domain.status}
|
||||||
leftIcon={
|
color={domain.status === DomainStatus.Live ? 'green' : 'orange'}
|
||||||
domain.status === DomainStatus.Live ? (
|
variant="ghost"
|
||||||
<CheckIcon />
|
icon={<i>^</i>}
|
||||||
) : (
|
/>
|
||||||
<CrossIcon />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{domain.status}
|
|
||||||
</Tag>
|
|
||||||
</Heading>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-start gap-1">
|
<div className="flex justify-start gap-1">
|
||||||
<i
|
<i
|
||||||
id="refresh"
|
id="refresh"
|
||||||
className="cursor-pointer"
|
className="cursor-pointer w-8 h-8"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
SetRefreshStatus(RefreshStatus.CHECKING);
|
SetRefreshStatus(RefreshStatus.CHECKING);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -117,17 +102,11 @@ const DomainCard = ({
|
|||||||
}, CHECK_FAIL_TIMEOUT);
|
}, CHECK_FAIL_TIMEOUT);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{refreshStatus === RefreshStatus.CHECKING ? (
|
{refreshStatus === RefreshStatus.CHECKING ? 'L' : 'R'}
|
||||||
<LoadingIcon className="animate-spin" />
|
|
||||||
) : (
|
|
||||||
'L'
|
|
||||||
)}
|
|
||||||
</i>
|
</i>
|
||||||
<Menu placement="bottom-end">
|
<Menu placement="bottom-end">
|
||||||
<MenuHandler>
|
<MenuHandler>
|
||||||
<Button iconOnly>
|
<button className="border-2 rounded-full w-8 h-8">...</button>
|
||||||
<GearIcon />
|
|
||||||
</Button>
|
|
||||||
</MenuHandler>
|
</MenuHandler>
|
||||||
<MenuList>
|
<MenuList>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@@ -164,13 +143,13 @@ const DomainCard = ({
|
|||||||
{domain.status === DomainStatus.Pending && (
|
{domain.status === DomainStatus.Pending && (
|
||||||
<Card className="bg-slate-100 p-4 text-sm">
|
<Card className="bg-slate-100 p-4 text-sm">
|
||||||
{refreshStatus === RefreshStatus.IDLE ? (
|
{refreshStatus === RefreshStatus.IDLE ? (
|
||||||
<Heading>
|
<Typography variant="small">
|
||||||
^ Add these records to your domain and refresh to check
|
^ Add these records to your domain and refresh to check
|
||||||
</Heading>
|
</Typography>
|
||||||
) : refreshStatus === RefreshStatus.CHECKING ? (
|
) : refreshStatus === RefreshStatus.CHECKING ? (
|
||||||
<Heading className="text-blue-500">
|
<Typography variant="small" className="text-blue-500">
|
||||||
^ Checking records for {domain.name}
|
^ Checking records for {domain.name}
|
||||||
</Heading>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex gap-2 text-red-500 mb-2">
|
<div className="flex gap-2 text-red-500 mb-2">
|
||||||
<div className="grow">
|
<div className="grow">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { Controller, useForm, SubmitHandler } from 'react-hook-form';
|
import { Controller, useForm, SubmitHandler } from 'react-hook-form';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
import { Domain } from 'gql-client';
|
import { Domain } from 'gql-client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -8,11 +9,10 @@ import {
|
|||||||
Option,
|
Option,
|
||||||
} from '@snowballtools/material-tailwind-react-fork';
|
} from '@snowballtools/material-tailwind-react-fork';
|
||||||
|
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||||
import { Modal } from 'components/shared/Modal';
|
import { Modal } from 'components/shared/Modal';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { Input } from 'components/shared/Input';
|
import { Input } from 'components/shared/Input';
|
||||||
import { useToast } from 'components/shared/Toast';
|
|
||||||
|
|
||||||
const DEFAULT_REDIRECT_OPTIONS = ['none'];
|
const DEFAULT_REDIRECT_OPTIONS = ['none'];
|
||||||
|
|
||||||
@@ -40,7 +40,6 @@ const EditDomainDialog = ({
|
|||||||
onUpdate,
|
onUpdate,
|
||||||
}: EditDomainDialogProp) => {
|
}: EditDomainDialogProp) => {
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
const { toast, dismiss } = useToast();
|
|
||||||
|
|
||||||
const getRedirectUrl = (domain: Domain) => {
|
const getRedirectUrl = (domain: Domain) => {
|
||||||
const redirectDomain = domain.redirectTo;
|
const redirectDomain = domain.redirectTo;
|
||||||
@@ -100,20 +99,10 @@ const EditDomainDialog = ({
|
|||||||
|
|
||||||
if (updateDomain) {
|
if (updateDomain) {
|
||||||
await onUpdate();
|
await onUpdate();
|
||||||
toast({
|
toast.success(`Domain ${domain.name} has been updated`);
|
||||||
id: 'domain_id_updated',
|
|
||||||
title: `Domain ${domain.name} has been updated`,
|
|
||||||
variant: 'success',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
reset();
|
reset();
|
||||||
toast({
|
toast.error(`Error updating domain ${domain.name}`);
|
||||||
id: 'domain_id_error_update',
|
|
||||||
title: `Error updating domain ${domain.name}`,
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOpen();
|
handleOpen();
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import { useState } from 'react';
|
|||||||
import { DeleteWebhookDialog } from 'components/projects/Dialog/DeleteWebhookDialog';
|
import { DeleteWebhookDialog } from 'components/projects/Dialog/DeleteWebhookDialog';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
import { Input } from 'components/shared/Input';
|
|
||||||
import { CopyIcon, TrashIcon } from 'components/shared/CustomIcon';
|
|
||||||
|
|
||||||
interface WebhookCardProps {
|
interface WebhookCardProps {
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
@@ -16,12 +14,11 @@ const WebhookCard = ({ webhookUrl, onDelete }: WebhookCardProps) => {
|
|||||||
|
|
||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-between w-full mb-3 gap-3">
|
<div className="flex justify-between w-full mb-3">
|
||||||
<Input value={webhookUrl} disabled />
|
{webhookUrl}
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<Button
|
<Button
|
||||||
iconOnly
|
size="sm"
|
||||||
size="md"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(webhookUrl);
|
navigator.clipboard.writeText(webhookUrl);
|
||||||
toast({
|
toast({
|
||||||
@@ -32,17 +29,16 @@ const WebhookCard = ({ webhookUrl, onDelete }: WebhookCardProps) => {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon />
|
Copy
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
iconOnly
|
size="sm"
|
||||||
size="md"
|
|
||||||
variant="danger"
|
variant="danger"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeleteDialogOpen(true);
|
setDeleteDialogOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TrashIcon />
|
X
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<DeleteWebhookDialog
|
<DeleteWebhookDialog
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
export { Avatar } from './Avatar';
|
|
||||||
export { Badge } from './Badge';
|
|
||||||
export { Button } from './Button';
|
|
||||||
export { Calendar } from './Calendar';
|
|
||||||
export { Checkbox } from './Checkbox';
|
|
||||||
export { DatePicker } from './DatePicker';
|
|
||||||
export { DotBorder } from './DotBorder';
|
|
||||||
export { Heading } from './Heading';
|
|
||||||
export { IconWithFrame } from './IconWithFrame';
|
|
||||||
export { InlineNotification } from './InlineNotification';
|
|
||||||
export { Input } from './Input';
|
|
||||||
export { Modal } from './Modal';
|
|
||||||
export { OverflownText } from './OverflownText';
|
|
||||||
export { Radio } from './Radio';
|
|
||||||
export { SegmentedControls } from './SegmentedControls';
|
|
||||||
export { Select } from './Select';
|
|
||||||
export { Sidebar } from './Sidebar';
|
|
||||||
export { Step } from './Steps';
|
|
||||||
export { Switch } from './Switch';
|
|
||||||
export { Table } from './Table';
|
|
||||||
export { Tabs } from './Tabs';
|
|
||||||
export { Tag } from './Tag';
|
|
||||||
export { useToast } from './Toast';
|
|
||||||
export { Tooltip } from './Tooltip';
|
|
||||||
export { UserSelect } from './UserSelect';
|
|
||||||
export { VerifyCodeInput } from './VerifyCodeInput';
|
|
||||||
export { WavyBorder } from './WavyBorder';
|
|
||||||
@@ -16,7 +16,8 @@ import { Toaster } from 'components/shared/Toast';
|
|||||||
import { LogErrorBoundary } from 'utils/log-error';
|
import { LogErrorBoundary } from 'utils/log-error';
|
||||||
import { baseUrl } from 'utils/constants';
|
import { baseUrl } from 'utils/constants';
|
||||||
|
|
||||||
console.log(`v-0.0.9`);
|
// @ts-ignore
|
||||||
|
console.log(`v-${__VERSION__}`);
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(
|
||||||
document.getElementById('root') as HTMLElement,
|
document.getElementById('root') as HTMLElement,
|
||||||
|
|||||||
@@ -1,19 +1,5 @@
|
|||||||
import { Heading } from 'components/shared/Heading';
|
|
||||||
|
|
||||||
const Settings = () => {
|
const Settings = () => {
|
||||||
return (
|
return <div className="p-5">Settings page</div>;
|
||||||
<section className="px-4 md:px-6 py-6 flex flex-col gap-6">
|
|
||||||
{/* Header */}
|
|
||||||
<div className="flex items-center">
|
|
||||||
<div className="grow">
|
|
||||||
<div className="flex gap-4 items-center">
|
|
||||||
<Heading as="h2" className="text-[24px]">
|
|
||||||
Settings
|
|
||||||
</Heading>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Settings;
|
export default Settings;
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { Link, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { ProjectCard } from 'components/projects/ProjectCard';
|
|
||||||
import { Heading, Badge, Button } from 'components/shared';
|
|
||||||
import { PlusIcon } from 'components/shared/CustomIcon';
|
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
|
||||||
import { Project } from 'gql-client';
|
import { Project } from 'gql-client';
|
||||||
|
import { Button } from 'components/shared/Button';
|
||||||
|
|
||||||
|
import { PlusIcon } from 'components/shared/CustomIcon';
|
||||||
|
import { ProjectCard } from 'components/projects/ProjectCard';
|
||||||
|
import { Heading } from 'components/shared/Heading';
|
||||||
|
import { Badge } from 'components/shared/Badge';
|
||||||
|
import { useGQLClient } from 'context/GQLClientContext';
|
||||||
|
|
||||||
const Projects = () => {
|
const Projects = () => {
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
@@ -26,7 +28,6 @@ const Projects = () => {
|
|||||||
return (
|
return (
|
||||||
<section className="px-4 md:px-6 py-6 flex flex-col gap-6">
|
<section className="px-4 md:px-6 py-6 flex flex-col gap-6">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
|
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="grow">
|
<div className="grow">
|
||||||
<div className="flex gap-4 items-center">
|
<div className="flex gap-4 items-center">
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Domain, DomainStatus } from 'gql-client';
|
||||||
import { Link, useNavigate, useOutletContext } from 'react-router-dom';
|
import { Link, useNavigate, useOutletContext } from 'react-router-dom';
|
||||||
import { RequestError } from 'octokit';
|
import { RequestError } from 'octokit';
|
||||||
|
|
||||||
import { useOctokit } from 'context/OctokitContext';
|
import { useOctokit } from '../../../../context/OctokitContext';
|
||||||
import { GitCommitWithBranch, OutletContextType } from '../../../../types';
|
import { GitCommitWithBranch, OutletContextType } from '../../../../types';
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||||
import { Button, Heading, Avatar, Tag } from 'components/shared';
|
import { Button } from 'components/shared/Button';
|
||||||
|
import { Heading } from 'components/shared/Heading';
|
||||||
|
import { Avatar } from 'components/shared/Avatar';
|
||||||
import { getInitials } from 'utils/geInitials';
|
import { getInitials } from 'utils/geInitials';
|
||||||
import {
|
import {
|
||||||
BranchStrokeIcon,
|
BranchStrokeIcon,
|
||||||
@@ -15,12 +18,12 @@ import {
|
|||||||
GithubStrokeIcon,
|
GithubStrokeIcon,
|
||||||
GlobeIcon,
|
GlobeIcon,
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
CalendarDaysIcon,
|
|
||||||
} from 'components/shared/CustomIcon';
|
} from 'components/shared/CustomIcon';
|
||||||
|
import { Tag } from 'components/shared/Tag';
|
||||||
import { Activity } from 'components/projects/project/overview/Activity';
|
import { Activity } from 'components/projects/project/overview/Activity';
|
||||||
import { OverviewInfo } from 'components/projects/project/overview/OverviewInfo';
|
import { OverviewInfo } from 'components/projects/project/overview/OverviewInfo';
|
||||||
|
import { CalendarDaysIcon } from 'components/shared/CustomIcon/CalendarDaysIcon';
|
||||||
import { relativeTimeMs } from 'utils/time';
|
import { relativeTimeMs } from 'utils/time';
|
||||||
import { Domain, DomainStatus } from 'gql-client';
|
|
||||||
|
|
||||||
const COMMITS_PER_PAGE = 4;
|
const COMMITS_PER_PAGE = 4;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useFieldArray, useForm } from 'react-hook-form';
|
import { useFieldArray, useForm } from 'react-hook-form';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { Environment, EnvironmentVariable } from 'gql-client';
|
||||||
|
|
||||||
import { Collapse } from '@snowballtools/material-tailwind-react-fork';
|
import { Collapse } from '@snowballtools/material-tailwind-react-fork';
|
||||||
|
|
||||||
import AddEnvironmentVariableRow from 'components/projects/project/settings/AddEnvironmentVariableRow';
|
import AddEnvironmentVariableRow from 'components/projects/project/settings/AddEnvironmentVariableRow';
|
||||||
import DisplayEnvironmentVariables from 'components/projects/project/settings/DisplayEnvironmentVariables';
|
import DisplayEnvironmentVariables from 'components/projects/project/settings/DisplayEnvironmentVariables';
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||||
import { EnvironmentVariablesFormValues } from '../../../../../types';
|
import { EnvironmentVariablesFormValues } from '../../../../../types';
|
||||||
import HorizontalLine from 'components/HorizontalLine';
|
import HorizontalLine from 'components/HorizontalLine';
|
||||||
import { Heading } from 'components/shared/Heading';
|
import { Heading } from 'components/shared/Heading';
|
||||||
@@ -15,13 +17,10 @@ import { Checkbox } from 'components/shared/Checkbox';
|
|||||||
import { PlusIcon } from 'components/shared/CustomIcon';
|
import { PlusIcon } from 'components/shared/CustomIcon';
|
||||||
import { InlineNotification } from 'components/shared/InlineNotification';
|
import { InlineNotification } from 'components/shared/InlineNotification';
|
||||||
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
import { useToast } from 'components/shared/Toast';
|
|
||||||
import { Environment, EnvironmentVariable } from 'gql-client';
|
|
||||||
|
|
||||||
export const EnvironmentVariablesTabPanel = () => {
|
export const EnvironmentVariablesTabPanel = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
const { toast, dismiss } = useToast();
|
|
||||||
|
|
||||||
const [environmentVariables, setEnvironmentVariables] = useState<
|
const [environmentVariables, setEnvironmentVariables] = useState<
|
||||||
EnvironmentVariable[]
|
EnvironmentVariable[]
|
||||||
@@ -119,25 +118,13 @@ export const EnvironmentVariablesTabPanel = () => {
|
|||||||
|
|
||||||
fetchEnvironmentVariables(id);
|
fetchEnvironmentVariables(id);
|
||||||
|
|
||||||
toast({
|
toast.success(
|
||||||
id:
|
createFormData.variables.length > 1
|
||||||
createFormData.variables.length > 1
|
? `${createFormData.variables.length} variables added`
|
||||||
? 'env_variable_added'
|
: `Variable added`,
|
||||||
: 'env_variables_added',
|
);
|
||||||
title:
|
|
||||||
createFormData.variables.length > 1
|
|
||||||
? `${createFormData.variables.length} variables added`
|
|
||||||
: `Variable added`,
|
|
||||||
variant: 'success',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
toast({
|
toast.error('Environment variables not added');
|
||||||
id: 'env_variables_not_added',
|
|
||||||
title: 'Environment variables not added',
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[id, client],
|
[id, client],
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
import toast from 'react-hot-toast';
|
||||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from '../../../../../../../context/GQLClientContext';
|
||||||
import { Table } from 'components/shared/Table';
|
import { Table } from 'components/shared/Table';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { InlineNotification } from 'components/shared/InlineNotification';
|
import { InlineNotification } from 'components/shared/InlineNotification';
|
||||||
import { ArrowRightCircleIcon } from 'components/shared/CustomIcon';
|
import { ArrowRightCircleIcon } from 'components/shared/CustomIcon';
|
||||||
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
import { useToast } from 'components/shared/Toast';
|
|
||||||
|
|
||||||
const Config = () => {
|
const Config = () => {
|
||||||
const { id, orgSlug } = useParams();
|
const { id, orgSlug } = useParams();
|
||||||
@@ -14,26 +14,15 @@ const Config = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const primaryDomainName = searchParams.get('name');
|
const primaryDomainName = searchParams.get('name');
|
||||||
const { toast, dismiss } = useToast();
|
|
||||||
|
|
||||||
const handleSubmitDomain = async () => {
|
const handleSubmitDomain = async () => {
|
||||||
if (primaryDomainName === null) {
|
if (primaryDomainName === null) {
|
||||||
toast({
|
toast.error('Cannot resolve domain name');
|
||||||
id: 'unresolvable_domain_name',
|
|
||||||
title: 'Cannot resolve domain name',
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
toast({
|
toast.error('Cannot find project');
|
||||||
id: 'domain_cannot_find_project',
|
|
||||||
title: 'Cannot find project',
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,20 +31,10 @@ const Config = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
toast({
|
toast.success('Domain added successfully');
|
||||||
id: 'domain_added_successfully',
|
|
||||||
title: 'Domain added successfully',
|
|
||||||
variant: 'success',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
navigate(`/${orgSlug}/projects/${id}/settings/domains`);
|
navigate(`/${orgSlug}/projects/${id}/settings/domains`);
|
||||||
} else {
|
} else {
|
||||||
toast({
|
toast.error('Error adding domain');
|
||||||
id: 'generic_error_adding_domain',
|
|
||||||
title: 'Error adding domaint',
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
DomainStatus,
|
DomainStatus,
|
||||||
Domain,
|
Domain,
|
||||||
Environment,
|
Environment,
|
||||||
Permission,
|
|
||||||
} from 'gql-client';
|
} from 'gql-client';
|
||||||
|
|
||||||
export const user: User = {
|
export const user: User = {
|
||||||
@@ -45,7 +44,7 @@ export const organization: Organization = {
|
|||||||
export const member: ProjectMember = {
|
export const member: ProjectMember = {
|
||||||
id: '1',
|
id: '1',
|
||||||
member: user,
|
member: user,
|
||||||
permissions: [Permission.Edit],
|
permissions: [],
|
||||||
isPending: false,
|
isPending: false,
|
||||||
createdAt: '2021-08-01T00:00:00.000Z',
|
createdAt: '2021-08-01T00:00:00.000Z',
|
||||||
updatedAt: '2021-08-01T00:00:00.000Z',
|
updatedAt: '2021-08-01T00:00:00.000Z',
|
||||||
@@ -71,7 +70,7 @@ export const environmentVariable1: EnvironmentVariable = {
|
|||||||
|
|
||||||
export const domain0: Domain = {
|
export const domain0: Domain = {
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'domain.com',
|
name: 'Domain',
|
||||||
createdAt: '2021-08-01T00:00:00.000Z',
|
createdAt: '2021-08-01T00:00:00.000Z',
|
||||||
updatedAt: '2021-08-01T00:00:00.000Z',
|
updatedAt: '2021-08-01T00:00:00.000Z',
|
||||||
branch: 'Branch',
|
branch: 'Branch',
|
||||||
@@ -79,16 +78,6 @@ export const domain0: Domain = {
|
|||||||
redirectTo: null,
|
redirectTo: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const domain1: Domain = {
|
|
||||||
id: '2',
|
|
||||||
name: 'www.domain.com',
|
|
||||||
createdAt: '2021-08-01T00:00:00.000Z',
|
|
||||||
updatedAt: '2021-08-01T00:00:00.000Z',
|
|
||||||
branch: 'Branch',
|
|
||||||
status: DomainStatus.Live,
|
|
||||||
redirectTo: domain0,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deployment0: Deployment = {
|
export const deployment0: Deployment = {
|
||||||
id: '1',
|
id: '1',
|
||||||
url: 'https://deployment.com',
|
url: 'https://deployment.com',
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
import { StoryObj, Meta } from '@storybook/react';
|
|
||||||
|
|
||||||
import DomainCard from 'components/projects/project/settings/DomainCard';
|
|
||||||
import { domain0, domain1, project } from '../../MockStoriesData';
|
|
||||||
|
|
||||||
const meta: Meta<typeof DomainCard> = {
|
|
||||||
title: 'Project/Settings/DomainCard',
|
|
||||||
component: DomainCard,
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
domains: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
domain: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
branches: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
project: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onUpdate: {
|
|
||||||
action: 'update',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj<typeof DomainCard>;
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
args: {
|
|
||||||
domains: [domain0, domain1],
|
|
||||||
domain: domain0,
|
|
||||||
branches: ['main'],
|
|
||||||
project: project,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import { StoryObj, Meta } from '@storybook/react';
|
|
||||||
|
|
||||||
import EditDomainDialog from 'components/projects/project/settings/EditDomainDialog';
|
|
||||||
|
|
||||||
const meta: Meta<typeof EditDomainDialog> = {
|
|
||||||
title: 'Components/EditDomainDialog',
|
|
||||||
component: EditDomainDialog,
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
domains: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
open: {
|
|
||||||
control: {
|
|
||||||
type: 'boolean',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
handleOpen: {
|
|
||||||
action: 'open',
|
|
||||||
},
|
|
||||||
domain: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
branches: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onUpdate: {
|
|
||||||
action: 'update',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj<typeof EditDomainDialog>;
|
|
||||||
|
|
||||||
export const Default: Story = {};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import WebhookCard from 'components/projects/project/settings/WebhookCard';
|
|
||||||
|
|
||||||
const meta: Meta<typeof WebhookCard> = {
|
|
||||||
title: 'Project/Settings/WebhookCard',
|
|
||||||
component: WebhookCard,
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
webhookUrl: {
|
|
||||||
control: {
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onDelete: {
|
|
||||||
action: 'delete',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj<typeof WebhookCard>;
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
args: {
|
|
||||||
webhookUrl: 'https://api.retool.com',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -13,6 +13,7 @@ export default defineConfig({
|
|||||||
context: '/src/context',
|
context: '/src/context',
|
||||||
components: '/src/components',
|
components: '/src/components',
|
||||||
pages: '/src/pages',
|
pages: '/src/pages',
|
||||||
|
types: '/src/types',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
|
|||||||
@@ -11264,6 +11264,11 @@ globby@11.1.0, globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.1.0:
|
|||||||
merge2 "^1.4.1"
|
merge2 "^1.4.1"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
|
goober@^2.1.10:
|
||||||
|
version "2.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.14.tgz#4a5c94fc34dc086a8e6035360ae1800005135acd"
|
||||||
|
integrity sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==
|
||||||
|
|
||||||
google-protobuf@^3.19.4:
|
google-protobuf@^3.19.4:
|
||||||
version "3.21.2"
|
version "3.21.2"
|
||||||
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
|
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
|
||||||
@@ -15323,6 +15328,13 @@ react-hook-form@^7.49.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.51.3.tgz#7486dd2d52280b6b28048c099a98d2545931cab3"
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.51.3.tgz#7486dd2d52280b6b28048c099a98d2545931cab3"
|
||||||
integrity sha512-cvJ/wbHdhYx8aviSWh28w9ImjmVsb5Y05n1+FW786vEZQJV5STNM0pW6ujS+oiBecb0ARBxJFyAnXj9+GHXACQ==
|
integrity sha512-cvJ/wbHdhYx8aviSWh28w9ImjmVsb5Y05n1+FW786vEZQJV5STNM0pW6ujS+oiBecb0ARBxJFyAnXj9+GHXACQ==
|
||||||
|
|
||||||
|
react-hot-toast@^2.4.1:
|
||||||
|
version "2.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994"
|
||||||
|
integrity sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==
|
||||||
|
dependencies:
|
||||||
|
goober "^2.1.10"
|
||||||
|
|
||||||
react-inspector@6.0.2:
|
react-inspector@6.0.2:
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-6.0.2.tgz#aa3028803550cb6dbd7344816d5c80bf39d07e9d"
|
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-6.0.2.tgz#aa3028803550cb6dbd7344816d5c80bf39d07e9d"
|
||||||
|
|||||||
Reference in New Issue
Block a user