feat: adapt app to cloud project graphql errors (#19384)

Co-authored-by: Tim Griesser <tgriesser10@gmail.com>
This commit is contained in:
Barthélémy Ledoux
2021-12-17 14:43:19 -06:00
committed by GitHub
parent 1cc3053f2b
commit 75328b6261
8 changed files with 117 additions and 47 deletions
+23 -27
View File
@@ -3,20 +3,22 @@
v-if="!currentProject?.projectId || !cloudViewer?.id"
:gql="props.gql"
/>
<RunsEmpty
v-else-if="!currentProject?.cloudProject?.runs?.nodes.length"
:gql="currentProject"
/>
<div
v-else
data-cy="runs"
>
<RunCard
v-for="run of currentProject?.cloudProject?.runs?.nodes"
:key="run.id"
:gql="run"
<template v-else-if="currentProject?.cloudProject?.__typename === 'CloudProject'">
<RunsEmpty
v-if="!currentProject?.cloudProject?.runs?.nodes.length"
:gql="currentProject"
/>
</div>
<div
v-else
data-cy="runs"
>
<RunCard
v-for="run of currentProject?.cloudProject?.runs?.nodes"
:key="run.id"
:gql="run"
/>
</div>
</template>
</template>
<script lang="ts" setup>
@@ -33,11 +35,14 @@ fragment RunsContainer on Query {
id
...RunsEmpty
cloudProject {
id
runs(first: 10) {
nodes {
id
...RunCard
__typename
... on CloudProject {
id
runs(first: 10) {
nodes {
id
...RunCard
}
}
}
}
@@ -56,15 +61,6 @@ const currentProject = computed(() => props.gql.currentProject)
const cloudViewer = computed(() => props.gql.cloudViewer)
</script>
<route>
{
name: "Runs",
meta: {
title: "Runs"
}
}
</route>
<style scoped>
.fade-enter-active, .fade-leave-active {
transition: opacity .3s
+14 -8
View File
@@ -1,13 +1,13 @@
<template>
<div
data-cy="no-runs"
class="min-h-full flex flex-col justify-center items-center leading-24px max-w-688px mx-auto"
class="flex flex-col mx-auto min-h-full max-w-688px leading-24px justify-center items-center"
>
<i-cy-dashboard-checkmark_x48 class="h-48px w-48px icon-dark-gray-500 icon-light-gray-100" />
<h2 class="text-18px mt-32px mb-24px text-gray-900">
<h2 class="mt-32px mb-24px text-18px text-gray-900">
{{ t("runs.empty.title") }}
</h2>
<ol class="list-decimal w-full text-gray-600 ml-16px">
<ol class="list-decimal ml-16px w-full text-gray-600">
<li>
<p class="mb-8px">
<i18n-t keypath="runs.empty.step1">
@@ -15,7 +15,7 @@
</i18n-t>
</p>
<ShikiHighlight
class="rounded border border-gray-100 -ml-16px"
class="border rounded border-gray-100 -ml-16px"
:code="projectIdCode"
lang="js"
line-numbers
@@ -64,11 +64,15 @@ fragment RunsEmpty on CurrentProject {
projectId
configFilePath
cloudProject {
id
recordKeys {
__typename
... on CloudProject {
id
...RecordKey
recordKeys {
id
...RecordKey
}
}
}
}
`
@@ -86,7 +90,9 @@ const projectIdCode = computed(() => {
const projectName = computed(() => props.gql.title)
const configFilePath = computed(() => props.gql.configFilePath)
const firstRecordKey = computed(() => {
return props.gql.cloudProject?.recordKeys?.[0]?.key ?? '<record-key>'
return props.gql.cloudProject?.__typename === 'CloudProject' && props.gql.cloudProject.recordKeys?.[0]
? props.gql.cloudProject?.recordKeys?.[0]?.key
: '<record-key>'
})
const recordCommand = computed(() => {
return `cypress run --record --key ${firstRecordKey.value}`
@@ -5,7 +5,7 @@ describe('<ProjectSettings />', () => {
it('displays the project, record key, and experiments sections', () => {
cy.mountFragment(ProjectSettingsFragmentDoc, {
onResult (ctx) {
if (ctx.currentProject?.cloudProject) {
if (ctx.currentProject?.cloudProject?.__typename === 'CloudProject') {
ctx.currentProject.cloudProject.recordKeys = []
}
},
@@ -2,7 +2,10 @@
<ProjectId
:gql="props.gql.currentProject"
/>
<template v-if="props.gql.currentProject?.cloudProject?.recordKeys?.length">
<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"
@@ -34,10 +37,13 @@ fragment ProjectSettings on Query {
...ProjectId
...Experiments
cloudProject {
id
recordKeys {
__typename
... on CloudProject {
id
...RecordKey
recordKeys {
id
...RecordKey
}
}
}
}
+40 -2
View File
@@ -161,6 +161,36 @@ type CloudProjectEdge {
node: CloudProject!
}
"""
Unable to find cloud project
"""
type CloudProjectNotFound {
"""
an error message
"""
message: String!
}
union CloudProjectResult =
CloudProject
| CloudProjectNotFound
| CloudProjectUnauthorized
"""
Unauthorized access
"""
type CloudProjectUnauthorized {
"""
does the user have a requested access pending
"""
hasRequestedAccess: Boolean
"""
an error message
"""
message: String!
}
type CloudRecordKey implements Node {
createdAt: DateTime
@@ -357,6 +387,9 @@ A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `dat
scalar DateTime
type Mutation {
"""
Create a project in the dashboard and return its object
"""
cloudProjectCreate(
ciProviders: [String!]
name: String!
@@ -364,6 +397,11 @@ type Mutation {
public: Boolean!
): CloudProject
"""
Request access to an organization from a projectId
"""
cloudProjectRequestAccess(projectSlug: String!): Boolean
"""
Adding as a test
"""
@@ -419,7 +457,7 @@ type Query {
"""
Lookup an individual project by the slug
"""
cloudProjectBySlug(slug: String!): CloudProject
cloudProjectBySlug(slug: String!): CloudProjectResult
"""
Lookup a list of projects by their slug
@@ -429,7 +467,7 @@ type Query {
A list of Project slugs
"""
slugs: [String!]!
): [CloudProject]
): [CloudProjectResult]
"""
A user within the Cypress Cloud
+25 -3
View File
@@ -140,6 +140,23 @@ type CloudProjectEdge {
node: CloudProject!
}
"""Unable to find cloud project"""
type CloudProjectNotFound {
"""an error message"""
message: String!
}
union CloudProjectResult = CloudProject | CloudProjectNotFound | CloudProjectUnauthorized
"""Unauthorized access"""
type CloudProjectUnauthorized {
"""does the user have a requested access pending"""
hasRequestedAccess: Boolean
"""an error message"""
message: String!
}
type CloudRecordKey implements Node {
createdAt: DateTime
@@ -334,7 +351,7 @@ type CurrentProject implements Node & ProjectLike {
browsers: [Browser!]
"""The remote associated project from Cypress Cloud"""
cloudProject: CloudProject
cloudProject: CloudProjectResult
"""List of all code generation candidates stories"""
codeGenCandidates(glob: String!): [FileParts]
@@ -545,8 +562,13 @@ type Mutation {
"""Create an Index HTML file for a new component testing project"""
appCreateComponentIndexHtml(template: String!): Boolean
clearActiveProject: Boolean
"""Create a project in the dashboard and return its object"""
cloudProjectCreate(ciProviders: [String!], name: String!, orgId: ID!, public: Boolean!): CloudProject
"""Request access to an organization from a projectId"""
cloudProjectRequestAccess(projectSlug: String!): Boolean
"""
Development only: Triggers or dismisses a prompted refresh by touching the file watched by our development scripts
"""
@@ -696,13 +718,13 @@ type Query {
): Node
"""Lookup an individual project by the slug"""
cloudProjectBySlug(slug: String!): CloudProject
cloudProjectBySlug(slug: String!): CloudProjectResult
"""Lookup a list of projects by their slug"""
cloudProjectsBySlugs(
"""A list of Project slugs"""
slugs: [String!]!
): [CloudProject]
): [CloudProjectResult]
"""A user within the Cypress Cloud"""
cloudViewer: CloudUser
@@ -41,7 +41,7 @@ export const CurrentProject = objectType({
})
t.field('cloudProject', {
type: 'CloudProject',
type: 'CloudProjectResult',
description: 'The remote associated project from Cypress Cloud',
resolve: async (source, args, ctx, info) => {
const projectId = await ctx.project.projectId(source.projectRoot)
+3 -1
View File
@@ -88,6 +88,9 @@ gulp.task(
// And we're finally ready for electron, watching for changes in
// /graphql to auto-restart the server
startCypressWatch,
// Before dev, fetch the latest "remote" schema from the Cypress cloud
syncRemoteGraphQL,
),
)
@@ -102,7 +105,6 @@ gulp.task('buildProd',
gulp.series(
viteClean,
syncRemoteGraphQL,
nexusCodegen,
graphqlCodegen,
generateShikiTheme,