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

[Archive]: Connect to backend #381

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8326bbb
Keep archived flag when loading rows
hermann-p May 13, 2024
6dca8cb
Add context menu entry to (un-)archive rows
hermann-p May 13, 2024
d602401
Add i18n for row context menu
hermann-p May 13, 2024
79d570b
Simplify query builder
hermann-p May 13, 2024
bac8df2
Keep `archived` flag during filter
hermann-p May 14, 2024
a3dd083
Ensure proper redraw when switching rows to/from archived
hermann-p May 14, 2024
9176e50
Change behaviour of `loadAllRows`
hermann-p May 15, 2024
1a9a27f
Fetch archived rows once when clicking "Show archived" button
hermann-p May 15, 2024
294c0df
Visualise archived rows in link overlay
hermann-p May 15, 2024
3fbe3d1
Fix multiple/unordered rows by merge-sort-like row loading
hermann-p May 21, 2024
31c6ee4
Center archive icon
hermann-p May 21, 2024
fbb2ce2
Adjusted Jenkinsfile for branch deployment
May 21, 2024
21e06ae
fix: linting
May 21, 2024
a5af4aa
fix issue with react-smooth-dnd
zingmane May 21, 2024
27892e2
improve dockerfile
zingmane May 21, 2024
505c39c
Fix text overlay crash
hermann-p May 27, 2024
ddb11c4
Unify colours of active buttons
hermann-p May 27, 2024
96c8893
Fix freshly archived rows jumping to top
hermann-p May 27, 2024
f2fe23c
Add lock bar to archived rows in entity view
hermann-p May 27, 2024
a0fcb40
Visualise selected archived rows
hermann-p May 27, 2024
d7b3d30
Add translation to `archived` history entries
hermann-p May 27, 2024
85c7922
Revert "Add lock bar to archived rows in entity view"
smnhgn Jun 18, 2024
5e18752
Revert "Revert "Add lock bar to archived rows in entity view""
smnhgn Jun 18, 2024
350b3f2
fix: remove restoreRowFromArchive from unlockBar
smnhgn Jun 18, 2024
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
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ ARG BUILD_ID=unknown
ENV BUILD_ID=${BUILD_ID}

RUN echo "Build with BUILD_ID: $BUILD_ID"
RUN npm run lint
RUN npm run test:ci
RUN npm run build
RUN npm prune --production
RUN npm run lint && \
npm run test:ci && \
npm run build && \
npm prune --production

FROM node:20.10.0-alpine

Expand Down
31 changes: 16 additions & 15 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ final String BRANCH = params.BRANCH
final boolean NOTIFY_SLACK_ON_FAILURE = params.NOTIFY_SLACK_ON_FAILURE
final boolean NOTIFY_SLACK_ON_SUCCESS = params.NOTIFY_SLACK_ON_SUCCESS

final String BRANCH_NAME = BRANCH ? BRANCH.tokenize('/').last() : ""
final String CLEAN_BRANCH_NAME = BRANCH ? BRANCH.replaceAll("[\\.\\_\\#]", "-").tokenize('/').last() : ""

final String DEPLOY_DIR = 'build/deploy'
final String TEST_COVERAGE_FILE = 'output/coverage/junit.xml'

final String IMAGE_NAME = "campudus/grud-frontend"
final String IMAGE_TAG = CLEAN_BRANCH_NAME && CLEAN_BRANCH_NAME != "master" ? CLEAN_BRANCH_NAME : "latest"
final String ARCHIVE_FILENAME_DIST = "grud-frontend-dist.tar.gz"
final GString DOCKER_BASE_IMAGE_TAG = "build-${BUILD_NUMBER}"

Expand Down Expand Up @@ -85,8 +87,7 @@ pipeline {
--label "GIT_COMMIT_DATE=${GIT_COMMIT_DATE}" \
--label "BUILD_DATE=${BUILD_DATE}" \
-t ${IMAGE_NAME}:${DOCKER_BASE_IMAGE_TAG}-${GIT_HASH} \
${BRANCH_NAME ? "-t ${IMAGE_NAME}:${BRANCH_NAME}" : ""} \
-t ${IMAGE_NAME}:latest \
-t ${IMAGE_NAME}:${IMAGE_TAG} \
-f Dockerfile --rm .
"""
}
Expand All @@ -102,16 +103,7 @@ pipeline {
steps {
withDockerRegistry([credentialsId: "dockerhub", url: ""]) {
sh "docker push ${IMAGE_NAME}:${DOCKER_BASE_IMAGE_TAG}-${GIT_HASH}"

script {
if (BRANCH_NAME) {
sh "docker push ${IMAGE_NAME}:${BRANCH_NAME}"
}

if (!BRANCH_NAME || BRANCH_NAME == 'master') {
sh "docker push ${IMAGE_NAME}:latest"
}
}
sh "docker push ${IMAGE_NAME}:${IMAGE_TAG}"
}
}
}
Expand All @@ -122,7 +114,12 @@ pipeline {
wrap([$class: 'BuildUser']) {
script {
if (NOTIFY_SLACK_ON_SUCCESS) {
slackOk(channel: SLACK_CHANNEL, message: BRANCH ? "BRANCH=${BRANCH}" : "")
final String logParams = [
BRANCH ? "BRANCH=${BRANCH}" : null,
"image: ${IMAGE_NAME}:${IMAGE_TAG}",
].minus(null).join(' ')

slackOk(channel: SLACK_CHANNEL, message: "${logParams}")
}
}
}
Expand All @@ -132,7 +129,11 @@ pipeline {
wrap([$class: 'BuildUser']) {
script {
if (NOTIFY_SLACK_ON_FAILURE) {
slackError(channel: SLACK_CHANNEL, message: BRANCH ? "BRANCH=${BRANCH}" : "")
final String logParams = [
BRANCH ? "BRANCH=${BRANCH}" : null,
].minus(null).join(' ')

slackError(channel: SLACK_CHANNEL, message: "${logParams}")
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions setupTests.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// babel polyfill: https://babeljs.io/docs/en/babel-polyfill
import "core-js/stable";
import "regenerator-runtime/runtime";

// https://github.com/kutlugsahin/react-smooth-dnd/issues/48
Object.defineProperty(global, "Node", {
value: { firstElementChild: "firstElementChild" }
});
18 changes: 14 additions & 4 deletions src/app/archivedRows/ToggleArchivedRowsButton.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import React, { useCallback } from "react";
import React, { useCallback, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import Action from "../redux/actionCreators";
import { selectShowArchivedState } from "../redux/reducers/tableView";

const ToggleArchivedRowsButton = ({ table }) => {
// prevent potential massive reload of archived rows
const [mustFetchArchivedRows, setMustFetchArchivedRows] = useState(true);

const showArchived = useSelector(selectShowArchivedState);
const dispatch = useDispatch();
const className = `filter-wrapper ${showArchived ? "active" : ""}`;
const className = `filter-wrapper ${showArchived ? "has-filter" : ""}`;
const toggleArchivedRows = useCallback(() => {
if (mustFetchArchivedRows) {
dispatch(Action.loadAllRows(table.id, true));
setMustFetchArchivedRows(false);
}
dispatch(Action.setShowArchivedRows(table, !showArchived));
}, [showArchived]);
}, [showArchived, mustFetchArchivedRows]);

return (
<div className={className}>
<button className="filter-popup-button" onClick={toggleArchivedRows}>
<button
className="filter-popup-button button__toggle-archived-rows"
onClick={toggleArchivedRows}
>
<i className="fa fa-archive" />
</button>
</div>
Expand Down
13 changes: 2 additions & 11 deletions src/app/archivedRows/helpers.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
// eslint-dsable-next-line
import { flip, memoize } from "lodash";
export const isRowArchived = row => Boolean(row.archived);

// eslint-disable-next-line
const memoizeWith = flip(memoize);

export const isRowArchived = memoizeWith(
row => row.id,
() => Math.random() < 0.5
); // TODO: implement once we decided on the data type

export const isLinkArchived = _ => Math.random() < 0.5; // TODO: implement once we decided on the data type
export const isLinkArchived = link => Boolean(link.archived);
3 changes: 2 additions & 1 deletion src/app/components/cells/Cell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ class Cell extends React.Component {
!f.isEqual(
getRelevantCellProps(this.props.cell),
getRelevantCellProps(nextProps.cell)
)
) ||
cell.row.archived !== nextCell.row.archived
);
};

Expand Down
6 changes: 5 additions & 1 deletion src/app/components/cells/link/LinkOverlay.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import withCachedLinks from "./LinkOverlayCache.jsx";
import { isTaxonomyTable } from "../../taxonomy/taxonomy";
import store from "../../../redux/store";
import { buildClassName } from "../../../helpers/buildClassName";
import { isRowArchived } from "../../../archivedRows/helpers";
const MAIN_BUTTON = 0;
const LINK_BUTTON = 1;
const LINKED_ITEMS = 0;
Expand Down Expand Up @@ -247,13 +248,14 @@ class LinkOverlay extends PureComponent {
}
};

return (
return row && cell ? (
<LinkItem
key={`${key}-${row.id}`}
refIfLinked={refIfLinked}
clickHandler={this.addLinkValue}
isLinked={isLinked}
isSelected={isSelected}
archived={isRowArchived(row)}
row={row}
toTable={f.get(["column", "toTable"], cell)}
cell={cell}
Expand All @@ -263,6 +265,8 @@ class LinkOverlay extends PureComponent {
selectedMode={selectedMode}
isPermissionDenied={row.hiddenByRowPermissions}
/>
) : (
undefined
);
};

Expand Down
15 changes: 10 additions & 5 deletions src/app/components/cells/link/LinkOverlayCache.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,21 @@ const withCachedLinks = Component => props => {
.then(
// row response -> link label format
f.compose(
f.map(({ id, values }) => ({ id, value: f.first(values) })),
f.map(({ values, ...foreignRow }) => ({
...foreignRow,
value: f.first(values)
})),
f.prop("rows")
)
)
.then(foreignRows => {
// update display values in state
const loadedDisplayValues = foreignRows.map(({ id, value }) => ({
id,
values: [getDisplayValue(column.toColumn, value)]
}));
const loadedDisplayValues = foreignRows.map(
({ value, ...foreignRow }) => ({
...foreignRow,
values: [getDisplayValue(column.toColumn, value)]
})
);
actions.addDisplayValues({
displayValues: [
{ tableId: column.toTable, values: loadedDisplayValues }
Expand Down
68 changes: 23 additions & 45 deletions src/app/components/cells/text/TextEditOverlay.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
import React from "react";
import { compose, lifecycle, withStateHandlers } from "recompose";
import i18n from "i18next";
import React, { useState } from "react";
import {
columnHasMaxLength,
columnHasMinLength,
isTextTooShort,
getTextLength,
isTextTooLong,
getTextLength
isTextTooShort
} from "../../../helpers/limitTextLength";

const TextEditOverlay = props => {
const {
editedValue,
setValue,
saveEdits,
readOnly,
cell: { column }
actions,
cell,
cell: { column, value },
langtag,
readOnly
} = props;

const [editedValue, setEditedValue] = useState(
(column.multilanguage ? value[langtag] : value) ?? ""
);
const saveEdits = () => {
const newValue = column.multilanguage
? { ...value, [langtag]: editedValue }
: editedValue;

console.log("saveEdits", cell, value, newValue);
actions.changeCellValue({ cell, oldValue: value, newValue });
};

const { minLength, maxLength } = column;
const [clickedOutside, setClickedOutside] = React.useState(false);
const minLengthText = columnHasMinLength(column)
Expand All @@ -40,7 +52,7 @@ const TextEditOverlay = props => {
if (isTextTooLong(column, value)) {
return;
}
setValue(evt);
setEditedValue(value);
};
const onBlur = () => {
if (shouldCatchOutsideClick) {
Expand Down Expand Up @@ -75,38 +87,4 @@ const TextEditOverlay = props => {
);
};

const enhance = compose(
withStateHandlers(
({ cell, value, langtag }) => ({
editedValue: cell.column.multilanguage ? value[langtag] : value
}),
{
setValue: () => event => ({ editedValue: event.target.value }),
saveEdits: (state, props) => () => {
const { editedValue } = state;
const { langtag, cell, value, actions } = props;
const { column, row, table } = cell;

const newValue = column.multilanguage
? { [langtag]: editedValue }
: editedValue;

actions.changeCellValue({
oldValue: value,
newValue,
tableId: table.id,
columnId: column.id,
rowId: row.id,
cell
});
}
}
),
lifecycle({
componentWillUnmount() {
this.props.saveEdits();
}
})
);

export default enhance(TextEditOverlay);
export default TextEditOverlay;
34 changes: 34 additions & 0 deletions src/app/components/contextMenu/RowContextMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
getAnnotation,
removeTranslationNeeded,
setCellAnnotation,
setRowArchived,
setRowFinal
} from "../../helpers/annotationHelper";
import { canConvert } from "../../helpers/cellValueConverter";
Expand Down Expand Up @@ -284,6 +285,21 @@ class RowContextMenu extends React.Component {
setRowFinal({ table, row, value: valueToSet });
};

setArchived = archived => () => {
const {
langtag,
cell: { row, table }
} = this.props;
setRowArchived({ table, row, archived });
if (archived) {
this.props.actions.toggleCellSelection({
select: false,
langtag,
tableId: table.id
});
}
};

setFinalItem = () => {
if (!canUserEditRowAnnotations(this.props.cell)) {
return null;
Expand All @@ -298,6 +314,23 @@ class RowContextMenu extends React.Component {
return this.mkItem(this.setFinal(!final), label, "lock");
};

setArchivedItem = () => {
if (!canUserEditRowAnnotations(this.props.cell)) {
return null;
} else {
const {
t,
cell: {
row: { archived }
}
} = this.props;
const label = t(
archived ? "archived.unset-archived" : "archived.set-archived"
);
return this.mkItem(this.setArchived(!archived), label, "archive");
}
};

openLinksFilteredItem = () => {
const { cell, langtag } = this.props;
if (cell.kind !== ColumnKinds.link || f.isEmpty(cell.value)) {
Expand Down Expand Up @@ -414,6 +447,7 @@ class RowContextMenu extends React.Component {
{this.mkItem(showDependency, "show_dependency", "code-fork")}
{this.mkItem(showTranslations, "show_translation", "flag")}
{this.setFinalItem()}
{this.setArchivedItem()}
{isDeletingRowAllowed || isDuplicatingRowAllowed ? (
<div className="separator--internal" />
) : null}
Expand Down
10 changes: 6 additions & 4 deletions src/app/components/history/diffItems/FlagDiff.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import f from "lodash/fp";
import i18n from "i18next";

import f from "lodash/fp";
import React from "react";
import { ifElse, when } from "../../../helpers/functools";

const FlagDiff = props => {
Expand All @@ -21,6 +20,9 @@ const FlagDiff = props => {
revision.value || revision.valueType
);

const translationKey =
value === "archived" ? "table:archived:is-archived" : `table:${value}`;

return (
<div
className={
Expand All @@ -34,7 +36,7 @@ const FlagDiff = props => {
event
}
>
{i18n.t(`table:${value}`)}
{i18n.t(translationKey)}
</div>
);
};
Expand Down
Loading