Custom workflow rule to set default comment visibility - youtrack

I am trying to add a workflow rule in YouTrack, which sets the visibility of newly posted comments that aren't made by a specific user.
Here's what I've tried:
rule set comment visibility to developers
when comments.added.last.author.login != "special" {
comments.last.permittedGroup = {group: Developers};
}
This works, in that all newly added comments that are not made by the special user are set as visible only to Developers. The problem is that this rule also prevents the visibility from being overridden; the visibility always reverts back to "Developers", after it is changed manually via the UI.
Obviously the rule in its current form is pretty simple and I guess (hope) there's a way to isolate the creation of a comment, rather than any update to it (which I guess is what it's currently catching).
Is there any way to only have this rule apply to newly created comments, rather than to any that have been updated?

The trick here is that YouTrack Workflow Language supports null-safety. When you add a comment, comments.added.last contains the comment, and a rule works as expected. When you edit something else, comments.added.last is null, thus comments.added.last.author.login is also null, and null != "special", indeed.
What you need is to check that there are newly created comments is this change, e.g.
when comments.added.isNotEmpty && comments.added.last.author.login != "special" {
comments.last.permittedGroup = {group: Developers};
}

Related

How to pass the scopes I need in the microsoftTeams.authentication.authenticate() method

After creating a teams-tab-app using the vscode teams toolkit, I see that in the default auth-start.html file the script tries to extract the scopes from the URL (that was constructed by the microsoftTeams.authentication.authenticate() method), however I don't see any reference in the documentation on how to pass these scopes in this method.
Does anyone know how to pass these scopes?
I've wondered about this myself when looking at a toolkit, but I haven't used it for any production systems so never bothered to look too deep. I do see that in useTeamsFx.tsx is where it's doing the redirect to startLoginPageUrl, so presumably you need to set REACT_APP_START_LOGIN_PAGE_URL to be the path to the auth-start.html, so you could set it to include a querystring as well. It needs the app Id so you'd need to set that as well, but the useTeamsFx also wants REACT_APP_CLIENT_ID which you'd set as well. As a result, it might make sense to store the scopes you want in your code or in an environment variable as well, and then compose the value you send to initiateLoginEndpoint. Basically, instead of
var startLoginPageUrl = process.env.REACT_APP_START_LOGIN_PAGE_URL;
...
initiateLoginEndpoint: startLoginPageUrl
...
you might instead make it
var startLoginPageUrl = process.env.REACT_APP_START_LOGIN_PAGE_URL;
var scopes = process.env.REACT_APP_SCOPES; // <-- this is added
...
initiateLoginEndpoint: `${startLoginPageUrl}?clientId=${clientId}&scope=${scopes}`
...
but this is untested, so no guarantees.
On a separate but related note, in my sample project, in auth-start, it refers to a very old version of MicrosoftTeams.min.js (v 1.6, and current is 1.11). I might just have a very old Teams Toolkit, but maybe not...

Stop operation in change()

Is there a way to stop an remove operation in model.document.on('change') ?
I listen to change with this code:
model.document.on('change',(eventInfo,batch) => {
// My code here.
}
And it works fine, in so far as I do get and can inspect all changes. But there does not appear to be any way to reject the change.
I tried to call eventInfo.stop() and reset() on the differ. Both of these methods does stop the change, but always later results in a model-nodelist-offset-out-of-bounds:
exception if I try to stop a remove operation.
What I am trying to do is to change how text delete works, so when the user delete text, instead of really deleting the text from the editor, I create a marker which marks which text have been "deleted" by the user. (For optional change control).
Instead of stopping the change, maybe you could save the data value after a change and "reset" to the previous value when a delete happens:
var oldData = '';
var editor = ClassicEditor
.create(document.querySelector('#editor'))
.then(editor => {
editor.model.document.on('change',(eventInfo, batch) => {
if(oldData.length > editor.getData().length) {
// or use eventInfo.source.differ.getChanges() and check for type: "remove"
editor.setData(oldData);
}
oldData = editor.getData();
});
})
.catch( error => {
console.error( error );
});
Note instead of checking the data length, you could loop through the changes happened using eventInfo.source.differ.getChanges() and checking if there were changes of type "remove".
An operation that was already applied (and the change event is fired after operations are applied) cannot be silently removed. They need to be either reverted (by applying new operations which will revert the state of the model to the previous one) or prevented before they actually get applied.
Reverting operations
The most obvious but extremely poorly performing solution is to use setData(). That will, however, reset the selection and may cause other issues.
A far more optimal solution is to apply reversed operations for each applied operation that you want to revert. Think like in git – you cannot remove a commit (ok, you can, but you'd have to do a force push, so you don't). Instead, you apply a reversed commit.
CKEditor 5's operations allow getting their reversed conterparts. You can then apply those. However, you need to make sure that the state of the model is correct after you do that – this is tricky because when working on such a low level, you lose the normalization logic which is implemented in the model writer.
Another disadvantage of this solution is that you will end up with empty undo steps. Undo steps are defined by batches. If you'll add to a batch operations which revert those which are already in it, that batch will be an empty undo step. Currently, I don't know of a mechanism which would allow removing it from the history.
Therefore, while reverting operations is doable, it's tricky and may not work flawlessly at the moment.
Preventing applying operations
This is a solution that I'd recommend. Instead of fixing an already changed model, make sure that it doesn't change at all.
CKEditor 5 features are implemented in the form of commands. Commands have their isEnabled state. If a command is disabled, it cannot be executed.
In CKEditor 5 even features such as support for typing are implemented in the form of commands (input, delete and forwardDelete). Hence, preventing typing can be achieved by disabling these commands.

How do I just add a custome variable to a Survey Monkey?

I am handling existing surveys via the API.
As part of this, I need each survey to have a custom variable defined for it.
I would like to use the API to add the custom variable, but the documentation states the FETCH would not do that, and PUT will replace rather than update the survey.
I am handling existing surveys, which I would not like to delete and replace, or am I miss-reading the docs?
Can I just send via PUT the following structure and it will keep everything else in place?
{
id : 112223333, //id of survey
custom_variables: {
'custom1':'custom1',
'custom2':'custom2'
}
}
I do see it resets the title, so, is this method safe? (i.e. wont remove any other data associated to this survey).
You're on the right track. You're going to want to use a PATCH HTTP request. That will only make updates, whereas a PUT request will replace the survey with the content you provide.
So your request will likely look something like this:
PATCH /v3/surveys/<survey_id>
{
"custom_variables": {
"custom1_name": "custom1_label",
"custom2_name": "custom2_label"
}
}
And that should only update your custom variables to the values you set. The docs do appear to suggest custom_variables won't get updated with a PATCH request but I think it does work.

How to apply metadata to all files in a content directory

I have a content directory called foo and I want all files under that directory to have an extra metadata item foovar: default, unless explicitly overridden in the file header. I think I'm supposed to do this with EXTRA_PATH_METADATA, but I can't figure out what incantation it wants.
(for my current use case I'm trying to apply template: sometemplate within this dir, but I'm interested in solving the general case as it would make several related headaches go away)
I think what you're looking for is actually DEFAULT_METADATA. Check out this portion of the documentation:
DEFAULT_METADATA = {}
The default metadata you want to use for all articles and pages.
So, in your case it might look something like this in your config file:
DEFAULT_METADATA = {'foovar': 'default'}
Then to assign your custom template(s), see this portion of the documentation.
This wasn't possible at the time I asked. I've since sent the devs a PR adding support, and it's been merged to master. Presumably it will go out in the next release. It makes EXTRA_PATH_METADATA recursive, so you can apply settings to a subdir like this:
EXTRA_PATH_METADATA = {'dirname/subdir': {'status': 'hidden'}}

Copy language content to another

I'm on IP 4.0.11.
Is it possible to copy all content of a language to another (ie to edit only texts and not style or html)? Is there an option or perhaps in database?
Thanks in advance.
At this time you can only copy pages. In your case I'd do like this:
Create a new language.
Create same menus in new language (same name and alias).
Then go to an original language.
Select page (copying parent copies children, too)
Click "copy" icon.
Go to a new language.
Select required menu.
Click "paste" icon.
Repeat 3-8.
It's a bit of manual work, but it's a fool-proof. It shouldn't take you very long. Changing a database may create many errors.
Thanks for answer, Audrius. This works fine with one caveat: The pages pasted into the new language still gets prepended with the old language's language prefix.
Example: copied english page "home" to Norwegian and set the url to "hjem". The new page now got the url /en/hjem instead of no/hjem as expected.
I'm on 4.0.16. Thankful for any hints.
Update May 21st:
Did some debugging. Apparently there is nothing in the code of Ip\Internal\Pages copySinglePage() that cares about changing the $copy['languageCode'] for the new page to be inserted.
Line 93 and onwards (referring to 4.0.16):
unset($copy['id']);
$copy['parentId'] = $newParentId;
$copy['pageOrder'] = $newIndex;
$copy['urlPath'] = UrlAllocator::allocatePath($copy['languageCode'], $copy['urlPath']);
whereas I'd also expect some logic setting
$copy['languageCode'] = something;
Hope this reaches the developers