Skip to content
This repository has been archived by the owner on Feb 28, 2024. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/feature/#144-editing-ticket-labels'
Browse files Browse the repository at this point in the history
  • Loading branch information
rjpaskin committed Feb 9, 2021
2 parents b85680c + b84604e commit 9240b98
Show file tree
Hide file tree
Showing 41 changed files with 1,478 additions and 153 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ gem 'haml'
gem 'jquery-rails'
gem 'octicons_helper'
gem 'octokit'
gem 'omniauth-github'
gem 'omniauth-github', '~> 1.4'
gem 'omniauth-rails_csrf_protection', '~> 0.1'
gem 'ranked-model', '~> 0.4'
gem 'redis-namespace'
Expand Down
10 changes: 5 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ GEM
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jwt (1.5.6)
jwt (2.2.2)
launchy (2.4.3)
addressable (~> 2.3)
loofah (2.3.1)
Expand All @@ -156,9 +156,9 @@ GEM
nio4r (2.5.2)
nokogiri (1.10.8)
mini_portile2 (~> 2.4.0)
oauth2 (1.4.0)
faraday (>= 0.8, < 0.13)
jwt (~> 1.0)
oauth2 (1.4.4)
faraday (>= 0.8, < 2.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
Expand Down Expand Up @@ -363,7 +363,7 @@ DEPENDENCIES
nokogiri (~> 1.10.8)
octicons_helper
octokit
omniauth-github
omniauth-github (~> 1.4)
omniauth-rails_csrf_protection (~> 0.1)
pg
puma (~> 3.12)
Expand Down
10 changes: 10 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception

private

def json_array_from(records)
Jbuilder.encode do |json|
json.array! records do |record|
json.merge! record.to_builder.attributes!
end
end
end
end
25 changes: 25 additions & 0 deletions app/controllers/labellings_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class LabellingsController < AuthenticatedController
load_and_authorize_resource :board
load_and_authorize_resource :board_ticket, through: :board, id_param: :ticket_id
load_and_authorize_resource :ticket, through: :board_ticket, singleton: true

def update
changeset = TicketLabelChangeset.new(
ticket: @ticket,
changes: labelling_params,
token: current_user_github_token
)

if changeset.save
render json: json_array_from(@ticket.display_labels.reload), status: :ok
else
render json: { errors: changeset.error_messages }, status: :unprocessable_entity
end
end

private

def labelling_params
params.require(:labelling).permit(add: [], remove: [])
end
end
7 changes: 7 additions & 0 deletions app/controllers/labels_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class LabelsController < AuthenticatedController
load_and_authorize_resource :repo

def index
render json: json_array_from(@repo.display_labels)
end
end
36 changes: 24 additions & 12 deletions app/javascript/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,43 @@ const createApiFunction = method => (url, body) =>

const post = createApiFunction("POST");
const put = createApiFunction("PUT");
const patch = createApiFunction("PATCH");

const formatURL = (url, params) => url.replace(/:([a-z_]+)/gi, (_, key) => params[key]);

export const getBoard = () => get(flightPlanConfig.api.boardURL);
export const getBoardNextActions = () => get(flightPlanConfig.api.nextActionsURL);
const {
boardURL,
nextActionsURL,
sluggedTicketURL,
repoLabelsURL,
createTicketMoveURL,
createTicketURL,
ticketLabellingURL
} = flightPlanConfig.api;

export const getBoard = () => get(boardURL);
export const getBoardNextActions = () => get(nextActionsURL);
export const getSwimlaneTickets = url => get(url);
export const getBoardTicket = url => get(url);
export const getBoardTicketFromSlug = (slug, number) => get(
formatURL(flightPlanConfig.api.sluggedTicketURL, { slug, number })
formatURL(sluggedTicketURL, { slug, number })
);
export const getRepoLabels = id => get(formatURL(repoLabelsURL, { id }));

export const createTicketMove = (boardTicketId, swimlaneId, indexInSwimlane) =>
post(formatURL(flightPlanConfig.api.createTicketMoveURL, { boardTicketId }), {
post(formatURL(createTicketMoveURL, { boardTicketId }), {
board_ticket: {
swimlane_id: swimlaneId,
swimlane_position: indexInSwimlane
}
});

export const createTicket = ticketAttributes =>
post(formatURL(flightPlanConfig.api.createTicketURL), {
ticket: {
repo_id: ticketAttributes['repo_id'],
swimlane: ticketAttributes['swimlane'],
title: ticketAttributes['title'],
description: ticketAttributes['description']
}
export const createTicket = ({ repo_id, swimlane, title, description }) =>
post(createTicketURL, {
ticket: { repo_id, swimlane, title, description }
});

export const updateTicketLabels = (boardTicketId, changes) => patch(
formatURL(ticketLabellingURL, { boardTicketId }),
{ labelling: changes }
);
11 changes: 1 addition & 10 deletions app/javascript/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,18 +231,9 @@ const entitiesReducer = (state = initialEntitiesState, { type, payload }) => {
}
};

const sliceReducer = combineReducers({
const rootReducer = combineReducers({
entities: entitiesReducer,
current
});

const rootReducer = (state = {}, action) => {
switch (action.type) {
case "RESET":
return {};
default:
return sliceReducer(state, action);
}
};

export default rootReducer;
32 changes: 20 additions & 12 deletions app/javascript/v2/components/Application.jsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,47 @@
import React from "react";
import { Provider } from "react-redux";
import { Router, Match } from "@reach/router";
import { Router } from "@reach/router";

import ErrorBoundary from "./ErrorBoundary";
import Board from "./Board";
import Header from "./Header";
import TicketModal from "./TicketModal";
import Notifications from "./Notifications";

import configureStore from "../../store";
import configureStore from "../store";

const store = configureStore();

const TicketModalWrapper = ({ owner, repo, number, location: { state }}) => (
<TicketModal
id={state && state.boardTicketId} /* may be null */
slug={`${owner}/${repo}`}
number={number}
/>
);

// Use a nested <Router> here instead of a <Match> so that
// further nested routers don't need to include the full
// owner-repo-number path in their routes
const BoardWrapper = () => (
<div className="flex flex-col h-screen">
<Header boards={flightPlanConfig.boards} />
<Board />
<Match path=":owner/:repo/:number">
{({ match, location: { state }}) => match && (
<TicketModal
id={state && state.boardTicketId} /* may be null */
slug={`${match.owner}/${match.repo}`}
number={match.number}
/>
)}
</Match>
<Router>
<TicketModalWrapper path=":owner/:repo/:number/*" />
</Router>
</div>
);

const Application = () => (
<ErrorBoundary>
<Provider store={store}>
<Router basepath={flightPlanConfig.api.htmlBoardURL}>
<BoardWrapper path="/*extras"/>
<BoardWrapper path="/*" />
</Router>
</Provider>

<Notifications />
</ErrorBoundary>
);

Expand Down
Loading

0 comments on commit 9240b98

Please sign in to comment.