--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { cloneDeep } from 'lodash';
+import { ProjectLink } from '../../types/types';
+import { createLink, deleteLink, getProjectLinks } from '../projectLinks';
+
+export default class ProjectLinksServiceMock {
+ projectLinks: ProjectLink[] = [];
+ idCounter: number = 0;
+
+ constructor() {
+ jest.mocked(getProjectLinks).mockImplementation(this.handleGetProjectLinks);
+ jest.mocked(createLink).mockImplementation(this.handleCreateLink);
+ jest.mocked(deleteLink).mockImplementation(this.handleDeleteLink);
+ }
+
+ handleGetProjectLinks = () => {
+ return this.reply(this.projectLinks);
+ };
+
+ handleCreateLink = ({ name, url }: { name: string; url: string }) => {
+ const link = {
+ id: `id${this.idCounter++}`,
+ name,
+ type: name,
+ url,
+ };
+ this.projectLinks.push(link);
+
+ return this.reply(link);
+ };
+
+ handleDeleteLink = (id: string) => {
+ this.projectLinks.filter((link) => link.id !== id);
+
+ return this.reply(undefined);
+ };
+
+ reset = () => {
+ this.projectLinks = [];
+ };
+
+ reply<T>(response: T): Promise<T> {
+ return Promise.resolve(cloneDeep(response));
+ }
+}
import projectBranchesRoutes from '../../apps/projectBranches/routes';
import ProjectDeletionApp from '../../apps/projectDeletion/App';
import projectDumpRoutes from '../../apps/projectDump/routes';
-import ProjectKeyApp from '../../apps/projectKey/Key';
-import ProjectLinksApp from '../../apps/projectLinks/App';
+import ProjectKeyApp from '../../apps/projectKey/ProjectKeyApp';
+import ProjectLinksApp from '../../apps/projectLinks/ProjectLinksApp';
import projectQualityGateRoutes from '../../apps/projectQualityGate/routes';
import projectQualityProfilesRoutes from '../../apps/projectQualityProfiles/routes';
import projectsRoutes from '../../apps/projects/routes';
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { createLink, deleteLink, getProjectLinks } from '../../api/projectLinks';
-import withComponentContext from '../../app/components/componentContext/withComponentContext';
-import DeferredSpinner from '../../components/ui/DeferredSpinner';
-import { translate } from '../../helpers/l10n';
-import { Component, ProjectLink } from '../../types/types';
-import Header from './Header';
-import Table from './Table';
-
-interface Props {
- component: Component;
-}
-
-interface State {
- links?: ProjectLink[];
- loading: boolean;
-}
-
-export class App extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { loading: true };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchLinks();
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.component.key !== this.props.component.key) {
- this.fetchLinks();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchLinks = () => {
- this.setState({ loading: true });
- getProjectLinks(this.props.component.key).then(
- (links) => {
- if (this.mounted) {
- this.setState({ links, loading: false });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- handleCreateLink = (name: string, url: string) => {
- return createLink({ name, projectKey: this.props.component.key, url }).then((link) => {
- if (this.mounted) {
- this.setState(({ links = [] }) => ({
- links: [...links, link],
- }));
- }
- });
- };
-
- handleDeleteLink = (linkId: string) => {
- return deleteLink(linkId).then(() => {
- if (this.mounted) {
- this.setState(({ links = [] }) => ({
- links: links.filter((link) => link.id !== linkId),
- }));
- }
- });
- };
-
- render() {
- return (
- <div className="page page-limited">
- <Helmet defer={false} title={translate('project_links.page')} />
- <Header onCreate={this.handleCreateLink} />
- <DeferredSpinner loading={this.state.loading}>
- {this.state.links && <Table links={this.state.links} onDelete={this.handleDeleteLink} />}
- </DeferredSpinner>
- </div>
- );
- }
-}
-
-export default withComponentContext(App);
onConfirm={this.props.onDelete}
>
{({ onClick }) => (
- <Button className="button-red js-delete-button" onClick={onClick}>
+ <Button
+ className="button-red js-delete-button"
+ aria-label={translateWithParameters('project_links.delete_x_link', link.name ?? '')}
+ onClick={onClick}
+ >
{translate('delete')}
</Button>
)}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { Helmet } from 'react-helmet-async';
+import { createLink, deleteLink, getProjectLinks } from '../../api/projectLinks';
+import withComponentContext from '../../app/components/componentContext/withComponentContext';
+import DeferredSpinner from '../../components/ui/DeferredSpinner';
+import { translate } from '../../helpers/l10n';
+import { Component, ProjectLink } from '../../types/types';
+import Header from './Header';
+import Table from './Table';
+
+interface Props {
+ component: Component;
+}
+
+interface State {
+ links?: ProjectLink[];
+ loading: boolean;
+}
+
+export class ProjectLinksApp extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = { loading: true };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchLinks();
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (prevProps.component.key !== this.props.component.key) {
+ this.fetchLinks();
+ }
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchLinks = () => {
+ const {
+ component: { key },
+ } = this.props;
+
+ this.setState({ loading: true });
+ getProjectLinks(key).then(
+ (links) => {
+ if (this.mounted) {
+ this.setState({ links, loading: false });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ handleCreateLink = (name: string, url: string) => {
+ const {
+ component: { key },
+ } = this.props;
+
+ return createLink({ name, projectKey: key, url }).then((link) => {
+ if (this.mounted) {
+ this.setState(({ links = [] }) => ({
+ links: [...links, link],
+ }));
+ }
+ });
+ };
+
+ handleDeleteLink = (linkId: string) => {
+ return deleteLink(linkId).then(() => {
+ if (this.mounted) {
+ this.setState(({ links = [] }) => ({
+ links: links.filter((link) => link.id !== linkId),
+ }));
+ }
+ });
+ };
+
+ render() {
+ const { loading, links } = this.state;
+ return (
+ <div className="page page-limited">
+ <Helmet defer={false} title={translate('project_links.page')} />
+ <Header onCreate={this.handleCreateLink} />
+ <DeferredSpinner loading={loading}>
+ {links && <Table links={links} onDelete={this.handleDeleteLink} />}
+ </DeferredSpinner>
+ </div>
+ );
+ }
+}
+
+export default withComponentContext(ProjectLinksApp);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { createLink, deleteLink, getProjectLinks } from '../../../api/projectLinks';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { waitAndUpdate } from '../../../helpers/testUtils';
-import { App } from '../App';
-
-// import { getProjectLinks, createLink, deleteLink } from '../../api/projectLinks';
-jest.mock('../../../api/projectLinks', () => ({
- getProjectLinks: jest.fn().mockResolvedValue([
- { id: '1', type: 'homepage', url: 'http://example.com' },
- { id: '2', name: 'foo', type: 'foo', url: 'http://example.com/foo' },
- ]),
- createLink: jest
- .fn()
- .mockResolvedValue({ id: '3', name: 'bar', type: 'bar', url: 'http://example.com/bar' }),
- deleteLink: jest.fn().mockResolvedValue(undefined),
-}));
-
-it('should fetch links and render', async () => {
- const wrapper = shallow(<App component={mockComponent({ key: 'comp' })} />);
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(getProjectLinks).toHaveBeenCalledWith('comp');
-});
-
-it('should fetch links when component changes', async () => {
- const wrapper = shallow(<App component={mockComponent({ key: 'comp' })} />);
- await waitAndUpdate(wrapper);
- expect(getProjectLinks).toHaveBeenLastCalledWith('comp');
-
- wrapper.setProps({ component: { key: 'another' } });
- expect(getProjectLinks).toHaveBeenLastCalledWith('another');
-});
-
-it('should create link', async () => {
- const wrapper = shallow(<App component={mockComponent({ key: 'comp' })} />);
- await waitAndUpdate(wrapper);
-
- wrapper.find('Header').prop<Function>('onCreate')('bar', 'http://example.com/bar');
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(createLink).toHaveBeenCalledWith({
- name: 'bar',
- projectKey: 'comp',
- url: 'http://example.com/bar',
- });
-});
-
-it('should delete link', async () => {
- const wrapper = shallow(<App component={mockComponent({ key: 'comp' })} />);
- await waitAndUpdate(wrapper);
-
- wrapper.find('Table').prop<Function>('onDelete')('foo');
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(deleteLink).toHaveBeenCalledWith('foo');
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { change, submit } from '../../../helpers/testUtils';
-import CreationModal from '../CreationModal';
-
-it('should create link', () => {
- const onClose = jest.fn();
- const onSubmit = jest.fn().mockResolvedValue(undefined);
- const wrapper = shallow(<CreationModal onClose={onClose} onSubmit={onSubmit} />);
- const form = wrapper.dive();
-
- change(form.find('#create-link-name'), 'foo');
- change(form.find('#create-link-url'), 'http://example.com/foo');
- expect(form).toMatchSnapshot();
-
- submit(wrapper);
- expect(onSubmit).toHaveBeenCalledWith('foo', 'http://example.com/foo');
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click } from '../../../helpers/testUtils';
-import Header from '../Header';
-
-it('should render', () => {
- expect(shallow(<Header onCreate={jest.fn()} />)).toMatchSnapshot();
-});
-
-it('should open creation modal', () => {
- const onCreate = jest.fn();
- const wrapper = shallow(<Header onCreate={onCreate} />);
- click(wrapper.find('Button'));
- expect(wrapper.find('CreationModal').exists()).toBe(true);
-
- wrapper.find('CreationModal').prop<Function>('onSubmit')('foo', 'http://example.com/foo');
- expect(onCreate).toHaveBeenCalledWith('foo', 'http://example.com/foo');
-
- wrapper.find('CreationModal').prop<Function>('onClose')();
- wrapper.update();
- expect(wrapper.find('CreationModal').exists()).toBe(false);
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import LinkRow from '../LinkRow';
-
-it('should render provided link', () => {
- expect(
- shallow(
- <LinkRow
- link={{ id: '12', type: 'homepage', url: 'http://example.com' }}
- onDelete={jest.fn()}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('should render custom link', () => {
- expect(
- shallow(
- <LinkRow
- link={{ id: '12', name: 'foo', type: 'foo', url: 'http://example.com' }}
- onDelete={jest.fn()}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('should render dangerous code as plain text', () => {
- expect(
- shallow(
- <LinkRow
- link={{ id: '12', name: 'dangerous', type: 'dangerous', url: 'javascript:alert("Hello")' }}
- onDelete={jest.fn()}
- />
- )
- ).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import userEvent from '@testing-library/user-event';
+import { last } from 'lodash';
+import React from 'react';
+import { Route } from 'react-router-dom';
+import { byRole, byText } from 'testing-library-selector';
+import ProjectLinksServiceMock from '../../../api/mocks/ProjectLinksServiceMock';
+import { mockComponent } from '../../../helpers/mocks/component';
+import { renderAppWithComponentContext } from '../../../helpers/testReactTestingUtils';
+import ProjectLinksApp from '../ProjectLinksApp';
+
+jest.mock('../../../api/projectLinks');
+
+const componentsMock = new ProjectLinksServiceMock();
+
+afterEach(() => {
+ componentsMock.reset();
+});
+
+it('renders project links app and can do CRUD operations', async () => {
+ const { ui } = getPageObjects();
+
+ const newLinkName1 = 'link1';
+ const newLinkName2 = 'issue';
+ renderProjectLinksApp();
+ await ui.appIsLoaded();
+
+ expect(ui.noResultsTable.get()).toBeInTheDocument();
+
+ // Create link
+ await ui.createLink(newLinkName1, 'https://link.com');
+ expect(ui.deleteLinkButton(newLinkName1).get()).toBeInTheDocument();
+ expect(ui.noResultsTable.query()).not.toBeInTheDocument();
+
+ // Create invalid link with provided type
+ await ui.createLink(newLinkName2, 'invalidurl');
+ expect(ui.deleteLinkButton(newLinkName2).query()).not.toBeInTheDocument();
+ expect(byText('project_links.issue').get()).toBeInTheDocument();
+
+ // Delete link
+ await ui.deleteLink(newLinkName1);
+ expect(ui.deleteLinkButton(newLinkName1).query()).not.toBeInTheDocument();
+});
+
+function renderProjectLinksApp() {
+ return renderAppWithComponentContext(
+ 'project/links',
+ () => <Route path="project/links" element={<ProjectLinksApp />} />,
+ {},
+ { component: mockComponent() }
+ );
+}
+
+function getPageObjects() {
+ const user = userEvent.setup();
+
+ const ui = {
+ pageTitle: byRole('heading', { name: 'project_links.page' }),
+ noResultsTable: byText('no_results'),
+ createLinkButton: byRole('button', { name: 'create' }),
+ nameInput: byRole('textbox', { name: /project_links.name/ }),
+ urlInput: byRole('textbox', { name: /project_links.url/ }),
+ cancelDialogButton: byRole('button', { name: 'cancel' }),
+ deleteLinkButton: (name: string) =>
+ byRole('button', { name: `project_links.delete_x_link.${name}` }),
+ deleteButton: byRole('button', { name: 'delete' }),
+ };
+
+ async function appIsLoaded() {
+ expect(await ui.pageTitle.find()).toBeInTheDocument();
+ }
+
+ async function createLink(name: string, url: string) {
+ await user.click(ui.createLinkButton.get());
+ await user.type(ui.nameInput.get(), name);
+ await user.type(ui.urlInput.get(), url);
+ await user.click(last(ui.createLinkButton.getAll()) as HTMLElement);
+ }
+
+ async function deleteLink(name: string) {
+ await user.click(ui.deleteLinkButton(name).get());
+ await user.click(ui.deleteButton.get());
+ }
+
+ return {
+ ui: { ...ui, appIsLoaded, createLink, deleteLink },
+ user,
+ };
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import Table from '../Table';
-
-it('should render', () => {
- const links = [
- { id: '1', type: 'homepage', url: 'http://example.com/homepage' },
- { id: '2', type: 'issue', url: 'http://example.com/issue' },
- { id: '3', name: 'foo', type: 'foo', url: 'http://example.com/foo' },
- { id: '4', name: 'bar', type: 'bar', url: 'http://example.com/bar' },
- ];
- expect(shallow(<Table links={links} onDelete={jest.fn()} />)).toMatchSnapshot();
-});
-
-it('should render empty', () => {
- expect(shallow(<Table links={[]} onDelete={jest.fn()} />)).toMatchSnapshot();
-});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should create link 1`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- prioritizeSeoTags={false}
- title="project_links.page"
- />
- <Header
- onCreate={[Function]}
- />
- <DeferredSpinner
- loading={false}
- >
- <Table
- links={
- [
- {
- "id": "1",
- "type": "homepage",
- "url": "http://example.com",
- },
- {
- "id": "2",
- "name": "foo",
- "type": "foo",
- "url": "http://example.com/foo",
- },
- {
- "id": "3",
- "name": "bar",
- "type": "bar",
- "url": "http://example.com/bar",
- },
- ]
- }
- onDelete={[Function]}
- />
- </DeferredSpinner>
-</div>
-`;
-
-exports[`should delete link 1`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- prioritizeSeoTags={false}
- title="project_links.page"
- />
- <Header
- onCreate={[Function]}
- />
- <DeferredSpinner
- loading={false}
- >
- <Table
- links={
- [
- {
- "id": "1",
- "type": "homepage",
- "url": "http://example.com",
- },
- {
- "id": "2",
- "name": "foo",
- "type": "foo",
- "url": "http://example.com/foo",
- },
- ]
- }
- onDelete={[Function]}
- />
- </DeferredSpinner>
-</div>
-`;
-
-exports[`should fetch links and render 1`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- prioritizeSeoTags={false}
- title="project_links.page"
- />
- <Header
- onCreate={[Function]}
- />
- <DeferredSpinner
- loading={false}
- >
- <Table
- links={
- [
- {
- "id": "1",
- "type": "homepage",
- "url": "http://example.com",
- },
- {
- "id": "2",
- "name": "foo",
- "type": "foo",
- "url": "http://example.com/foo",
- },
- ]
- }
- onDelete={[Function]}
- />
- </DeferredSpinner>
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should create link 1`] = `
-<Modal
- contentLabel="project_links.create_new_project_link"
- onRequestClose={[MockFunction]}
- size="small"
->
- <form
- onSubmit={[Function]}
- >
- <header
- className="modal-head"
- >
- <h2>
- project_links.create_new_project_link
- </h2>
- </header>
- <div
- className="modal-body"
- >
- <MandatoryFieldsExplanation
- className="modal-field"
- />
- <div
- className="modal-field"
- >
- <label
- htmlFor="create-link-name"
- >
- project_links.name
- <MandatoryFieldMarker />
- </label>
- <input
- autoFocus={true}
- id="create-link-name"
- maxLength={128}
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value=""
- />
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="create-link-url"
- >
- project_links.url
- <MandatoryFieldMarker />
- </label>
- <input
- id="create-link-url"
- maxLength={128}
- name="url"
- onChange={[Function]}
- required={true}
- type="text"
- value=""
- />
- </div>
- </div>
- <footer
- className="modal-foot"
- >
- <DeferredSpinner
- className="spacer-right"
- loading={false}
- />
- <SubmitButton
- disabled={false}
- id="create-link-confirm"
- >
- create
- </SubmitButton>
- <ResetButtonLink
- disabled={false}
- onClick={[Function]}
- >
- cancel
- </ResetButtonLink>
- </footer>
- </form>
-</Modal>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<Fragment>
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- project_links.page
- </h1>
- <div
- className="page-actions"
- >
- <Button
- id="create-project-link"
- onClick={[Function]}
- >
- create
- </Button>
- </div>
- <div
- className="page-description"
- >
- project_links.page.description
- </div>
- </header>
-</Fragment>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render custom link 1`] = `
-<tr
- data-name="foo"
->
- <td
- className="nowrap"
- >
- <div>
- <ProjectLinkIcon
- className="little-spacer-right"
- type="foo"
- />
- <div
- className="display-inline-block text-top"
- >
- <span
- className="js-name"
- >
- foo
- </span>
- </div>
- </div>
- </td>
- <td
- className="nowrap js-url"
- >
- <ForwardRef(Link)
- target="_blank"
- to="http://example.com"
- >
- http://example.com
- </ForwardRef(Link)>
- </td>
- <td
- className="thin nowrap"
- >
- <ConfirmButton
- confirmButtonText="delete"
- confirmData="12"
- isDestructive={true}
- modalBody="project_links.are_you_sure_to_delete_x_link.foo"
- modalHeader="project_links.delete_project_link"
- onConfirm={[MockFunction]}
- >
- <Component />
- </ConfirmButton>
- </td>
-</tr>
-`;
-
-exports[`should render dangerous code as plain text 1`] = `
-<tr
- data-name="dangerous"
->
- <td
- className="nowrap"
- >
- <div>
- <ProjectLinkIcon
- className="little-spacer-right"
- type="dangerous"
- />
- <div
- className="display-inline-block text-top"
- >
- <span
- className="js-name"
- >
- dangerous
- </span>
- </div>
- </div>
- </td>
- <td
- className="nowrap js-url"
- >
- javascript:alert("Hello")
- </td>
- <td
- className="thin nowrap"
- >
- <ConfirmButton
- confirmButtonText="delete"
- confirmData="12"
- isDestructive={true}
- modalBody="project_links.are_you_sure_to_delete_x_link.dangerous"
- modalHeader="project_links.delete_project_link"
- onConfirm={[MockFunction]}
- >
- <Component />
- </ConfirmButton>
- </td>
-</tr>
-`;
-
-exports[`should render provided link 1`] = `
-<tr>
- <td
- className="nowrap"
- >
- <div>
- <ProjectLinkIcon
- className="little-spacer-right"
- type="homepage"
- />
- <div
- className="display-inline-block text-top"
- >
- <div>
- <span
- className="js-name"
- >
- project_links.homepage
- </span>
- </div>
- <div
- className="note little-spacer-top"
- >
- <span
- className="js-type"
- >
- sonar.links.homepage
- </span>
- </div>
- </div>
- </div>
- </td>
- <td
- className="nowrap js-url"
- >
- <ForwardRef(Link)
- target="_blank"
- to="http://example.com"
- >
- http://example.com
- </ForwardRef(Link)>
- </td>
- <td
- className="thin nowrap"
- />
-</tr>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<div
- className="boxed-group boxed-group-inner"
->
- <table
- className="data zebra"
- id="project-links"
- >
- <thead>
- <tr>
- <th
- className="nowrap"
- >
- project_links.name
- </th>
- <th
- className="nowrap width-100"
- >
- project_links.url
- </th>
- <th
- className="thin"
- >
-
- </th>
- </tr>
- </thead>
- <tbody>
- <LinkRow
- key="1"
- link={
- {
- "id": "1",
- "type": "homepage",
- "url": "http://example.com/homepage",
- }
- }
- onDelete={[MockFunction]}
- />
- <LinkRow
- key="2"
- link={
- {
- "id": "2",
- "type": "issue",
- "url": "http://example.com/issue",
- }
- }
- onDelete={[MockFunction]}
- />
- <LinkRow
- key="4"
- link={
- {
- "id": "4",
- "name": "bar",
- "type": "bar",
- "url": "http://example.com/bar",
- }
- }
- onDelete={[MockFunction]}
- />
- <LinkRow
- key="3"
- link={
- {
- "id": "3",
- "name": "foo",
- "type": "foo",
- "url": "http://example.com/foo",
- }
- }
- onDelete={[MockFunction]}
- />
- </tbody>
- </table>
-</div>
-`;
-
-exports[`should render empty 1`] = `
-<div
- className="note"
->
- no_results
-</div>
-`;
project_links.create_new_project_link=Create New Project Link
project_links.delete_project_link=Delete Project Link
project_links.are_you_sure_to_delete_x_link=Are you sure you want to delete the "{0}" link?
+project_links.delete_x_link=Delete "{0}" link
project_links.name=Name
project_links.url=URL