Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
.docsPageTitle {
margin-bottom: $spacing-size-1;

span:nth-of-type(2) {
letter-spacing: -1.2px;
}

@media screen and (min-width: $breakpoint-docs-nav-medium) {
line-height: var(--line-height-ultra-tight);
}
Expand Down Expand Up @@ -60,8 +56,6 @@
.version {
font-size: var(--text-fs-sm);
font-weight: var(--text-regular);
// The header's nth-of-type span rule would otherwise tighten this.
letter-spacing: normal;
color: var(--color-text-tertiary);
}

Expand Down
2 changes: 0 additions & 2 deletions documentation/ag-grid-docs/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,6 @@ export const DEBUG_SCRIPT_FILE_NAME = 'ag-grid-debug.js';
export const PRODUCTION_CHANGELOG_JSON_URL = 'https://www.ag-grid.com/changelog/changelog.json';

export const ZI_FORM_ID = 'aad0527d-5af6-4263-8dcd-60f3ac998d5d';
export type TrialLicenceFormType = 'emailOnly' | 'allFields' | 'original';
export const DEFAULT_TRIAL_LICENSE_FORM: TrialLicenceFormType = 'allFields';

// Google Tag Manager
export const PUBLIC_GTM_ID = import.meta.env?.PUBLIC_GTM_ID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,12 @@
"name": "Edit Validation",
"url": "./cell-editing-validation"
}
},
"getEditValidationErrors": {
"more": {
"name": "Edit Validation",
"url": "./cell-editing-validation"
}
}
},
"export": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@
"eyebrow": "Pro Edition",
"heading": "Want Scheduling Logic Built In?",
"body_text": "Want Scheduling Logic Built In? Try Scheduler Pro Compare Features",
"ctas": [
{
"text": "See Scheduler Pro",
"href": "/products/scheduler-pro/",
"title": "See Scheduler Pro"
}
],
"media": []
},
{
Expand Down
48 changes: 30 additions & 18 deletions documentation/ag-grid-docs/src/content/docs/skills/index.mdoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ We are actively developing and releasing new versions of our skills. Feedback is

## Setup

One skills package covers all of our products: [AG Grid](https://www.ag-grid.com/), [AG Charts](https://www.ag-grid.com/charts/) and [AG Studio](https://www.ag-grid.com/studio/).

### Installation

A skill is a folder of files that you install in your project repository or your home directory. Use the skills CLI to copy the files from the [ag-grid/skills](https://github.com/ag-grid/skills) repository to your machine:
Expand All @@ -19,39 +21,49 @@ A skill is a folder of files that you install in your project repository or your
npx skills add ag-grid/skills
```

{% note %}
In order for `npx skills add` to install skills into your repo, the config folder for your agent must already exist, e.g. `.claude/` or `.codex/` in your repo root. This is normally created the first time you run the agent in the repo.
{% /note %}

### Updating

We refine the skills and extend them to cover new AG Grid and AG Charts releases, so update at any time to pick up the latest guidance:
We refine the skills and extend them to cover new Grid, Charts and Studio releases, so update at any time to pick up the latest guidance:

```bash
npx skills update ag-grid/skills
```

## Skills

Each skill teaches your coding agent how to carry out a specific task with AG Grid and AG Charts, following our official guidance. Once installed, invoke a skill by name and the agent works through it for you.
We currently provide two skills. If there's something else you'd like to see, [open an issue](https://github.com/ag-grid/skills/issues) to suggest a skill.

### ag-dev

`ag-dev` is a general development assistant that helps agents write correct code on the first attempt.

Coding harnesses like Claude Code and Codex will often automatically use it when planning or writing code that interacts with our libraries - simply installing the skill will improve the results you get during development. However, because automatic triggering is best-effort, for the most consistent results we recommend explicitly telling your agent to use the ag-dev skill, especially when working on complicated tasks:

```bash
Add a custom context-menu item that copies the names of selected data
columns (use the ag-dev skill)
```

It includes a list of rules for the agent to follow to avoid common LLM pitfalls, debugging guidance, and instructions for accessing version-matched documentation to ensure that your agent uses the APIs for the installed version of the library.

## ag-update
### ag-update

Upgrading across major versions normally means reading every release's breaking changes and working out which ones touch your code. The `ag-update` skill hands that work to your coding agent: it reads the AG Grid migration documentation, checks it against your repository, and produces a Markdown file listing the changes needed to move to a new version.

To let the skill detect everything for you, invoke it from your coding agent:

```
```bash
Use the ag-update skill to upgrade my-app
```

You can also tell it exactly what to update, down to individual projects and target versions.

```
Use the ag-update skill to update all projects in this monorepo except apps/demo-app to AG Grid v36
```bash
Use the ag-update skill to update all projects in this monorepo
except apps/demo-app to AG Grid v36
```

### Example run
#### Example run

A typical run, updating a single project to AG Grid v36, looks like this:

Expand All @@ -77,18 +89,18 @@ Done — performance/typescript is on AG Grid 36.0.0 and AG Charts 14.0.0.

`AG_UPDATE_CHANGES.md` contains an entry for each change, grouped by product and version transition, labelled `BREAKING` or `BEHAVIOUR`, and paired with how to mitigate it:

```md
```bash
## Grid v35.x -> v36.x

### BEHAVIOUR: ValidationModule no longer bundled by default

Change: The `ValidationModule` is no longer included in the `AllCommunityModule` and `AllEnterpriseModule` bundles, keeping production bundles smaller by default. Without it, console messages are reduced to an error code and a documentation link.
Change: The `ValidationModule` is no longer included in the
`AllCommunityModule` and `AllEnterpriseModule` bundles, keeping
production bundles smaller by default. Without it, console messages
are reduced to an error code and a documentation link.

Mitigation: To restore the full development-time diagnostics, call `enableDevValidations()` before any grid is created.
Mitigation: To restore the full development-time diagnostics, call
`enableDevValidations()` before any grid is created.
```

Review the generated files, then ask the agent to apply the plan. It bumps the versions in `package.json`, reinstalls dependencies, and validates the result against your build, typecheck, and dev server.

## Upcoming skills

We are expanding the set of skills to cover more of the AG Grid and AG Charts development workflow. Watch the [ag-grid/skills](https://github.com/ag-grid/skills) repository, or [open an issue](https://github.com/ag-grid/skills/issues) to suggest a skill.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@use 'design-system' as *;

.consentLabel {
display: flex;
align-items: flex-start;
gap: $spacing-size-2;
cursor: pointer;

input[type='checkbox'] {
// Keep the box aligned with the first line of the label text
flex-shrink: 0;
margin-top: 1px;
}
}

.errorContainer {
display: flex;
align-items: flex-start;
margin-left: 1.75rem;
}

// Indents a checkbox that is only revealed by the one above it
.nested {
margin-left: 1.75rem;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import classnames from 'classnames';
import type { ComponentPropsWithRef, FunctionComponent, ReactNode } from 'react';

import styles from './ConsentCheckbox.module.scss';

interface Props {
id: string;
label: ReactNode;
/** Validation message; presence of a message puts the field into its error state */
error?: string;
/** Indents the field, for a checkbox only revealed by the one above it */
nested?: boolean;
inputProps: ComponentPropsWithRef<'input'>;
}

export const ConsentCheckbox: FunctionComponent<Props> = ({ id, label, error, nested, inputProps }: Props) => {
return (
<div className={classnames('input-field', { 'input-error': error }, { [styles.nested]: nested })}>
<label className={styles.consentLabel} htmlFor={id}>
<input type="checkbox" id={id} {...inputProps} />
<span>{label}</span>
</label>
<div className={styles.errorContainer}>{error && <p className="error">{error}</p>}</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { PRIVACY_POLICY_URL } from '@ag-website-shared/constants';
import type { ReactElement } from 'react';

/**
* Consent copy shared by every web-to-lead form, so the wording stays identical
* across the site. See AG-17996.
*/
export const CONSENT_LABELS: Record<string, ReactElement | string> = {
dataProcessing: (
<>
I agree to my data being processed in accordance with the{' '}
<a href={PRIVACY_POLICY_URL} target="_blank" rel="noopener noreferrer">
Privacy Policy
</a>
</>
),
marketingEmail: "I'd like to receive product updates and marketing emails",
emailTracking: 'I consent to tracking of email opens and clicks',
/**
* Temporary stand-in for IP geolocation: email tracking consent only applies to
* France and Italy, so visitors declare it themselves to reveal that checkbox.
*/
franceOrItaly: 'I live in France or Italy',
};

export const DATA_PROCESSING_CONSENT_REQUIRED = 'You must agree to the Privacy Policy to continue';
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,10 @@
font-family: inherit;
}

.privacyMessage {
font-size: var(--text-fs-xs);
line-height: var(--text-lh-xs);
color: color-mix(in srgb, var(--color-text-secondary), var(--color-bg-primary) 30%);
margin: 0;

a {
font-weight: var(--text-regular);
}
.consents {
display: flex;
flex-direction: column;
gap: $spacing-size-2;
}

.tertiaryButton {
Expand All @@ -73,6 +68,8 @@
}

.errorContainer {
display: flex;
align-items: flex-start;
margin-top: 0.25rem;

&:empty {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { ConsentCheckbox } from '@ag-website-shared/components/consent-fields/ConsentCheckbox';
import {
CONSENT_LABELS,
DATA_PROCESSING_CONSENT_REQUIRED,
} from '@ag-website-shared/components/consent-fields/consentMessages';
import { initCaptcha } from '@ag-website-shared/components/contact-form/initCaptcha';
import { Icon } from '@ag-website-shared/components/icon/Icon';
import { CONTACT_FORM_DATA, PRIVACY_POLICY_URL, RECAPTCHA_URL, STUDIO_FORM_DATA } from '@ag-website-shared/constants';
import { CONSENT_FIELD_IDS, CONTACT_FORM_DATA, RECAPTCHA_URL, STUDIO_FORM_DATA } from '@ag-website-shared/constants';
import { LIBRARY } from '@constants';
import { getIsDev, getIsProduction } from '@utils/env';
import classnames from 'classnames';
import type { FunctionComponent } from 'react';
import type { ChangeEvent, FunctionComponent } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';

Expand All @@ -25,6 +30,10 @@ const {
captchaSettingsKeyName,
} = getIsProduction() ? contactFormData.production : contactFormData.default;

const { dataProcessingConsentId, marketingEmailConsentId, emailTrackingConsentId, franceOrItalyId } = getIsProduction()
? CONSENT_FIELD_IDS.production
: CONSENT_FIELD_IDS.default;

const isDev = getIsDev();

const ENQUIRY_TYPE_OPTIONS = [
Expand Down Expand Up @@ -82,14 +91,30 @@ export const ContactForm: FunctionComponent<Props> = ({
const [isDisabled, setIsDisabled] = useState(false);
const [captchaError, setCaptchaError] = useState(false);

const [isFranceOrItaly, setIsFranceOrItaly] = useState(false);

const {
register,
handleSubmit,
setValue,
formState: { errors },
} = useForm<FormValues>({
mode: 'onBlur',
});

// Email tracking consent only applies to France and Italy, so hiding it must also
// withdraw it — never submit a consent the visitor can no longer see
const handleFranceOrItalyChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
const { checked } = e.target;
setIsFranceOrItaly(checked);
if (!checked) {
setValue(emailTrackingConsentId, '');
}
},
[setValue]
);

useEffect(() => {
const searchParams = new URLSearchParams(window.location.search);
const hasDebugFlag = searchParams.has('debug');
Expand Down Expand Up @@ -246,6 +271,44 @@ export const ContactForm: FunctionComponent<Props> = ({
</div>
</div>
)}
<div className={styles.consents}>
<ConsentCheckbox
id={dataProcessingConsentId}
label={CONSENT_LABELS.dataProcessing}
error={(errors as any)[dataProcessingConsentId]?.message as string}
inputProps={{
value: '1',
...register(dataProcessingConsentId, { required: DATA_PROCESSING_CONSENT_REQUIRED }),
}}
/>

<ConsentCheckbox
id={marketingEmailConsentId}
label={CONSENT_LABELS.marketingEmail}
inputProps={{ value: '1', ...register(marketingEmailConsentId) }}
/>

<ConsentCheckbox
id={franceOrItalyId}
label={CONSENT_LABELS.franceOrItaly}
inputProps={{
name: franceOrItalyId,
value: '1',
checked: isFranceOrItaly,
onChange: handleFranceOrItalyChange,
}}
/>

{isFranceOrItaly && (
<ConsentCheckbox
id={emailTrackingConsentId}
label={CONSENT_LABELS.emailTracking}
nested
inputProps={{ value: '1', ...register(emailTrackingConsentId) }}
/>
)}
</div>

<div className={classnames('input-field', { 'input-error': captchaError })}>
<div className="g-recaptcha" data-sitekey={captchaSiteKey} />
<div className={styles.errorContainer}>
Expand All @@ -258,9 +321,6 @@ export const ContactForm: FunctionComponent<Props> = ({
type="submit"
value={submitLabel || 'Send us a message'}
/>
<p className={styles.privacyMessage}>
By submitting this form you agree to our <a href={PRIVACY_POLICY_URL}>Privacy Policy</a>.
</p>
<p>
For technical support, visit our{' '}
<a
Expand Down
Loading
Loading