Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ProjectLanguages] Add new analysis language or select new default #751

Merged
merged 26 commits into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7cdb330
Make project languages editable
imnasnainaec Aug 21, 2020
a974ca7
Make project languages editable
imnasnainaec Aug 21, 2020
b55a826
Stop editing, start adding!
imnasnainaec Sep 11, 2020
9ad87fb
Merge branch 'master' into change-analysis-language
imnasnainaec Oct 8, 2020
4116b55
Add new analysis writing system or bump existing to top.
imnasnainaec Oct 8, 2020
634b253
Remove unused EditableWritingSystem
imnasnainaec Oct 8, 2020
b84c3dc
Merge branch 'master' into change-analysis-language
imnasnainaec Oct 9, 2020
f03649e
Merge branch 'master' into change-analysis-language
johnthagen Oct 16, 2020
75eed1c
Merge branch 'master' into change-analysis-language
johnthagen Oct 23, 2020
99355b3
Merge branch 'master' into change-analysis-language
imnasnainaec Oct 29, 2020
08ab18b
Merge branch 'master' into change-analysis-language
imnasnainaec Nov 9, 2020
6e31853
component -> function
imnasnainaec Nov 9, 2020
ea2f24b
Add unit test
imnasnainaec Nov 9, 2020
ed85ace
Merge branch 'master' into change-analysis-language
imnasnainaec Nov 9, 2020
215bb14
Merge branch 'master' into change-analysis-language
imnasnainaec Nov 24, 2020
6cba66e
Merge branch 'master' into change-analysis-language
imnasnainaec Nov 24, 2020
9170eea
Add tooltips for analysis langauge buttons.
imnasnainaec Nov 24, 2020
392a426
Merge branch 'master' into change-analysis-language
imnasnainaec Nov 30, 2020
6ae34e6
Merge branch 'master' into change-analysis-language
imnasnainaec Dec 2, 2020
28cc1fd
Merge branch 'master' into change-analysis-language
imnasnainaec Dec 2, 2020
6ca57b3
Merge branch 'master' into change-analysis-language
imnasnainaec Dec 4, 2020
65ac68e
Merge branch 'master' into change-analysis-language
imnasnainaec Dec 7, 2020
7544c57
Merge branch 'master' into change-analysis-language
imnasnainaec Dec 11, 2020
07b8265
Merge branch 'master' into change-analysis-language
imnasnainaec Dec 14, 2020
61bdf0f
Add test to prevent duplicate analysis language.
imnasnainaec Dec 15, 2020
c13cdf7
Merge branch 'master' into change-analysis-language
imnasnainaec Dec 15, 2020
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
197 changes: 163 additions & 34 deletions src/components/ProjectSettings/ProjectLanguages/ProjectLanguages.tsx
Original file line number Diff line number Diff line change
@@ -1,66 +1,195 @@
import { Grid, Typography } from "@material-ui/core";
import { Button, Grid, Tooltip, Typography } from "@material-ui/core";
import { Add, ArrowUpward, Clear, Done } from "@material-ui/icons";
import { LanguagePicker, languagePickerStrings_en } from "mui-language-picker";
import React from "react";
import {
LocalizeContextProps,
Translate,
withLocalize,
} from "react-localize-redux";
import { Translate } from "react-localize-redux";

import { updateProject } from "../../../backend";
import { Project, WritingSystem } from "../../../types/project";
import theme from "../../../types/theme";

interface LanguageProps {
project: Project;
}

class ProjectLanguages extends React.Component<
LanguageProps & LocalizeContextProps
interface LanguageState {
add: boolean;
name: string;
bcp47: string;
font: string;
}

export default class ProjectLanguages extends React.Component<
LanguageProps,
LanguageState
> {
renderWritingSystem(ws: WritingSystem, index?: number) {
constructor(props: LanguageProps) {
super(props);
this.state = this.defaultState;
}

private defaultState: LanguageState = {
add: false,
name: "",
bcp47: "",
font: "",
};

setNewAnalysisDefault(index: number) {
const newDefault = this.props.project.analysisWritingSystems.splice(
index,
1
)[0];
this.props.project.analysisWritingSystems.splice(0, 0, newDefault);
updateProject(this.props.project)
.then(() => this.resetState())
.catch((err) => console.error(err));
}

addAnalysisWritingSystem() {
const ws = {
name: this.state.name,
bcp47: this.state.bcp47,
font: this.state.font,
};
this.props.project.analysisWritingSystems.push(ws);
updateProject(this.props.project)
.then(() => this.resetState())
.catch((err) => console.error(err));
}

isNewWritingSystem() {
return (
<React.Fragment key={index}>
<Grid container spacing={1}>
{index !== undefined && <Grid item>{`${index + 1}. `}</Grid>}
<Grid item>
<Translate id="projectSettings.language.name" />
{": "}
{ws.name} {", "}
</Grid>
<Grid item>
<Translate id="projectSettings.language.bcp47" />
{": "}
{ws.bcp47}
{", "}
</Grid>
<Grid item>
<Translate id="projectSettings.language.font" />
{": "}
{ws.font}
</Grid>
</Grid>
</React.Fragment>
this.state.bcp47 &&
!this.props.project.analysisWritingSystems
.map((ws) => ws.bcp47)
.includes(this.state.bcp47)
);
}

resetState() {
this.setState(this.defaultState);
}

render() {
return (
<React.Fragment>
<Typography>
<Translate id="projectSettings.language.vernacular" />
{": "}
{this.renderWritingSystem(this.props.project.vernacularWritingSystem)}
<ImmutableWritingSystem
ws={this.props.project.vernacularWritingSystem}
/>
</Typography>
<Typography style={{ marginTop: theme.spacing(1) }}>
<Translate id="projectSettings.language.analysis" />
{": "}
{this.props.project.analysisWritingSystems.map(
(writingSystem, index) =>
this.renderWritingSystem(writingSystem, index)
(writingSystem, index) => (
<ImmutableWritingSystem
key={index}
ws={writingSystem}
index={index}
icon={index && <MakeDefaultButton />}
iconAction={() => this.setNewAnalysisDefault(index)}
/>
)
)}
</Typography>
{this.state.add ? (
<Grid container spacing={1} alignItems="center">
<Grid item>
<LanguagePicker
value={this.state.name}
setCode={(bcp47: string) => this.setState({ bcp47 })}
name={this.state.bcp47}
setName={(name: string) => this.setState({ name })}
font={this.state.font}
setFont={(font: string) => this.setState({ font })}
t={languagePickerStrings_en}
/>
</Grid>{" "}
<Grid item>
<Button
id="submitNewLang"
size="large"
disabled={!this.isNewWritingSystem()}
onClick={() => this.addAnalysisWritingSystem()}
>
<Done />
</Button>
</Grid>{" "}
<Grid item>
<Button size="large" onClick={() => this.resetState()}>
<Clear />
</Button>
</Grid>
</Grid>
) : (
<Tooltip
title={
<Translate id="projectSettings.language.addAnalysisLanguage" />
}
placement="right"
>
<Button
id="addNewLang"
onClick={() => this.setState({ add: true })}
>
<Add />
</Button>
</Tooltip>
)}
</React.Fragment>
);
}
}

export default withLocalize(ProjectLanguages);
function MakeDefaultButton() {
return (
<Tooltip
title={
<Translate id="projectSettings.language.makeDefaultAnalysisLanguage" />
}
placement="right"
>
<ArrowUpward fontSize="inherit" />
</Tooltip>
);
}

interface ImmutableWritingSystemProps {
ws: WritingSystem;
index?: number;
icon?: any;
iconAction?: () => void;
}

export function ImmutableWritingSystem(props: ImmutableWritingSystemProps) {
return (
<Grid container spacing={1}>
{props.index !== undefined && <Grid item>{`${props.index + 1}. `}</Grid>}
<Grid item>
<Translate id="projectSettings.language.name" />
{": "}
{props.ws.name} {", "}
</Grid>
<Grid item>
<Translate id="projectSettings.language.bcp47" />
{": "}
{props.ws.bcp47}
{", "}
</Grid>
<Grid item>
<Translate id="projectSettings.language.font" />
{": "}
{props.ws.font}
</Grid>
{props.icon ? (
<Grid item>
<Button onClick={props.iconAction}>{props.icon}</Button>
</Grid>
) : null}
</Grid>
);
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,70 @@
import { LanguagePicker } from "mui-language-picker";
import React from "react";
import { Provider } from "react-redux";
import renderer from "react-test-renderer";
import renderer, {
ReactTestInstance,
ReactTestRenderer,
} from "react-test-renderer";
import configureMockStore from "redux-mock-store";

import { defaultProject, Project } from "../../../../types/project";
import {
defaultProject,
Project,
WritingSystem,
} from "../../../../types/project";
import { defaultState } from "../../../App/DefaultState";
import ProjectLanguages from "../ProjectLanguages";

jest.mock("../../../../backend", () => {
return { updateProject: (proj: Project) => mockUpdateProject(proj) };
});

const createMockStore = configureMockStore([]);
const mockStore = createMockStore(defaultState);
let mockProject: Project = {
...defaultProject,
analysisWritingSystems: [
{ name: "a", bcp47: "a", font: "" },
{ name: "b", bcp47: "b", font: "" },
],
};
describe("Testing login component", () => {
it("Renders without crashing", () => {
renderer.act(() => {
renderer.create(
<Provider store={mockStore}>
<ProjectLanguages project={mockProject} />
</Provider>
);
});
const mockAnalysisWritingSystems: WritingSystem[] = [
{ name: "a", bcp47: "a", font: "" },
{ name: "b", bcp47: "b", font: "" },
];
const mockUpdateProject = jest.fn((proj: Project) => {
return Promise.resolve(proj);
});

let projectMaster: ReactTestRenderer;
let projectHandle: ReactTestInstance;

function mockProject(systems?: WritingSystem[]) {
return { ...defaultProject, analysisWritingSystems: systems ?? [] };
}

function renderProjLangs(proj: Project) {
renderer.act(() => {
projectMaster = renderer.create(
<Provider store={mockStore}>
<ProjectLanguages project={proj} />
</Provider>
);
});
}

describe("ProjectLanguages", () => {
it("renders without crashing", () => {
renderProjLangs(mockProject([...mockAnalysisWritingSystems]));
});

it("can add language to project", () => {
renderProjLangs(mockProject([...mockAnalysisWritingSystems]));
expect(projectMaster.root.findAllByType(LanguagePicker).length).toEqual(0);
projectMaster.root.findByProps({ id: "addNewLang" }).props.onClick();
expect(projectMaster.root.findAllByType(LanguagePicker).length).toEqual(1);
projectHandle = projectMaster.root.findByType(LanguagePicker);
projectHandle.props.setCode("z");
projectHandle.props.setName("z");
projectMaster.root.findByProps({ id: "submitNewLang" }).props.onClick();
expect(mockUpdateProject).toBeCalledWith(
mockProject([
...mockAnalysisWritingSystems,
{ name: "z", bcp47: "z", font: "" },
])
);
});
});
12 changes: 11 additions & 1 deletion src/resources/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,17 @@
],
"bcp47": ["BCP 47 Code", "BCP 47", "BCP 47"],
"name": ["Name", "Nombre", "Nom"],
"font": ["Font", "Font", "Font"]
"font": ["Font", "Font", "Font"],
"addAnalysisLanguage": [
"Add an alternate analysis language.",
"Add an alternate analysis language.",
"Add an alternate analysis language."
],
"makeDefaultAnalysisLanguage": [
"Make this the default analysis language.",
"Make this the default analysis language.",
"Make this the default analysis language."
]
},
"name": ["Project Name", "Nombre del proyecto", "Nom du projet"],
"projectList": ["Projects", "Proyectos", "Projets"],
Expand Down