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

feat: First Time Onboarding #2732

Merged
merged 4 commits into from
Feb 4, 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
19 changes: 12 additions & 7 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import nightwind from 'nightwind/helper';
import { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet';
import { useSelector } from 'react-redux';
import { createHashRouter, RouterProvider } from 'react-router-dom';
import { createHashRouter, redirect, RouterProvider } from 'react-router-dom';
import ErrorLayout from './app/ErrorLayout';
import Flag from './app/flags/Flag';
import NewFlag from './app/flags/NewFlag';
Expand All @@ -14,6 +14,7 @@ import NewSegment from './app/segments/NewSegment';
import Segment from './app/segments/Segment';
import SessionProvider from './components/SessionProvider';
import { Theme } from './types/Preferences';
import { store } from './store';
const Flags = loadable(() => import('./app/flags/Flags'));
const Variants = loadable(() => import('./app/flags/variants/Variants'));
const Rules = loadable(() => import('./app/flags/rules/Rules'));
Expand All @@ -27,11 +28,15 @@ const Preferences = loadable(() => import('./app/preferences/Preferences'));
const Namespaces = loadable(() => import('./app/namespaces/Namespaces'));
const Tokens = loadable(() => import('./app/tokens/Tokens'));

const namespacesRoutes = [
const namespacedRoutes = [
{
element: <Flags />,
handle: {
namespaced: true
element: <Onboarding firstTime={true} />,
loader: () => {
const state = store.getState();
if (state?.user.completedOnboarding) {
return redirect('/flags');
}
return null;
},
index: true
},
Expand Down Expand Up @@ -97,7 +102,7 @@ const router = createHashRouter([
children: [
{
path: 'namespaces/:namespaceKey',
children: namespacesRoutes
children: namespacedRoutes
},
{
path: 'settings',
Expand Down Expand Up @@ -125,7 +130,7 @@ const router = createHashRouter([
path: 'support',
element: <Support />
},
...namespacesRoutes
...namespacedRoutes
]
},
{
Expand Down
27 changes: 26 additions & 1 deletion ui/src/app/Onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ import {
PuzzlePieceIcon,
StarIcon
} from '@heroicons/react/24/outline';
import { useDispatch } from 'react-redux';
import Button from '~/components/forms/buttons/Button';
import { Icon } from '~/types/Icon';
import { cls } from '~/utils/helpers';
import { useNavigate } from 'react-router-dom';
import { onboardingCompleted } from './events/eventSlice';

const gettingStartedTiles = [
{
Expand Down Expand Up @@ -123,7 +127,14 @@ function OnboardingTile(props: OnboardingTileProps) {
);
}

export default function Onboarding() {
interface OnboardingProps {
firstTime?: boolean;
}

export default function Onboarding({ firstTime = false }: OnboardingProps) {
const navigate = useNavigate();
const dispatch = useDispatch();

return (
<>
<div className="flex flex-row justify-between pb-5 sm:items-center">
Expand All @@ -135,6 +146,20 @@ export default function Onboarding() {
Here are some things to help you get started with Flipt
</p>
</div>
{firstTime && (
<div className="mt-4">
<Button
variant="soft"
title="Complete Onboarding"
onClick={() => {
dispatch(onboardingCompleted());
navigate('/flags');
}}
>
Continue to Dashboard
</Button>
</div>
)}
</div>
<div className="my-8">
<div className="grid w-full auto-rows-[12rem] grid-cols-1 gap-4 sm:grid-cols-3">
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/console/Console.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ export default function Console() {
Copy as curl
</Button>
<Button
primary
variant="primary"
className="ml-3"
type="submit"
disabled={!(formik.dirty && formik.isValid)}
Expand Down
30 changes: 30 additions & 0 deletions ui/src/app/events/eventSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createSelector, createSlice } from '@reduxjs/toolkit';
import { RootState } from '~/store';

export const eventKey = 'event';
interface IEventState {
completedOnboarding: boolean;
}

const initialState: IEventState = {
completedOnboarding: false
};

export const eventSlice = createSlice({
name: 'event',
initialState,
reducers: {
onboardingCompleted: (state) => {
state.completedOnboarding = true;
}
}
});

export const { onboardingCompleted } = eventSlice.actions;

export const selectCompletedOnboarding = createSelector(
[(state: RootState) => state.user],
(user) => user.completedOnboarding
);

export default eventSlice.reducer;
2 changes: 1 addition & 1 deletion ui/src/app/flags/Flags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function Flags() {
<div className="mt-4">
<Link to={`${path}/new`}>
<Button
primary
variant="primary"
disabled={readOnly}
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
>
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/flags/rollouts/Rollouts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export default function Rollouts(props: RolloutsProps) {
</div>
<div className="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
<Button
primary
variant="primary"
type="button"
disabled={readOnly}
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/flags/rules/Rules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export default function Rules() {
{rules && rules.length > 0 && (
<div className="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
<Button
primary
variant="primary"
type="button"
onClick={() => setShowRuleForm(true)}
disabled={readOnly}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/flags/variants/Variants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default function Variants() {
{flag.variants && flag.variants.length > 0 && (
<div className="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
<Button
primary
variant="primary"
type="button"
disabled={readOnly}
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/namespaces/Namespaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export default function Namespaces() {
</div>
<div className="mt-4">
<Button
primary
variant="primary"
disabled={readOnly}
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
onClick={() => {
Expand Down
1 change: 1 addition & 0 deletions ui/src/app/preferences/Preferences.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default function Preferences() {
timezone: timezone,
theme: theme
};

const { inTimezone } = useTimezone();
const isUTC = useMemo(() => timezone === Timezone.UTC, [timezone]);

Expand Down
4 changes: 2 additions & 2 deletions ui/src/app/refs/refsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export const refsSlice = createSlice({
export const { currentRefChanged } = refsSlice.actions;

export const selectCurrentRef = createSelector(
[(state: RootState) => state.refs.currentRef],
(ref) => ref
[(state: RootState) => state.refs],
(refs) => refs.currentRef
);

export default refsSlice.reducer;
2 changes: 1 addition & 1 deletion ui/src/app/segments/Segment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ export default function Segment() {
{segment.constraints && segment.constraints.length > 0 && (
<div className="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
<Button
primary
variant="primary"
type="button"
disabled={readOnly}
title={
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/segments/Segments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function Segments() {
<div className="mt-4">
<Link to={`${path}/new`}>
<Button
primary
variant="primary"
disabled={readOnly}
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
>
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/tokens/Tokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export default function Tokens() {
</div>
{tokenAuthEnabled && tokens?.length > 0 && (
<div className="mt-4">
<Button primary onClick={() => setShowTokenForm(true)}>
<Button variant="primary" onClick={() => setShowTokenForm(true)}>
<PlusIcon
className="text-white -ml-1.5 mr-1 h-5 w-5"
aria-hidden="true"
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/flags/FlagForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export default function FlagForm(props: { flag?: IFlag }) {
Cancel
</Button>
<Button
primary
variant="primary"
className="ml-3 min-w-[80px]"
type="submit"
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/flags/VariantForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ const VariantForm = forwardRef((props: VariantFormProps, ref: any) => {
<div className="flex justify-end space-x-3">
<Button onClick={() => setOpen(false)}>Cancel</Button>
<Button
primary
variant="primary"
className="min-w-[80px]"
type="submit"
disabled={
Expand Down
16 changes: 9 additions & 7 deletions ui/src/components/forms/buttons/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export type ButtonProps = {
children: React.ReactNode;
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
type?: 'button' | 'submit' | 'reset';
primary?: boolean;
variant?: 'primary' | 'secondary' | 'soft';
className?: string;
title?: string;
disabled?: boolean;
Expand All @@ -16,7 +16,7 @@ export default function Button(props: ButtonProps) {
onClick,
children,
type = 'button',
primary = false,
variant = 'secondary',
title,
disabled = false
} = props;
Expand All @@ -28,14 +28,16 @@ export default function Button(props: ButtonProps) {
!disabled && onClick && onClick(e);
}}
className={cls(
'cursor-hand mb-1 inline-flex items-center justify-center rounded-md border px-4 py-2 text-sm font-medium shadow-sm focus:outline-none focus:ring-1 focus:ring-offset-1',
'cursor-hand mb-1 inline-flex items-center justify-center rounded-md px-4 py-2 text-sm font-medium focus:outline-none focus:ring-1 focus:ring-offset-1',
className,
{
'cursor-not-allowed': disabled,
'text-white bg-violet-400 border-transparent enabled:bg-violet-600 enabled:hover:bg-violet-500 enabled:focus:ring-violet-600':
primary,
'bg-white text-gray-500 border-violet-300 enabled:hover:bg-gray-50 enabled:focus:ring-gray-500':
!primary
'text-white bg-violet-400 border border-transparent shadow-sm enabled:bg-violet-600 enabled:hover:bg-violet-500 enabled:focus:ring-violet-600':
variant === 'primary',
'bg-white text-gray-500 border-violet-300 border shadow-sm enabled:hover:bg-gray-50 enabled:focus:ring-gray-500':
variant === 'secondary',
'text-violet-700 border-violet-300 enabled:hover:bg-violet-100 enabled:focus:ring-violet-500':
variant === 'soft'
}
)}
disabled={disabled}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/namespaces/NamespaceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ const NamespaceForm = forwardRef((props: NamespaceFormProps, ref: any) => {
<div className="flex justify-end space-x-3">
<Button onClick={() => setOpen(false)}>Cancel</Button>
<Button
primary
variant="primary"
className="min-w-[80px]"
type="submit"
disabled={
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/panels/CopyToNamespacePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default function CopyToNamespacePanel(props: CopyToNamespacePanelProps) {
</div>
<div className="mt-5 flex flex-row-reverse space-x-2 space-x-reverse sm:mt-4">
<Button
primary
variant="primary"
type="button"
onClick={() => {
handleSubmit()
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/panels/DeletePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function DeletePanel(props: DeletePanelProps) {
</div>
<div className="mt-5 flex flex-row-reverse space-x-2 space-x-reverse sm:mt-4">
<Button
primary
variant="primary"
type="button"
onClick={() => {
handleSubmit()
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/rollouts/forms/EditRolloutForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ export default function EditRolloutForm(props: EditRolloutFormProps) {
<div className="flex justify-end space-x-3">
<Button onClick={() => setOpen(false)}>Cancel</Button>
<Button
primary
variant="primary"
type="submit"
className="min-w-[80px]"
disabled={!formik.isValid || formik.isSubmitting}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/rollouts/forms/RolloutForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ export default function RolloutForm(props: RolloutFormProps) {
<div className="flex justify-end space-x-3">
<Button onClick={() => setOpen(false)}>Cancel</Button>
<Button
primary
variant="primary"
type="submit"
className="min-w-[80px]"
disabled={!formik.isValid || formik.isSubmitting}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/rules/forms/RuleForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ export default function RuleForm(props: RuleFormProps) {
<div className="flex justify-end space-x-3">
<Button onClick={() => setOpen(false)}>Cancel</Button>
<Button
primary
variant="primary"
type="submit"
className="min-w-[80px]"
disabled={
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/segments/ConstraintForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ const ConstraintForm = forwardRef((props: ConstraintFormProps, ref: any) => {
Cancel
</Button>
<Button
primary
variant="primary"
type="submit"
className="min-w-[80px]"
disabled={
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/segments/SegmentForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ export default function SegmentForm(props: SegmentFormProps) {
Cancel
</Button>
<Button
primary
variant="primary"
className="ml-3 min-w-[80px]"
type="submit"
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/tokens/ShowTokenPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default function ShowTokenPanel(props: ShowTokenPanelProps) {
<div className="mt-5 sm:mt-6">
<Button
className="inline-flex justify-center sm:w-full"
primary
variant="primary"
onClick={() => setOpen(false)}
>
Close
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/tokens/TokenForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ const TokenForm = forwardRef((props: TokenFormProps, ref: any) => {
Cancel
</Button>
<Button
primary
variant="primary"
type="submit"
className="min-w-[80px]"
disabled={
Expand Down
Loading
Loading