|
3 | 3 | <Teleport v-if="flags.projectBackground" to="#fixed-background-teleport"> |
4 | 4 | <ProjectBackgroundGradient :project="project" /> |
5 | 5 | </Teleport> |
6 | | - <div v-if="route.name.startsWith('type-id-settings')" class="normal-page no-sidebar"> |
7 | | - <div class="normal-page__header"> |
8 | | - <div |
9 | | - class="mb-4 flex flex-wrap items-center gap-x-2 gap-y-3 border-0 border-b-[1px] border-solid border-divider pb-4 text-lg font-semibold" |
10 | | - > |
11 | | - <nuxt-link |
12 | | - :to="`/${project.project_type}/${project.slug ? project.slug : project.id}`" |
13 | | - class="flex items-center gap-2 hover:underline hover:brightness-[--hover-brightness]" |
| 6 | + <template v-if="isSettings"> |
| 7 | + <div v-if="canAccessSettings" class="normal-page no-sidebar"> |
| 8 | + <div class="normal-page__header"> |
| 9 | + <div |
| 10 | + class="mb-4 flex flex-wrap items-center gap-x-2 gap-y-3 border-0 border-b-[1px] border-solid border-divider pb-4 text-lg font-semibold" |
14 | 11 | > |
15 | | - <Avatar :src="project.icon_url" size="32px" /> |
16 | | - {{ project.title }} |
17 | | - </nuxt-link> |
18 | | - <ChevronRightIcon /> |
19 | | - <span class="flex grow font-extrabold text-contrast">{{ |
20 | | - formatMessage(messages.settingsTitle) |
21 | | - }}</span> |
22 | | - <div class="flex gap-2"> |
23 | | - <ButtonStyled> |
24 | | - <nuxt-link to="/dashboard/projects" |
25 | | - ><ListIcon /> {{ formatMessage(messages.visitProjectsDashboard) }} |
26 | | - </nuxt-link> |
27 | | - </ButtonStyled> |
| 12 | + <nuxt-link |
| 13 | + :to="`/${project.project_type}/${project.slug ? project.slug : project.id}`" |
| 14 | + class="flex items-center gap-2 hover:underline hover:brightness-[--hover-brightness]" |
| 15 | + > |
| 16 | + <Avatar :src="project.icon_url" size="32px" /> |
| 17 | + {{ project.title }} |
| 18 | + </nuxt-link> |
| 19 | + <ChevronRightIcon /> |
| 20 | + <span class="flex grow font-extrabold text-contrast">{{ |
| 21 | + formatMessage(messages.settingsTitle) |
| 22 | + }}</span> |
| 23 | + <div class="flex gap-2"> |
| 24 | + <ButtonStyled> |
| 25 | + <nuxt-link to="/dashboard/projects" |
| 26 | + ><ListIcon /> {{ formatMessage(messages.visitProjectsDashboard) }} |
| 27 | + </nuxt-link> |
| 28 | + </ButtonStyled> |
| 29 | + </div> |
28 | 30 | </div> |
| 31 | + <ProjectMemberHeader |
| 32 | + v-if="currentMember && false" |
| 33 | + :project="project" |
| 34 | + :versions="versions" |
| 35 | + :current-member="currentMember" |
| 36 | + :is-settings="isSettings" |
| 37 | + :set-processing="setProcessing" |
| 38 | + :all-members="allMembers" |
| 39 | + :update-members="invalidateProject" |
| 40 | + :auth="auth" |
| 41 | + :tags="tags" |
| 42 | + /> |
| 43 | + </div> |
| 44 | + <div class="normal-page__content"> |
| 45 | + <NuxtPage /> |
29 | 46 | </div> |
30 | | - <ProjectMemberHeader |
31 | | - v-if="currentMember && false" |
32 | | - :project="project" |
33 | | - :versions="versions" |
34 | | - :current-member="currentMember" |
35 | | - :is-settings="route.name.startsWith('type-id-settings')" |
36 | | - :set-processing="setProcessing" |
37 | | - :all-members="allMembers" |
38 | | - :update-members="invalidateProject" |
39 | | - :auth="auth" |
40 | | - :tags="tags" |
41 | | - /> |
42 | | - </div> |
43 | | - <div class="normal-page__content"> |
44 | | - <NuxtPage /> |
45 | 47 | </div> |
46 | | - </div> |
| 48 | + </template> |
47 | 49 |
|
48 | 50 | <div v-else> |
49 | 51 | <NewModal |
|
811 | 813 | :project="project" |
812 | 814 | :versions="versions" |
813 | 815 | :current-member="currentMember" |
814 | | - :is-settings="route.name.startsWith('type-id-settings')" |
| 816 | + :is-settings="isSettings" |
815 | 817 | :route-name="route.name" |
816 | 818 | :set-processing="setProcessing" |
817 | 819 | :collapsed="collapsedChecklist" |
@@ -1826,6 +1828,8 @@ const { data: organizationRaw } = useQuery({ |
1826 | 1828 | // Return null when the project no longer belongs to an organization. |
1827 | 1829 | const organization = computed(() => (projectRaw.value?.organization ? organizationRaw.value : null)) |
1828 | 1830 |
|
| 1831 | +const isSettings = computed(() => route.name.startsWith('type-id-settings')) |
| 1832 | +
|
1829 | 1833 | // Transform versionsV3 to be same shape as versionsV2 for compatibility in project pages |
1830 | 1834 | const versionsRaw = computed(() => { |
1831 | 1835 | return (versionsV3.value ?? []).map((v) => { |
@@ -2262,11 +2266,27 @@ const currentMember = computed(() => { |
2262 | 2266 | return val |
2263 | 2267 | }) |
2264 | 2268 |
|
| 2269 | +const canAccessSettings = computed(() => !!currentMember.value?.accepted) |
| 2270 | +
|
2265 | 2271 | const hasEditDetailsPermission = computed(() => { |
2266 | 2272 | const EDIT_DETAILS = 1 << 2 |
2267 | 2273 | return (currentMember.value?.permissions & EDIT_DETAILS) === EDIT_DETAILS |
2268 | 2274 | }) |
2269 | 2275 |
|
| 2276 | +watch( |
| 2277 | + [isSettings, currentMember], |
| 2278 | + () => { |
| 2279 | + if (isSettings.value && !canAccessSettings.value) { |
| 2280 | + showError({ |
| 2281 | + fatal: true, |
| 2282 | + statusCode: 401, |
| 2283 | + statusMessage: 'Unauthorized', |
| 2284 | + }) |
| 2285 | + } |
| 2286 | + }, |
| 2287 | + { flush: 'sync', immediate: true }, |
| 2288 | +) |
| 2289 | +
|
2270 | 2290 | const projectTypeDisplay = computed(() => { |
2271 | 2291 | if (!project.value) return '' |
2272 | 2292 | return formatProjectType( |
|
0 commit comments