Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3711e01a77 | ||
|
|
63c9cb6b92 | ||
|
|
f039e116d7 | ||
|
|
93621baea5 | ||
|
|
eaa17fa48d | ||
|
|
9ce94fbbfc | ||
|
|
69548e6ed0 | ||
|
|
5cd2ba1362 | ||
|
|
f15d347804 | ||
|
|
c95118715a | ||
|
|
21e7ac3cbe | ||
|
|
81de95bd28 | ||
|
|
d80ed07093 | ||
|
|
b2ac86c759 | ||
|
|
295cf40c6e | ||
|
|
92827b2c9d | ||
|
|
e1076690c1 | ||
|
|
70dd9b9c2c |
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
undecided:
|
||||
- "@calcom/prisma"
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { NextApiRequest } from "next";
|
||||
|
||||
import { getStripeCustomerIdFromUserId } from "@calcom/app-store/stripepayment/lib/customer";
|
||||
import stripe from "@calcom/app-store/stripepayment/lib/server";
|
||||
import { getDubCustomer } from "@calcom/features/auth/lib/dub";
|
||||
import stripe from "@calcom/features/ee/payments/server/stripe";
|
||||
import { IS_PRODUCTION } from "@calcom/lib/constants";
|
||||
import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"@axiomhq/winston": "^1.2.0",
|
||||
"@calcom/platform-constants": "*",
|
||||
"@calcom/platform-enums": "*",
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.156",
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.160",
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
|
||||
"@calcom/platform-types": "*",
|
||||
"@calcom/platform-utils": "*",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ReassignBookingOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/outpu
|
||||
import { RescheduleBookingOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/outputs/reschedule-booking.output";
|
||||
import { BookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/bookings.service";
|
||||
import { VERSION_2024_08_13_VALUE, VERSION_2024_08_13 } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -155,12 +156,7 @@ export class BookingsController_2024_08_13 {
|
||||
|
||||
@Get("/")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
})
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@Permissions([BOOKING_READ])
|
||||
@ApiOperation({ summary: "Get all bookings" })
|
||||
async getBookings(
|
||||
@@ -245,13 +241,10 @@ export class BookingsController_2024_08_13 {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Permissions([BOOKING_WRITE])
|
||||
@UseGuards(ApiAuthGuard, BookingUidGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({
|
||||
summary: "Mark a booking absence - provided authorization header refers to owner of the booking.",
|
||||
})
|
||||
@ApiOperation({ summary: "Mark a booking absence" })
|
||||
async markNoShow(
|
||||
@Param("bookingUid") bookingUid: string,
|
||||
@Body() body: MarkAbsentBookingInput_2024_08_13,
|
||||
@@ -269,13 +262,11 @@ export class BookingsController_2024_08_13 {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Permissions([BOOKING_WRITE])
|
||||
@UseGuards(ApiAuthGuard, BookingUidGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({
|
||||
summary:
|
||||
"Automatically reassign booking to a new host automatically - provided authorization header refers to person who reassigned the booking.",
|
||||
})
|
||||
@ApiOperation({ summary: "Automatically reassign booking to a new host" })
|
||||
async reassignBooking(
|
||||
@Param("bookingUid") bookingUid: string,
|
||||
@GetUser() user: UserWithProfile
|
||||
@@ -292,13 +283,11 @@ export class BookingsController_2024_08_13 {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Permissions([BOOKING_WRITE])
|
||||
@UseGuards(ApiAuthGuard, BookingUidGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({
|
||||
summary:
|
||||
"Reassign a booking to a specific user specified by the :userId - provided authorization header refers to person who reassigned the booking.",
|
||||
})
|
||||
@ApiOperation({ summary: "Reassign a booking to a specific user" })
|
||||
async reassignBookingToUser(
|
||||
@Param("bookingUid") bookingUid: string,
|
||||
@Param("userId") userId: number,
|
||||
@@ -322,13 +311,11 @@ export class BookingsController_2024_08_13 {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Permissions([BOOKING_WRITE])
|
||||
@UseGuards(ApiAuthGuard, BookingUidGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({
|
||||
summary:
|
||||
"Confirm booking that requires a confirmation - provided authorization header refers to owner of the booking.",
|
||||
})
|
||||
@ApiOperation({ summary: "Confirm booking that requires a confirmation" })
|
||||
async confirmBooking(
|
||||
@Param("bookingUid") bookingUid: string,
|
||||
@GetUser() user: UserWithProfile
|
||||
@@ -345,13 +332,11 @@ export class BookingsController_2024_08_13 {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Permissions([BOOKING_WRITE])
|
||||
@UseGuards(ApiAuthGuard, BookingUidGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({
|
||||
summary:
|
||||
"Decline booking that requires a confirmation - provided authorization header refers to owner of the booking.",
|
||||
})
|
||||
@ApiOperation({ summary: "Decline booking that requires a confirmation" })
|
||||
async declineBooking(
|
||||
@Param("bookingUid") bookingUid: string,
|
||||
@Body() body: DeclineBookingInput_2024_08_13,
|
||||
@@ -368,6 +353,7 @@ export class BookingsController_2024_08_13 {
|
||||
@Get("/:bookingUid/calendar-links")
|
||||
@UseGuards(ApiAuthGuard, BookingUidGuard)
|
||||
@Permissions([BOOKING_READ])
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({
|
||||
summary: "Get 'Add to Calendar' links for a booking",
|
||||
description:
|
||||
|
||||
@@ -14,6 +14,7 @@ import { GoogleCalendarService } from "@/ee/calendars/services/gcal.service";
|
||||
import { IcsFeedService } from "@/ee/calendars/services/ics-feed.service";
|
||||
import { OutlookService } from "@/ee/calendars/services/outlook.service";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -34,7 +35,7 @@ import {
|
||||
Post,
|
||||
Body,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiParam, ApiQuery, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiParam, ApiQuery, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { User } from "@prisma/client";
|
||||
import { plainToClass } from "class-transformer";
|
||||
import { Request } from "express";
|
||||
@@ -68,6 +69,7 @@ export class CalendarsController {
|
||||
|
||||
@Post("/ics-feed/save")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Save an ICS feed" })
|
||||
async createIcsFeed(
|
||||
@GetUser("id") userId: number,
|
||||
@@ -79,12 +81,14 @@ export class CalendarsController {
|
||||
|
||||
@Get("/ics-feed/check")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Check an ICS feed" })
|
||||
async checkIcsFeed(@GetUser("id") userId: number): Promise<ApiResponse> {
|
||||
return await this.icsFeedService.check(userId);
|
||||
}
|
||||
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@Get("/busy-times")
|
||||
@ApiOperation({
|
||||
summary: "Get busy times",
|
||||
@@ -113,6 +117,7 @@ export class CalendarsController {
|
||||
|
||||
@Get("/")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Get all calendars" })
|
||||
async getCalendars(@GetUser("id") userId: number): Promise<ConnectedCalendarsOutput> {
|
||||
const calendars = await this.calendarsService.getCalendars(userId);
|
||||
@@ -129,6 +134,7 @@ export class CalendarsController {
|
||||
name: "calendar",
|
||||
})
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@Get("/:calendar/connect")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Get oAuth connect URL" })
|
||||
@@ -199,6 +205,7 @@ export class CalendarsController {
|
||||
name: "calendar",
|
||||
})
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@Post("/:calendar/credentials")
|
||||
@ApiOperation({ summary: "Sync credentials" })
|
||||
async syncCredentials(
|
||||
@@ -227,6 +234,7 @@ export class CalendarsController {
|
||||
@Get("/:calendar/check")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard, PermissionsGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@Permissions([APPS_READ])
|
||||
@ApiOperation({ summary: "Check a calendar connection" })
|
||||
async check(@GetUser("id") userId: number, @Param("calendar") calendar: string): Promise<ApiResponse> {
|
||||
@@ -251,6 +259,7 @@ export class CalendarsController {
|
||||
name: "calendar",
|
||||
})
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@Post("/:calendar/disconnect")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Disconnect a calendar" })
|
||||
|
||||
+5
-24
@@ -7,6 +7,7 @@ import { EventTypeResponseTransformPipe } from "@/ee/event-types/event-types_202
|
||||
import { EventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/event-types.service";
|
||||
import { InputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/input-event-types.service";
|
||||
import { VERSION_2024_06_14_VALUE } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -67,12 +68,7 @@ export class EventTypesController_2024_06_14 {
|
||||
@Post("/")
|
||||
@Permissions([EVENT_TYPE_WRITE])
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
})
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Create an event type" })
|
||||
async createEventType(
|
||||
@Body() body: CreateEventTypeInput_2024_06_14,
|
||||
@@ -94,12 +90,7 @@ export class EventTypesController_2024_06_14 {
|
||||
@Get("/:eventTypeId")
|
||||
@Permissions([EVENT_TYPE_READ])
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
})
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Get an event type" })
|
||||
async getEventTypeById(
|
||||
@Param("eventTypeId") eventTypeId: string,
|
||||
@@ -149,12 +140,7 @@ export class EventTypesController_2024_06_14 {
|
||||
@Patch("/:eventTypeId")
|
||||
@Permissions([EVENT_TYPE_WRITE])
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
})
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Update an event type" })
|
||||
async updateEventType(
|
||||
@@ -179,12 +165,7 @@ export class EventTypesController_2024_06_14 {
|
||||
@Delete("/:eventTypeId")
|
||||
@Permissions([EVENT_TYPE_WRITE])
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
})
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Delete an event type" })
|
||||
async deleteEventType(
|
||||
@Param("eventTypeId") eventTypeId: number,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { GetMeOutput } from "@/ee/me/outputs/get-me.output";
|
||||
import { UpdateMeOutput } from "@/ee/me/outputs/update-me.output";
|
||||
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -10,7 +11,7 @@ import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-us
|
||||
import { UsersService } from "@/modules/users/services/users.service";
|
||||
import { UserWithProfile, UsersRepository } from "@/modules/users/users.repository";
|
||||
import { Controller, UseGuards, Get, Patch, Body } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { PROFILE_READ, PROFILE_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { userSchemaResponse } from "@calcom/platform-types";
|
||||
@@ -21,6 +22,7 @@ import { userSchemaResponse } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, PermissionsGuard)
|
||||
@DocsTags("Me")
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
export class MeController {
|
||||
constructor(
|
||||
private readonly usersRepository: UsersRepository,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ProviderVerifyAccessTokenOutput } from "@/ee/provider/outputs/verify-access-token.output";
|
||||
import { ProviderVerifyClientOutput } from "@/ee/provider/outputs/verify-client.output";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository";
|
||||
@@ -16,7 +17,7 @@ import {
|
||||
UnauthorizedException,
|
||||
UseGuards,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiExcludeController, ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
@@ -24,6 +25,9 @@ import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
path: "/v2/provider",
|
||||
version: API_VERSIONS_VALUES,
|
||||
})
|
||||
// note(Lauris): this controller is used by useOAuthClient and useOAuthFlow internal hooks and if customer
|
||||
// wants to know if access token is expired then the flow is to make request and then receive message it expired.
|
||||
@ApiExcludeController()
|
||||
@DocsTags("Platform / Cal Provider")
|
||||
export class CalProviderController {
|
||||
constructor(private readonly oauthClientRepository: OAuthClientRepository) {}
|
||||
@@ -53,6 +57,7 @@ export class CalProviderController {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiOperation({ summary: "Verify an access token" })
|
||||
@ApiHeader(ACCESS_TOKEN_HEADER)
|
||||
async verifyAccessToken(
|
||||
@Param("clientId") clientId: string,
|
||||
@GetUser() user: UserWithProfile
|
||||
|
||||
+2
-6
@@ -1,5 +1,6 @@
|
||||
import { SchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/schedules.service";
|
||||
import { VERSION_2024_06_14, VERSION_2024_06_11 } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -46,12 +47,7 @@ import {
|
||||
default: VERSION_2024_06_11,
|
||||
},
|
||||
})
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
|
||||
required: true,
|
||||
})
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
export class SchedulesController_2024_06_11 {
|
||||
constructor(private readonly schedulesService: SchedulesService_2024_06_11) {}
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { ApiHeaderOptions } from "@nestjs/swagger";
|
||||
|
||||
import { X_CAL_CLIENT_ID, X_CAL_SECRET_KEY } from "@calcom/platform-constants";
|
||||
|
||||
export const OPTIONAL_X_CAL_CLIENT_ID_HEADER: ApiHeaderOptions = {
|
||||
name: X_CAL_CLIENT_ID,
|
||||
description: "For platform customers - OAuth client ID",
|
||||
required: false,
|
||||
};
|
||||
|
||||
export const OPTIONAL_X_CAL_SECRET_KEY_HEADER: ApiHeaderOptions = {
|
||||
name: X_CAL_SECRET_KEY,
|
||||
description: "For platform customers - OAuth client secret key",
|
||||
required: false,
|
||||
};
|
||||
|
||||
export const X_CAL_CLIENT_ID_HEADER: ApiHeaderOptions = {
|
||||
name: X_CAL_CLIENT_ID,
|
||||
description: "For platform customers - OAuth client ID",
|
||||
required: false,
|
||||
};
|
||||
|
||||
export const X_CAL_SECRET_KEY_HEADER: ApiHeaderOptions = {
|
||||
name: X_CAL_SECRET_KEY,
|
||||
description: "For platform customers - OAuth client secret key",
|
||||
required: false,
|
||||
};
|
||||
|
||||
export const OPTIONAL_API_KEY_HEADER: ApiHeaderOptions = {
|
||||
name: "Authorization",
|
||||
description:
|
||||
"For non-platform customers - value must be `Bearer <token>` where `<token>` is api key prefixed with cal_",
|
||||
required: false,
|
||||
};
|
||||
|
||||
export const API_KEY_HEADER: ApiHeaderOptions = {
|
||||
name: "Authorization",
|
||||
description: "value must be `Bearer <token>` where `<token>` is api key prefixed with cal_",
|
||||
required: true,
|
||||
};
|
||||
|
||||
export const API_KEY_OR_ACCESS_TOKEN_HEADER: ApiHeaderOptions = {
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` is api key prefixed with cal_ or managed user access token",
|
||||
required: true,
|
||||
};
|
||||
|
||||
export const OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER: ApiHeaderOptions = {
|
||||
name: "Authorization",
|
||||
description:
|
||||
"value must be `Bearer <token>` where `<token>` is api key prefixed with cal_ or managed user access token",
|
||||
required: false,
|
||||
};
|
||||
|
||||
export const ACCESS_TOKEN_HEADER: ApiHeaderOptions = {
|
||||
name: "Authorization",
|
||||
description: "value must be `Bearer <token>` where `<token>` is managed user access token",
|
||||
required: true,
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { RefreshApiKeyInput } from "@/modules/api-keys/inputs/refresh-api-key.input";
|
||||
import { RefreshApiKeyOutput } from "@/modules/api-keys/outputs/refresh-api-key.output";
|
||||
import { ApiKeysService } from "@/modules/api-keys/services/api-keys.service";
|
||||
@@ -23,12 +24,7 @@ export class ApiKeysController {
|
||||
summary: "Refresh API Key",
|
||||
description: `Generate a new API key and delete the current one. Provide API key to refresh as a Bearer token in the Authorization header (e.g. "Authorization: Bearer <apiKey>").`,
|
||||
})
|
||||
@ApiHeader({
|
||||
name: "Authorization",
|
||||
description: "Bearer <apiKey>",
|
||||
required: true,
|
||||
schema: { type: "string" },
|
||||
})
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
@Post("/refresh")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
async refresh(
|
||||
|
||||
@@ -9,8 +9,7 @@ import { UsersService } from "@/modules/users/services/users.service";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import { Injectable, NotFoundException, ForbiddenException } from "@nestjs/common";
|
||||
|
||||
import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
|
||||
import { getClientSecretFromPayment } from "@calcom/platform-libraries";
|
||||
import { checkAdminOrOwner, getClientSecretFromPayment } from "@calcom/platform-libraries";
|
||||
import type { TeamQuery } from "@calcom/platform-libraries";
|
||||
import { enrichUserWithDelegationConferencingCredentialsWithoutOrgId } from "@calcom/platform-libraries/app-store";
|
||||
import { getEnabledAppsFromCredentials, getAppFromSlug } from "@calcom/platform-libraries/app-store";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import {
|
||||
@@ -37,7 +38,7 @@ import {
|
||||
Req,
|
||||
HttpException,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiParam, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiParam, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToInstance } from "class-transformer";
|
||||
import { Request } from "express";
|
||||
|
||||
@@ -70,6 +71,7 @@ export class ConferencingController {
|
||||
@Post("/:app/connect")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Connect your conferencing application" })
|
||||
@ApiParam({
|
||||
name: "app",
|
||||
@@ -98,6 +100,7 @@ export class ConferencingController {
|
||||
@Get("/:app/oauth/auth-url")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Get OAuth conferencing app auth url" })
|
||||
@ApiParam({
|
||||
name: "app",
|
||||
@@ -204,6 +207,7 @@ export class ConferencingController {
|
||||
@Get("/")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "List your conferencing applications" })
|
||||
async listInstalledConferencingApps(
|
||||
@GetUser("id") userId: number
|
||||
@@ -220,6 +224,7 @@ export class ConferencingController {
|
||||
@Post("/:app/default")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Set your default conferencing application" })
|
||||
@ApiParam({
|
||||
name: "app",
|
||||
@@ -238,6 +243,7 @@ export class ConferencingController {
|
||||
@Get("/default")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Get your default conferencing application" })
|
||||
async getDefault(@GetUser("id") userId: number): Promise<GetDefaultConferencingAppOutputResponseDto> {
|
||||
const defaultconferencingApp = await this.conferencingService.getUserDefaultConferencingApp(userId);
|
||||
@@ -247,6 +253,7 @@ export class ConferencingController {
|
||||
@Delete("/:app/disconnect")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Disconnect your conferencing application" })
|
||||
@ApiParam({
|
||||
name: "app",
|
||||
|
||||
+4
-2
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import { DestinationCalendarsInputBodyDto } from "@/modules/destination-calendars/inputs/destination-calendars.input";
|
||||
@@ -9,7 +10,7 @@ import {
|
||||
import { DestinationCalendarsService } from "@/modules/destination-calendars/services/destination-calendars.service";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import { Body, Controller, Put, UseGuards } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -19,11 +20,12 @@ import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
version: API_VERSIONS_VALUES,
|
||||
})
|
||||
@DocsTags("Destination Calendars")
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@UseGuards(ApiAuthGuard)
|
||||
export class DestinationCalendarsController {
|
||||
constructor(private readonly destinationCalendarsService: DestinationCalendarsService) {}
|
||||
|
||||
@Put("/")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiOperation({ summary: "Update destination calendars" })
|
||||
async updateDestinationCalendars(
|
||||
@Body() input: DestinationCalendarsInputBodyDto,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import { GetWebhook } from "@/modules/webhooks/decorators/get-webhook-decorator";
|
||||
import { IsUserEventTypeWebhookGuard } from "@/modules/webhooks/guards/is-user-event-type-webhook-guard";
|
||||
@@ -25,7 +26,7 @@ import {
|
||||
Patch,
|
||||
ParseIntPipe,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { Webhook } from "@prisma/client";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
@@ -38,6 +39,7 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsUserEventTypeWebhookGuard)
|
||||
@DocsTags("Event Types / Webhooks")
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
export class EventTypeWebhooksController {
|
||||
constructor(
|
||||
private readonly webhooksService: WebhooksService,
|
||||
|
||||
+7
-3
@@ -31,11 +31,10 @@ import {
|
||||
Query,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiOperation, ApiTags as DocsTags, ApiHeader } from "@nestjs/swagger";
|
||||
import { User, MembershipRole } from "@prisma/client";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { Pagination } from "@calcom/platform-types";
|
||||
import { SUCCESS_STATUS, X_CAL_SECRET_KEY } from "@calcom/platform-constants";
|
||||
|
||||
@Controller({
|
||||
path: "/v2/oauth-clients/:clientId/users",
|
||||
@@ -43,6 +42,11 @@ import { Pagination } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, OAuthClientGuard, OrganizationRolesGuard)
|
||||
@DocsTags("Platform / Managed Users")
|
||||
@ApiHeader({
|
||||
name: X_CAL_SECRET_KEY,
|
||||
description: "OAuth client secret key",
|
||||
required: true,
|
||||
})
|
||||
export class OAuthClientUsersController {
|
||||
private readonly logger = new Logger("UserController");
|
||||
|
||||
|
||||
+7
-2
@@ -16,11 +16,11 @@ import { WebhookOutputPipe } from "@/modules/webhooks/pipes/WebhookOutputPipe";
|
||||
import { OAuthClientWebhooksService } from "@/modules/webhooks/services/oauth-clients-webhooks.service";
|
||||
import { WebhooksService } from "@/modules/webhooks/services/webhooks.service";
|
||||
import { Controller, Post, Body, UseGuards, Get, Param, Query, Delete, Patch } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { Webhook, MembershipRole } from "@prisma/client";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { SUCCESS_STATUS, X_CAL_SECRET_KEY } from "@calcom/platform-constants";
|
||||
import { SkipTakePagination } from "@calcom/platform-types";
|
||||
|
||||
import { OAuthClientGuard } from "../../guards/oauth-client-guard";
|
||||
@@ -31,6 +31,11 @@ import { OAuthClientGuard } from "../../guards/oauth-client-guard";
|
||||
})
|
||||
@UseGuards(NextAuthGuard, OrganizationRolesGuard, OAuthClientGuard)
|
||||
@DocsTags("Platform / Webhooks")
|
||||
@ApiHeader({
|
||||
name: X_CAL_SECRET_KEY,
|
||||
description: "OAuth client secret key",
|
||||
required: true,
|
||||
})
|
||||
export class OAuthClientWebhooksController {
|
||||
constructor(
|
||||
private readonly webhooksService: WebhooksService,
|
||||
|
||||
+20
-5
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { GetOrgId } from "@/modules/auth/decorators/get-org-id/get-org-id.decorator";
|
||||
import { MembershipRoles } from "@/modules/auth/decorators/roles/membership-roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -9,7 +10,6 @@ import { CreateOAuthClientResponseDto } from "@/modules/oauth-clients/controller
|
||||
import { GetOAuthClientResponseDto } from "@/modules/oauth-clients/controllers/oauth-clients/responses/GetOAuthClientResponse.dto";
|
||||
import { GetOAuthClientsResponseDto } from "@/modules/oauth-clients/controllers/oauth-clients/responses/GetOAuthClientsResponse.dto";
|
||||
import { OAuthClientGuard } from "@/modules/oauth-clients/guards/oauth-client-guard";
|
||||
import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository";
|
||||
import { OAuthClientsService } from "@/modules/oauth-clients/services/oauth-clients/oauth-clients.service";
|
||||
import { OrganizationsRepository } from "@/modules/organizations/index/organizations.repository";
|
||||
import { UsersRepository } from "@/modules/users/users.repository";
|
||||
@@ -26,10 +26,15 @@ import {
|
||||
HttpStatus,
|
||||
Logger,
|
||||
UseGuards,
|
||||
NotFoundException,
|
||||
BadRequestException,
|
||||
} from "@nestjs/common";
|
||||
import { ApiCreatedResponse as DocsCreatedResponse, ApiTags } from "@nestjs/swagger";
|
||||
import {
|
||||
ApiCreatedResponse as DocsCreatedResponse,
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
ApiExcludeEndpoint,
|
||||
ApiHeader,
|
||||
} from "@nestjs/swagger";
|
||||
import { User, MembershipRole } from "@prisma/client";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -41,11 +46,11 @@ import { CreateOAuthClientInput, UpdateOAuthClientInput, Pagination } from "@cal
|
||||
})
|
||||
@ApiTags("OAuth Clients")
|
||||
@UseGuards(ApiAuthGuard, OrganizationRolesGuard)
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
export class OAuthClientsController {
|
||||
private readonly logger = new Logger("OAuthClientController");
|
||||
|
||||
constructor(
|
||||
private readonly oauthClientRepository: OAuthClientRepository,
|
||||
private readonly oAuthClientsService: OAuthClientsService,
|
||||
private readonly userRepository: UsersRepository,
|
||||
private readonly teamsRepository: OrganizationsRepository
|
||||
@@ -58,6 +63,7 @@ export class OAuthClientsController {
|
||||
description: "Create an OAuth client",
|
||||
type: CreateOAuthClientResponseDto,
|
||||
})
|
||||
@ApiOperation({ summary: "Create an OAuth client" })
|
||||
async createOAuthClient(
|
||||
@GetOrgId() organizationId: number,
|
||||
@Body() body: CreateOAuthClientInput
|
||||
@@ -68,7 +74,9 @@ export class OAuthClientsController {
|
||||
|
||||
const organization = await this.teamsRepository.findByIdIncludeBilling(organizationId);
|
||||
if (!organization?.platformBilling || !organization?.platformBilling?.subscriptionId) {
|
||||
throw new BadRequestException("Team is not subscribed, cannot create an OAuth Client.");
|
||||
throw new BadRequestException(
|
||||
"Team is not subscribed to platform plan, cannot create an OAuth Client."
|
||||
);
|
||||
}
|
||||
|
||||
const oAuthClientCredentials = await this.oAuthClientsService.createOAuthClient(organizationId, body);
|
||||
@@ -81,6 +89,7 @@ export class OAuthClientsController {
|
||||
|
||||
@Get("/")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Get all OAuth clients" })
|
||||
@MembershipRoles([MembershipRole.ADMIN, MembershipRole.OWNER, MembershipRole.MEMBER])
|
||||
async getOAuthClients(@GetOrgId() organizationId: number): Promise<GetOAuthClientsResponseDto> {
|
||||
const clients = await this.oAuthClientsService.getOAuthClients(organizationId);
|
||||
@@ -91,6 +100,7 @@ export class OAuthClientsController {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@MembershipRoles([MembershipRole.ADMIN, MembershipRole.OWNER, MembershipRole.MEMBER])
|
||||
@UseGuards(OAuthClientGuard)
|
||||
@ApiOperation({ summary: "Get an OAuth client" })
|
||||
async getOAuthClientById(@Param("clientId") clientId: string): Promise<GetOAuthClientResponseDto> {
|
||||
const client = await this.oAuthClientsService.getOAuthClientById(clientId);
|
||||
return { status: SUCCESS_STATUS, data: client };
|
||||
@@ -100,6 +110,9 @@ export class OAuthClientsController {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@MembershipRoles([MembershipRole.ADMIN, MembershipRole.OWNER, MembershipRole.MEMBER])
|
||||
@UseGuards(OAuthClientGuard)
|
||||
// note(Lauris): Excluding this endpoint because we have oauth-clients-users.controller to fetch oAuth users and I am leaving this endpoint
|
||||
// just in case someone is using it.
|
||||
@ApiExcludeEndpoint()
|
||||
async getOAuthClientManagedUsersById(
|
||||
@Param("clientId") clientId: string,
|
||||
@Query() queryParams: Pagination
|
||||
@@ -118,6 +131,7 @@ export class OAuthClientsController {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@MembershipRoles([MembershipRole.ADMIN, MembershipRole.OWNER])
|
||||
@UseGuards(OAuthClientGuard)
|
||||
@ApiOperation({ summary: "Update an OAuth client" })
|
||||
async updateOAuthClient(
|
||||
@Param("clientId") clientId: string,
|
||||
@Body() body: UpdateOAuthClientInput
|
||||
@@ -131,6 +145,7 @@ export class OAuthClientsController {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@MembershipRoles([MembershipRole.ADMIN, MembershipRole.OWNER])
|
||||
@UseGuards(OAuthClientGuard)
|
||||
@ApiOperation({ summary: "Delete an OAuth client" })
|
||||
async deleteOAuthClient(@Param("clientId") clientId: string): Promise<GetOAuthClientResponseDto> {
|
||||
this.logger.log(`Deleting OAuth Client with ID: ${clientId}`);
|
||||
const client = await this.oAuthClientsService.deleteOAuthClient(clientId);
|
||||
|
||||
+3
-1
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -28,7 +29,7 @@ import {
|
||||
Query,
|
||||
UseGuards,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { SkipTakePagination } from "@calcom/platform-types";
|
||||
@@ -39,6 +40,7 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Attributes")
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
export class OrganizationsAttributesController {
|
||||
constructor(private readonly organizationsAttributesService: OrganizationAttributesService) {}
|
||||
// Gets all attributes for an organization
|
||||
|
||||
+3
-1
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -20,7 +21,7 @@ import { GetAllAttributeOptionOutput } from "@/modules/organizations/attributes/
|
||||
import { UpdateAttributeOptionOutput } from "@/modules/organizations/attributes/options/outputs/update-option.output";
|
||||
import { OrganizationAttributeOptionService } from "@/modules/organizations/attributes/options/services/organization-attributes-option.service";
|
||||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, UseGuards } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
@@ -30,6 +31,7 @@ import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Attributes / Options")
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
export class OrganizationsAttributesOptionsController {
|
||||
constructor(private readonly organizationsAttributesOptionsService: OrganizationAttributeOptionService) {}
|
||||
|
||||
|
||||
+9
-1
@@ -1,4 +1,9 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
@@ -23,7 +28,7 @@ import {
|
||||
HttpStatus,
|
||||
Patch,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { User } from "@prisma/client";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
@@ -37,6 +42,9 @@ import { CreateDelegationCredentialInput } from "./inputs/create-delegation-cred
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Delegation Credentials")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsDelegationCredentialController {
|
||||
constructor(private readonly delegationCredentialService: OrganizationsDelegationCredentialService) {}
|
||||
|
||||
|
||||
+10
-2
@@ -1,6 +1,11 @@
|
||||
import { CreatePhoneCallInput } from "@/ee/event-types/event-types_2024_06_14/inputs/create-phone-call.input";
|
||||
import { CreatePhoneCallOutput } from "@/ee/event-types/event-types_2024_06_14/outputs/create-phone-call.output";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
@@ -35,7 +40,7 @@ import {
|
||||
NotFoundException,
|
||||
Query,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { ERROR_STATUS, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { handleCreatePhoneCall } from "@calcom/platform-libraries";
|
||||
@@ -56,7 +61,10 @@ export type EventTypeHandlerResponse = {
|
||||
path: "/v2/organizations/:orgId",
|
||||
version: API_VERSIONS_VALUES,
|
||||
})
|
||||
@DocsTags("Orgs / Event Types")
|
||||
@DocsTags("Orgs / Teams / Event Types")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsEventTypesController {
|
||||
constructor(
|
||||
private readonly organizationsEventTypesService: OrganizationsEventTypesService,
|
||||
|
||||
+9
-1
@@ -1,4 +1,9 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -30,7 +35,7 @@ import {
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -42,6 +47,9 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Memberships")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsMembershipsController {
|
||||
constructor(private organizationsMembershipService: OrganizationsMembershipService) {}
|
||||
|
||||
|
||||
+4
-1
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { X_CAL_CLIENT_ID_HEADER, X_CAL_SECRET_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
@@ -28,7 +29,7 @@ import {
|
||||
HttpStatus,
|
||||
Delete,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
@@ -40,6 +41,8 @@ const SCALE = "SCALE";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Orgs")
|
||||
@ApiHeader(X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(X_CAL_SECRET_KEY_HEADER)
|
||||
export class OrganizationsOrganizationsController {
|
||||
constructor(private readonly managedOrganizationsService: ManagedOrganizationsService) {}
|
||||
|
||||
|
||||
+10
-2
@@ -1,5 +1,10 @@
|
||||
import { SchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/schedules.service";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -23,7 +28,7 @@ import {
|
||||
HttpStatus,
|
||||
Query,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import {
|
||||
@@ -42,7 +47,9 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
version: API_VERSIONS_VALUES,
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Schedules")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsSchedulesController {
|
||||
constructor(
|
||||
private schedulesService: SchedulesService_2024_06_11,
|
||||
@@ -52,6 +59,7 @@ export class OrganizationsSchedulesController {
|
||||
@Roles("ORG_ADMIN")
|
||||
@PlatformPlan("ESSENTIALS")
|
||||
@Get("/schedules")
|
||||
@DocsTags("Orgs / Schedules")
|
||||
@ApiOperation({ summary: "Get all schedules" })
|
||||
async getOrganizationSchedules(
|
||||
@Param("orgId", ParseIntPipe) orgId: number,
|
||||
|
||||
+9
-1
@@ -1,6 +1,11 @@
|
||||
import { BookingUidGuard } from "@/ee/bookings/2024-08-13/guards/booking-uid.guard";
|
||||
import { BookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/bookings.service";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
@@ -13,7 +18,7 @@ import { IsTeamInOrg } from "@/modules/auth/guards/teams/is-team-in-org.guard";
|
||||
import { GetOrganizationsTeamsBookingsInput_2024_08_13 } from "@/modules/organizations/teams/bookings/inputs/get-organizations-teams-bookings.input";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import { Controller, UseGuards, Get, Param, ParseIntPipe, Query, HttpStatus, HttpCode } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { GetBookingsOutput_2024_08_13 } from "@calcom/platform-types";
|
||||
@@ -24,6 +29,9 @@ import { GetBookingsOutput_2024_08_13 } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, IsTeamInOrg, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Teams / Bookings")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsTeamsBookingsController {
|
||||
constructor(private readonly bookingsService: BookingsService_2024_08_13) {}
|
||||
|
||||
|
||||
+13
-4
@@ -1,4 +1,9 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { GetTeam } from "@/modules/auth/decorators/get-team/get-team.decorator";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
@@ -30,10 +35,11 @@ import {
|
||||
Patch,
|
||||
Post,
|
||||
Body,
|
||||
Headers,
|
||||
Req,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
import { Request } from "express";
|
||||
|
||||
import { SUCCESS_STATUS, X_CAL_CLIENT_ID } from "@calcom/platform-constants";
|
||||
import { OrgTeamOutputDto } from "@calcom/platform-types";
|
||||
@@ -46,11 +52,13 @@ import { Team } from "@calcom/prisma/client";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Teams")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsTeamsController {
|
||||
constructor(private organizationsTeamsService: OrganizationsTeamsService) {}
|
||||
|
||||
@Get()
|
||||
@DocsTags("Teams")
|
||||
@ApiOperation({ summary: "Get all teams" })
|
||||
@Roles("ORG_ADMIN")
|
||||
@PlatformPlan("ESSENTIALS")
|
||||
@@ -148,8 +156,9 @@ export class OrganizationsTeamsController {
|
||||
@Param("orgId", ParseIntPipe) orgId: number,
|
||||
@Body() body: CreateOrgTeamDto,
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Headers(X_CAL_CLIENT_ID) oAuthClientId?: string
|
||||
@Req() req: Request
|
||||
): Promise<OrgTeamOutputResponseDto> {
|
||||
const oAuthClientId = req.headers[X_CAL_CLIENT_ID] as string | undefined;
|
||||
const team = oAuthClientId
|
||||
? await this.organizationsTeamsService.createPlatformOrgTeam(orgId, oAuthClientId, body, user)
|
||||
: await this.organizationsTeamsService.createOrgTeam(orgId, body, user);
|
||||
|
||||
+9
-1
@@ -1,4 +1,9 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -33,7 +38,7 @@ import {
|
||||
UnprocessableEntityException,
|
||||
Logger,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -46,6 +51,9 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, IsTeamInOrg, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Teams / Memberships")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsTeamsMembershipsController {
|
||||
private logger = new Logger("OrganizationsTeamsMembershipsController");
|
||||
|
||||
|
||||
+3
-3
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -8,11 +9,9 @@ import { IsOrgGuard } from "@/modules/auth/guards/organizations/is-org.guard";
|
||||
import { IsRoutingFormInTeam } from "@/modules/auth/guards/routing-forms/is-routing-form-in-team.guard";
|
||||
import { IsTeamInOrg } from "@/modules/auth/guards/teams/is-team-in-org.guard";
|
||||
import { Controller, Get, Param, UseGuards } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
import { ApiHeader, ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { RoutingFormResponseOutput } from "@calcom/platform-types";
|
||||
|
||||
import { RoutingFormsResponsesService } from "../../../../routing-forms-responses/services/routing-forms-responses.service";
|
||||
import { GetRoutingFormResponsesOutput } from "../outputs/get-routing-form-responses.output";
|
||||
@@ -30,6 +29,7 @@ import { GetRoutingFormResponsesOutput } from "../outputs/get-routing-form-respo
|
||||
PlatformPlanGuard,
|
||||
IsAdminAPIEnabledGuard
|
||||
)
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
export class OrganizationsTeamsRoutingFormsResponsesController {
|
||||
constructor(private readonly routingFormsResponsesService: RoutingFormsResponsesService) {}
|
||||
|
||||
|
||||
+12
-3
@@ -1,5 +1,10 @@
|
||||
import { SchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/schedules.service";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -10,7 +15,7 @@ import { RolesGuard } from "@/modules/auth/guards/roles/roles.guard";
|
||||
import { IsTeamInOrg } from "@/modules/auth/guards/teams/is-team-in-org.guard";
|
||||
import { IsUserInOrgTeam } from "@/modules/auth/guards/users/is-user-in-org-team.guard";
|
||||
import { Controller, UseGuards, Get, Param, ParseIntPipe } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { GetSchedulesOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
@@ -20,7 +25,9 @@ import { GetSchedulesOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
version: API_VERSIONS_VALUES,
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, IsTeamInOrg, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Teams / Schedules")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsTeamsSchedulesController {
|
||||
constructor(private schedulesService: SchedulesService_2024_06_11) {}
|
||||
|
||||
@@ -29,7 +36,9 @@ export class OrganizationsTeamsSchedulesController {
|
||||
@UseGuards(IsUserInOrgTeam)
|
||||
@Get("/users/:userId/schedules")
|
||||
@DocsTags("Orgs / Teams / Users / Schedules")
|
||||
@ApiOperation({ summary: "Get schedules of a team member" })
|
||||
@ApiOperation({
|
||||
summary: "Get schedules of a team member",
|
||||
})
|
||||
async getUserSchedules(
|
||||
@Param("userId", ParseIntPipe) userId: number
|
||||
): Promise<GetSchedulesOutput_2024_06_11> {
|
||||
|
||||
+9
-1
@@ -1,4 +1,9 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { GetOrg } from "@/modules/auth/decorators/get-org/get-org.decorator";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
@@ -33,7 +38,7 @@ import {
|
||||
Query,
|
||||
} from "@nestjs/common";
|
||||
import { ClassSerializerInterceptor } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToInstance } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -47,6 +52,9 @@ import { Team } from "@calcom/prisma/client";
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@UseGuards(IsOrgGuard)
|
||||
@DocsTags("Orgs / Users")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsUsersController {
|
||||
constructor(private readonly organizationsUsersService: OrganizationsUsersService) {}
|
||||
|
||||
|
||||
+9
-1
@@ -1,4 +1,9 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -35,7 +40,7 @@ import {
|
||||
Query,
|
||||
} from "@nestjs/common";
|
||||
import { ClassSerializerInterceptor } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToInstance } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -48,6 +53,9 @@ import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@UseGuards(IsOrgGuard)
|
||||
@DocsTags("Orgs / Users / OOO")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsUsersOOOController {
|
||||
constructor(
|
||||
private readonly userOOOService: UserOOOService,
|
||||
|
||||
+9
-1
@@ -1,4 +1,9 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import {
|
||||
OPTIONAL_API_KEY_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -32,7 +37,7 @@ import {
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -44,6 +49,9 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, PlatformPlanGuard, IsAdminAPIEnabledGuard)
|
||||
@DocsTags("Orgs / Webhooks")
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_HEADER)
|
||||
export class OrganizationsWebhooksController {
|
||||
constructor(
|
||||
private organizationsWebhooksService: OrganizationsWebhooksService,
|
||||
|
||||
+4
-3
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import {
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
import { SelectedCalendarsService } from "@/modules/selected-calendars/services/selected-calendars.service";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import { Body, Controller, Post, UseGuards, Delete, Query } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -22,11 +23,12 @@ import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
version: API_VERSIONS_VALUES,
|
||||
})
|
||||
@DocsTags("Selected Calendars")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
export class SelectedCalendarsController {
|
||||
constructor(private readonly selectedCalendarsService: SelectedCalendarsService) {}
|
||||
|
||||
@Post("/")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiOperation({ summary: "Add a selected calendar" })
|
||||
async addSelectedCalendar(
|
||||
@Body() input: SelectedCalendarsInputDto,
|
||||
@@ -41,7 +43,6 @@ export class SelectedCalendarsController {
|
||||
}
|
||||
|
||||
@Delete("/")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@ApiOperation({ summary: "Delete a selected calendar" })
|
||||
async deleteSelectedCalendar(
|
||||
@Query() queryParams: SelectedCalendarsQueryParamsInputDto,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { VERSION_2024_09_04 } from "@/lib/api-versions";
|
||||
import { OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER, OPTIONAL_X_CAL_CLIENT_ID_HEADER } from "@/lib/docs/headers";
|
||||
import { GetOptionalUser } from "@/modules/auth/decorators/get-optional-user/get-optional-user.decorator";
|
||||
import { OptionalApiAuthGuard } from "@/modules/auth/guards/optional-api-auth/optional-api-auth.guard";
|
||||
import { GetReservedSlotOutput_2024_09_04 } from "@/modules/slots/slots-2024-09-04/outputs/get-reserved-slot.output";
|
||||
@@ -13,12 +14,10 @@ import {
|
||||
Delete,
|
||||
Post,
|
||||
Param,
|
||||
Res,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Patch,
|
||||
UseGuards,
|
||||
BadRequestException,
|
||||
} from "@nestjs/common";
|
||||
import {
|
||||
ApiOperation,
|
||||
@@ -223,8 +222,12 @@ export class SlotsController_2024_09_04 {
|
||||
@UseGuards(OptionalApiAuthGuard)
|
||||
@ApiOperation({
|
||||
summary: "Reserve a slot",
|
||||
description: "Make a slot not available for others to book for a certain period of time.",
|
||||
description: `Make a slot not available for others to book for a certain period of time. If you authenticate using oAuth credentials, api key or access token
|
||||
then you can also specify custom duration for how long the slot should be reserved for (defaults to 5 minutes).`,
|
||||
})
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
async reserveSlot(
|
||||
@Body() body: ReserveSlotInput_2024_09_04,
|
||||
@GetOptionalUser() user: User
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import {
|
||||
@@ -23,7 +24,7 @@ import {
|
||||
Headers,
|
||||
Param,
|
||||
} from "@nestjs/common";
|
||||
import { ApiTags as DocsTags, ApiOperation } from "@nestjs/swagger";
|
||||
import { ApiTags as DocsTags, ApiOperation, ApiHeader } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
import { Request } from "express";
|
||||
import { stringify } from "querystring";
|
||||
@@ -42,6 +43,7 @@ export class StripeController {
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Get stripe connect URL" })
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
async redirect(
|
||||
@Req() req: Request,
|
||||
@Headers("Authorization") authorization: string,
|
||||
@@ -100,6 +102,7 @@ export class StripeController {
|
||||
@Get("/check")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Check stripe connection" })
|
||||
async check(@GetUser() user: UserWithProfile): Promise<StripCredentialsCheckOutputResponseDto> {
|
||||
return await this.stripeService.checkIfIndividualStripeAccountConnected(user.id);
|
||||
@@ -108,6 +111,7 @@ export class StripeController {
|
||||
@Get("/check/:teamId")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({ summary: "Check team stripe connection" })
|
||||
async checkTeamStripeConnection(
|
||||
@Param("teamId") teamId: string
|
||||
|
||||
+7
-1
@@ -1,6 +1,7 @@
|
||||
import { CreatePhoneCallInput } from "@/ee/event-types/event-types_2024_06_14/inputs/create-phone-call.input";
|
||||
import { CreatePhoneCallOutput } from "@/ee/event-types/event-types_2024_06_14/outputs/create-phone-call.output";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
@@ -31,7 +32,7 @@ import {
|
||||
NotFoundException,
|
||||
Query,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { ERROR_STATUS, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { handleCreatePhoneCall } from "@calcom/platform-libraries";
|
||||
@@ -63,6 +64,7 @@ export class TeamsEventTypesController {
|
||||
@Roles("TEAM_ADMIN")
|
||||
@PlatformPlan("ESSENTIALS")
|
||||
@UseGuards(ApiAuthGuard, RolesGuard)
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
@Post("/")
|
||||
@ApiOperation({ summary: "Create an event type" })
|
||||
async createTeamEventType(
|
||||
@@ -86,6 +88,7 @@ export class TeamsEventTypesController {
|
||||
|
||||
@Roles("TEAM_ADMIN")
|
||||
@UseGuards(ApiAuthGuard, RolesGuard)
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
@Get("/:eventTypeId")
|
||||
@ApiOperation({ summary: "Get an event type" })
|
||||
async getTeamEventType(
|
||||
@@ -109,6 +112,7 @@ export class TeamsEventTypesController {
|
||||
@Roles("TEAM_ADMIN")
|
||||
@Post("/:eventTypeId/create-phone-call")
|
||||
@UseGuards(ApiAuthGuard, RolesGuard)
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
@ApiOperation({ summary: "Create a phone call" })
|
||||
async createPhoneCall(
|
||||
@Param("eventTypeId") eventTypeId: number,
|
||||
@@ -162,6 +166,7 @@ export class TeamsEventTypesController {
|
||||
|
||||
@Roles("TEAM_ADMIN")
|
||||
@UseGuards(ApiAuthGuard, RolesGuard)
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
@Patch("/:eventTypeId")
|
||||
@ApiOperation({ summary: "Update a team event type" })
|
||||
async updateTeamEventType(
|
||||
@@ -193,6 +198,7 @@ export class TeamsEventTypesController {
|
||||
|
||||
@Roles("TEAM_ADMIN")
|
||||
@UseGuards(ApiAuthGuard, RolesGuard)
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
@Delete("/:eventTypeId")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Delete a team event type" })
|
||||
|
||||
+3
-1
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import { RolesGuard } from "@/modules/auth/guards/roles/roles.guard";
|
||||
@@ -27,7 +28,7 @@ import {
|
||||
HttpStatus,
|
||||
Logger,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -40,6 +41,7 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard, RolesGuard)
|
||||
@DocsTags("Teams / Memberships")
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
export class TeamsMembershipsController {
|
||||
private logger = new Logger("TeamsMembershipsController");
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
@@ -14,7 +15,7 @@ import { TeamsService } from "@/modules/teams/teams/services/teams.service";
|
||||
import { TeamsRepository } from "@/modules/teams/teams/teams.repository";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import { Controller, UseGuards, Get, Param, ParseIntPipe, Delete, Patch, Post, Body } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
@@ -26,6 +27,7 @@ import { TeamOutputDto } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@DocsTags("Teams")
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
export class TeamsController {
|
||||
constructor(private teamsService: TeamsService, private teamsRepository: TeamsRepository) {}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { TimezonesService } from "@/modules/timezones/services/timezones.service";
|
||||
import { Controller, Get } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiExcludeController, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { CityTimezones } from "@calcom/platform-libraries";
|
||||
@@ -11,6 +11,8 @@ import { ApiResponse } from "@calcom/platform-types";
|
||||
path: "/v2/timezones",
|
||||
version: API_VERSIONS_VALUES,
|
||||
})
|
||||
// note(Lauris): controller used only internally by atoms
|
||||
@ApiExcludeController()
|
||||
@DocsTags("Timezones")
|
||||
export class TimezonesController {
|
||||
constructor(private readonly timezonesService: TimezonesService) {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { API_KEY_HEADER } from "@/lib/docs/headers";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
@@ -15,7 +16,7 @@ import { WebhookOutputPipe } from "@/modules/webhooks/pipes/WebhookOutputPipe";
|
||||
import { UserWebhooksService } from "@/modules/webhooks/services/user-webhooks.service";
|
||||
import { WebhooksService } from "@/modules/webhooks/services/webhooks.service";
|
||||
import { Controller, Post, Body, UseGuards, Get, Param, Query, Delete, Patch } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { Webhook } from "@prisma/client";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
@@ -28,6 +29,7 @@ import { SkipTakePagination } from "@calcom/platform-types";
|
||||
})
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@DocsTags("Webhooks")
|
||||
@ApiHeader(API_KEY_HEADER)
|
||||
export class WebhooksController {
|
||||
constructor(
|
||||
private readonly webhooksService: WebhooksService,
|
||||
|
||||
+2647
-761
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,8 @@ import { DubReferralsPage } from "./DubReferralsPage";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Cal.com referral program - Earn money by sharing your link",
|
||||
description: "Earn 20% recurring commissions for a full year by referring others to Cal.com, while giving your referrals 20% off for 12 months. Share your link and start earning today!",
|
||||
description:
|
||||
"Earn 20% recurring commissions for a full year by referring others to Cal.com, while giving your referrals 20% off for 12 months. Share your link and start earning today!",
|
||||
};
|
||||
|
||||
// Export the appropriate component based on the feature flag
|
||||
|
||||
@@ -87,6 +87,7 @@ const PlainChat = IS_PLAIN_CHAT_ENABLED
|
||||
|
||||
const shouldOpenPlain = pathname === "/event-types" && searchParams?.has("openPlain");
|
||||
const userEmail = session?.user?.email;
|
||||
const isPaidUser = session?.user.belongsToActiveTeam || !!session?.user.org;
|
||||
|
||||
const isAppDomain = useMemo(() => {
|
||||
const restrictedPathsSet = new Set(
|
||||
@@ -166,14 +167,6 @@ const PlainChat = IS_PLAIN_CHAT_ENABLED
|
||||
},
|
||||
],
|
||||
chatButtons: [
|
||||
{
|
||||
icon: "chat",
|
||||
text: "Ask a question",
|
||||
threadDetails: {
|
||||
labelTypeIds: ["lt_01JFJWNWAC464N8DZ6YE71YJRF"],
|
||||
tierIdentifier: { externalId: data.userTier },
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: "bulb",
|
||||
text: "Send feedback",
|
||||
@@ -238,6 +231,17 @@ const PlainChat = IS_PLAIN_CHAT_ENABLED
|
||||
},
|
||||
};
|
||||
|
||||
if (isPaidUser) {
|
||||
plainChatConfig.chatButtons.push({
|
||||
icon: "chat",
|
||||
text: "Ask a question",
|
||||
threadDetails: {
|
||||
labelTypeIds: ["lt_01JFJWNWAC464N8DZ6YE71YJRF"],
|
||||
tierIdentifier: { externalId: data.userTier },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") {
|
||||
window.__PLAIN_CONFIG__ = plainChatConfig;
|
||||
}
|
||||
|
||||
+12
-4
@@ -174,6 +174,8 @@ function responseWithHeaders({ url, res, req }: { url: URL; res: NextResponse; r
|
||||
export const config = {
|
||||
// Next.js Doesn't support spread operator in config matcher, so, we must list all paths explicitly here.
|
||||
// https://github.com/vercel/next.js/discussions/42458
|
||||
// WARNING: DO NOT ADD AN ENDING SLASH "/" TO THE PATHS BELOW
|
||||
// THIS WILL MAKE THEM NOT MATCH AND HENCE NOT HIT MIDDLEWARE
|
||||
matcher: [
|
||||
"/403",
|
||||
"/500",
|
||||
@@ -204,10 +206,16 @@ export const config = {
|
||||
"/booking/:path*",
|
||||
"/payment/:path*",
|
||||
"/routing-forms/:path*",
|
||||
"/team/:path*",
|
||||
"/org/:path*",
|
||||
"/:user/:type/",
|
||||
"/:user/",
|
||||
"/org/:orgSlug/instant-meeting/team/:slug/:type",
|
||||
"/org/:orgSlug/team/:slug/:type",
|
||||
"/org/:orgSlug/team/:slug",
|
||||
"/org/:orgSlug/:user/:type",
|
||||
"/org/:orgSlug/:user",
|
||||
"/org/:orgSlug",
|
||||
"/team/:slug/:type",
|
||||
"/team/:slug",
|
||||
"/:user/:type",
|
||||
"/:user",
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@calcom/web",
|
||||
"version": "5.1.11",
|
||||
"version": "5.1.12",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"analyze": "ANALYZE=true next build",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import stripe from "@calcom/app-store/stripepayment/lib/server";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { StripeBillingService } from "@calcom/features/ee/billing/stripe-billling-service";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { IS_STRIPE_ENABLED } from "@calcom/lib/constants";
|
||||
import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
|
||||
@@ -43,6 +43,7 @@ export async function moveUserToMatchingOrg({ email }: { email: string }) {
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { token } = verifySchema.parse(req.query);
|
||||
const billingService = new StripeBillingService();
|
||||
|
||||
const foundToken = await prisma.verificationToken.findFirst({
|
||||
where: {
|
||||
@@ -130,7 +131,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
});
|
||||
|
||||
if (IS_STRIPE_ENABLED && userMetadataParsed.stripeCustomerId) {
|
||||
await stripe.customers.update(userMetadataParsed.stripeCustomerId, {
|
||||
await billingService.updateCustomer({
|
||||
customerId: userMetadataParsed.stripeCustomerId,
|
||||
email: updatedEmail,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { buffer } from "micro";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import type Stripe from "stripe";
|
||||
|
||||
import stripe from "@calcom/app-store/stripepayment/lib/server";
|
||||
import stripe from "@calcom/features/ee/payments/server/stripe";
|
||||
import { IS_PRODUCTION } from "@calcom/lib/constants";
|
||||
import { getErrorFromUnknown } from "@calcom/lib/errors";
|
||||
import { HttpError as HttpCode } from "@calcom/lib/http-error";
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
|
||||
import { filterSegmentsRouter } from "@calcom/trpc/server/routers/viewer/filterSegments/_router";
|
||||
|
||||
export default createNextApiHandler(filterSegmentsRouter);
|
||||
@@ -57,7 +57,7 @@ test.describe("Change App Theme Test", () => {
|
||||
|
||||
await page.waitForTimeout(3000);
|
||||
const themeValue = await page.evaluate(() => localStorage.getItem("app-theme"));
|
||||
expect(themeValue).toBe("system");
|
||||
expect(themeValue).toBe("light");
|
||||
|
||||
const systemTheme = await page.evaluate(() => {
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 227 KiB After Width: | Height: | Size: 239 KiB |
@@ -80,6 +80,9 @@
|
||||
<path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20" ></path>
|
||||
<circle cx="12" cy="8" r="2" ></circle>
|
||||
</symbol>
|
||||
<symbol class="lucide lucide-bookmark" viewBox="0 0 24 24" fill="inherit" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="bookmark">
|
||||
<path d="m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z" ></path>
|
||||
</symbol>
|
||||
<symbol class="lucide lucide-building" viewBox="0 0 24 24" fill="inherit" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="building">
|
||||
<rect width="16" height="20" x="4" y="2" rx="2" ry="2" ></rect>
|
||||
<path d="M9 22v-4h6v4" ></path>
|
||||
@@ -418,6 +421,11 @@
|
||||
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" ></path>
|
||||
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" ></path>
|
||||
</symbol>
|
||||
<symbol class="lucide lucide-list-filter" viewBox="0 0 24 24" fill="inherit" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="list-filter">
|
||||
<path d="M3 6h18" ></path>
|
||||
<path d="M7 12h10" ></path>
|
||||
<path d="M10 18h4" ></path>
|
||||
</symbol>
|
||||
<symbol class="lucide lucide-loader" viewBox="0 0 24 24" fill="inherit" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="loader">
|
||||
<path d="M12 2v4" ></path>
|
||||
<path d="m16.2 7.8 2.9-2.9" ></path>
|
||||
@@ -605,6 +613,10 @@
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ></rect>
|
||||
<path d="m9 12 2 2 4-4" ></path>
|
||||
</symbol>
|
||||
<symbol class="lucide lucide-square-pen" viewBox="0 0 24 24" fill="inherit" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="square-pen">
|
||||
<path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" ></path>
|
||||
<path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z" ></path>
|
||||
</symbol>
|
||||
<symbol class="lucide lucide-star" viewBox="0 0 24 24" fill="inherit" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="star">
|
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" ></polygon>
|
||||
</symbol>
|
||||
|
||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
@@ -2452,7 +2452,6 @@
|
||||
"published": "منشور",
|
||||
"unpublished": "غير منشور",
|
||||
"publish": "نشر",
|
||||
"org_publish_error": "لم يتمكن نشر المنظمة",
|
||||
"troubleshooter_tooltip": "افتح أداة استكشاف الأخطاء وإصلاحها واكتشف ما هو الخطأ في جدولك",
|
||||
"need_help": "هل تحتاج إلى مساعدة؟",
|
||||
"troubleshooter": "أداة استكشاف الأخطاء وإصلاحها",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "خطة الفريق غير نشطة",
|
||||
"inactive_team_plan_description": "خطة فريقك غير نشطة. تحقق من اشتراكك أو تواصل مع دعم العملاء",
|
||||
"limited_access_trial_mode": "وصول محدود خلال فترة التجربة. الميزة متاحة بعد انتهاء فترة التجربة.",
|
||||
"earn_20_percent_affiliate": "اكسب 20% كشريك تسويقي",
|
||||
"referral_program": "برنامج الإحالة",
|
||||
"dub_disabled_error_message": "تحتاج إلى مفتاح واجهة برمجة تطبيقات Dub ومعرف البرنامج لاستخدام هذه الصفحة.",
|
||||
"uid": "المعرف الفريد",
|
||||
"link": "رابط",
|
||||
"rows_per_page": "صفوف في الصفحة",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "نصيحة: يمكنك إضافة '+' بين أسماء المستخدمين: cal.com/anna+brian لإنشاء اجتماع جماعي ديناميكي",
|
||||
"user_has_no_team_yet": "ليس لديك فريق بعد",
|
||||
"no_team_members": "ليس لديك أعضاء في الفريق بعد",
|
||||
"hide_team_profile_link": "إخفاء رابط ملف الفريق",
|
||||
"hide_team_profile_link_description": "إخفاء رابط ملف الفريق على صفحات الحجز",
|
||||
"display": "عرض",
|
||||
"could_not_find_slug_to_publish_org": "تعذر العثور على الاسم المختصر لنشر المؤسسة",
|
||||
"picklist": "قائمة الاختيار",
|
||||
"name_or_email": "الاسم أو البريد الإلكتروني",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "إذا لم يتم العثور على جهة اتصال، يتم الرجوع إلى مالك العميل المحتمل إذا كان موجودًا",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ أضف السلاسل الجديدة أعلاه هنا ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Dərc Edildi",
|
||||
"unpublished": "Dərc Edilmədi",
|
||||
"publish": "Dərc Et",
|
||||
"org_publish_error": "Təşkilat dərc edilə bilmədi",
|
||||
"troubleshooter_tooltip": "Problemləri həll edən vasitəni açın və cədvəlinizdə nə səhv olduğunu öyrənin",
|
||||
"need_help": "Köməyə ehtiyacınız var?",
|
||||
"troubleshooter": "Problemləri həll edən vasitə",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Qeyri-aktiv komanda planı",
|
||||
"inactive_team_plan_description": "Komanda planınız qeyri-aktivdir. Abunəliyinizi yoxlayın və ya müştəri dəstəyi ilə əlaqə saxlayın",
|
||||
"limited_access_trial_mode": "Sınaq müddətində məhdud giriş. Xüsusiyyət sınaq müddəti bitdikdən sonra əlçatan olacaq.",
|
||||
"earn_20_percent_affiliate": "20% Tərəfdaş Qazancı",
|
||||
"referral_program": "Referral Proqramı",
|
||||
"dub_disabled_error_message": "Bu səhifəni istifadə etmək üçün Dub API Açarı və Proqram İD-si lazımdır.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "səhifə başına sətir",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Məsləhət: Dinamik qrup görüşü yaratmaq üçün istifadəçi adları arasında '+' işarəsi istifadə edə bilərsiniz: cal.com/anna+brian",
|
||||
"user_has_no_team_yet": "Hələ komandanız yoxdur",
|
||||
"no_team_members": "Hələ komanda üzvləriniz yoxdur",
|
||||
"hide_team_profile_link": "Komanda Profil Linkini Gizlət",
|
||||
"hide_team_profile_link_description": "Rezervasiya səhifələrində komanda profil linkini gizlət",
|
||||
"display": "Göstər",
|
||||
"could_not_find_slug_to_publish_org": "Təşkilatı dərc etmək üçün slug tapılmadı",
|
||||
"picklist": "Seçim siyahısı",
|
||||
"name_or_email": "Ad və ya E-poçt",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Əgər əlaqə tapılmazsa, mövcud olduğu təqdirdə potensial müştəri sahibinə qayıt",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Yeni sətirləri bura əlavə edin ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Публикувано",
|
||||
"unpublished": "Непубликувано",
|
||||
"publish": "Публикувай",
|
||||
"org_publish_error": "Организацията не можа да бъде публикувана",
|
||||
"troubleshooter_tooltip": "Отворете инструмента за отстраняване на проблеми и разберете какво не е наред с вашия график",
|
||||
"need_help": "Нужда от помощ?",
|
||||
"troubleshooter": "Инструмент за отстраняване на проблеми",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Неактивен план за екип",
|
||||
"inactive_team_plan_description": "Вашият план за екип е неактивен. Проверете абонамента си или се свържете с отдела за обслужване на клиенти",
|
||||
"limited_access_trial_mode": "Ограничен достъп по време на пробния период. Функцията ще бъде достъпна след края на пробния период.",
|
||||
"earn_20_percent_affiliate": "Печелете 20% като партньор",
|
||||
"referral_program": "Програма за препоръки",
|
||||
"dub_disabled_error_message": "Нуждаете се от Dub API ключ и идентификатор на програма, за да използвате тази страница.",
|
||||
"uid": "UID",
|
||||
"link": "Връзка",
|
||||
"rows_per_page": "реда на страница",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Съвет: Можете да добавите '+' между потребителските имена: cal.com/anna+brian, за да създадете динамична групова среща",
|
||||
"user_has_no_team_yet": "Все още нямате екип",
|
||||
"no_team_members": "Все още нямате членове на екипа",
|
||||
"hide_team_profile_link": "Скриване на връзката към профила на екипа",
|
||||
"hide_team_profile_link_description": "Скриване на връзката към профила на екипа на страниците за резервации",
|
||||
"display": "Показване",
|
||||
"could_not_find_slug_to_publish_org": "Не може да се намери слъг за публикуване на организацията",
|
||||
"picklist": "Списък за избор",
|
||||
"name_or_email": "Име или имейл",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Ако не е намерен контакт, връщане към собственика на лийда, ако съществува",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Добавете новите си низове над този ред ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publicat",
|
||||
"unpublished": "No publicat",
|
||||
"publish": "Publica",
|
||||
"org_publish_error": "No s'ha pogut publicar l'organització",
|
||||
"troubleshooter_tooltip": "Obre el solucionador de problemes i descobreix què passa amb el teu calendari",
|
||||
"need_help": "Necessites ajuda?",
|
||||
"troubleshooter": "Solucionador de problemes",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Pla d'equip inactiu",
|
||||
"inactive_team_plan_description": "El teu pla d'equip està inactiu. Comprova la teva subscripció o contacta amb el suport al client",
|
||||
"limited_access_trial_mode": "Accés limitat durant el període de prova. Funció disponible després de finalitzar la prova.",
|
||||
"earn_20_percent_affiliate": "Guanya un 20% d'afiliació",
|
||||
"referral_program": "Programa de recomanació",
|
||||
"dub_disabled_error_message": "Necessites una clau API de Dub i un ID de programa per utilitzar aquesta pàgina.",
|
||||
"uid": "UID",
|
||||
"link": "Enllaç",
|
||||
"rows_per_page": "files per pàgina",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Consell: Pots afegir un '+' entre noms d'usuari: cal.com/anna+brian per crear una reunió de grup dinàmica",
|
||||
"user_has_no_team_yet": "Encara no tens cap equip",
|
||||
"no_team_members": "Encara no tens membres a l'equip",
|
||||
"hide_team_profile_link": "Amaga l'enllaç del perfil d'equip",
|
||||
"hide_team_profile_link_description": "Amaga l'enllaç del perfil d'equip a les pàgines de reserva",
|
||||
"display": "Visualització",
|
||||
"could_not_find_slug_to_publish_org": "No s'ha pogut trobar l'slug per publicar l'organització",
|
||||
"picklist": "Llista de selecció",
|
||||
"name_or_email": "Nom o correu electrònic",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Si no es troba cap contacte, recorre al propietari del lead si existeix",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Afegiu les vostres noves cadenes a dalt ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publikováno",
|
||||
"unpublished": "Nepublikováno",
|
||||
"publish": "Publikovat",
|
||||
"org_publish_error": "Organizaci se nepodařilo publikovat",
|
||||
"troubleshooter_tooltip": "Otevřete nástroj pro řešení problémů a zjistěte, co je špatně s vaším rozvrhem",
|
||||
"need_help": "Potřebujete pomoc?",
|
||||
"troubleshooter": "Nástroj pro řešení problémů",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Neaktivní týmový plán",
|
||||
"inactive_team_plan_description": "Váš týmový plán je neaktivní. Zkontrolujte své předplatné nebo kontaktujte zákaznickou podporu",
|
||||
"limited_access_trial_mode": "Omezený přístup během zkušební doby. Funkce bude dostupná po skončení zkušební doby.",
|
||||
"earn_20_percent_affiliate": "Získejte 20% jako partner",
|
||||
"referral_program": "Doporučovací program",
|
||||
"dub_disabled_error_message": "Pro použití této stránky potřebujete Dub API klíč a ID programu.",
|
||||
"uid": "UID",
|
||||
"link": "Odkaz",
|
||||
"rows_per_page": "řádků na stránku",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Tip: Mezi uživatelská jména můžete vložit '+': cal.com/anna+brian pro vytvoření dynamické skupinové schůzky",
|
||||
"user_has_no_team_yet": "Zatím nemáte žádný tým",
|
||||
"no_team_members": "Zatím nemáte žádné členy týmu",
|
||||
"hide_team_profile_link": "Skrýt odkaz na profil týmu",
|
||||
"hide_team_profile_link_description": "Skrýt odkaz na profil týmu na stránkách rezervací",
|
||||
"display": "Zobrazení",
|
||||
"could_not_find_slug_to_publish_org": "Nelze najít slug pro publikování organizace",
|
||||
"picklist": "Výběrový seznam",
|
||||
"name_or_email": "Jméno nebo e-mail",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Pokud není nalezen žádný kontakt, použít vlastníka leadu, pokud existuje",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Přidejte své nové řetězce nahoru ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Udgivet",
|
||||
"unpublished": "Ikke udgivet",
|
||||
"publish": "Udgiv",
|
||||
"org_publish_error": "Organisationen kunne ikke udgives",
|
||||
"troubleshooter_tooltip": "Åbn fejlfindingen og find ud af, hvad der er galt med din tidsplan",
|
||||
"need_help": "Brug for hjælp?",
|
||||
"troubleshooter": "Fejlfinding",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Inaktiv teamplan",
|
||||
"inactive_team_plan_description": "Din teamplan er inaktiv. Tjek dit abonnement eller kontakt kundesupport",
|
||||
"limited_access_trial_mode": "Begrænset adgang under prøveperioden. Funktionen er tilgængelig efter prøveperioden slutter.",
|
||||
"earn_20_percent_affiliate": "Tjen 20% som partner",
|
||||
"referral_program": "Henvisningsprogram",
|
||||
"dub_disabled_error_message": "Du skal have en Dub API-nøgle og program-id for at bruge denne side.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "rækker pr. side",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Tip: Du kan tilføje et '+' mellem brugernavne: cal.com/anna+brian for at lave et dynamisk gruppemøde",
|
||||
"user_has_no_team_yet": "Du har ikke et team endnu",
|
||||
"no_team_members": "Du har ikke nogen teammedlemmer endnu",
|
||||
"hide_team_profile_link": "Skjul teamprofillink",
|
||||
"hide_team_profile_link_description": "Skjul teamprofillinket på bookingsider",
|
||||
"display": "Vis",
|
||||
"could_not_find_slug_to_publish_org": "Kunne ikke finde slug til at publicere organisationen",
|
||||
"picklist": "Valgliste",
|
||||
"name_or_email": "Navn eller e-mail",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Hvis ingen kontakt findes, fald tilbage til lead-ejeren, hvis denne eksisterer",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Tilføj dine nye strenge ovenfor her ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Veröffentlicht",
|
||||
"unpublished": "Unveröffentlicht",
|
||||
"publish": "Veröffentlichen",
|
||||
"org_publish_error": "Organisation konnte nicht veröffentlicht werden",
|
||||
"troubleshooter_tooltip": "Öffnen Sie die Problembehandlung und finden Sie heraus, was mit Ihrem Zeitplan nicht stimmt",
|
||||
"need_help": "Brauchst du Hilfe?",
|
||||
"troubleshooter": "Problembehandlung",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Inaktiver Team-Plan",
|
||||
"inactive_team_plan_description": "Ihr Team-Plan ist inaktiv. Überprüfen Sie Ihr Abonnement oder wenden Sie sich an den Kundensupport",
|
||||
"limited_access_trial_mode": "Eingeschränkter Zugriff während der Testphase. Funktion nach Ablauf der Testphase verfügbar.",
|
||||
"earn_20_percent_affiliate": "20% Partnerprovision verdienen",
|
||||
"referral_program": "Empfehlungsprogramm",
|
||||
"dub_disabled_error_message": "Du benötigst einen Dub API-Schlüssel und eine Programm-ID, um diese Seite zu nutzen.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "Zeilen pro Seite",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Tipp: Sie können ein '+' zwischen Benutzernamen setzen: cal.com/anna+brian, um ein dynamisches Gruppenmeeting zu erstellen",
|
||||
"user_has_no_team_yet": "Sie haben noch kein Team",
|
||||
"no_team_members": "Sie haben noch keine Teammitglieder",
|
||||
"hide_team_profile_link": "Team-Profillink ausblenden",
|
||||
"hide_team_profile_link_description": "Den Team-Profillink auf Buchungsseiten ausblenden",
|
||||
"display": "Anzeige",
|
||||
"could_not_find_slug_to_publish_org": "Konnte keinen Slug finden, um die Organisation zu veröffentlichen",
|
||||
"picklist": "Auswahlliste",
|
||||
"name_or_email": "Name oder E-Mail",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Wenn kein Kontakt gefunden wird, auf den Lead-Eigentümer zurückgreifen, falls vorhanden",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Fügen Sie Ihre neuen Code-Zeilen über dieser hinzu ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Δημοσιευμένο",
|
||||
"unpublished": "Μη δημοσιευμένο",
|
||||
"publish": "Δημοσίευση",
|
||||
"org_publish_error": "Ο οργανισμός δεν μπόρεσε να δημοσιευτεί",
|
||||
"troubleshooter_tooltip": "Ανοίξτε τον αντιμετωπιστή προβλημάτων και βρείτε τι δεν πάει καλά με το πρόγραμμά σας",
|
||||
"need_help": "Χρειάζεστε βοήθεια;",
|
||||
"troubleshooter": "Αντιμετωπιστής προβλημάτων",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Ανενεργό πλάνο ομάδας",
|
||||
"inactive_team_plan_description": "Το πλάνο της ομάδας σας είναι ανενεργό. Ελέγξτε τη συνδρομή σας ή επικοινωνήστε με την εξυπηρέτηση πελατών",
|
||||
"limited_access_trial_mode": "Περιορισμένη πρόσβαση κατά τη διάρκεια της δοκιμαστικής περιόδου. Η λειτουργία θα είναι διαθέσιμη μετά το τέλος της δοκιμαστικής περιόδου.",
|
||||
"earn_20_percent_affiliate": "Κέρδισε 20% ως συνεργάτης",
|
||||
"referral_program": "Πρόγραμμα παραπομπών",
|
||||
"dub_disabled_error_message": "Χρειάζεστε ένα κλειδί API Dub και ένα αναγνωριστικό προγράμματος για να χρησιμοποιήσετε αυτή τη σελίδα.",
|
||||
"uid": "UID",
|
||||
"link": "Σύνδεσμος",
|
||||
"rows_per_page": "γραμμές ανά σελίδα",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Συμβουλή: Μπορείτε να προσθέσετε ένα '+' μεταξύ των ονομάτων χρήστη: cal.com/anna+brian για να δημιουργήσετε μια δυναμική ομαδική συνάντηση",
|
||||
"user_has_no_team_yet": "Δεν έχετε ακόμη ομάδα",
|
||||
"no_team_members": "Δεν έχετε ακόμη μέλη ομάδας",
|
||||
"hide_team_profile_link": "Απόκρυψη συνδέσμου προφίλ ομάδας",
|
||||
"hide_team_profile_link_description": "Απόκρυψη του συνδέσμου προφίλ ομάδας στις σελίδες κράτησης",
|
||||
"display": "Εμφάνιση",
|
||||
"could_not_find_slug_to_publish_org": "Δεν βρέθηκε το slug για τη δημοσίευση του οργανισμού",
|
||||
"picklist": "Λίστα επιλογών",
|
||||
"name_or_email": "Όνομα ή Email",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Αν δεν βρεθεί επαφή, επιστροφή στον ιδιοκτήτη του lead εάν υπάρχει",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Προσθέστε τις νέες συμβολοσειρές σας πάνω από εδώ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -3038,6 +3038,29 @@
|
||||
"tip_username_plus": "Tip: You can a '+' between usernames: cal.com/anna+brian to make a dynamic group meeting",
|
||||
"user_has_no_team_yet": "You don't have a team yet",
|
||||
"no_team_members": "You don't have team members yet",
|
||||
"segment": "Segment",
|
||||
"rename": "Rename",
|
||||
"rename_segment": "Rename Segment",
|
||||
"delete_segment": "Delete Segment",
|
||||
"duplicate_segment": "Duplicate Segment",
|
||||
"delete_segment_confirmation": "Are you sure you want to delete this segment? This action cannot be undone.",
|
||||
"filter_segment_updated": "Filter segment updated",
|
||||
"error_updating_filter_segment": "Error updating filter segment",
|
||||
"filter_segment_duplicated": "Filter segment duplicated",
|
||||
"error_duplicating_filter_segment": "Error duplicating filter segment",
|
||||
"filter_segment_deleted": "Filter segment deleted",
|
||||
"error_deleting_filter_segment": "Error deleting filter segment",
|
||||
"save_segment": "Save Segment",
|
||||
"segment_not_found": "Segment not found",
|
||||
"filter_segment_saved": "Filter segment saved",
|
||||
"no_segments": "No segments",
|
||||
"error_saving_filter_segment": "Error saving filter segment",
|
||||
"override_segment": "Save overrides to \"{{name}}\"",
|
||||
"create_new_segment": "Create new segment",
|
||||
"save_for_team": "Save for team",
|
||||
"select_team": "Select team",
|
||||
"please_select_team": "Please select a team",
|
||||
"personal": "Personal",
|
||||
"hide_team_profile_link": "Hide Team Profile Link",
|
||||
"hide_team_profile_link_description": "Hide the team profile link on booking pages",
|
||||
"display": "Display",
|
||||
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publicado",
|
||||
"unpublished": "No Publicado",
|
||||
"publish": "Publicar",
|
||||
"org_publish_error": "No se pudo publicar la organización",
|
||||
"troubleshooter_tooltip": "Abre el solucionador de problemas y descubre qué está mal con tu horario",
|
||||
"need_help": "¿Necesitas ayuda?",
|
||||
"troubleshooter": "Solucionador de Problemas",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Plan de equipo inactivo",
|
||||
"inactive_team_plan_description": "Tu plan de equipo está inactivo. Revisa tu suscripción o comunícate con el soporte al cliente",
|
||||
"limited_access_trial_mode": "Acceso limitado durante la prueba. Función disponible después de que termine la prueba.",
|
||||
"earn_20_percent_affiliate": "Gana 20% como afiliado",
|
||||
"referral_program": "Programa de referidos",
|
||||
"dub_disabled_error_message": "Necesitas una clave API de Dub y un ID de programa para usar esta página.",
|
||||
"uid": "UID",
|
||||
"link": "Enlace",
|
||||
"rows_per_page": "filas por página",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Consejo: Puedes usar un '+' entre nombres de usuario: cal.com/anna+brian para crear una reunión grupal dinámica",
|
||||
"user_has_no_team_yet": "Aún no tienes un equipo",
|
||||
"no_team_members": "Aún no tienes miembros en tu equipo",
|
||||
"hide_team_profile_link": "Ocultar enlace del perfil del equipo",
|
||||
"hide_team_profile_link_description": "Ocultar el enlace del perfil del equipo en las páginas de reserva",
|
||||
"display": "Mostrar",
|
||||
"could_not_find_slug_to_publish_org": "No se pudo encontrar el slug para publicar la organización",
|
||||
"picklist": "Lista de selección",
|
||||
"name_or_email": "Nombre o correo electrónico",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Si no se encuentra ningún contacto, recurrir al propietario del lead si existe",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Agrega tus nuevas cadenas arriba de esta línea ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publicado",
|
||||
"unpublished": "No Publicado",
|
||||
"publish": "Publicar",
|
||||
"org_publish_error": "No se pudo publicar la organización",
|
||||
"troubleshooter_tooltip": "Abre el solucionador de problemas y averigua qué está mal con tu horario",
|
||||
"need_help": "¿Necesita ayuda?",
|
||||
"troubleshooter": "Solucionador de Problemas",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Plan de equipo inactivo",
|
||||
"inactive_team_plan_description": "Tu plan de equipo está inactivo. Revisa tu suscripción o contacta con el soporte al cliente",
|
||||
"limited_access_trial_mode": "Acceso limitado durante la prueba. Función disponible después de que termine la prueba.",
|
||||
"earn_20_percent_affiliate": "Gana 20% de afiliado",
|
||||
"referral_program": "Programa de referidos",
|
||||
"dub_disabled_error_message": "Necesitas una clave API de Dub y un ID de programa para usar esta página.",
|
||||
"uid": "UID",
|
||||
"link": "Enlace",
|
||||
"rows_per_page": "filas por página",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Consejo: Puedes usar un '+' entre nombres de usuario: cal.com/anna+brian para crear una reunión de grupo dinámica",
|
||||
"user_has_no_team_yet": "Aún no tienes un equipo",
|
||||
"no_team_members": "Aún no tienes miembros en tu equipo",
|
||||
"hide_team_profile_link": "Ocultar enlace del perfil del equipo",
|
||||
"hide_team_profile_link_description": "Ocultar el enlace del perfil del equipo en las páginas de reserva",
|
||||
"display": "Mostrar",
|
||||
"could_not_find_slug_to_publish_org": "No se pudo encontrar el slug para publicar la organización",
|
||||
"picklist": "Lista de selección",
|
||||
"name_or_email": "Nombre o correo electrónico",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Si no se encuentra ningún contacto, recurrir al propietario del lead si existe",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Agregue sus nuevas cadenas arriba ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Avaldatud",
|
||||
"unpublished": "Avaldamata",
|
||||
"publish": "Avalda",
|
||||
"org_publish_error": "Organisatsiooni ei saanud avaldada",
|
||||
"troubleshooter_tooltip": "Avage tõrkeotsing ja selgitage välja, mis teie ajakavas valesti on",
|
||||
"need_help": "Abi vajama?",
|
||||
"troubleshooter": "Veaotsing",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Mitteaktiivne meeskonnaplaan",
|
||||
"inactive_team_plan_description": "Teie meeskonnaplaan on mitteaktiivne. Kontrollige oma tellimust või võtke ühendust klienditoega",
|
||||
"limited_access_trial_mode": "Piiratud juurdepääs prooviperioodi ajal. Funktsioon on saadaval pärast prooviperioodi lõppu.",
|
||||
"earn_20_percent_affiliate": "Teeni 20% partnertasu",
|
||||
"referral_program": "Soovitusprogramm",
|
||||
"dub_disabled_error_message": "Selle lehe kasutamiseks vajad Dub API võtit ja programmi ID-d.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "rida lehel",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Nõuanne: Saate kasutajanimede vahele lisada '+': cal.com/anna+brian, et luua dünaamiline grupikohtumise",
|
||||
"user_has_no_team_yet": "Teil pole veel meeskonda",
|
||||
"no_team_members": "Teil pole veel meeskonnaliikmeid",
|
||||
"hide_team_profile_link": "Peida meeskonna profiili link",
|
||||
"hide_team_profile_link_description": "Peida meeskonna profiili link broneerimislehtedel",
|
||||
"display": "Kuva",
|
||||
"could_not_find_slug_to_publish_org": "Organisatsiooni avaldamiseks ei leitud lühinime",
|
||||
"picklist": "Valikloend",
|
||||
"name_or_email": "Nimi või e-post",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Kui kontakti ei leita, kasuta võimalusel liidi omanikku",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Argitaratuta",
|
||||
"unpublished": "Argitaratu gabe",
|
||||
"publish": "Argitaratu",
|
||||
"org_publish_error": "Ezin izan da erakundea argitaratu",
|
||||
"troubleshooter_tooltip": "Ireki arazoen konpontzailea eta ikusi zer dagoen gaizki zure ordutegian",
|
||||
"need_help": "Laguntza behar?",
|
||||
"troubleshooter": "Arazoen konpontzailea",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Talde plan inaktiboa",
|
||||
"inactive_team_plan_description": "Zure talde plana inaktiboa dago. Egiaztatu zure harpidetza edo jarri harremanetan bezeroen laguntzarekin",
|
||||
"limited_access_trial_mode": "Sarbide mugatua proba aldian. Eginbidea proba amaitu ondoren erabilgarri.",
|
||||
"earn_20_percent_affiliate": "Irabazi %20 afiliatuen bidez",
|
||||
"referral_program": "Erreferentzia programa",
|
||||
"dub_disabled_error_message": "Dub API gako bat eta programa ID bat behar dituzu orrialde hau erabiltzeko.",
|
||||
"uid": "UID",
|
||||
"link": "Esteka",
|
||||
"rows_per_page": "errenkada orrialdeko",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Aholkua: '+' bat jar dezakezu erabiltzaile-izenen artean: cal.com/anna+brian talde-bilera dinamiko bat sortzeko",
|
||||
"user_has_no_team_yet": "Oraindik ez duzu talderik",
|
||||
"no_team_members": "Oraindik ez dituzu taldekiderik",
|
||||
"hide_team_profile_link": "Ezkutatu taldearen profil esteka",
|
||||
"hide_team_profile_link_description": "Ezkutatu taldearen profil esteka erreserba orrialdeetan",
|
||||
"display": "Bistaratu",
|
||||
"could_not_find_slug_to_publish_org": "Ezin izan da erakundea argitaratzeko slug-a aurkitu",
|
||||
"picklist": "Hautaketa-zerrenda",
|
||||
"name_or_email": "Izena edo helbide elektronikoa",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Kontakturik aurkitzen ez bada, itzuli bezeroen arduradunera existitzen bada",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Gehitu zure kate berriak honen gainean ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Julkaistu",
|
||||
"unpublished": "Julkaisematon",
|
||||
"publish": "Julkaise",
|
||||
"org_publish_error": "Organisaatiota ei voitu julkaista",
|
||||
"troubleshooter_tooltip": "Avaa vianmääritys ja selvitä mikä aikataulussasi on vialla",
|
||||
"need_help": "Tarvitsetko apua?",
|
||||
"troubleshooter": "Vianmääritys",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Ei-aktiivinen tiimitilaus",
|
||||
"inactive_team_plan_description": "Tiimitilauksesi ei ole aktiivinen. Tarkista tilauksesi tai ota yhteyttä asiakastukeen",
|
||||
"limited_access_trial_mode": "Rajoitettu pääsy kokeilun aikana. Ominaisuus käytettävissä kokeilun päätyttyä.",
|
||||
"earn_20_percent_affiliate": "Ansaitse 20% kumppanina",
|
||||
"referral_program": "Suositteluohjelma",
|
||||
"dub_disabled_error_message": "Tarvitset Dub API -avaimen ja ohjelmatunnuksen käyttääksesi tätä sivua.",
|
||||
"uid": "UID",
|
||||
"link": "Linkki",
|
||||
"rows_per_page": "riviä per sivu",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Vinkki: Voit lisätä '+'-merkin käyttäjänimien väliin: cal.com/anna+brian luodaksesi dynaamisen ryhmätapaamisen",
|
||||
"user_has_no_team_yet": "Sinulla ei ole vielä tiimiä",
|
||||
"no_team_members": "Sinulla ei ole vielä tiimin jäseniä",
|
||||
"hide_team_profile_link": "Piilota tiimin profiililinkki",
|
||||
"hide_team_profile_link_description": "Piilota tiimin profiililinkki varaussivuilta",
|
||||
"display": "Näyttö",
|
||||
"could_not_find_slug_to_publish_org": "Organisaation julkaisemiseen tarvittavaa lyhytosoitetta ei löytynyt",
|
||||
"picklist": "Valintalistaus",
|
||||
"name_or_email": "Nimi tai sähköposti",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Jos yhteyshenkilöä ei löydy, käytä liidin omistajaa, jos sellainen on olemassa",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Lisää uudet merkkijonot tämän yläpuolelle ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publiée",
|
||||
"unpublished": "Non publiée",
|
||||
"publish": "Publier",
|
||||
"org_publish_error": "L'organisation n'a pas pu être publiée",
|
||||
"troubleshooter_tooltip": "Ouvrez l'outil de dépannage et déterminez ce qui ne va pas avec votre planning",
|
||||
"need_help": "Besoin d'aide ?",
|
||||
"troubleshooter": "Dépannage",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Plan d'équipe inactif",
|
||||
"inactive_team_plan_description": "Votre plan d'équipe est inactif. Vérifiez votre abonnement ou contactez le support client",
|
||||
"limited_access_trial_mode": "Accès limité pendant l'essai. Fonctionnalité disponible après la fin de l'essai.",
|
||||
"earn_20_percent_affiliate": "Gagnez 20 % d'affiliation",
|
||||
"referral_program": "Programme de parrainage",
|
||||
"dub_disabled_error_message": "Vous avez besoin d'une clé API Dub et d'un identifiant de programme pour utiliser cette page.",
|
||||
"uid": "UID",
|
||||
"link": "Lien",
|
||||
"rows_per_page": "lignes par page",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Astuce : Vous pouvez ajouter un '+' entre les noms d'utilisateur : cal.com/anna+brian pour créer une réunion de groupe dynamique",
|
||||
"user_has_no_team_yet": "Vous n'avez pas encore d'équipe",
|
||||
"no_team_members": "Vous n'avez pas encore de membres d'équipe",
|
||||
"hide_team_profile_link": "Masquer le lien du profil d'équipe",
|
||||
"hide_team_profile_link_description": "Masquer le lien du profil d'équipe sur les pages de réservation",
|
||||
"display": "Affichage",
|
||||
"could_not_find_slug_to_publish_org": "Impossible de trouver le slug pour publier l'organisation",
|
||||
"picklist": "Liste de sélection",
|
||||
"name_or_email": "Nom ou e-mail",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Si aucun contact n'est trouvé, se rabattre sur le propriétaire du lead s'il existe",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Ajoutez vos nouvelles chaînes ci-dessus ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "מפורסם",
|
||||
"unpublished": "לא מפורסם",
|
||||
"publish": "פרסום",
|
||||
"org_publish_error": "אי אפשר לפרסם את הארגון",
|
||||
"troubleshooter_tooltip": "אפשר לפתוח את פותר הבעיות ולנסות לפענח מה לא תקין בלוח הזמנים שלך",
|
||||
"need_help": "צריך עזרה?",
|
||||
"troubleshooter": "פותר בעיות",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "תוכנית צוות לא פעילה",
|
||||
"inactive_team_plan_description": "תוכנית הצוות שלך אינה פעילה. בדוק את המנוי שלך או פנה לתמיכת הלקוחות",
|
||||
"limited_access_trial_mode": "גישה מוגבלת במהלך תקופת הניסיון. התכונה תהיה זמינה לאחר סיום תקופת הניסיון.",
|
||||
"earn_20_percent_affiliate": "הרווח 20% שותפים",
|
||||
"referral_program": "תוכנית הפניות",
|
||||
"dub_disabled_error_message": "אתה צריך מפתח API של Dub ומזהה תוכנית כדי להשתמש בדף זה.",
|
||||
"uid": "מזהה ייחודי",
|
||||
"link": "קישור",
|
||||
"rows_per_page": "שורות לעמוד",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "טיפ: ניתן להוסיף '+' בין שמות משתמשים: cal.com/anna+brian ליצירת פגישה קבוצתית דינמית",
|
||||
"user_has_no_team_yet": "עדיין אין לך צוות",
|
||||
"no_team_members": "עדיין אין לך חברי צוות",
|
||||
"hide_team_profile_link": "הסתר קישור לפרופיל הצוות",
|
||||
"hide_team_profile_link_description": "הסתר את קישור פרופיל הצוות בדפי ההזמנות",
|
||||
"display": "תצוגה",
|
||||
"could_not_find_slug_to_publish_org": "לא ניתן למצוא מזהה URL לפרסום הארגון",
|
||||
"picklist": "רשימת בחירה",
|
||||
"name_or_email": "שם או אימייל",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "אם לא נמצא איש קשר, חזור לבעל הליד אם הוא קיים",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Közzétett",
|
||||
"unpublished": "Kiadatlan",
|
||||
"publish": "Közzététel",
|
||||
"org_publish_error": "A szervezetet nem lehetett közzétenni",
|
||||
"troubleshooter_tooltip": "Nyissa meg a hibaelhárítót, és derítse ki, mi a probléma az ütemezéssel",
|
||||
"need_help": "Segítségre van szükséged?",
|
||||
"troubleshooter": "Hibakereső",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Inaktív csapat előfizetés",
|
||||
"inactive_team_plan_description": "Az Ön csapat előfizetése inaktív. Ellenőrizze előfizetését vagy vegye fel a kapcsolatot az ügyfélszolgálattal",
|
||||
"limited_access_trial_mode": "Korlátozott hozzáférés a próbaidőszak alatt. A funkció a próbaidőszak végén lesz elérhető.",
|
||||
"earn_20_percent_affiliate": "Keress 20% jutalékot",
|
||||
"referral_program": "Ajánlói program",
|
||||
"dub_disabled_error_message": "Dub API kulcsra és Program azonosítóra van szükséged az oldal használatához.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "sor oldalanként",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Tipp: Használhat '+' jelet a felhasználónevek között: cal.com/anna+brian dinamikus csoportos találkozó létrehozásához",
|
||||
"user_has_no_team_yet": "Még nincs csapatod",
|
||||
"no_team_members": "Még nincsenek csapattagjaid",
|
||||
"hide_team_profile_link": "Csapatprofil link elrejtése",
|
||||
"hide_team_profile_link_description": "Csapatprofil link elrejtése a foglalási oldalakon",
|
||||
"display": "Megjelenítés",
|
||||
"could_not_find_slug_to_publish_org": "Nem található slug a szervezet közzétételéhez",
|
||||
"picklist": "Választólista",
|
||||
"name_or_email": "Név vagy e-mail",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Ha nem található kapcsolat, visszalépés a lead tulajdonoshoz, ha létezik",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Adja hozzá az új karakterláncokat fent ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Pubblicato",
|
||||
"unpublished": "Pubblicazione annullata",
|
||||
"publish": "Pubblica",
|
||||
"org_publish_error": "Non è stato possibile pubblicare l'organizzazione",
|
||||
"troubleshooter_tooltip": "Apri lo strumento di soluzione dei problemi per individuare il problema del tuo programma",
|
||||
"need_help": "Hai bisogno di aiuto?",
|
||||
"troubleshooter": "Risoluzione problemi",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Piano team inattivo",
|
||||
"inactive_team_plan_description": "Il tuo piano team è inattivo. Controlla il tuo abbonamento o contatta l'assistenza clienti",
|
||||
"limited_access_trial_mode": "Accesso limitato durante la prova. Funzionalità disponibile al termine del periodo di prova.",
|
||||
"earn_20_percent_affiliate": "Guadagna il 20% come affiliato",
|
||||
"referral_program": "Programma di referral",
|
||||
"dub_disabled_error_message": "Hai bisogno di una chiave API Dub e di un ID programma per utilizzare questa pagina.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "righe per pagina",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Suggerimento: Puoi aggiungere un '+' tra i nomi utente: cal.com/anna+brian per creare un incontro di gruppo dinamico",
|
||||
"user_has_no_team_yet": "Non hai ancora un team",
|
||||
"no_team_members": "Non hai ancora membri del team",
|
||||
"hide_team_profile_link": "Nascondi link al profilo del team",
|
||||
"hide_team_profile_link_description": "Nascondi il link al profilo del team nelle pagine di prenotazione",
|
||||
"display": "Visualizzazione",
|
||||
"could_not_find_slug_to_publish_org": "Impossibile trovare lo slug per pubblicare l'organizzazione",
|
||||
"picklist": "Lista di selezione",
|
||||
"name_or_email": "Nome o email",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Se non viene trovato alcun contatto, passa al proprietario del lead se esiste",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Aggiungi le tue nuove stringhe qui sopra ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "公開済み",
|
||||
"unpublished": "未公開",
|
||||
"publish": "公開する",
|
||||
"org_publish_error": "組織を公開できませんでした",
|
||||
"troubleshooter_tooltip": "トラブルシューティングを開いて、スケジュールの問題を解決する",
|
||||
"need_help": "サポートが必要ですか?",
|
||||
"troubleshooter": "トラブルシューティング",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "非アクティブなチームプラン",
|
||||
"inactive_team_plan_description": "チームプランが非アクティブです。サブスクリプションを確認するか、カスタマーサポートにお問い合わせください",
|
||||
"limited_access_trial_mode": "トライアル期間中はアクセスが制限されます。この機能はトライアル終了後に利用可能になります。",
|
||||
"earn_20_percent_affiliate": "20%のアフィリエイト報酬を獲得",
|
||||
"referral_program": "紹介プログラム",
|
||||
"dub_disabled_error_message": "このページを使用するには、Dub APIキーとプログラムIDが必要です。",
|
||||
"uid": "UID",
|
||||
"link": "リンク",
|
||||
"rows_per_page": "ページあたりの行数",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "ヒント:ユーザー名の間に '+'を入れることで動的なグループミーティングを作成できます:cal.com/anna+brian",
|
||||
"user_has_no_team_yet": "まだチームがありません",
|
||||
"no_team_members": "まだチームメンバーがいません",
|
||||
"hide_team_profile_link": "チームプロフィールリンクを非表示",
|
||||
"hide_team_profile_link_description": "予約ページでチームプロフィールリンクを非表示にする",
|
||||
"display": "表示",
|
||||
"could_not_find_slug_to_publish_org": "組織を公開するためのスラッグが見つかりませんでした",
|
||||
"picklist": "選択リスト",
|
||||
"name_or_email": "名前またはメールアドレス",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "連絡先が見つからない場合、リード所有者が存在すればそちらにフォールバックする",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ この上に新しい文字列を追加してください ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "បានបោះពុម្ពផ្សាយ",
|
||||
"unpublished": "មិនបានបោះពុម្ពផ្សាយ",
|
||||
"publish": "បោះពុម្ពផ្សាយ",
|
||||
"org_publish_error": "អង្គការមិនអាចបោះពុម្ពផ្សាយបានទេ",
|
||||
"troubleshooter_tooltip": "បើកឧបករណ៍ដោះស្រាយបញ្ហា និងស្វែងរកអ្វីដែលខុសក្នុងកាលវិភាគរបស់អ្នក",
|
||||
"need_help": "ត្រូវការជំនួយ?",
|
||||
"troubleshooter": "ឧបករណ៍ដោះស្រាយបញ្ហា",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "ផែនការក្រុមដែលមិនសកម្ម",
|
||||
"inactive_team_plan_description": "ផែនការក្រុមរបស់អ្នកមិនសកម្មទេ។ សូមពិនិត្យមើលការជាវរបស់អ្នក ឬទាក់ទងសេវាកម្មអតិថិជន",
|
||||
"limited_access_trial_mode": "ការចូលប្រើមានកំណត់ក្នុងអំឡុងពេលសាកល្បង។ មុខងារនេះនឹងមានបន្ទាប់ពីការសាកល្បងបញ្ចប់។",
|
||||
"earn_20_percent_affiliate": "ទទួលបាន 20% ពីសម្ព័ន្ធមិត្ត",
|
||||
"referral_program": "កម្មវិធីណែនាំ",
|
||||
"dub_disabled_error_message": "អ្នកត្រូវការ Dub API Key និង Program Id ដើម្បីប្រើទំព័រនេះ។",
|
||||
"uid": "UID",
|
||||
"link": "តំណភ្ជាប់",
|
||||
"rows_per_page": "ជួរដេកក្នុងមួយទំព័រ",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "គន្លឹះ៖ អ្នកអាចដាក់សញ្ញា '+' រវាងឈ្មោះអ្នកប្រើប្រាស់៖ cal.com/anna+brian ដើម្បីបង្កើតការប្រជុំក្រុមដែលមានការផ្លាស់ប្តូរ",
|
||||
"user_has_no_team_yet": "អ្នកមិនទាន់មានក្រុមនៅឡើយទេ",
|
||||
"no_team_members": "អ្នកមិនទាន់មានសមាជិកក្រុមនៅឡើយទេ",
|
||||
"hide_team_profile_link": "លាក់តំណភ្ជាប់ទម្រង់ក្រុម",
|
||||
"hide_team_profile_link_description": "លាក់តំណភ្ជាប់ទម្រង់ក្រុមនៅលើទំព័រកក់",
|
||||
"display": "បង្ហាញ",
|
||||
"could_not_find_slug_to_publish_org": "មិនអាចរកឃើញ slug ដើម្បីផ្សព្វផ្សាយអង្គភាពទេ",
|
||||
"picklist": "បញ្ជីជម្រើស",
|
||||
"name_or_email": "ឈ្មោះ ឬអ៊ីមែល",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "ប្រសិនបើមិនមានទំនាក់ទំនងត្រូវបានរកឃើញទេ ត្រឡប់ទៅម្ចាស់ Lead ប្រសិនបើមាន",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ បន្ថែមខ្សែអក្សរថ្មីរបស់អ្នកនៅខាងលើនេះ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "게시됨",
|
||||
"unpublished": "게시되지 않음",
|
||||
"publish": "게시",
|
||||
"org_publish_error": "조직을 게시할 수 없습니다",
|
||||
"troubleshooter_tooltip": "문제 해결 도구를 열고 일정에 무엇이 잘못되었는지 확인하세요",
|
||||
"need_help": "도움이 필요하세요?",
|
||||
"troubleshooter": "문제 해결 도구",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "비활성 팀 플랜",
|
||||
"inactive_team_plan_description": "팀 플랜이 비활성 상태입니다. 구독을 확인하거나 고객 지원에 문의하세요",
|
||||
"limited_access_trial_mode": "체험 기간 동안 제한된 액세스. 체험 종료 후 기능 사용 가능.",
|
||||
"earn_20_percent_affiliate": "20% 제휴 수익 창출",
|
||||
"referral_program": "추천 프로그램",
|
||||
"dub_disabled_error_message": "이 페이지를 사용하려면 Dub API 키와 프로그램 ID가 필요합니다.",
|
||||
"uid": "UID",
|
||||
"link": "링크",
|
||||
"rows_per_page": "페이지당 행 수",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "팁: 사용자 이름 사이에 '+'를 추가할 수 있습니다: cal.com/anna+brian으로 동적 그룹 미팅을 만들 수 있습니다",
|
||||
"user_has_no_team_yet": "아직 팀이 없습니다",
|
||||
"no_team_members": "아직 팀원이 없습니다",
|
||||
"hide_team_profile_link": "팀 프로필 링크 숨기기",
|
||||
"hide_team_profile_link_description": "예약 페이지에서 팀 프로필 링크 숨기기",
|
||||
"display": "표시",
|
||||
"could_not_find_slug_to_publish_org": "조직을 게시할 슬러그를 찾을 수 없습니다",
|
||||
"picklist": "선택 목록",
|
||||
"name_or_email": "이름 또는 이메일",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "연락처를 찾을 수 없는 경우, 리드 소유자가 있으면 대체",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ 여기에 새 문자열을 추가하세요 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Gepubliceerd",
|
||||
"unpublished": "Niet gepubliceerd",
|
||||
"publish": "Publiceren",
|
||||
"org_publish_error": "Organisatie kon niet worden gepubliceerd",
|
||||
"troubleshooter_tooltip": "Open de probleemoplosser en ontdek wat er mis is met je schema",
|
||||
"need_help": "Hulp nodig?",
|
||||
"troubleshooter": "Probleemoplosser",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Inactief teamabonnement",
|
||||
"inactive_team_plan_description": "Uw teamabonnement is inactief. Controleer uw abonnement of neem contact op met de klantenondersteuning",
|
||||
"limited_access_trial_mode": "Beperkte toegang tijdens proefperiode. Functie beschikbaar na afloop van de proefperiode.",
|
||||
"earn_20_percent_affiliate": "Verdien 20% als affiliate",
|
||||
"referral_program": "Verwijzingsprogramma",
|
||||
"dub_disabled_error_message": "Je hebt een Dub API-sleutel en programma-ID nodig om deze pagina te gebruiken.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "rijen per pagina",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Tip: U kunt een '+' tussen gebruikersnamen plaatsen: cal.com/anna+brian om een dynamische groepsbijeenkomst te maken",
|
||||
"user_has_no_team_yet": "U heeft nog geen team",
|
||||
"no_team_members": "U heeft nog geen teamleden",
|
||||
"hide_team_profile_link": "Teamprofiellink verbergen",
|
||||
"hide_team_profile_link_description": "Verberg de teamprofiellink op boekingspagina's",
|
||||
"display": "Weergave",
|
||||
"could_not_find_slug_to_publish_org": "Kon geen slug vinden om de organisatie te publiceren",
|
||||
"picklist": "Keuzelijst",
|
||||
"name_or_email": "Naam of e-mail",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Als er geen contactpersoon wordt gevonden, val dan terug op de lead-eigenaar als deze bestaat",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Voeg uw nieuwe strings hierboven toe ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publisert",
|
||||
"unpublished": "Upublisert",
|
||||
"publish": "Publiser",
|
||||
"org_publish_error": "Organisasjonen kunne ikke publiseres",
|
||||
"troubleshooter_tooltip": "Åpne feilsøkeren og finn ut hva som er galt med timeplanen din",
|
||||
"need_help": "Trenger du hjelp?",
|
||||
"troubleshooter": "Feilsøker",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Inaktiv teamplan",
|
||||
"inactive_team_plan_description": "Din teamplan er inaktiv. Sjekk abonnementet ditt eller ta kontakt med kundeservice",
|
||||
"limited_access_trial_mode": "Begrenset tilgang under prøveperioden. Funksjonen blir tilgjengelig etter at prøveperioden er over.",
|
||||
"earn_20_percent_affiliate": "Tjen 20% som partner",
|
||||
"referral_program": "Henvisningsprogram",
|
||||
"dub_disabled_error_message": "Du trenger en Dub API-nøkkel og program-ID for å bruke denne siden.",
|
||||
"uid": "UID",
|
||||
"link": "Lenke",
|
||||
"rows_per_page": "rader per side",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Tips: Du kan legge til '+' mellom brukernavn: cal.com/anna+brian for å lage et dynamisk gruppemøte",
|
||||
"user_has_no_team_yet": "Du har ikke et team ennå",
|
||||
"no_team_members": "Du har ingen teammedlemmer ennå",
|
||||
"hide_team_profile_link": "Skjul teamprofillenke",
|
||||
"hide_team_profile_link_description": "Skjul teamprofillenken på bestillingssider",
|
||||
"display": "Visning",
|
||||
"could_not_find_slug_to_publish_org": "Kunne ikke finne slug for å publisere organisasjonen",
|
||||
"picklist": "Valgliste",
|
||||
"name_or_email": "Navn eller e-post",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Hvis ingen kontakt blir funnet, fall tilbake til leadeier hvis den eksisterer",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Legg til dine nye strenger over her ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Opublikowane",
|
||||
"unpublished": "Nieopublikowane",
|
||||
"publish": "Opublikuj",
|
||||
"org_publish_error": "Nie udało się opublikować organizacji",
|
||||
"troubleshooter_tooltip": "Otwórz narzędzie do rozwiązywania problemów i sprawdź, co jest nie tak z Twoim harmonogramem",
|
||||
"need_help": "Potrzebujesz pomocy?",
|
||||
"troubleshooter": "Narzędzie do rozwiązywania problemów",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Nieaktywny plan zespołowy",
|
||||
"inactive_team_plan_description": "Twój plan zespołowy jest nieaktywny. Sprawdź swoją subskrypcję lub skontaktuj się z obsługą klienta",
|
||||
"limited_access_trial_mode": "Ograniczony dostęp w trybie próbnym. Funkcja dostępna po zakończeniu okresu próbnego.",
|
||||
"earn_20_percent_affiliate": "Zarabiaj 20% jako partner afiliacyjny",
|
||||
"referral_program": "Program poleceń",
|
||||
"dub_disabled_error_message": "Potrzebujesz klucza API Dub i identyfikatora programu, aby korzystać z tej strony.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "wierszy na stronę",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Wskazówka: Możesz dodać '+' między nazwami użytkowników: cal.com/anna+brian, aby utworzyć dynamiczne spotkanie grupowe",
|
||||
"user_has_no_team_yet": "Nie masz jeszcze zespołu",
|
||||
"no_team_members": "Nie masz jeszcze członków zespołu",
|
||||
"hide_team_profile_link": "Ukryj link do profilu zespołu",
|
||||
"hide_team_profile_link_description": "Ukryj link do profilu zespołu na stronach rezerwacji",
|
||||
"display": "Wyświetlanie",
|
||||
"could_not_find_slug_to_publish_org": "Nie można znaleźć sluga do opublikowania organizacji",
|
||||
"picklist": "Lista wyboru",
|
||||
"name_or_email": "Imię lub email",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Jeśli nie znaleziono kontaktu, powróć do właściciela leada, jeśli istnieje",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Dodaj nowe ciągi powyżej ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publicado",
|
||||
"unpublished": "Não publicado",
|
||||
"publish": "Publicar",
|
||||
"org_publish_error": "Não foi possível publicar a organização",
|
||||
"troubleshooter_tooltip": "Abra o solucionador de problemas e descubra o que há de errado com sua programação",
|
||||
"need_help": "Precisa de ajuda?",
|
||||
"troubleshooter": "Solucionador de problemas",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Plano de equipe inativo",
|
||||
"inactive_team_plan_description": "Seu plano de equipe está inativo. Verifique sua assinatura ou entre em contato com o suporte ao cliente",
|
||||
"limited_access_trial_mode": "Acesso limitado durante o período de teste. Recurso disponível após o término do teste.",
|
||||
"earn_20_percent_affiliate": "Ganhe 20% como afiliado",
|
||||
"referral_program": "Programa de indicação",
|
||||
"dub_disabled_error_message": "Você precisa de uma chave de API Dub e um ID de programa para usar esta página.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "linhas por página",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Dica: Você pode usar um '+' entre nomes de usuário: cal.com/anna+brian para criar uma reunião de grupo dinâmica",
|
||||
"user_has_no_team_yet": "Você ainda não tem uma equipe",
|
||||
"no_team_members": "Você ainda não tem membros na equipe",
|
||||
"hide_team_profile_link": "Ocultar link do perfil da equipe",
|
||||
"hide_team_profile_link_description": "Ocultar o link do perfil da equipe nas páginas de agendamento",
|
||||
"display": "Exibir",
|
||||
"could_not_find_slug_to_publish_org": "Não foi possível encontrar o slug para publicar a organização",
|
||||
"picklist": "Lista de seleção",
|
||||
"name_or_email": "Nome ou e-mail",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Se nenhum contato for encontrado, recorrer ao proprietário do lead, se existir",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Adicione suas novas strings aqui em cima ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publicada",
|
||||
"unpublished": "Não publicada",
|
||||
"publish": "Publicar",
|
||||
"org_publish_error": "Não foi possível publicar a organização",
|
||||
"troubleshooter_tooltip": "Abra o solucionador de problemas e descubra o que está errado com o seu agendamento",
|
||||
"need_help": "Precisa de ajuda?",
|
||||
"troubleshooter": "Solucionador de problemas",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Plano de equipa inativo",
|
||||
"inactive_team_plan_description": "O seu plano de equipa está inativo. Verifique a sua subscrição ou contacte o apoio ao cliente",
|
||||
"limited_access_trial_mode": "Acesso limitado durante o período de teste. Funcionalidade disponível após o término do teste.",
|
||||
"earn_20_percent_affiliate": "Ganhe 20% como afiliado",
|
||||
"referral_program": "Programa de indicação",
|
||||
"dub_disabled_error_message": "Você precisa de uma chave de API Dub e um ID de programa para usar esta página.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "linhas por página",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Dica: Pode adicionar um '+' entre nomes de utilizador: cal.com/anna+brian para criar uma reunião de grupo dinâmica",
|
||||
"user_has_no_team_yet": "Ainda não tem uma equipa",
|
||||
"no_team_members": "Ainda não tem membros na equipa",
|
||||
"hide_team_profile_link": "Ocultar link do perfil da equipe",
|
||||
"hide_team_profile_link_description": "Ocultar o link do perfil da equipe nas páginas de agendamento",
|
||||
"display": "Exibir",
|
||||
"could_not_find_slug_to_publish_org": "Não foi possível encontrar o slug para publicar a organização",
|
||||
"picklist": "Lista de seleção",
|
||||
"name_or_email": "Nome ou e-mail",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Se nenhum contato for encontrado, recorrer ao proprietário do lead, se existir",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publicat",
|
||||
"unpublished": "Nepublicat",
|
||||
"publish": "Publicați",
|
||||
"org_publish_error": "Organizația nu a putut fi publicată",
|
||||
"troubleshooter_tooltip": "Deschideți instrumentul de depanare și aflați ce este în neregulă cu programul dvs.",
|
||||
"need_help": "Aveți nevoie de ajutor?",
|
||||
"troubleshooter": "Instrument de Depanare",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Plan de echipă inactiv",
|
||||
"inactive_team_plan_description": "Planul dvs. de echipă este inactiv. Verificați-vă abonamentul sau contactați serviciul de asistență pentru clienți",
|
||||
"limited_access_trial_mode": "Acces limitat în timpul perioadei de probă. Funcționalitatea va fi disponibilă după încheierea perioadei de probă.",
|
||||
"earn_20_percent_affiliate": "Câștigă 20% afiliat",
|
||||
"referral_program": "Program de recomandare",
|
||||
"dub_disabled_error_message": "Ai nevoie de o cheie API Dub și un ID de program pentru a utiliza această pagină.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "rânduri pe pagină",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Sfat: Puteți adăuga un '+' între numele de utilizator: cal.com/anna+brian pentru a crea o întâlnire de grup dinamică",
|
||||
"user_has_no_team_yet": "Nu aveți încă o echipă",
|
||||
"no_team_members": "Nu aveți încă membri în echipă",
|
||||
"hide_team_profile_link": "Ascunde link-ul profilului echipei",
|
||||
"hide_team_profile_link_description": "Ascunde link-ul profilului echipei pe paginile de programare",
|
||||
"display": "Afișare",
|
||||
"could_not_find_slug_to_publish_org": "Nu s-a putut găsi slug-ul pentru publicarea organizației",
|
||||
"picklist": "Listă de selecție",
|
||||
"name_or_email": "Nume sau email",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Dacă nu este găsit niciun contact, se revine la proprietarul lead-ului dacă acesta există",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Adăugați stringurile noi deasupra acestui rând ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Опубликовано",
|
||||
"unpublished": "Не опубликовано",
|
||||
"publish": "Опубликовать",
|
||||
"org_publish_error": "Не удалось опубликовать организацию",
|
||||
"troubleshooter_tooltip": "Откройте средство устранения неполадок и выясните, что не так с вашим расписанием",
|
||||
"need_help": "Нужна помощь?",
|
||||
"troubleshooter": "Средство устранения неполадок",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Неактивный тарифный план команды",
|
||||
"inactive_team_plan_description": "Ваш тарифный план команды неактивен. Проверьте вашу подписку или обратитесь в службу поддержки",
|
||||
"limited_access_trial_mode": "Ограниченный доступ во время пробного периода. Функция будет доступна после окончания пробного периода.",
|
||||
"earn_20_percent_affiliate": "Получайте 20% партнерских отчислений",
|
||||
"referral_program": "Реферальная программа",
|
||||
"dub_disabled_error_message": "Для использования этой страницы вам нужен API-ключ Dub и идентификатор программы.",
|
||||
"uid": "UID",
|
||||
"link": "Ссылка",
|
||||
"rows_per_page": "строк на странице",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Совет: Вы можете добавить '+' между именами пользователей: cal.com/anna+brian для создания динамической групповой встречи",
|
||||
"user_has_no_team_yet": "У вас пока нет команды",
|
||||
"no_team_members": "У вас пока нет участников команды",
|
||||
"hide_team_profile_link": "Скрыть ссылку на профиль команды",
|
||||
"hide_team_profile_link_description": "Скрыть ссылку на профиль команды на страницах бронирования",
|
||||
"display": "Отображение",
|
||||
"could_not_find_slug_to_publish_org": "Не удалось найти slug для публикации организации",
|
||||
"picklist": "Список выбора",
|
||||
"name_or_email": "Имя или электронная почта",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Если контакт не найден, использовать владельца лида, если он существует",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Добавьте строки выше ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publikované",
|
||||
"unpublished": "Nepublikované",
|
||||
"publish": "Publikovať",
|
||||
"org_publish_error": "Organizáciu sa nepodarilo publikovať",
|
||||
"troubleshooter_tooltip": "Otvorte nástroj na riešenie problémov a zistite, čo je zle s vaším plánom",
|
||||
"need_help": "Potrebujete pomoc?",
|
||||
"troubleshooter": "Nástroj na riešenie problémov",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Neaktívny tímový plán",
|
||||
"inactive_team_plan_description": "Váš tímový plán je neaktívny. Skontrolujte svoje predplatné alebo kontaktujte zákaznícku podporu",
|
||||
"limited_access_trial_mode": "Obmedzený prístup počas skúšobnej doby. Funkcia bude dostupná po skončení skúšobnej doby.",
|
||||
"earn_20_percent_affiliate": "Získajte 20% ako partner",
|
||||
"referral_program": "Partnerský program",
|
||||
"dub_disabled_error_message": "Na použitie tejto stránky potrebujete Dub API kľúč a ID programu.",
|
||||
"uid": "UID",
|
||||
"link": "Odkaz",
|
||||
"rows_per_page": "riadkov na stránku",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Tip: Medzi používateľské mená môžete vložiť '+': cal.com/anna+brian na vytvorenie dynamického skupinového stretnutia",
|
||||
"user_has_no_team_yet": "Zatiaľ nemáte žiadny tím",
|
||||
"no_team_members": "Zatiaľ nemáte žiadnych členov tímu",
|
||||
"hide_team_profile_link": "Skryť odkaz na profil tímu",
|
||||
"hide_team_profile_link_description": "Skryť odkaz na profil tímu na stránkach rezervácií",
|
||||
"display": "Zobrazenie",
|
||||
"could_not_find_slug_to_publish_org": "Nepodarilo sa nájsť slug na zverejnenie organizácie",
|
||||
"picklist": "Zoznam na výber",
|
||||
"name_or_email": "Meno alebo email",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Ak sa nenájde žiadny kontakt, použije sa vlastník leadu, ak existuje",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Pridajte svoje nové reťazce nad túto líniu ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Objavljeno",
|
||||
"unpublished": "Neobjavljeno",
|
||||
"publish": "Objavi",
|
||||
"org_publish_error": "Organizacija nije mogla biti objavljena",
|
||||
"troubleshooter_tooltip": "Otvorite alat za rešavanje problema i saznajte šta nije u redu sa vašim rasporedom",
|
||||
"need_help": "Potrebna vam je pomoć?",
|
||||
"troubleshooter": "Alat za rešavanje problema",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Neaktivan timski plan",
|
||||
"inactive_team_plan_description": "Vaš timski plan je neaktivan. Proverite vašu pretplatu ili se obratite korisničkoj podršci",
|
||||
"limited_access_trial_mode": "Ograničen pristup tokom probnog perioda. Funkcija dostupna nakon završetka probnog perioda.",
|
||||
"earn_20_percent_affiliate": "Zaradite 20% kao afiliejt",
|
||||
"referral_program": "Program preporuka",
|
||||
"dub_disabled_error_message": "Potreban vam je Dub API ključ i ID programa da biste koristili ovu stranicu.",
|
||||
"uid": "UID",
|
||||
"link": "Link",
|
||||
"rows_per_page": "redova po stranici",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Savet: Možete dodati '+' između korisničkih imena: cal.com/anna+brian da napravite dinamički grupni sastanak",
|
||||
"user_has_no_team_yet": "Još uvek nemate tim",
|
||||
"no_team_members": "Još uvek nemate članove tima",
|
||||
"hide_team_profile_link": "Sakrij link profila tima",
|
||||
"hide_team_profile_link_description": "Sakrij link profila tima na stranicama za zakazivanje",
|
||||
"display": "Prikaz",
|
||||
"could_not_find_slug_to_publish_org": "Nije moguće pronaći slug za objavljivanje organizacije",
|
||||
"picklist": "Lista za izbor",
|
||||
"name_or_email": "Ime ili email",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Ako kontakt nije pronađen, vrati se na vlasnika potencijalnog klijenta ako postoji",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Dodajte svoje nove stringove iznad ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Publicerad",
|
||||
"unpublished": "Opublicerad",
|
||||
"publish": "Publicera",
|
||||
"org_publish_error": "Organisationen kunde inte publiceras",
|
||||
"troubleshooter_tooltip": "Öppna felsökaren och ta reda på vad som är fel med ditt schema",
|
||||
"need_help": "Behöver du hjälp?",
|
||||
"troubleshooter": "Felsökare",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Inaktiv teamplan",
|
||||
"inactive_team_plan_description": "Din teamplan är inaktiv. Kontrollera din prenumeration eller kontakta kundsupport",
|
||||
"limited_access_trial_mode": "Begränsad åtkomst under provperioden. Funktionen blir tillgänglig efter att provperioden avslutas.",
|
||||
"earn_20_percent_affiliate": "Tjäna 20% som affiliate",
|
||||
"referral_program": "Referensprogram",
|
||||
"dub_disabled_error_message": "Du behöver en Dub API-nyckel och program-ID för att använda denna sida.",
|
||||
"uid": "UID",
|
||||
"link": "Länk",
|
||||
"rows_per_page": "rader per sida",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Tips: Du kan lägga till ett '+' mellan användarnamn: cal.com/anna+brian för att skapa ett dynamiskt gruppmöte",
|
||||
"user_has_no_team_yet": "Du har inget team ännu",
|
||||
"no_team_members": "Du har inga teammedlemmar ännu",
|
||||
"hide_team_profile_link": "Dölj teamprofilslänk",
|
||||
"hide_team_profile_link_description": "Dölj teamprofilslänken på bokningssidor",
|
||||
"display": "Visa",
|
||||
"could_not_find_slug_to_publish_org": "Kunde inte hitta slug för att publicera organisationen",
|
||||
"picklist": "Urvalslista",
|
||||
"name_or_email": "Namn eller e-post",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Om ingen kontakt hittas, återgå till lead-ägaren om sådan finns",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Yayınlandı",
|
||||
"unpublished": "Yayınlanmadı",
|
||||
"publish": "Yayınla",
|
||||
"org_publish_error": "Organizasyon yayınlanamadı",
|
||||
"troubleshooter_tooltip": "Sorun gidericiyi açın ve programınızda neyin yanlış olduğunu öğrenin",
|
||||
"need_help": "Yardıma mı ihtiyacınız var?",
|
||||
"troubleshooter": "Sorun Giderici",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Aktif olmayan ekip planı",
|
||||
"inactive_team_plan_description": "Ekip planınız aktif değil. Aboneliğinizi kontrol edin veya müşteri desteğiyle iletişime geçin",
|
||||
"limited_access_trial_mode": "Deneme süresi boyunca sınırlı erişim. Özellik deneme süresi sona erdikten sonra kullanılabilir.",
|
||||
"earn_20_percent_affiliate": "Yüzde 20 Ortaklık Kazancı",
|
||||
"referral_program": "Referans Programı",
|
||||
"dub_disabled_error_message": "Bu sayfayı kullanmak için bir Dub API Anahtarı ve Program Kimliği'ne ihtiyacınız var.",
|
||||
"uid": "UID",
|
||||
"link": "Bağlantı",
|
||||
"rows_per_page": "sayfa başına satır",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "İpucu: Dinamik bir grup toplantısı oluşturmak için kullanıcı adları arasına '+' ekleyebilirsiniz: cal.com/anna+brian",
|
||||
"user_has_no_team_yet": "Henüz bir ekibiniz yok",
|
||||
"no_team_members": "Henüz ekip üyeniz yok",
|
||||
"hide_team_profile_link": "Takım Profil Bağlantısını Gizle",
|
||||
"hide_team_profile_link_description": "Rezervasyon sayfalarında takım profil bağlantısını gizle",
|
||||
"display": "Görüntüleme",
|
||||
"could_not_find_slug_to_publish_org": "Organizasyonu yayınlamak için kısa ad bulunamadı",
|
||||
"picklist": "Seçim listesi",
|
||||
"name_or_email": "İsim veya E-posta",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Hiçbir kişi bulunamazsa, eğer varsa müşteri adayı sahibine geri dön",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Yeni dizelerinizi yukarıya ekleyin ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Опубліковано",
|
||||
"unpublished": "Неопубліковано",
|
||||
"publish": "Опублікувати",
|
||||
"org_publish_error": "Не вдалося опублікувати організацію",
|
||||
"troubleshooter_tooltip": "Відкрийте засіб усунення несправностей і з'ясуйте, що не так з вашим розкладом",
|
||||
"need_help": "Потрібна допомога?",
|
||||
"troubleshooter": "Засіб усунення несправностей",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Неактивний план команди",
|
||||
"inactive_team_plan_description": "Ваш командний план неактивний. Перевірте вашу підписку або зверніться до служби підтримки",
|
||||
"limited_access_trial_mode": "Обмежений доступ під час пробного періоду. Функція буде доступна після завершення пробного періоду.",
|
||||
"earn_20_percent_affiliate": "Отримайте 20% партнерської винагороди",
|
||||
"referral_program": "Реферальна програма",
|
||||
"dub_disabled_error_message": "Вам потрібен API-ключ Dub та ідентифікатор програми, щоб використовувати цю сторінку.",
|
||||
"uid": "UID",
|
||||
"link": "Посилання",
|
||||
"rows_per_page": "рядків на сторінку",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Порада: Ви можете додати '+' між іменами користувачів: cal.com/anna+brian, щоб створити динамічну групову зустріч",
|
||||
"user_has_no_team_yet": "У вас ще немає команди",
|
||||
"no_team_members": "У вас ще немає учасників команди",
|
||||
"hide_team_profile_link": "Приховати посилання на профіль команди",
|
||||
"hide_team_profile_link_description": "Приховати посилання на профіль команди на сторінках бронювання",
|
||||
"display": "Відображення",
|
||||
"could_not_find_slug_to_publish_org": "Не вдалося знайти слаг для публікації організації",
|
||||
"picklist": "Список вибору",
|
||||
"name_or_email": "Ім'я або електронна пошта",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Якщо контакт не знайдено, використовувати власника ліда, якщо він існує",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "Đã xuất bản",
|
||||
"unpublished": "Chưa xuất bản",
|
||||
"publish": "Xuất bản",
|
||||
"org_publish_error": "Không thể xuất bản tổ chức",
|
||||
"troubleshooter_tooltip": "Mở trình khắc phục sự cố và tìm hiểu điều gì sai với lịch trình của bạn",
|
||||
"need_help": "Cần hỗ trợ?",
|
||||
"troubleshooter": "Trình khắc phục sự cố",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "Gói nhóm không hoạt động",
|
||||
"inactive_team_plan_description": "Gói nhóm của bạn đang không hoạt động. Kiểm tra đăng ký của bạn hoặc liên hệ với bộ phận hỗ trợ khách hàng",
|
||||
"limited_access_trial_mode": "Truy cập hạn chế trong thời gian dùng thử. Tính năng sẽ khả dụng sau khi kết thúc thời gian dùng thử.",
|
||||
"earn_20_percent_affiliate": "Kiếm 20% tiền giới thiệu",
|
||||
"referral_program": "Chương trình giới thiệu",
|
||||
"dub_disabled_error_message": "Bạn cần Khóa API Dub và ID Chương trình để sử dụng trang này.",
|
||||
"uid": "UID",
|
||||
"link": "Liên kết",
|
||||
"rows_per_page": "hàng mỗi trang",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "Mẹo: Bạn có thể thêm dấu '+' giữa các tên người dùng: cal.com/anna+brian để tạo cuộc họp nhóm động",
|
||||
"user_has_no_team_yet": "Bạn chưa có nhóm nào",
|
||||
"no_team_members": "Bạn chưa có thành viên nhóm nào",
|
||||
"hide_team_profile_link": "Ẩn liên kết hồ sơ nhóm",
|
||||
"hide_team_profile_link_description": "Ẩn liên kết hồ sơ nhóm trên trang đặt lịch",
|
||||
"display": "Hiển thị",
|
||||
"could_not_find_slug_to_publish_org": "Không tìm thấy slug để xuất bản tổ chức",
|
||||
"picklist": "Danh sách chọn",
|
||||
"name_or_email": "Tên hoặc email",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "Nếu không tìm thấy liên hệ, chuyển sang chủ sở hữu khách hàng tiềm năng nếu tồn tại",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "已发布",
|
||||
"unpublished": "未发布",
|
||||
"publish": "发布",
|
||||
"org_publish_error": "无法发布组织",
|
||||
"troubleshooter_tooltip": "打开问题排查器并找出您的日程安排有什么问题",
|
||||
"need_help": "需要帮助?",
|
||||
"troubleshooter": "问题排查器",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "非活跃团队计划",
|
||||
"inactive_team_plan_description": "您的团队计划处于非活跃状态。请检查您的订阅或联系客户支持",
|
||||
"limited_access_trial_mode": "试用期间访问受限。此功能将在试用结束后可用。",
|
||||
"earn_20_percent_affiliate": "赚取20%联盟佣金",
|
||||
"referral_program": "推荐计划",
|
||||
"dub_disabled_error_message": "您需要Dub API密钥和程序ID才能使用此页面。",
|
||||
"uid": "用户ID",
|
||||
"link": "链接",
|
||||
"rows_per_page": "每页行数",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "提示:您可以在用户名之间添加'+':cal.com/anna+brian 来创建动态群组会议",
|
||||
"user_has_no_team_yet": "您还没有团队",
|
||||
"no_team_members": "您还没有团队成员",
|
||||
"hide_team_profile_link": "隐藏团队资料链接",
|
||||
"hide_team_profile_link_description": "在预约页面上隐藏团队资料链接",
|
||||
"display": "显示",
|
||||
"could_not_find_slug_to_publish_org": "找不到要发布组织的短链接",
|
||||
"picklist": "选择列表",
|
||||
"name_or_email": "姓名或电子邮箱",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "如果未找到联系人,则在存在潜在客户所有者的情况下回退到潜在客户所有者",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ 在此上方添加您的新字符串 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -2452,7 +2452,6 @@
|
||||
"published": "已發佈",
|
||||
"unpublished": "未發佈",
|
||||
"publish": "發佈",
|
||||
"org_publish_error": "無法發佈組織",
|
||||
"troubleshooter_tooltip": "打開故障排除工具,找出您的日程安排有什麼問題",
|
||||
"need_help": "需要協助?",
|
||||
"troubleshooter": "故障排除工具",
|
||||
@@ -3009,6 +3008,9 @@
|
||||
"inactive_team_plan": "未啟用的團隊方案",
|
||||
"inactive_team_plan_description": "您的團隊方案未啟用。請檢查您的訂閱或聯繫客戶支援",
|
||||
"limited_access_trial_mode": "試用期間功能受限。試用結束後即可使用完整功能。",
|
||||
"earn_20_percent_affiliate": "賺取20%聯盟佣金",
|
||||
"referral_program": "推薦計劃",
|
||||
"dub_disabled_error_message": "您需要Dub API金鑰和程式ID才能使用此頁面。",
|
||||
"uid": "UID",
|
||||
"link": "連結",
|
||||
"rows_per_page": "每頁行數",
|
||||
@@ -3016,6 +3018,12 @@
|
||||
"tip_username_plus": "提示:您可以在使用者名稱之間加上 '+':cal.com/anna+brian 來建立動態群組會議",
|
||||
"user_has_no_team_yet": "您還沒有團隊",
|
||||
"no_team_members": "您還沒有團隊成員",
|
||||
"hide_team_profile_link": "隱藏團隊資料連結",
|
||||
"hide_team_profile_link_description": "在預約頁面上隱藏團隊資料連結",
|
||||
"display": "顯示",
|
||||
"could_not_find_slug_to_publish_org": "找不到要發布組織的短網址",
|
||||
"picklist": "選項清單",
|
||||
"name_or_email": "姓名或電子郵件",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "如果找不到聯絡人,則回退到潛在客戶擁有者(如果存在)",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ 請在此處新增您的字串 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
@@ -3,6 +3,20 @@ title: 'Introduction to API v2'
|
||||
description: 'Introduction to Cal.com API v2 endpoints'
|
||||
---
|
||||
|
||||
## Platform endpoints
|
||||
Platform customers have the following endpoints available:
|
||||
|
||||
1. Endpoints prefixed with "Platform".
|
||||
2. Endpoints with no prefix e.g "Bookings", "Event Types".
|
||||
3. If you are at least on the ESSENTIALS plan, then all endpoints prefixed with "Orgs" except "Orgs / Attributes", "Orgs / Attributes / Options" and "Orgs / Teams / Routing forms / Responses".
|
||||
|
||||
## Organizations endpoints
|
||||
Organizations customers have all the endpoints except the ones prefixed with "Platform" and "Teams" and "Orgs / Orgs" because
|
||||
children organizations are only allowed in the platform plan right now.
|
||||
|
||||
## Teams endpoints
|
||||
Teams customers have all the endpoints except the ones prefixed with "Platform" and "Orgs".
|
||||
|
||||
## Authentication
|
||||
|
||||
The Cal.com API has 3 authentication methods:
|
||||
@@ -40,7 +54,7 @@ You need to use OAuth credentials when:
|
||||
|
||||
1. Managing managed users [API reference](https://cal.com/docs/api-reference/v2/platform-managed-users/create-a-managed-user)
|
||||
2. Creating OAuth client webhooks [API reference](https://cal.com/docs/api-reference/v2/platform-webhooks/create-a-webhook)
|
||||
3. Refreshing tokens of a managed user [API reference](https://cal.com/docs/api-reference/v2/oauth/post-v2oauth-refresh)
|
||||
3. Refreshing tokens of a managed user [API reference](https://cal.com/docs/api-reference/v2/platform-managed-users/refresh-managed-user-tokens)
|
||||
4. Teams related endpoints: Managing organization teams [API reference](https://cal.com/docs/api-reference/v2/orgs-teams/create-a-team), adding managed users as members to teams [API reference](https://cal.com/docs/api-reference/v2/orgs-teams-memberships/create-a-membership), creating team event types [API reference](https://cal.com/docs/api-reference/v2/orgs-event-types/create-an-event-type).
|
||||
|
||||
OAuth credentials can be accessed in the platform dashboard https://app.cal.com/settings/platform after you have created an OAuth client. Each one has an ID and secret. You then need to pass them as request headers:
|
||||
@@ -63,11 +77,3 @@ Validity period: access tokens are valid for 60 minutes and refresh tokens for 1
|
||||
|
||||
Recovering tokens: if you ever lose managed user's access or refresh tokens, you can force refresh them using the OAuth client credentials and store them in your database [API reference](https://cal.com/docs/api-reference/v2/platform-managed-users/force-refresh-tokens).
|
||||
|
||||
## Navigating endpoints
|
||||
Platform customers have the following endpoints available:
|
||||
|
||||
1. Endpoints prefixed with "Platform".
|
||||
2. Endpoints with no prefix e.g "Bookings", "Event Types".
|
||||
3. If you are at least on the ESSENTIALS plan, then all endpoints prefixed with "Orgs" except "Orgs / Attributes".
|
||||
|
||||
Non-platform customers have all the endpoints except the ones prefixed with "Platform".
|
||||
+2624
-708
File diff suppressed because it is too large
Load Diff
@@ -2449,7 +2449,6 @@ checksums:
|
||||
published: ad5e035c44f71ed32d41e47c7643f32f
|
||||
unpublished: 7239558b647feca27aac552977234c50
|
||||
publish: 4aa95ba4793bb293e771bd73b4f87c0f
|
||||
org_publish_error: d41336ed09d192987160a1f5f0440773
|
||||
troubleshooter_tooltip: 09454c97ca0c80bd8d0485dd79ba0c86
|
||||
need_help: 04e7322f2d3ffb2d73ff2f64b71637c8
|
||||
troubleshooter: ac4a51cd3ebfacdd646583bf158235f5
|
||||
@@ -3006,6 +3005,9 @@ checksums:
|
||||
inactive_team_plan: 25f9f6f4b074eeec440bc61aa8638cf7
|
||||
inactive_team_plan_description: 15de96578b521a59f65b7fa69e9a4888
|
||||
limited_access_trial_mode: c501618906970336bf51e5d715efed8d
|
||||
earn_20_percent_affiliate: 8805417839624540ef151441c68d8b02
|
||||
referral_program: bc858f75f37326cc8cb8645d3bca6e4c
|
||||
dub_disabled_error_message: 5f77315bfefcd9e3268a54ea96c9a7de
|
||||
uid: 379cc5edfadebfc2d792e341bf7a190b
|
||||
link: 60f0aa33e70ca6df3b6659802b16f433
|
||||
rows_per_page: c95a0b385cad1e73b95619fe92a61cb6
|
||||
@@ -3013,5 +3015,11 @@ checksums:
|
||||
tip_username_plus: d3279ca90f8abdd965844998dd29bebc
|
||||
user_has_no_team_yet: a8d58d1e2b62cfb97b61afd1b72385c4
|
||||
no_team_members: a8329bca21c7026eb28cde53c0d2911a
|
||||
hide_team_profile_link: e21a893cc987056b6fbdf83a4e3813a9
|
||||
hide_team_profile_link_description: 8070f11216814e43b8b72c24eb8f9cfd
|
||||
display: 9e4db8e7b3d215db7148240466ed796a
|
||||
could_not_find_slug_to_publish_org: 86399c898effaf4d2b6113e91ffebb95
|
||||
picklist: 5a3d44808605be31190c9956ecc5e412
|
||||
name_or_email: d6e1cc7612211a2f7080b5096510f282
|
||||
salesforce_round_robin_skip_fallback_to_lead_owner: 95ba66cdc5f1422c48d907e9d4d442b9
|
||||
ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS: 18323f2f3fabb169a7cb50ff62433850
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import type { TextComponent } from "../lib";
|
||||
|
||||
@@ -27,91 +26,14 @@ export async function isValidCalURL(url: string) {
|
||||
error,
|
||||
};
|
||||
|
||||
const urlWithoutCal = url.replace(regex, "");
|
||||
const response = await fetch(url);
|
||||
|
||||
const urlParts = urlWithoutCal.split("/");
|
||||
const usernameOrTeamSlug = urlParts[0];
|
||||
const eventTypeSlug = urlParts[1];
|
||||
|
||||
if (!usernameOrTeamSlug || !eventTypeSlug)
|
||||
if (response.status !== 200)
|
||||
return {
|
||||
isValid: false,
|
||||
error,
|
||||
};
|
||||
|
||||
// Find all potential users with the given username
|
||||
const potentialUsers = await prisma.user.findMany({
|
||||
where: {
|
||||
username: usernameOrTeamSlug,
|
||||
},
|
||||
include: {
|
||||
eventTypes: {
|
||||
where: {
|
||||
slug: eventTypeSlug,
|
||||
hidden: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Find all potential teams with the given slug
|
||||
const potentialTeams = await prisma.team.findMany({
|
||||
where: {
|
||||
slug: usernameOrTeamSlug,
|
||||
},
|
||||
include: {
|
||||
eventTypes: {
|
||||
where: {
|
||||
slug: eventTypeSlug,
|
||||
hidden: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Check if any user has the matching eventTypeSlug
|
||||
const matchingUser = potentialUsers.find((user) => user.eventTypes.length > 0);
|
||||
|
||||
// Check if any team has the matching eventTypeSlug
|
||||
const matchingTeam = potentialTeams.find((team) => team.eventTypes.length > 0);
|
||||
|
||||
if (!matchingUser && !matchingTeam)
|
||||
return {
|
||||
isValid: false,
|
||||
error: {
|
||||
...error,
|
||||
text: `${usernameOrTeamSlug} team or user is not valid.`,
|
||||
},
|
||||
};
|
||||
|
||||
const userOrTeam = matchingUser || matchingTeam;
|
||||
|
||||
if (!userOrTeam)
|
||||
return {
|
||||
isValid: false,
|
||||
error,
|
||||
};
|
||||
|
||||
// Retrieve the correct user or team
|
||||
const userOrTeamId = userOrTeam.id;
|
||||
|
||||
const eventType = await prisma.eventType.findFirst({
|
||||
where: {
|
||||
userId: userOrTeamId,
|
||||
slug: eventTypeSlug,
|
||||
hidden: false,
|
||||
},
|
||||
});
|
||||
|
||||
if (!eventType)
|
||||
return {
|
||||
isValid: false,
|
||||
error: {
|
||||
...error,
|
||||
text: `The event ${eventTypeSlug} doesn't exist.`,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import stripe from "@calcom/app-store/stripepayment/lib/server";
|
||||
import { StripeBillingService } from "@calcom/features/ee/billing/stripe-billling-service";
|
||||
|
||||
export async function getCustomerAndCheckoutSession(checkoutSessionId: string) {
|
||||
const checkoutSession = await stripe.checkout.sessions.retrieve(checkoutSessionId);
|
||||
const billingService = new StripeBillingService();
|
||||
const checkoutSession = await billingService.getCheckoutSession(checkoutSessionId);
|
||||
const customerOrCustomerId = checkoutSession.customer;
|
||||
let customerId = null;
|
||||
|
||||
@@ -16,7 +17,7 @@ export async function getCustomerAndCheckoutSession(checkoutSessionId: string) {
|
||||
} else {
|
||||
customerId = customerOrCustomerId.id;
|
||||
}
|
||||
const stripeCustomer = await stripe.customers.retrieve(customerId);
|
||||
const stripeCustomer = await billingService.getCustomer(customerId);
|
||||
if (stripeCustomer.deleted) {
|
||||
return { checkoutSession, stripeCustomer: null };
|
||||
}
|
||||
|
||||
@@ -274,6 +274,24 @@ test.describe("Popup Tests", () => {
|
||||
pathname: configuredLink,
|
||||
});
|
||||
});
|
||||
|
||||
test("should open embed iframe on click - Configured with hide eventType details", async ({
|
||||
page,
|
||||
embeds,
|
||||
}) => {
|
||||
await deleteAllBookingsByEmail("embed-user@example.com");
|
||||
const calNamespace = "popupHideEventTypeDetails";
|
||||
|
||||
await embeds.gotoPlayground({ calNamespace, url: "/" });
|
||||
|
||||
await page.click(`[data-cal-namespace="${calNamespace}"]`);
|
||||
|
||||
const embedIframe = await getEmbedIframe({ calNamespace, page, pathname: "/free/30min" });
|
||||
|
||||
await expect(embedIframe).toBeEmbedCalLink(calNamespace, embeds.getActionFiredDetails, {
|
||||
pathname: "/free/30min",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function expectPrerenderedIframe({
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { NextApiResponse } from "next";
|
||||
|
||||
import stripe from "@calcom/app-store/stripepayment/lib/server";
|
||||
import { getPremiumMonthlyPlanPriceId } from "@calcom/app-store/stripepayment/lib/utils";
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { sendEmailVerification } from "@calcom/features/auth/lib/verifyEmail";
|
||||
import { createOrUpdateMemberships } from "@calcom/features/auth/signup/utils/createOrUpdateMemberships";
|
||||
import { prefillAvatar } from "@calcom/features/auth/signup/utils/prefillAvatar";
|
||||
import { StripeBillingService } from "@calcom/features/ee/billing/stripe-billling-service";
|
||||
import { checkIfEmailIsBlockedInWatchlistController } from "@calcom/features/watchlist/operations/check-if-email-in-watchlist.controller";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { getLocaleFromRequest } from "@calcom/lib/getLocaleFromRequest";
|
||||
@@ -40,6 +40,8 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
|
||||
})
|
||||
.parse(req.body);
|
||||
|
||||
const billingService = new StripeBillingService();
|
||||
|
||||
const shouldLockByDefault = await checkIfEmailIsBlockedInWatchlistController(_email);
|
||||
|
||||
log.debug("handler", { email: _email });
|
||||
@@ -96,7 +98,8 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
|
||||
}
|
||||
|
||||
// Create the customer in Stripe
|
||||
const customer = await stripe.customers.create({
|
||||
|
||||
const customer = await billingService.createCustomer({
|
||||
email,
|
||||
metadata: {
|
||||
email /* Stripe customer email can be changed, so we add this to keep track of which email was used to signup */,
|
||||
@@ -108,22 +111,18 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
|
||||
|
||||
// Pro username, must be purchased
|
||||
if (req.usernameStatus.statusCode === 402) {
|
||||
const checkoutSession = await stripe.checkout.sessions.create({
|
||||
const checkoutSession = await billingService.createSubscriptionCheckout({
|
||||
mode: "subscription",
|
||||
customer: customer.id,
|
||||
line_items: [
|
||||
{
|
||||
price: getPremiumMonthlyPlanPriceId(),
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
success_url: returnUrl,
|
||||
cancel_url: returnUrl,
|
||||
allow_promotion_codes: true,
|
||||
customerId: customer.stripeCustomerId,
|
||||
successUrl: returnUrl,
|
||||
cancelUrl: returnUrl,
|
||||
priceId: getPremiumMonthlyPlanPriceId(),
|
||||
quantity: 1,
|
||||
allowPromotionCodes: true,
|
||||
});
|
||||
|
||||
/** We create a username-less user until he pays */
|
||||
checkoutSessionId = checkoutSession.id;
|
||||
checkoutSessionId = checkoutSession.sessionId;
|
||||
username = null;
|
||||
}
|
||||
|
||||
@@ -168,7 +167,7 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
|
||||
},
|
||||
});
|
||||
// Wrapping in a transaction as if one fails we want to rollback the whole thing to preventa any data inconsistencies
|
||||
const { membership } = await createOrUpdateMemberships({
|
||||
await createOrUpdateMemberships({
|
||||
user,
|
||||
team,
|
||||
});
|
||||
@@ -190,14 +189,14 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
|
||||
});
|
||||
} else {
|
||||
// Create the user
|
||||
const user = await prisma.user.create({
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
username,
|
||||
email,
|
||||
locked: shouldLockByDefault,
|
||||
password: { create: { hash: hashedPassword } },
|
||||
metadata: {
|
||||
stripeCustomerId: customer.id,
|
||||
stripeCustomerId: customer.stripeCustomerId,
|
||||
checkoutSessionId,
|
||||
},
|
||||
creationSource: CreationSource.WEBAPP,
|
||||
@@ -221,7 +220,7 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(201).json({ message: "Created user", stripeCustomerId: customer.id });
|
||||
return res.status(201).json({ message: "Created user", stripeCustomerId: customer.stripeCustomerId });
|
||||
}
|
||||
|
||||
export default usernameHandler(handler);
|
||||
|
||||
@@ -11,30 +11,21 @@ import { getTimeMax, getTimeMin } from "./lib/datesForCache";
|
||||
|
||||
const log = logger.getSubLogger({ prefix: ["CalendarCacheRepository"] });
|
||||
|
||||
/** Enable or disable the expanded cache. Enabled by default. */
|
||||
const ENABLE_EXPANDED_CACHE = process.env.ENABLE_EXPANDED_CACHE !== "0";
|
||||
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
const ONE_MONTH_IN_MS = 30 * MS_PER_DAY;
|
||||
const CACHING_TIME = ONE_MONTH_IN_MS;
|
||||
|
||||
export function parseKeyForCache(args: FreeBusyArgs): string {
|
||||
const { timeMin: _timeMin, timeMax: _timeMax, items } = args;
|
||||
function parseKeyForCache(args: FreeBusyArgs): string {
|
||||
// Ensure that calendarIds are unique
|
||||
const uniqueItems = uniqueBy(items, ["id"]);
|
||||
const { timeMin, timeMax } = handleMinMax(_timeMin, _timeMax);
|
||||
const key = JSON.stringify({ timeMin, timeMax, items: uniqueItems });
|
||||
const uniqueItems = uniqueBy(args.items, ["id"]);
|
||||
const key = JSON.stringify({
|
||||
timeMin: getTimeMin(args.timeMin),
|
||||
timeMax: getTimeMax(args.timeMax),
|
||||
items: uniqueItems,
|
||||
});
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* By expanding the cache to whole months, we can save round trips to the third party APIs.
|
||||
* In this case we already have the data in the database, so we can just return it.
|
||||
*/
|
||||
function handleMinMax(min: string, max: string) {
|
||||
if (!ENABLE_EXPANDED_CACHE) return { timeMin: min, timeMax: max };
|
||||
return { timeMin: getTimeMin(min), timeMax: getTimeMax(max) };
|
||||
}
|
||||
|
||||
type FreeBusyArgs = { timeMin: string; timeMax: string; items: { id: string }[] };
|
||||
|
||||
export class CalendarCacheRepository implements ICalendarCacheRepository {
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { getTimeMin, getTimeMax } from "./datesForCache";
|
||||
|
||||
describe("getTimeMin", () => {
|
||||
// Tested on multiple dates
|
||||
// vi.setSystemTime("2030-04-21T00:00:13Z");
|
||||
it("should return start of current month when no date is passed", () => {
|
||||
const result = getTimeMin();
|
||||
const expected = new Date();
|
||||
expected.setUTCDate(1);
|
||||
expected.setUTCHours(0, 0, 0, 0);
|
||||
expect(result).toBe(expected.toISOString());
|
||||
});
|
||||
|
||||
it("should return start of month for a given date", () => {
|
||||
const result = getTimeMin("2025-03-15T10:30:00Z");
|
||||
expect(result).toMatchInlineSnapshot(`"2025-03-01T00:00:00.000Z"`);
|
||||
});
|
||||
|
||||
it("should handle dates at the start of month", () => {
|
||||
const result = getTimeMin("2026-03-01T00:00:00Z");
|
||||
expect(result).toMatchInlineSnapshot(`"2026-03-01T00:00:00.000Z"`);
|
||||
});
|
||||
|
||||
it("should handle DST changes", () => {
|
||||
const result = getTimeMin("2024-10-27T01:30:00Z");
|
||||
expect(result).toMatchInlineSnapshot(`"2024-10-01T00:00:00.000Z"`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getTimeMax", () => {
|
||||
it("should return the start of the overnext month when no date is passed", () => {
|
||||
const result = getTimeMax();
|
||||
const expected = new Date();
|
||||
expected.setUTCMonth(expected.getUTCMonth() + 2);
|
||||
expected.setUTCDate(1);
|
||||
expected.setUTCHours(0, 0, 0, 0);
|
||||
expect(result).toBe(expected.toISOString());
|
||||
});
|
||||
|
||||
it("should return the start of overnext month for dates between start of current month and end of next month", () => {
|
||||
const testDate = "2024-03-15T10:30:00Z";
|
||||
const result = getTimeMax(testDate);
|
||||
expect(result).toMatchInlineSnapshot(`"2024-05-01T00:00:00.000Z"`);
|
||||
});
|
||||
|
||||
it("should return end of month for dates beyond overnext month", () => {
|
||||
const testDate = "2024-05-15T10:30:00Z";
|
||||
const result = getTimeMax(testDate);
|
||||
expect(result).toMatchInlineSnapshot(`"2024-07-01T00:00:00.000Z"`);
|
||||
});
|
||||
|
||||
it("should handle dates at the end of month", () => {
|
||||
const testDate = "2024-03-31T23:59:59Z";
|
||||
const result = getTimeMax(testDate);
|
||||
expect(result).toMatchInlineSnapshot(`"2024-05-01T00:00:00.000Z"`);
|
||||
});
|
||||
|
||||
it("should handle October correctly (31 days)", () => {
|
||||
const testDate = "2024-10-15T10:30:00Z";
|
||||
const result = getTimeMax(testDate);
|
||||
expect(result).toMatchInlineSnapshot(`"2024-12-01T00:00:00.000Z"`);
|
||||
});
|
||||
|
||||
it("should handle DST changes", () => {
|
||||
const testDate = "2024-10-27T01:30:00Z"; // DST change in Europe
|
||||
const result = getTimeMax(testDate);
|
||||
expect(result).toMatchInlineSnapshot(`"2024-12-01T00:00:00.000Z"`);
|
||||
});
|
||||
|
||||
it("should handle dates around DST changes in next month", () => {
|
||||
const testDate = "2024-09-15T10:30:00Z"; // September, next month includes DST change
|
||||
const result = getTimeMax(testDate);
|
||||
expect(result).toMatchInlineSnapshot(`"2024-11-01T00:00:00.000Z"`);
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,66 @@
|
||||
/** Expand the start date to the beginning of the current month */
|
||||
export const getTimeMin = (timeMin?: string) => {
|
||||
const date = timeMin ? new Date(timeMin) : new Date();
|
||||
date.setDate(1);
|
||||
date.setHours(0, 0, 0, 0);
|
||||
return date.toISOString();
|
||||
// Set to UTC to avoid timezone issues
|
||||
const result = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));
|
||||
result.setUTCHours(0, 0, 0, 0);
|
||||
return result.toISOString();
|
||||
};
|
||||
|
||||
/** Expand the end date to the end of the next month */
|
||||
/**
|
||||
* Expand the end date to the start of the overnext month if date
|
||||
* is between start of current month and end of next month,
|
||||
* otherwise return start of overnext month from the passed date
|
||||
* @example
|
||||
* Today: March 15, 2024 ▼-------------▼ getTimeMax returns May 1st 00:00:00
|
||||
* Mar Apr May Jun
|
||||
* ├────────┼────────┼────────┼────────┤
|
||||
* Current Month █████████| | | |
|
||||
* Next Month | █████████| | |
|
||||
**/
|
||||
export function getTimeMax(timeMax?: string) {
|
||||
const date = timeMax ? new Date(timeMax) : new Date();
|
||||
date.setMonth(date.getMonth() + 1);
|
||||
date.setDate(0);
|
||||
date.setHours(0, 0, 0, 0);
|
||||
return date.toISOString();
|
||||
const now = new Date();
|
||||
const currentMonth = now.getUTCMonth();
|
||||
const currentYear = now.getUTCFullYear();
|
||||
|
||||
if (!timeMax) {
|
||||
// If no date passed, return start of the overnext month from current date
|
||||
const result = new Date(Date.UTC(currentYear, currentMonth + 2, 1));
|
||||
result.setUTCHours(0, 0, 0, 0);
|
||||
return result.toISOString();
|
||||
}
|
||||
|
||||
const date = new Date(timeMax);
|
||||
const dateMonth = date.getUTCMonth();
|
||||
const dateYear = date.getUTCFullYear();
|
||||
|
||||
// If the date is within current month or next month, return start of overnext month
|
||||
// Otherwise, return start of overnext month from the date
|
||||
let targetYear = dateYear;
|
||||
let targetMonth = dateMonth;
|
||||
|
||||
// Check if date is within current month or next month
|
||||
const isWithinCurrentOrNextMonth =
|
||||
(dateYear === currentYear && dateMonth <= currentMonth + 1) ||
|
||||
(dateYear === currentYear + 1 && currentMonth === 11 && dateMonth === 0);
|
||||
|
||||
if (isWithinCurrentOrNextMonth) {
|
||||
// For dates within current month or next month, return start of overnext month
|
||||
targetMonth = dateMonth + 2;
|
||||
if (targetMonth > 11) {
|
||||
targetMonth = 0;
|
||||
targetYear++;
|
||||
}
|
||||
} else {
|
||||
// For dates beyond overnext month, return start of overnext month from the date
|
||||
targetMonth = dateMonth + 2;
|
||||
if (targetMonth > 11) {
|
||||
targetMonth = 0;
|
||||
targetYear++;
|
||||
}
|
||||
}
|
||||
|
||||
const result = new Date(Date.UTC(targetYear, targetMonth, 1));
|
||||
result.setUTCHours(0, 0, 0, 0);
|
||||
return result.toISOString();
|
||||
}
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import type { SortingState, OnChangeFn, VisibilityState } from "@tanstack/react-table";
|
||||
import type { SortingState, OnChangeFn, VisibilityState, ColumnSizingState } from "@tanstack/react-table";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useQueryState, parseAsArrayOf, parseAsJson, parseAsInteger } from "nuqs";
|
||||
import { createContext, useCallback, useRef, useEffect } from "react";
|
||||
import { z } from "zod";
|
||||
import { createContext, useCallback, useEffect, useRef } from "react";
|
||||
|
||||
import { type FilterValue, ZFilterValue, ZSorting, ZColumnVisibility } from "./lib/types";
|
||||
|
||||
const ZActiveFilter = z.object({
|
||||
f: z.string(),
|
||||
v: ZFilterValue.optional(),
|
||||
});
|
||||
|
||||
type ActiveFilter = z.infer<typeof ZActiveFilter>;
|
||||
import { useSegments } from "./lib/segments";
|
||||
import {
|
||||
type FilterValue,
|
||||
ZSorting,
|
||||
ZColumnVisibility,
|
||||
ZActiveFilter,
|
||||
ZColumnSizing,
|
||||
type FilterSegmentOutput,
|
||||
type ActiveFilters,
|
||||
} from "./lib/types";
|
||||
|
||||
export type DataTableContextType = {
|
||||
tableIdentifier: string;
|
||||
ctaContainerRef?: React.RefObject<HTMLDivElement>;
|
||||
|
||||
activeFilters: ActiveFilter[];
|
||||
activeFilters: ActiveFilters;
|
||||
clearAll: (exclude?: string[]) => void;
|
||||
addFilter: (columnId: string) => void;
|
||||
updateFilter: (columnId: string, value: FilterValue) => void;
|
||||
@@ -29,29 +32,41 @@ export type DataTableContextType = {
|
||||
columnVisibility: VisibilityState;
|
||||
setColumnVisibility: OnChangeFn<VisibilityState>;
|
||||
|
||||
columnSizing: ColumnSizingState;
|
||||
setColumnSizing: OnChangeFn<ColumnSizingState>;
|
||||
|
||||
pageIndex: number;
|
||||
pageSize: number;
|
||||
setPageIndex: (pageIndex: number) => void;
|
||||
setPageSize: (pageSize: number) => void;
|
||||
setPageIndex: (pageIndex: number | null) => void;
|
||||
setPageSize: (pageSize: number | null) => void;
|
||||
|
||||
offset: number;
|
||||
limit: number;
|
||||
|
||||
segments: FilterSegmentOutput[];
|
||||
selectedSegment: FilterSegmentOutput | undefined;
|
||||
segmentId: number | undefined;
|
||||
setSegmentId: (id: number | null) => void;
|
||||
canSaveSegment: boolean;
|
||||
};
|
||||
|
||||
export const DataTableContext = createContext<DataTableContextType | null>(null);
|
||||
|
||||
const DEFAULT_ACTIVE_FILTERS: ActiveFilter[] = [];
|
||||
const DEFAULT_ACTIVE_FILTERS: ActiveFilters = [];
|
||||
const DEFAULT_SORTING: SortingState = [];
|
||||
const DEFAULT_COLUMN_VISIBILITY: VisibilityState = {};
|
||||
const DEFAULT_COLUMN_SIZING: ColumnSizingState = {};
|
||||
const DEFAULT_PAGE_SIZE = 10;
|
||||
|
||||
interface DataTableProviderProps {
|
||||
tableIdentifier?: string;
|
||||
children: React.ReactNode;
|
||||
ctaContainerClassName?: string;
|
||||
defaultPageSize?: number;
|
||||
}
|
||||
|
||||
export function DataTableProvider({
|
||||
tableIdentifier: _tableIdentifier,
|
||||
children,
|
||||
defaultPageSize = DEFAULT_PAGE_SIZE,
|
||||
ctaContainerClassName,
|
||||
@@ -68,13 +83,25 @@ export function DataTableProvider({
|
||||
"cols",
|
||||
parseAsJson(ZColumnVisibility.parse).withDefault(DEFAULT_COLUMN_VISIBILITY)
|
||||
);
|
||||
|
||||
const [columnSizing, setColumnSizing] = useQueryState<ColumnSizingState>(
|
||||
"widths",
|
||||
parseAsJson(ZColumnSizing.parse).withDefault(DEFAULT_COLUMN_SIZING)
|
||||
);
|
||||
const [segmentId, setSegmentId] = useQueryState("segment", parseAsInteger.withDefault(-1));
|
||||
const [pageIndex, setPageIndex] = useQueryState("page", parseAsInteger.withDefault(0));
|
||||
const [pageSize, setPageSize] = useQueryState("size", parseAsInteger.withDefault(defaultPageSize));
|
||||
|
||||
const pathname = usePathname() as string | null;
|
||||
const tableIdentifier = _tableIdentifier ?? pathname ?? undefined;
|
||||
if (!tableIdentifier) {
|
||||
throw new Error("tableIdentifier is required");
|
||||
}
|
||||
|
||||
const addFilter = useCallback(
|
||||
(columnId: string) => {
|
||||
if (!activeFilters?.some((filter) => filter.f === columnId)) {
|
||||
// do not reset the page to 0 here,
|
||||
// because we don't have the filter value yet (`v: undefined`)
|
||||
setActiveFilters([...activeFilters, { f: columnId, v: undefined }]);
|
||||
}
|
||||
},
|
||||
@@ -83,15 +110,23 @@ export function DataTableProvider({
|
||||
|
||||
const clearAll = useCallback(
|
||||
(exclude?: string[]) => {
|
||||
setPageIndex(0);
|
||||
setActiveFilters((prev) => prev.filter((filter) => exclude?.includes(filter.f)));
|
||||
setPageIndex(null);
|
||||
setActiveFilters((prev) => {
|
||||
const remainingFilters = prev.filter((filter) => exclude?.includes(filter.f));
|
||||
return remainingFilters.length === 0 ? null : remainingFilters;
|
||||
});
|
||||
},
|
||||
[setActiveFilters]
|
||||
[setActiveFilters, setPageIndex]
|
||||
);
|
||||
|
||||
const setPageIndexWrapper = useCallback(
|
||||
(newPageIndex: number | null) => setPageIndex(newPageIndex || null),
|
||||
[setPageIndex]
|
||||
);
|
||||
|
||||
const updateFilter = useCallback(
|
||||
(columnId: string, value: FilterValue) => {
|
||||
setPageIndex(0);
|
||||
setPageIndex(null);
|
||||
setActiveFilters((prev) => {
|
||||
let added = false;
|
||||
const newFilters = prev.map((item) => {
|
||||
@@ -107,25 +142,46 @@ export function DataTableProvider({
|
||||
return newFilters;
|
||||
});
|
||||
},
|
||||
[setActiveFilters]
|
||||
[setActiveFilters, setPageIndex]
|
||||
);
|
||||
|
||||
const removeFilter = useCallback(
|
||||
(columnId: string) => {
|
||||
setPageIndex(0);
|
||||
setActiveFilters((prev) => prev.filter((filter) => filter.f !== columnId));
|
||||
setPageIndex(null);
|
||||
setActiveFilters((prev) => {
|
||||
const remainingFilters = prev.filter((filter) => filter.f !== columnId);
|
||||
return remainingFilters.length === 0 ? null : remainingFilters;
|
||||
});
|
||||
},
|
||||
[setActiveFilters]
|
||||
[setActiveFilters, setPageIndex]
|
||||
);
|
||||
|
||||
const setPageSizeAndGoToFirstPage = useCallback(
|
||||
(newPageSize: number) => {
|
||||
setPageSize(newPageSize);
|
||||
setPageIndex(0);
|
||||
(newPageSize: number | null) => {
|
||||
setPageSize(newPageSize === DEFAULT_PAGE_SIZE ? null : newPageSize);
|
||||
setPageIndex(null);
|
||||
},
|
||||
[setPageSize, setPageIndex]
|
||||
);
|
||||
|
||||
const { segments, selectedSegment, canSaveSegment, setSegmentIdAndSaveToLocalStorage } = useSegments({
|
||||
tableIdentifier,
|
||||
activeFilters,
|
||||
sorting,
|
||||
columnVisibility,
|
||||
columnSizing,
|
||||
pageSize,
|
||||
defaultPageSize,
|
||||
segmentId,
|
||||
setSegmentId,
|
||||
setActiveFilters,
|
||||
setSorting,
|
||||
setColumnVisibility,
|
||||
setColumnSizing,
|
||||
setPageSize,
|
||||
setPageIndex,
|
||||
});
|
||||
|
||||
const ctaContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
useEffect(() => {
|
||||
if (ctaContainerClassName) {
|
||||
@@ -137,6 +193,7 @@ export function DataTableProvider({
|
||||
return (
|
||||
<DataTableContext.Provider
|
||||
value={{
|
||||
tableIdentifier,
|
||||
ctaContainerRef,
|
||||
activeFilters,
|
||||
addFilter,
|
||||
@@ -147,12 +204,19 @@ export function DataTableProvider({
|
||||
setSorting,
|
||||
columnVisibility,
|
||||
setColumnVisibility,
|
||||
columnSizing,
|
||||
setColumnSizing,
|
||||
pageIndex,
|
||||
pageSize,
|
||||
setPageIndex,
|
||||
setPageIndex: setPageIndexWrapper,
|
||||
setPageSize: setPageSizeAndGoToFirstPage,
|
||||
limit: pageSize,
|
||||
offset: pageIndex * pageSize,
|
||||
segments,
|
||||
selectedSegment,
|
||||
segmentId: segmentId || undefined,
|
||||
setSegmentId: setSegmentIdAndSaveToLocalStorage,
|
||||
canSaveSegment,
|
||||
}}>
|
||||
{children}
|
||||
</DataTableContext.Provider>
|
||||
|
||||
@@ -6,7 +6,6 @@ import type { Table as ReactTableType, Header, HeaderGroup } from "@tanstack/rea
|
||||
import { useVirtualizer, type Virtualizer, type VirtualItem } from "@tanstack/react-virtual";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import kebabCase from "lodash/kebabCase";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useEffect, useState, memo, useMemo } from "react";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
@@ -34,6 +33,7 @@ export type DataTablePropsFromWrapper<TData> = {
|
||||
testId?: string;
|
||||
bodyTestId?: string;
|
||||
children?: React.ReactNode;
|
||||
enableColumnResizing?: boolean;
|
||||
className?: string;
|
||||
containerClassName?: string;
|
||||
headerClassName?: string;
|
||||
@@ -45,7 +45,6 @@ export type DataTableProps<TData> = DataTablePropsFromWrapper<TData> & {
|
||||
onRowMouseclick?: (row: Row<TData>) => void;
|
||||
onScroll?: (e: Pick<React.UIEvent<HTMLDivElement, UIEvent>, "target">) => void;
|
||||
tableOverlay?: React.ReactNode;
|
||||
identifier?: string;
|
||||
enableColumnResizing?: boolean;
|
||||
};
|
||||
|
||||
@@ -57,7 +56,6 @@ export function DataTable<TData>({
|
||||
onRowMouseclick,
|
||||
onScroll,
|
||||
children,
|
||||
identifier: _identifier,
|
||||
enableColumnResizing,
|
||||
testId,
|
||||
bodyTestId,
|
||||
@@ -68,9 +66,6 @@ export function DataTable<TData>({
|
||||
paginationMode = "infinite",
|
||||
...rest
|
||||
}: DataTableProps<TData> & React.ComponentPropsWithoutRef<"div">) {
|
||||
const pathname = usePathname() as string | null;
|
||||
const identifier = _identifier ?? pathname ?? undefined;
|
||||
|
||||
const { rows } = table.getRowModel();
|
||||
|
||||
const rowVirtualizer = useVirtualizer({
|
||||
@@ -102,10 +97,9 @@ export function DataTable<TData>({
|
||||
const columnSizingVars = useColumnSizingVars({ table });
|
||||
|
||||
usePersistentColumnResizing({
|
||||
enabled: Boolean(enableColumnResizing && identifier),
|
||||
enabled: Boolean(enableColumnResizing),
|
||||
table,
|
||||
tableContainerRef,
|
||||
identifier,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user