Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dev tool] Add clear app to devtool #289

Merged
merged 1 commit into from
Sep 27, 2024
Merged
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
95 changes: 91 additions & 4 deletions client/www/pages/_devtool/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { useRouter } from 'next/router';
import { TokenContext } from '@/lib/contexts';
import { useIsHydrated } from '@/lib/hooks/useIsHydrated';
import { DashResponse } from '@/lib/types';
import { successToast } from '@/lib/toast';
import { DashResponse, InstantApp } from '@/lib/types';
import config from '@/lib/config';
import { useAuthToken, useTokenFetch } from '@/lib/auth';
import { jsonFetch } from '@/lib/fetch';
import { APIResponse, useAuthToken, useTokenFetch } from '@/lib/auth';
import { Sandbox } from '@/components/dash/Sandbox';
import { Explorer } from '@/components/dash/explorer/Explorer';
import { init } from '@instantdb/react';
import { useEffect, useState } from 'react';
import { SectionHeading, Stack, TabBar, twel } from '@/components/ui';
import { useEffect, useState, useContext } from 'react';
import { Button, Checkbox, Dialog, SectionHeading, SubsectionHeading, Stack, TabBar, Content, twel, useDialog } from '@/components/ui';
import Auth from '@/components/dash/Auth';
import { isMinRole } from '@/pages/dash/index'
import { TrashIcon } from '@heroicons/react/solid';

type InstantReactClient = ReturnType<typeof init>;

Expand Down Expand Up @@ -187,6 +191,10 @@ export default function Devtool() {
id: 'sandbox',
label: 'Sandbox',
},
{
id: 'admin',
label: 'Admin',
},
{
id: 'help',
label: 'Help',
Expand All @@ -203,6 +211,10 @@ export default function Devtool() {
<div className="min-w-[960px] w-full">
<Sandbox app={app} />
</div>
) : tab === 'admin' ? (
<div className="min-w-[960px] w-full p-4">
<Admin dashResponse={dashResponse} app={app} />
</div>
) : tab === 'help' ? (
<div className="min-w-[960px] w-full p-4">
<Help />
Expand All @@ -215,6 +227,81 @@ export default function Devtool() {
);
}

function Admin({
dashResponse,
app,
}: {
dashResponse: APIResponse<DashResponse>;
app: InstantApp;
}) {
const token = useContext(TokenContext);
const [clearAppOk, updateClearAppOk] = useState(false);
const clearDialog = useDialog();

return (
<Stack className="gap-2 text-sm max-w-sm">
{isMinRole('owner', app.user_app_role) ? (
<div className="space-y-2">
<SectionHeading>Danger zone</SectionHeading>
<Content>
These are destructive actions and will irreversibly delete associated data.
</Content>
<div>
<div className="flex flex-col space-y-6">
<Button variant="destructive" onClick={clearDialog.onOpen}>
<TrashIcon height={'1rem'} /> Clear app
</Button>
</div>
</div>
<Dialog {...clearDialog}>
<div className="flex flex-col gap-2">
<SubsectionHeading className="text-red-600">
Clear app
</SubsectionHeading>
<Content className="space-y-2">
<p>Clearing an app will irreversibly delete all namespaces, triples, and permissions.</p>
<p>All other data like app id, admin token, users, billing, team members, etc. will remain.</p>
<p>This is equivalent to deleting all your namespaces in the explorer and clearing your permissions.</p>
</Content>
<Checkbox
checked={clearAppOk}
onChange={(c) => updateClearAppOk(c)}
label="I understand and want to clear this app."
/>
<Button
disabled={!clearAppOk}
variant="destructive"
onClick={async () => {
await jsonFetch(`${config.apiURI}/dash/apps/${app.id}/clear`, {
method: 'POST',
headers: {
authorization: `Bearer ${token}`,
'content-type': 'application/json',
},
});

clearDialog.onClose();
dashResponse.mutate();
successToast('App cleared!');
}}
>
Clear data
</Button>
</div>
</Dialog>
</div>
) :
<>
<SectionHeading>Insufficent Role</SectionHeading>
<Content>
Only app owners can use admin features in the devtool.
</Content>
</>
}
</Stack>
)
}

function Help() {
return (
<Stack className="gap-2 text-sm max-w-sm">
Expand Down
2 changes: 1 addition & 1 deletion client/www/pages/dash/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const tabs: Tab[] = [

const tabIndex = new Map(tabs.map((t) => [t.id, t]));

function isMinRole(minRole: Role, role: Role) {
export function isMinRole(minRole: Role, role: Role) {
return roleOrder.indexOf(role) >= roleOrder.indexOf(minRole);
}

Expand Down