Update contributor profiles #123
@@ -1,6 +1,7 @@
|
|||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import { and, notEmpty } from '@ember/object/computed';
|
import { and, notEmpty } from '@ember/object/computed';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
|
import { isPresent } from '@ember/utils';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
|
|
||||||
@@ -26,6 +27,12 @@ export default Component.extend({
|
|||||||
|
|
||||||
init () {
|
init () {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
this.setDefaultAttributes();
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
|
||||||
|
setDefaultAttributes () {
|
||||||
|
if (isPresent(this.attributes)) { return; }
|
||||||
|
|
||||||
this.set('attributes', {
|
this.set('attributes', {
|
||||||
account: null,
|
account: null,
|
||||||
@@ -37,8 +44,6 @@ export default Component.extend({
|
|||||||
gitea_username: null,
|
gitea_username: null,
|
||||||
wiki_username: null
|
wiki_username: null
|
||||||
});
|
});
|
||||||
|
|
||||||
this.reset();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
|
|||||||
@@ -1,62 +1,50 @@
|
|||||||
<form {{action "submit" on="submit"}}>
|
<form {{action "submit" on="submit"}}>
|
||||||
<p>
|
<p>
|
||||||
{{input name="account"
|
<label for="c-account">Ethereum account</label>
|
||||||
type="text"
|
{{input name="account" id="c-account"
|
||||||
|
type="text" value=account
|
||||||
placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4"
|
placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4"
|
||||||
value=account
|
|
||||||
class=(if isValidAccount "valid" "")}}
|
class=(if isValidAccount "valid" "")}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<select required onchange={{action (mut kind) value="target.value"}}>
|
<label for="c-kind">Kind</label>
|
||||||
|
<select required onchange={{action (mut kind) value="target.value"}} id="c-kind">
|
||||||
<option value="person" selected={{eq kind "person"}}>Person</option>
|
<option value="person" selected={{eq kind "person"}}>Person</option>
|
||||||
<option value="organization" selected={{eq kind "organization"}}>Organization</option>
|
<option value="organization" selected={{eq kind "organization"}}>Organization</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{input name="name"
|
<label for="c-name">Name</label>
|
||||||
type="text"
|
{{input name="name" type="text" value=name placeholder="Zero Cool"
|
||||||
placeholder="Name"
|
class=(if isValidName "valid" "") id="c-name"}}
|
||||||
value=name
|
|
||||||
class=(if isValidName "valid" "")}}
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{input name="url"
|
<label for="c-url">URL</label>
|
||||||
type="text"
|
{{input name="url" type="text" value=url placeholder="http://zerocool.bit"
|
||||||
placeholder="URL"
|
class=(if isValidURL "valid" "") id="c-url"}}
|
||||||
value=url
|
|
||||||
class=(if isValidURL "valid" "")}}
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{input name="github_uid"
|
<label for="c-github-uid">GitHub UID</label>
|
||||||
type="text"
|
{{input name="github_uid" type="text" value=github_uid placeholder="2342"
|
||||||
placeholder="GitHub UID (123)"
|
class=(if isValidGithubUID "valid" "") id="c-github-uid"}}
|
||||||
value=github_uid
|
|
||||||
class=(if isValidGithubUID "valid" "")}}
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{input name="github_username"
|
<label for="c-github-username">GitHub username</label>
|
||||||
type="text"
|
{{input name="github_username" type="text" value=github_username placeholder="zerocool"
|
||||||
placeholder="GitHub username"
|
class=(if isValidGithubUsername "valid" "") id="c-github-username"}}
|
||||||
value=github_username
|
|
||||||
class=(if isValidGithubUsername "valid" "")}}
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{input name="gitea_username"
|
<label for="c-gitea-username">Gitea username</label>
|
||||||
type="text"
|
{{input name="gitea_username" type="text" value=gitea_username placeholder="zerocool"
|
||||||
placeholder="Gitea username"
|
class=(if isValidGiteaUsername "valid" "") id="c-gitea-username"}}
|
||||||
value=gitea_username
|
|
||||||
class=(if isValidGiteaUsername "valid" "")}}
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{input name="wiki_username"
|
<label for="c-wiki-username">Wiki username</label>
|
||||||
type="text"
|
{{input name="wiki_username" type="text" value=wiki_username placeholder="ZeroCool"
|
||||||
placeholder="Wiki Username"
|
class=(if isValidWikiUsername "valid" "") id="c-wiki-username"}}
|
||||||
value=wiki_username
|
|
||||||
class=(if isValidWikiUsername "valid" "")}}
|
|
||||||
</p>
|
</p>
|
||||||
<p class="actions">
|
<p class="actions">
|
||||||
{{input type="submit"
|
{{input type="submit" disabled=inProgress
|
||||||
disabled=inProgress
|
|
||||||
value=(if inProgress "Processing" "Save")}}
|
value=(if inProgress "Processing" "Save")}}
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
<a href="https://ipfs.io/ipfs/{{c.contributor.ipfsHash}}" target="_blank" rel="noopener">Inspect IPFS profile</a>
|
<a href="https://ipfs.io/ipfs/{{c.contributor.ipfsHash}}" target="_blank" rel="noopener">Inspect IPFS profile</a>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
<li>
|
||||||
|
{{link-to "Edit profile" "contributors.edit" c.contributor.id}}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{{#if c.showMetadata}}
|
{{#if c.showMetadata}}
|
||||||
<pre>{{c.contributor.ipfsData}}</pre>
|
<pre>{{c.contributor.ipfsData}}</pre>
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import Controller from '@ember/controller';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
|
||||||
|
kredits: service(),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
|
||||||
|
save (attributes) {
|
||||||
|
return this.kredits
|
||||||
|
.updateContributor(this.model.id, attributes)
|
||||||
|
.then(() => this.transitionToRoute('index'))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,21 +1,16 @@
|
|||||||
import Controller from '@ember/controller';
|
import Controller from '@ember/controller';
|
||||||
import { alias } from '@ember/object/computed';
|
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
|
|
||||||
kredits: service(),
|
kredits: service(),
|
||||||
|
|
||||||
contributors: alias('kredits.contributors'),
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|
||||||
save (contributor) {
|
save (contributor) {
|
||||||
return this.kredits.addContributor(contributor)
|
return this.kredits
|
||||||
.then(contributor => {
|
.addContributor(contributor)
|
||||||
this.transitionToRoute('index');
|
.then(() => this.transitionToRoute('index'))
|
||||||
return contributor;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Router.map(function() {
|
|||||||
});
|
});
|
||||||
this.route('contributors', function() {
|
this.route('contributors', function() {
|
||||||
this.route('new');
|
this.route('new');
|
||||||
|
this.route('edit', { path: ':id/edit' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import Route from '@ember/routing/route';
|
||||||
|
import { alias } from '@ember/object/computed';
|
||||||
|
|
||||||
|
export default Route.extend({
|
||||||
|
|
||||||
|
kredits: service(),
|
||||||
|
contributors: alias('kredits.contributors'),
|
||||||
|
|
||||||
|
model(params) {
|
||||||
|
return this.kredits.contributors.findBy('id', params.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController (controller, model) {
|
||||||
|
this._super(controller, model);
|
||||||
|
|
||||||
|
controller.set('attributes', {
|
||||||
|
account: model.account,
|
||||||
|
name: model.name,
|
||||||
|
kind: model.kind,
|
||||||
|
url: model.url,
|
||||||
|
github_username: model.github_username,
|
||||||
|
github_uid: model.github_uid,
|
||||||
|
gitea_username: model.gitea_username,
|
||||||
|
wiki_username: model.wiki_username
|
||||||
|
|
|||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
+53
-21
@@ -47,7 +47,7 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
kreditsByContributor: computed('contributionsUnconfirmed.@each.vetoed', 'contributors', function() {
|
kreditsByContributor: computed('contributionsUnconfirmed.@each.vetoed', 'contributors.[]', function() {
|
||||||
const contributionsUnconfirmed = this.contributionsUnconfirmed.filterBy('vetoed', false);
|
const contributionsUnconfirmed = this.contributionsUnconfirmed.filterBy('vetoed', false);
|
||||||
const contributionsGrouped = groupBy(contributionsUnconfirmed, 'contributorId');
|
const contributionsGrouped = groupBy(contributionsUnconfirmed, 'contributorId');
|
||||||
const contributorsWithUnconfirmed = contributionsGrouped.map(c => c.value.toString());
|
const contributorsWithUnconfirmed = contributionsGrouped.map(c => c.value.toString());
|
||||||
@@ -87,7 +87,7 @@ export default Service.extend({
|
|||||||
// This is called in the application route's beforeModel(). So it is
|
// This is called in the application route's beforeModel(). So it is
|
||||||
// initialized before everything else, and we can rely on the ethProvider and
|
// initialized before everything else, and we can rely on the ethProvider and
|
||||||
// the potential currentUserAccounts to be available
|
// the potential currentUserAccounts to be available
|
||||||
getEthProvider: function() {
|
getEthProvider () {
|
||||||
let ethProvider;
|
let ethProvider;
|
||||||
|
|
||||||
return new RSVP.Promise(async (resolve) => {
|
return new RSVP.Promise(async (resolve) => {
|
||||||
@@ -136,7 +136,7 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup () {
|
||||||
return this.getEthProvider().then((providerAndSigner) => {
|
return this.getEthProvider().then((providerAndSigner) => {
|
||||||
let kredits = new Kredits(providerAndSigner.ethProvider, providerAndSigner.ethSigner, {
|
let kredits = new Kredits(providerAndSigner.ethProvider, providerAndSigner.ethSigner, {
|
||||||
addresses: { Kernel: config.kreditsKernelAddress },
|
addresses: { Kernel: config.kreditsKernelAddress },
|
||||||
@@ -172,14 +172,14 @@ export default Service.extend({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
loadInitialData() {
|
loadInitialData () {
|
||||||
return this.getContributors()
|
return this.getContributors()
|
||||||
.then(contributors => this.contributors.pushObjects(contributors))
|
.then(contributors => this.contributors.pushObjects(contributors))
|
||||||
.then(() => this.getContributions())
|
.then(() => this.getContributions())
|
||||||
.then(contributions => this.contributions.pushObjects(contributions))
|
.then(contributions => this.contributions.pushObjects(contributions))
|
||||||
},
|
},
|
||||||
|
|
||||||
addContributor(attributes) {
|
addContributor (attributes) {
|
||||||
if (attributes.github_uid) {
|
if (attributes.github_uid) {
|
||||||
const uidInt = parseInt(attributes.github_uid);
|
const uidInt = parseInt(attributes.github_uid);
|
||||||
attributes.github_uid = uidInt;
|
attributes.github_uid = uidInt;
|
||||||
@@ -190,13 +190,24 @@ export default Service.extend({
|
|||||||
return this.kredits.Contributor.add(attributes, { gasLimit: 350000 })
|
return this.kredits.Contributor.add(attributes, { gasLimit: 350000 })
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.debug('[kredits] add contributor response', data);
|
console.debug('[kredits] add contributor response', data);
|
||||||
const contributor = Contributor.create(attributes);
|
|
||||||
this.contributors.pushObject(contributor);
|
|
||||||
return contributor;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getContributors() {
|
updateContributor (id, attributes) {
|
||||||
|
if (attributes.github_uid) {
|
||||||
|
const uidInt = parseInt(attributes.github_uid);
|
||||||
|
attributes.github_uid = uidInt;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.debug('[kredits] update contributor', attributes);
|
||||||
|
|
||||||
|
return this.kredits.Contributor.updateProfile(id, attributes, { gasLimit: 350000 })
|
||||||
|
.then(data => {
|
||||||
|
console.debug('[kredits] updateProfile response', data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getContributors () {
|
||||||
return this.kredits.Contributor.all()
|
return this.kredits.Contributor.all()
|
||||||
.then((contributors) => {
|
.then((contributors) => {
|
||||||
return contributors.map((contributor) => {
|
return contributors.map((contributor) => {
|
||||||
@@ -205,7 +216,7 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addContribution(attributes) {
|
addContribution (attributes) {
|
||||||
console.debug('[kredits] add contribution', attributes);
|
console.debug('[kredits] add contribution', attributes);
|
||||||
|
|
||||||
return this.kredits.Contribution.addContribution(attributes, { gasLimit: 300000 })
|
return this.kredits.Contribution.addContribution(attributes, { gasLimit: 300000 })
|
||||||
@@ -220,7 +231,7 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addProposal(attributes) {
|
addProposal (attributes) {
|
||||||
console.debug('[kredits] add proposal', attributes);
|
console.debug('[kredits] add proposal', attributes);
|
||||||
|
|
||||||
return this.kredits.Proposal.addProposal(attributes)
|
return this.kredits.Proposal.addProposal(attributes)
|
||||||
@@ -231,7 +242,7 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getProposals() {
|
getProposals () {
|
||||||
return this.kredits.Proposal.all()
|
return this.kredits.Proposal.all()
|
||||||
.then((proposals) => {
|
.then((proposals) => {
|
||||||
return proposals.map((proposal) => {
|
return proposals.map((proposal) => {
|
||||||
@@ -241,7 +252,7 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getContributions() {
|
getContributions () {
|
||||||
return this.kredits.Contribution.all({page: {size: 200}})
|
return this.kredits.Contribution.all({page: {size: 200}})
|
||||||
.then(contributions => {
|
.then(contributions => {
|
||||||
return contributions.map(contribution => {
|
return contributions.map(contribution => {
|
||||||
@@ -251,7 +262,7 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
vote(proposalId) {
|
vote (proposalId) {
|
||||||
console.debug('[kredits] vote for', proposalId);
|
console.debug('[kredits] vote for', proposalId);
|
||||||
|
|
||||||
return this.kredits.Proposal.functions.vote(proposalId)
|
return this.kredits.Proposal.functions.vote(proposalId)
|
||||||
@@ -261,7 +272,7 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
veto(contributionId) {
|
veto (contributionId) {
|
||||||
console.debug('[kredits] veto against', contributionId);
|
console.debug('[kredits] veto against', contributionId);
|
||||||
|
|
||||||
return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
|
return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
|
||||||
@@ -292,7 +303,12 @@ export default Service.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Contract events
|
// Contract events
|
||||||
addContractEventHandlers() {
|
addContractEventHandlers () {
|
||||||
|
this.kredits.Contributor
|
||||||
|
.on('ContributorProfileUpdated', this.handleContributorChange.bind(this))
|
||||||
|
.on('ContributorAccountUpdated', this.handleContributorChange.bind(this))
|
||||||
|
.on('ContributorAdded', this.handleContributorChange.bind(this))
|
||||||
|
|
||||||
this.kredits.Contribution
|
this.kredits.Contribution
|
||||||
.on('ContributionVetoed', this.handleContributionVetoed.bind(this))
|
.on('ContributionVetoed', this.handleContributionVetoed.bind(this))
|
||||||
|
|
||||||
@@ -305,7 +321,23 @@ export default Service.extend({
|
|||||||
.on('Transfer', this.handleTransfer.bind(this));
|
.on('Transfer', this.handleTransfer.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
handleContributionVetoed(contributionId) {
|
async handleContributorChange (contributorId, ...args) {
|
||||||
|
console.debug('[kredits] Contributor add/update event received for ID', contributorId);
|
||||||
|
console.debug('[kredits] Event data:', args);
|
||||||
|
const contributorData = await this.kredits.Contributor.getById(contributorId);
|
||||||
|
const newContributor = Contributor.create(contributorData);
|
||||||
|
|
||||||
|
const oldContributor = this.contributors.findBy('id', contributorId.toString());
|
||||||
|
if (oldContributor) {
|
||||||
|
console.debug('[kredits] old contributor', oldContributor);
|
||||||
|
this.contributors.removeObject(oldContributor);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.debug('[kredits] new contributor', newContributor);
|
||||||
|
this.contributors.pushObject(newContributor);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleContributionVetoed (contributionId) {
|
||||||
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
|
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
|
||||||
const contribution = this.contributions.findBy('id', contributionId);
|
const contribution = this.contributions.findBy('id', contributionId);
|
||||||
console.debug('[kredits] contribution', contribution);
|
console.debug('[kredits] contribution', contribution);
|
||||||
@@ -315,7 +347,7 @@ export default Service.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleProposalCreated(proposalId) {
|
handleProposalCreated (proposalId) {
|
||||||
let proposal = this.findProposalById(proposalId);
|
let proposal = this.findProposalById(proposalId);
|
||||||
|
|
||||||
if (proposal) {
|
if (proposal) {
|
||||||
@@ -331,7 +363,7 @@ export default Service.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TODO: We may want to reload that proposal to show the voter as voted
|
// TODO: We may want to reload that proposal to show the voter as voted
|
||||||
handleProposalVoted(proposalId, voterId, totalVotes) {
|
handleProposalVoted (proposalId, voterId, totalVotes) {
|
||||||
let proposal = this.findProposalById(proposalId);
|
let proposal = this.findProposalById(proposalId);
|
||||||
|
|
||||||
if (proposal) {
|
if (proposal) {
|
||||||
@@ -339,7 +371,7 @@ export default Service.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleProposalExecuted(proposalId, contributorId, amount) {
|
handleProposalExecuted (proposalId, contributorId, amount) {
|
||||||
let proposal = this.findProposalById(proposalId);
|
let proposal = this.findProposalById(proposalId);
|
||||||
|
|
||||||
if (proposal.get('isExecuted')) {
|
if (proposal.get('isExecuted')) {
|
||||||
@@ -354,7 +386,7 @@ export default Service.extend({
|
|||||||
.incrementProperty('balance', amount);
|
.incrementProperty('balance', amount);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTransfer(from, to, value) {
|
handleTransfer (from, to, value) {
|
||||||
value = value.toNumber();
|
value = value.toNumber();
|
||||||
|
|
||||||
this.contributors
|
this.contributors
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ section#add-proposal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
input[type=text], select {
|
input[type=text], select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
@@ -25,9 +31,14 @@ section#add-proposal {
|
|||||||
background-color: rgba(22, 21, 40, 0.3);
|
background-color: rgba(22, 21, 40, 0.3);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
|
transition: border-color 0.1s linear;
|
||||||
|
|
||||||
&:focus, &.valid {
|
&:focus, &.valid {
|
||||||
background-color: rgba(22, 21, 40, 0.6);
|
background-color: rgba(22, 21, 40, 0.6);
|
||||||
}
|
}
|
||||||
|
&:focus {
|
||||||
|
border-color: $blue;
|
||||||
|
}
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: rgba(238, 238, 238, 0.5);
|
color: rgba(238, 238, 238, 0.5);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<main class="center-column">
|
||||||
|
|
||||||
|
<section id="add-contributor">
|
||||||
|
<header>
|
||||||
|
<h2>Update contributor profile</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{{add-contributor attributes=attributes save=(action "save")}}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{add-contributor contributors=contributors save=(action "save")}}
|
{{add-contributor save=(action "save")}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user
do you think we can use the
accountsarray here already? with adding more services we at some point would want to directly add entries to the accounts array.That should be a separate PR, as it requires quite some changes in the code.