feat(unify): rearrange settings (#20332)

* rearrange settings

* add empty states

* update tests & add new

* appease TS

* address PR comments
This commit is contained in:
Shawn Taylor
2022-02-27 20:38:00 -05:00
committed by GitHub
parent 72ca01431d
commit f7599ddc76
16 changed files with 359 additions and 205 deletions

View File

@@ -34,12 +34,12 @@ describe('App: Settings', () => {
cy.wait('@ReconfigureProject')
})
describe('Project Settings', () => {
describe('Cloud Settings', () => {
it('shows the projectId section when there is a projectId', () => {
cy.startAppServer('e2e')
cy.visitApp()
cy.findByText('Settings').click()
cy.findByText('Project Settings').click()
cy.findByText('Dashboard Settings').click()
cy.findByText('Project ID').should('be.visible')
})
@@ -49,7 +49,7 @@ describe('App: Settings', () => {
cy.visitApp()
cy.findByText('Settings').click()
cy.findByText('Project Settings').click()
cy.findByText('Dashboard Settings').click()
cy.findByText('Record Key').should('be.visible')
})
@@ -59,12 +59,26 @@ describe('App: Settings', () => {
cy.visitApp()
cy.findByText('Settings').click()
cy.findByText('Project Settings').click()
cy.findByText('Dashboard Settings').click()
cy.get('[data-cy="record-key"]').should('contain', '***')
cy.get('[aria-label="Record Key Visibility Toggle"]').click()
cy.get('[data-cy="record-key"]').should('contain', '2aaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')
})
it('opens cloud settings when clicking on "Manage Keys"', () => {
cy.startAppServer('e2e')
cy.loginUser()
cy.intercept('mutation-ExternalLink_OpenExternal', { 'data': { 'openExternal': true } }).as('OpenExternal')
cy.__incorrectlyVisitAppWithIntercept('settings')
cy.findByText('Dashboard Settings').click()
cy.findByText('Manage Keys').click()
cy.wait('@OpenExternal')
.its('request.body.variables.url')
.should('equal', 'http:/test.cloud/cloud-project/settings')
})
})
describe('Project Settings', () => {
it('shows the Spec Patterns section (default specPattern value)', () => {
cy.scaffoldProject('simple-ct')
cy.openProject('simple-ct')
@@ -144,18 +158,6 @@ describe('App: Settings', () => {
// TODO: The Edit button isn't hooked up to do anything when it should trigger the openFileInIDE mutation (https://cypress-io.atlassian.net/browse/UNIFY-1164)
it.skip('opens cypress.config.js file after clicking "Edit" button', () => {
})
it('opens cloud settings when clicking on "Manage Keys"', () => {
cy.startAppServer('e2e')
cy.loginUser()
cy.intercept('mutation-ExternalLink_OpenExternal', { 'data': { 'openExternal': true } }).as('OpenExternal')
cy.__incorrectlyVisitAppWithIntercept('settings')
cy.findByText('Project Settings').click()
cy.findByText('Manage Keys').click()
cy.wait('@OpenExternal')
.its('request.body.variables.url')
.should('equal', 'http:/test.cloud/cloud-project/settings')
})
})
describe('external editor', () => {
@@ -232,15 +234,16 @@ describe('App: Settings', () => {
})
describe('App: Settings without cloud', () => {
it('hides the projectId section when there is no projectId', () => {
it('the projectId section shows a prompt to connect when there is no projectId', () => {
cy.scaffoldProject('simple-ct')
cy.openProject('simple-ct')
cy.startAppServer('component')
cy.visitApp()
cy.findByText('Settings').click()
cy.findByText('Project Settings').click()
cy.findByText('Project ID').should('not.exist')
cy.findByText('Dashboard Settings').click()
cy.findByText('Project ID').should('exist')
cy.contains('button', 'Log in to the Cypress Dashboard').should('be.visible')
})
it('have returned browsers', () => {

View File

@@ -0,0 +1,81 @@
import CloudConnectButton from './CloudConnectButton.vue'
import { CloudConnectButtonFragmentDoc } from '../generated/graphql-test'
import { CloudUserStubs } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-CloudTypes'
describe('<CloudConnectButton />', () => {
it('show user connect if not connected', () => {
cy.mountFragment(CloudConnectButtonFragmentDoc, {
onResult: (result) => {
result.cloudViewer = null
},
render (gqlVal) {
return <div class="h-screen"><CloudConnectButton gql={gqlVal} /></div>
},
})
cy.contains('button', 'Log in').should('be.visible')
})
const cloudViewer = {
...CloudUserStubs.me,
organizationControl: null,
organizations: {
__typename: 'CloudOrganizationConnection' as const,
nodes: [
{
__typename: 'CloudOrganization' as const,
id: '1',
name: 'Test Org',
projects: {
__typename: 'CloudProjectConnection' as const,
nodes: [
{
__typename: 'CloudProject' as const,
id: '1',
name: 'Test Project',
slug: 'test-project',
},
],
},
},
{
__typename: 'CloudOrganization' as const,
id: '2',
name: 'Test Org 2',
projects: {
__typename: 'CloudProjectConnection' as const,
nodes: [],
},
},
],
},
}
it('show project connect if not connected', () => {
cy.mountFragment(CloudConnectButtonFragmentDoc, {
onResult: (result) => {
result.cloudViewer = cloudViewer
},
render (gqlVal) {
return <div class="h-screen"><CloudConnectButton gql={gqlVal} /></div>
},
})
cy.contains('button', 'Connect your project').should('be.visible')
})
it('shows connect project dialog', () => {
cy.mountFragment(CloudConnectButtonFragmentDoc, {
onResult: (result) => {
result.cloudViewer = cloudViewer
},
render (gqlVal) {
return <div class="h-screen"><CloudConnectButton gql={gqlVal} /></div>
},
})
cy.contains('button', 'Connect your project').click()
cy.get('[role="dialog"]').should('be.visible')
cy.get('[role="dialog"] h2').should('contain', 'Connect Project')
})
})

View File

@@ -0,0 +1,65 @@
<template>
<Button
:class="props.class"
:prefix-icon="isLoggedIn ? ChainIcon : UserIcon"
prefix-icon-class="icon-dark-white icon-light-transparent"
@click="openConnection"
>
{{ isLoggedIn ? t('runs.connect.buttonProject') : t('runs.connect.buttonUser') }}
</Button>
<LoginModal
v-model="isLoginOpen"
:gql="props.gql"
/>
<CloudConnectModals
v-if="isProjectConnectOpen"
:show="isProjectConnectOpen"
:gql="props.gql"
@cancel="isProjectConnectOpen = false"
@success="isProjectConnectOpen = false; emit('success')"
/>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { gql } from '@urql/vue'
import UserIcon from '~icons/cy/user-outline_x16.svg'
import ChainIcon from '~icons/cy/chain-link_x16.svg'
import Button from '@cy/components/Button.vue'
import CloudConnectModals from './modals/CloudConnectModals.vue'
import LoginModal from '@cy/gql-components/topnav/LoginModal.vue'
import { useI18n } from '@cy/i18n'
import type { CloudConnectButtonFragment } from '../generated/graphql'
const { t } = useI18n()
gql`
fragment CloudConnectButton on Query {
...CloudConnectModals
...LoginModal
}
`
const emit = defineEmits<{
(event: 'success'): void
}>()
const props = defineProps<{
gql: CloudConnectButtonFragment,
class?: string
}>()
const isLoginOpen = ref(false)
const isProjectConnectOpen = ref(false)
const isLoggedIn = computed(() => Boolean(props.gql.cloudViewer?.id))
function openConnection () {
if (!isLoggedIn.value) {
// start logging in the user
isLoginOpen.value = true
} else {
// if user is already logged in connect a cloud project
isProjectConnectOpen.value = true
}
}
</script>

View File

@@ -1,9 +1,8 @@
import RunsConnect from './RunsConnect.vue'
import { RunsConnectFragmentDoc } from '../generated/graphql-test'
import { CloudUserStubs } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-CloudTypes'
describe('<RunsConnect />', () => {
it('show user connect if not connected', () => {
it('show connect button', () => {
cy.mountFragment(RunsConnectFragmentDoc, {
onResult: (result) => {
result.cloudViewer = null
@@ -15,67 +14,4 @@ describe('<RunsConnect />', () => {
cy.contains('button', 'Log in').should('be.visible')
})
const cloudViewer = {
...CloudUserStubs.me,
organizationControl: null,
organizations: {
__typename: 'CloudOrganizationConnection' as const,
nodes: [
{
__typename: 'CloudOrganization' as const,
id: '1',
name: 'Test Org',
projects: {
__typename: 'CloudProjectConnection' as const,
nodes: [
{
__typename: 'CloudProject' as const,
id: '1',
name: 'Test Project',
slug: 'test-project',
},
],
},
},
{
__typename: 'CloudOrganization' as const,
id: '2',
name: 'Test Org 2',
projects: {
__typename: 'CloudProjectConnection' as const,
nodes: [],
},
},
],
},
}
it('show project connect if not connected', () => {
cy.mountFragment(RunsConnectFragmentDoc, {
onResult: (result) => {
result.cloudViewer = cloudViewer
},
render (gqlVal) {
return <div class="h-screen"><RunsConnect gql={gqlVal} /></div>
},
})
cy.contains('button', 'Connect your project').should('be.visible')
})
it('shows connect project dialog', () => {
cy.mountFragment(RunsConnectFragmentDoc, {
onResult: (result) => {
result.cloudViewer = cloudViewer
},
render (gqlVal) {
return <div class="h-screen"><RunsConnect gql={gqlVal} /></div>
},
})
cy.contains('button', 'Connect your project').click()
cy.get('[role="dialog"]').should('be.visible')
cy.get('[role="dialog"] h2').should('contain', 'Connect Project')
})
})

View File

@@ -17,48 +17,28 @@
</p>
</div>
</div>
<Button
<CloudConnectButton
:gql="props.gql"
class="mx-auto mt-40px"
:prefix-icon="isLoggedIn ? ChainIcon : UserIcon"
prefix-icon-class="icon-dark-white icon-light-transparent"
@click="openConnection"
>
{{ isLoggedIn ? t('runs.connect.buttonProject') : t('runs.connect.buttonUser') }}
</Button>
<LoginModal
v-model="isLoginOpen"
:gql="props.gql"
/>
<CloudConnectModals
v-if="isProjectConnectOpen"
:show="isProjectConnectOpen"
:gql="props.gql"
@cancel="isProjectConnectOpen = false"
@success="isProjectConnectOpen = false; emit('success')"
@success="emit('success')"
/>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { gql } from '@urql/vue'
import SmartIcon from '~icons/cy/illustration-gear_x120.svg'
import DebugIcon from '~icons/cy/illustration-debug_x120.svg'
import ChartIcon from '~icons/cy/illustration-chart_x120.svg'
import UserIcon from '~icons/cy/user-outline_x16.svg'
import ChainIcon from '~icons/cy/chain-link_x16.svg'
import Button from '@cy/components/Button.vue'
import CloudConnectModals from './modals/CloudConnectModals.vue'
import LoginModal from '@cy/gql-components/topnav/LoginModal.vue'
import { useI18n } from '@cy/i18n'
import CloudConnectButton from './CloudConnectButton.vue'
import type { RunsConnectFragment } from '../generated/graphql'
const { t } = useI18n()
gql`
fragment RunsConnect on Query {
...CloudConnectModals
...LoginModal
...CloudConnectButton
}
`
@@ -70,20 +50,6 @@ const props = defineProps<{
gql: RunsConnectFragment
}>()
const isLoginOpen = ref(false)
const isProjectConnectOpen = ref(false)
const isLoggedIn = computed(() => Boolean(props.gql.cloudViewer?.id))
function openConnection () {
if (!isLoggedIn.value) {
// start logging in the user
isLoginOpen.value = true
} else {
// if user is already logged in connect a cloud project
isProjectConnectOpen.value = true
}
}
const notions = [
{
icon: SmartIcon,

View File

@@ -10,6 +10,20 @@ describe('<SettingsContainer />', { viewportHeight: 800, viewportWidth: 900 }, (
cy.percySnapshot()
})
it('expands and collapses project settings', () => {
mountSettingsContainer()
cy.contains('Project Settings').click()
cy.findByText(defaultMessages.settingsPage.experiments.title).scrollIntoView().should('be.visible')
cy.findByText(defaultMessages.settingsPage.specPattern.title).scrollIntoView().should('be.visible')
cy.findByText(defaultMessages.settingsPage.config.title).scrollIntoView().should('be.visible')
cy.percySnapshot()
cy.findByText('Project Settings').click()
cy.findByText(defaultMessages.settingsPage.experiments.title).should('not.exist')
})
it('expands and collapses device settings', () => {
mountSettingsContainer()
@@ -25,17 +39,14 @@ describe('<SettingsContainer />', { viewportHeight: 800, viewportWidth: 900 }, (
cy.findByText(defaultMessages.settingsPage.editor.title).should('not.exist')
})
it('expands and collapses project settings', () => {
it('expands and collapses cloud settings', () => {
mountSettingsContainer()
cy.contains('Project Settings').click()
cy.contains('Dashboard Settings').click()
cy.findByText(defaultMessages.settingsPage.projectId.title).scrollIntoView().should('be.visible')
cy.findByText(defaultMessages.settingsPage.experiments.title).scrollIntoView().should('be.visible')
cy.findByText(defaultMessages.settingsPage.specPattern.title).scrollIntoView().should('be.visible')
cy.findByText(defaultMessages.settingsPage.config.title).scrollIntoView().should('be.visible')
cy.percySnapshot()
cy.findByText('Project Settings').click()
cy.findByText('Dashboard Settings').click()
cy.findByText(defaultMessages.settingsPage.projectId.title).should('not.exist')
})

View File

@@ -4,16 +4,6 @@
data-cy="settings"
>
<div class="space-y-24px">
<SettingsCard
:title="t('settingsPage.device.title')"
:description="t('settingsPage.device.description')"
:icon="IconLaptop"
max-height="800px"
>
<ExternalEditorSettings :gql="props.gql" />
<ProxySettings :gql="props.gql" />
<TestingPreferences :gql="props.gql" />
</SettingsCard>
<SettingsCard
:title="t('settingsPage.project.title')"
:description="t('settingsPage.project.description')"
@@ -25,9 +15,27 @@
:gql="props.gql"
/>
</SettingsCard>
<SettingsCard
:title="t('settingsPage.device.title')"
:description="t('settingsPage.device.description')"
:icon="IconLaptop"
max-height="800px"
>
<ExternalEditorSettings :gql="props.gql" />
<ProxySettings :gql="props.gql" />
<TestingPreferences :gql="props.gql" />
</SettingsCard>
<SettingsCard
:title="t('settingsPage.cloud.title')"
:description="t('settingsPage.cloud.description')"
:icon="IconOdometer"
max-height="10000px"
>
<CloudSettings :gql="props.gql" />
</SettingsCard>
</div>
<hr class="border-gray-100">
<p class="font-light mx-auto text-center max-w-500px text-16px text-gray-500 leading-24px">
<p class="mx-auto font-light text-center text-gray-500 max-w-500px text-16px leading-24px">
{{ t('settingsPage.footer.text') }}
</p>
<Button
@@ -49,11 +57,13 @@ import Button from '@cy/components/Button.vue'
import ExternalEditorSettings from './device/ExternalEditorSettings.vue'
import ProxySettings from './device/ProxySettings.vue'
import SettingsCard from './SettingsCard.vue'
import CloudSettings from './project/CloudSettings.vue'
import ProjectSettings from './project/ProjectSettings.vue'
import TestingPreferences from './device/TestingPreferences.vue'
import type { SettingsContainerFragment } from '../generated/graphql'
import { SettingsContainer_ReconfigureProjectDocument } from '../generated/graphql'
import IconLaptop from '~icons/cy/laptop_x24.svg'
import IconOdometer from '~icons/cy/object-odometer_x24.svg'
import IconFolder from '~icons/cy/folder-outline_x24.svg'
import SettingsIcon from '~icons/cy/settings_x16.svg'
@@ -69,6 +79,7 @@ gql`
fragment SettingsContainer on Query {
...TestingPreferences
...ProjectSettings
...CloudSettings
...ExternalEditorSettings
...ProxySettings
}`

View File

@@ -0,0 +1,69 @@
import { defaultMessages } from '@cy/i18n'
import { CloudSettingsFragmentDoc } from '../../generated/graphql-test'
import CloudSettings from './CloudSettings.vue'
describe('<CloudSettings />', () => {
it('displays the project Id and record key sections', () => {
cy.mountFragment(CloudSettingsFragmentDoc, {
render: (gqlVal) => {
return (
<div class="py-4 px-8 children:py-24px">
<CloudSettings gql={gqlVal}/>
</div>
)
},
})
cy.findByText(defaultMessages.settingsPage.projectId.title).should('be.visible')
cy.findByText(defaultMessages.settingsPage.recordKey.title).should('be.visible')
cy.percySnapshot()
})
it('shows connect button when projectId is not present', () => {
cy.mountFragment(CloudSettingsFragmentDoc, {
onResult (ctx) {
if (ctx.currentProject?.cloudProject?.__typename === 'CloudProject') {
ctx.currentProject.projectId = null
ctx.currentProject.cloudProject.recordKeys = []
}
},
render: (gqlVal) => {
return (
<div class="py-4 px-8 children:py-24px">
<CloudSettings gql={gqlVal}/>
</div>
)
},
})
cy.findByText(defaultMessages.settingsPage.projectId.title).should('be.visible')
cy.findByText(defaultMessages.runs.connect.buttonUser).should('be.visible')
cy.findByText(defaultMessages.settingsPage.recordKey.title).should('not.exist')
cy.percySnapshot()
})
it('hides record key when not present', () => {
cy.mountFragment(CloudSettingsFragmentDoc, {
onResult (ctx) {
if (ctx.currentProject?.cloudProject?.__typename === 'CloudProject') {
ctx.currentProject.projectId = null
ctx.currentProject.cloudProject.recordKeys = []
}
},
render: (gqlVal) => {
return (
<div class="py-4 px-8 children:py-24px">
<CloudSettings gql={gqlVal}/>
</div>
)
},
})
cy.findByText(defaultMessages.settingsPage.recordKey.title).should('not.exist')
cy.percySnapshot()
})
})

View File

@@ -0,0 +1,45 @@
<template>
<ProjectId :gql="props.gql" />
<template
v-if="props.gql.currentProject?.cloudProject?.__typename === 'CloudProject'
&& props.gql.currentProject.cloudProject.recordKeys?.length"
>
<RecordKey
v-for="key of props.gql.currentProject.cloudProject.recordKeys"
:key="key.id"
:gql="key"
:manage-keys-url="props.gql.currentProject.cloudProject.cloudProjectSettingsUrl"
/>
</template>
</template>
<script lang="ts" setup>
import { gql } from '@urql/vue'
import RecordKey from './RecordKey.vue'
import ProjectId from './ProjectId.vue'
import type { CloudSettingsFragment } from '../../generated/graphql'
gql`
fragment CloudSettings on Query {
...ProjectId
currentProject {
id
cloudProject {
__typename
... on CloudProject {
id
cloudProjectSettingsUrl
recordKeys {
id
...RecordKey
}
}
}
}
}
`
const props = defineProps<{
gql: CloudSettingsFragment
}>()
</script>

View File

@@ -1,3 +1,4 @@
import { set } from 'lodash'
import { ProjectIdFragmentDoc } from '../../generated/graphql-test'
import ProjectId from './ProjectId.vue'
@@ -11,7 +12,7 @@ describe('<ProjectId />', () => {
cy.mountFragment(ProjectIdFragmentDoc, {
onResult: (result) => {
result.projectId = givenProjectId
set(result, 'currentProject.projectId', givenProjectId)
},
render: (gqlVal) => (
<div class="py-4 px-8">

View File

@@ -1,6 +1,5 @@
<template>
<SettingsSection
v-if="props.gql?.projectId"
code="projectId"
data-cy="settings-projectId"
>
@@ -19,17 +18,23 @@
</ExternalLink>
</i18n-t>
</template>
<div class="flex gap-10px items-center">
<div
v-if="props.gql.currentProject?.projectId"
class="flex gap-10px items-center"
>
<CodeBox
:code="props.gql?.projectId || ''"
:code="props.gql.currentProject?.projectId"
:prefix-icon="IconOctothorpe"
/>
<CopyButton
v-if="props.gql?.projectId"
:text="props.gql?.projectId"
:text="props.gql.currentProject?.projectId"
variant="outline"
/>
</div>
<CloudConnectButton
v-else
:gql="props.gql"
/>
</SettingsSection>
</template>
@@ -42,18 +47,21 @@ import SettingsSection from '../SettingsSection.vue'
import ExternalLink from '@cy/gql-components/ExternalLink.vue'
import CodeBox from './CodeBox.vue'
import type { ProjectIdFragment } from '../../generated/graphql'
import CloudConnectButton from '../../runs/CloudConnectButton.vue'
const { t } = useI18n()
gql`
fragment ProjectId on CurrentProject {
id
projectId
}
`
fragment ProjectId on Query {
currentProject {
id
projectId
}
...CloudConnectButton
}`
const props = defineProps<{
gql?: ProjectIdFragment | null
gql: ProjectIdFragment
}>()
</script>

View File

@@ -3,7 +3,7 @@ import { ProjectSettingsFragmentDoc } from '../../generated/graphql-test'
import ProjectSettings from './ProjectSettings.vue'
describe('<ProjectSettings />', () => {
it('displays the project Id, record key, and experiments sections', () => {
it('displays the experiments section', () => {
cy.mountFragment(ProjectSettingsFragmentDoc, {
render: (gqlVal) => {
@@ -15,33 +15,8 @@ describe('<ProjectSettings />', () => {
},
})
cy.findByText(defaultMessages.settingsPage.projectId.title).should('be.visible')
cy.findByText(defaultMessages.settingsPage.recordKey.title).should('be.visible')
cy.findByText(defaultMessages.settingsPage.experiments.title).should('be.visible')
cy.percySnapshot()
})
it('hides project Id, and record key when not present', () => {
cy.mountFragment(ProjectSettingsFragmentDoc, {
onResult (ctx) {
if (ctx.currentProject?.cloudProject?.__typename === 'CloudProject') {
ctx.currentProject.projectId = null
ctx.currentProject.cloudProject.recordKeys = []
}
},
render: (gqlVal) => {
return (
<div class="py-4 px-8 children:py-24px">
<ProjectSettings gql={gqlVal}/>
</div>
)
},
})
cy.findByText(defaultMessages.settingsPage.projectId.title).should('not.exist')
cy.findByText(defaultMessages.settingsPage.recordKey.title).should('not.exist')
cy.percySnapshot()
})
})

View File

@@ -1,16 +1,4 @@
<template>
<ProjectId :gql="props.gql.currentProject" />
<template
v-if="props.gql.currentProject?.cloudProject?.__typename === 'CloudProject'
&& props.gql.currentProject.cloudProject.recordKeys?.length"
>
<RecordKey
v-for="key of props.gql.currentProject.cloudProject.recordKeys"
:key="key.id"
:gql="key"
:manage-keys-url="props.gql.currentProject.cloudProject.cloudProjectSettingsUrl"
/>
</template>
<SpecPatterns :gql="props.gql.currentProject" />
<Experiments :gql="props.gql.currentProject" />
<Config :gql="props.gql" />
@@ -18,9 +6,7 @@
<script lang="ts" setup>
import { gql } from '@urql/vue'
import RecordKey from './RecordKey.vue'
import Experiments from './Experiments.vue'
import ProjectId from './ProjectId.vue'
import Config from './Config.vue'
import SpecPatterns from './SpecPatterns.vue'
import type { ProjectSettingsFragment } from '../../generated/graphql'
@@ -29,19 +15,7 @@ gql`
fragment ProjectSettings on Query {
currentProject {
id
...ProjectId
...Experiments
cloudProject {
__typename
... on CloudProject {
id
cloudProjectSettingsUrl
recordKeys {
id
...RecordKey
}
}
}
...SpecPatterns_Settings
}
...Config

View File

@@ -1,3 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 3C9.44771 3 9 3.44772 9 4C9 4.55228 9.44771 5 10 5V3ZM10 11C9.44771 11 9 11.4477 9 12C9 12.5523 9.44771 13 10 13V11ZM6 5C6.55228 5 7 4.55228 7 4C7 3.44772 6.55228 3 6 3V5ZM6 13C6.55228 13 7 12.5523 7 12C7 11.4477 6.55228 11 6 11V13ZM5 7C4.44772 7 4 7.44772 4 8C4 8.55228 4.44772 9 5 9V7ZM11 9C11.5523 9 12 8.55228 12 8C12 7.44772 11.5523 7 11 7V9ZM10 5H11V3H10V5ZM11 11H10V13H11V11ZM5 5H6V3H5V5ZM6 11H5V13H6V11ZM5 9H11V7H5V9ZM2 8C2 6.34315 3.34315 5 5 5V3C2.23858 3 0 5.23858 0 8H2ZM0 8C0 10.7614 2.23858 13 5 13V11C3.34315 11 2 9.65685 2 8H0ZM14 8C14 9.65685 12.6569 11 11 11V13C13.7614 13 16 10.7614 16 8H14ZM16 8C16 5.23858 13.7614 3 11 3V5C12.6569 5 14 6.34315 14 8H16Z" fill="#1B1E2E" class="icon-dark"/>
<path d="M10 3C9.44771 3 9 3.44772 9 4C9 4.55228 9.44771 5 10 5V3ZM10 11C9.44771 11 9 11.4477 9 12C9 12.5523 9.44771 13 10 13V11ZM6 5C6.55228 5 7 4.55228 7 4C7 3.44772 6.55228 3 6 3V5ZM6 13C6.55228 13 7 12.5523 7 12C7 11.4477 6.55228 11 6 11V13ZM5 7C4.44772 7 4 7.44772 4 8C4 8.55228 4.44772 9 5 9V7ZM11 9C11.5523 9 12 8.55228 12 8C12 7.44772 11.5523 7 11 7V9ZM10 5H11V3H10V5ZM11 11H10V13H11V11ZM5 5H6V3H5V5ZM6 11H5V13H6V11ZM5 9H11V7H5V9ZM2 8C2 6.34315 3.34315 5 5 5V3C2.23858 3 0 5.23858 0 8H2ZM0 8C0 10.7614 2.23858 13 5 13V11C3.34315 11 2 9.65685 2 8H0ZM14 8C14 9.65685 12.6569 11 11 11V13C13.7614 13 16 10.7614 16 8H14ZM16 8C16 5.23858 13.7614 3 11 3V5C12.6569 5 14 6.34315 14 8H16Z" fill="currentColor" class="icon-dark"/>
</svg>

Before

Width:  |  Height:  |  Size: 826 B

After

Width:  |  Height:  |  Size: 831 B

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 12.9996C2 7.47679 6.47715 2.99963 12 2.99963C17.5228 2.99963 22 7.47679 22 12.9996C22 16.2713 20.4289 19.176 18 21.0004H6C3.57111 19.176 2 16.2713 2 12.9996ZM12 13.9996C12.5523 13.9996 13 13.5519 13 12.9996C13 12.7235 12.8881 12.4735 12.7071 12.2925C12.5261 12.1116 12.2761 11.9996 12 11.9996C11.4477 11.9996 11 12.4473 11 12.9996C11 13.5519 11.4477 13.9996 12 13.9996Z" fill="#D0D2E0" class="icon-light"/>
<path d="M6 21.0004L5.39942 21.7999C5.57262 21.93 5.78338 22.0004 6 22.0004V21.0004ZM18 21.0004V22.0004C18.2166 22.0004 18.4274 21.93 18.6006 21.7999L18 21.0004ZM11.2929 12.2925C10.9024 12.6831 10.9024 13.3162 11.2929 13.7067C11.6834 14.0973 12.3166 14.0973 12.7071 13.7067L11.2929 12.2925ZM17.7071 8.70674C18.0976 8.31622 18.0976 7.68305 17.7071 7.29253C17.3166 6.902 16.6834 6.902 16.2929 7.29253L17.7071 8.70674ZM3 12.9996C3 8.02907 7.02944 3.99963 12 3.99963V1.99963C5.92487 1.99963 1 6.9245 1 12.9996H3ZM12 3.99963C16.9706 3.99963 21 8.02907 21 12.9996H23C23 6.9245 18.0751 1.99963 12 1.99963V3.99963ZM6.60058 20.2008C4.41232 18.5571 3 15.9435 3 12.9996H1C1 16.5991 2.7299 19.7948 5.39942 21.7999L6.60058 20.2008ZM21 12.9996C21 15.9435 19.5877 18.5571 17.3994 20.2008L18.6006 21.7999C21.2701 19.7948 23 16.5991 23 12.9996H21ZM12 12.9996V14.9996C13.1046 14.9996 14 14.1042 14 12.9996H12ZM12 12.9996H10C10 14.1042 10.8954 14.9996 12 14.9996V12.9996ZM12 12.9996V10.9996C10.8954 10.9996 10 11.8951 10 12.9996H12ZM6 22.0004H18V20.0004H6V22.0004ZM14 12.9996C14 12.4476 13.775 11.9463 13.4142 11.5854L12 12.9996H14ZM13.4142 11.5854C13.0534 11.2246 12.552 10.9996 12 10.9996V12.9996L13.4142 11.5854ZM12.7071 13.7067L13.4142 12.9996L12 11.5854L11.2929 12.2925L12.7071 13.7067ZM13.4142 12.9996L17.7071 8.70674L16.2929 7.29253L12 11.5854L13.4142 12.9996Z" fill="currentColor" class="icon-dark"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.68012 8.09402C6.09073 7.5658 6.56611 7.09041 7.09433 6.6798L7.75731 7.34278C8.14783 7.7333 8.14783 8.36647 7.75731 8.75699C7.36678 9.14752 6.73362 9.14752 6.34309 8.75699L5.68012 8.09402ZM4.06189 13.9996C4.02104 13.672 4 13.3383 4 12.9996C4 12.661 4.02104 12.3272 4.06189 11.9996H5C5.55228 11.9996 6 12.4473 6 12.9996C6 13.5519 5.55228 13.9996 5 13.9996H4.06189ZM19.9381 11.9996C19.979 12.3272 20 12.661 20 12.9996C20 13.3383 19.979 13.672 19.9381 13.9996H19C18.4477 13.9996 18 13.5519 18 12.9996C18 12.4473 18.4477 11.9996 19 11.9996H19.9381ZM13 5.06153V5.99963C13 6.55192 12.5523 6.99963 12 6.99963C11.4477 6.99963 11 6.55192 11 5.99963V5.06153C11.3276 5.02068 11.6613 4.99963 12 4.99963C12.3387 4.99963 12.6724 5.02068 13 5.06153Z" fill="currentColor" class="icon-dark"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -373,6 +373,10 @@
"title": "Project Settings",
"description": "Review the configuration settings currently in use for this project."
},
"cloud": {
"title": "Dashboard Settings",
"description": "Review the configuration settings for recording to the Cypress Dashboard."
},
"experiments": {
"title": "Experiments",
"description": "If you'd like to try out new features that we're working on, you can enable beta features for your project by turning on the experimental features you'd like to try. {0}",