diff --git a/.github/workflows/orphaned-features-check.yml b/.github/workflows/orphaned-features-check.yml index b3254e06ce9e..ee239cebf867 100644 --- a/.github/workflows/orphaned-features-check.yml +++ b/.github/workflows/orphaned-features-check.yml @@ -60,10 +60,7 @@ jobs: exit 0 fi - # Why only 5? - # Because, we're not in a hurry and anything larger than that would - # make the PR too intimidatingly big to review. - npm run find-orphaned-features -- delete --max 5 --verbose /tmp/orphaned-features.json + npm run find-orphaned-features -- delete --verbose /tmp/orphaned-features.json git status diff --git a/assets/images/social-cards/actions.png b/assets/images/social-cards/actions.png new file mode 100644 index 000000000000..e9e60b7cc489 Binary files /dev/null and b/assets/images/social-cards/actions.png differ diff --git a/assets/images/social-cards/copilot.png b/assets/images/social-cards/copilot.png new file mode 100644 index 000000000000..9278a93657f6 Binary files /dev/null and b/assets/images/social-cards/copilot.png differ diff --git a/assets/images/social-cards/default.png b/assets/images/social-cards/default.png new file mode 100644 index 000000000000..715cbb8e3efa Binary files /dev/null and b/assets/images/social-cards/default.png differ diff --git a/assets/images/social-cards/issues.png b/assets/images/social-cards/issues.png new file mode 100644 index 000000000000..afedca548a4d Binary files /dev/null and b/assets/images/social-cards/issues.png differ diff --git a/assets/images/social-cards/security.png b/assets/images/social-cards/security.png new file mode 100644 index 000000000000..25c557b0e574 Binary files /dev/null and b/assets/images/social-cards/security.png differ diff --git a/data/reusables/copilot/differences-cfi-cfb-table.md b/data/reusables/copilot/differences-cfi-cfb-table.md index a42c3ac890cf..14ec865dd40a 100644 --- a/data/reusables/copilot/differences-cfi-cfb-table.md +++ b/data/reusables/copilot/differences-cfi-cfb-table.md @@ -3,7 +3,7 @@ | | {% data variables.product.prodname_copilot_free_short %} | {% data variables.product.prodname_copilot_pro_short %} | {% data variables.product.prodname_copilot_pro_plus_short %} | {% data variables.product.prodname_copilot_business_short %} | {% data variables.product.prodname_copilot_enterprise_short %} | | --- | --- | --- | --- | --- | --- | | Pricing | Not applicable | {% data variables.copilot.cfi_price_per_month %} per month, or
{% data variables.copilot.cfi_price_per_year %} per year
(free for some users) | {% data variables.copilot.cpp_price_per_month %} per month, or
{% data variables.copilot.cpp_price_per_year %} per year
| {% data variables.copilot.cfb_price_per_month %} per granted seat per month | {% data variables.copilot.ce_price_per_month %} per granted seat per month | -| Premium requests | 50 per month | 300 per month | 1500 per month | 300 per month | 1000 per month | +| Premium requests | 50 per month | 300 per month | 1500 per month | 300 per user per month | 1000 per user per month | | Purchase additional premium requests at $0.04/request| {% octicon "x" aria-label="Not included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% endrowheaders %} @@ -89,8 +89,8 @@ | --- | --- | --- | --- | --- | --- | | {% data variables.product.prodname_copilot_for_prs %} | {% octicon "x" aria-label="Not included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | | Audit logs | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} |{% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | -| {% data variables.product.prodname_copilot_short %} knowledge bases |{% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | -| Fine tuning a custom large language model (limited {% data variables.release-phases.public_preview %})[^6] | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | +| {% data variables.product.prodname_copilot_short %} knowledge bases |{% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "check" aria-label="Included" %} | +| Fine tuning a custom large language model (limited {% data variables.release-phases.public_preview %})[^6] | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "x" aria-label="Not included" %} | {% octicon "check" aria-label="Included" %} | | {% data variables.product.prodname_copilot_cli_short %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% octicon "check" aria-label="Included" %} | {% endrowheaders %} diff --git a/data/reusables/copilot/premium-requests-for-enterprises.md b/data/reusables/copilot/premium-requests-for-enterprises.md index 1f616968082d..84c3462bab5c 100644 --- a/data/reusables/copilot/premium-requests-for-enterprises.md +++ b/data/reusables/copilot/premium-requests-for-enterprises.md @@ -1,6 +1,6 @@ Each {% data variables.product.prodname_copilot_short %} plan includes a per-user allowance for premium requests: -* 300 requests per month for {% data variables.product.prodname_copilot_business_short %} -* 1000 requests per month for {% data variables.product.prodname_copilot_enterprise_short %} +* 300 requests per user per month for {% data variables.product.prodname_copilot_business_short %} +* 1000 requests per user per month for {% data variables.product.prodname_copilot_enterprise_short %} {% data variables.product.prodname_copilot_chat_short %}, {% data variables.product.prodname_copilot_agent_short %} mode, {% data variables.product.prodname_copilot_short %} code review, and {% data variables.product.prodname_copilot_extensions_short %} use premium requests, with usage varying by model. diff --git a/src/frame/components/DefaultLayout.tsx b/src/frame/components/DefaultLayout.tsx index 57ca23c59120..65656ee71a9a 100644 --- a/src/frame/components/DefaultLayout.tsx +++ b/src/frame/components/DefaultLayout.tsx @@ -59,6 +59,20 @@ export const DefaultLayout = (props: Props) => { const metaDescription = page.introPlainText ? page.introPlainText : t('default_description') + const SOCIAL_CATEGORIES = new Set(['security', 'actions', 'issues', 'copilot']) + const SOCIAL_CARD_IMG_BASE_URL = '/assets/cb-345/images/social-cards' + + function getCategoryImageUrl(category: string): string { + return `${SOCIAL_CARD_IMG_BASE_URL}/${category}.png` + } + + function getSocialCardImage(): string { + if (currentProduct && SOCIAL_CATEGORIES.has(currentProduct.id)) { + return getCategoryImageUrl(currentProduct.id) + } + return getCategoryImageUrl('default') + } + return ( @@ -111,10 +125,7 @@ export const DefaultLayout = (props: Props) => { - + )} diff --git a/src/frame/components/ui/MarkdownContent/UnrenderedMarkdownContent.tsx b/src/frame/components/ui/MarkdownContent/UnrenderedMarkdownContent.tsx index 7fec3217e515..ac54ebe8c0fc 100644 --- a/src/frame/components/ui/MarkdownContent/UnrenderedMarkdownContent.tsx +++ b/src/frame/components/ui/MarkdownContent/UnrenderedMarkdownContent.tsx @@ -60,6 +60,15 @@ export const UnrenderedMarkdownContent = ({ {...props} href={href} target={openLinksInNewTab ? '_blank' : undefined} + rel={openLinksInNewTab ? 'noopener noreferrer' : undefined} + onClick={(e) => { + // For some reason we need to override the default onClick to get these links to open in a new tab + if (openLinksInNewTab) { + e.stopPropagation() + e.preventDefault() + window.open(href, '_blank') + } + }} data-group-key={eventGroupKey} data-group-id={eventGroupId} > diff --git a/src/shielding/middleware/rate-limit.ts b/src/shielding/middleware/rate-limit.ts index e3e1712216a7..e093a17f5995 100644 --- a/src/shielding/middleware/rate-limit.ts +++ b/src/shielding/middleware/rate-limit.ts @@ -14,7 +14,7 @@ if (isNaN(MAX)) { } // We apply this rate limiter to _all_ routes in src/shielding/index.ts except for `/api/*` routes -export function createRateLimiter(max = MAX, isAPILimiter = false) { +export function createRateLimiter(max = MAX) { return rateLimit({ // 1 minute windowMs: EXPIRES_IN_AS_SECONDS * 1000, @@ -47,14 +47,9 @@ export function createRateLimiter(max = MAX, isAPILimiter = false) { return true } - // We handle /api/* routes with a separate rate limiter - // When it is a separate rate limiter, isAPILimiter will be passed as true - if (req.path.startsWith('/api/') || isAPILimiter) { - return false - } - - // If the request is not suspicious, don't rate limit it - if (!isSuspiciousRequest(req)) { + // If the query string looks totally regular and is not a + // search endpoint, then skip + if (!isSuspiciousSearchRequest(req)) { return true } @@ -137,7 +132,14 @@ const MISC_KEYS = [ * @param {Request} req * @returns boolean */ -function isSuspiciousRequest(req: Request) { +function isSuspiciousSearchRequest(req: Request) { + if ( + req.originalUrl.includes('/api/search') || + req.originalUrl.includes('/api/ai-search') || + req.originalUrl.includes('/api/combined-search') + ) + return false + const keys = Object.keys(req.query) // Since this function can only speculate by query strings (at the