Jurnal de schimbări
Ce e nou.
Fiecare îmbunătățire a platformei, pe măsură ce se livrează.
· SecurityService
Limita de autorizare pentru constituirea furnizorului de salarii
Aranjează noul ************* suprafaţa şi aplică cine ar putea Ajunge la ea. TimecardService deține motorul și nu sesiune; aceasta deține sesiune și decide. SecurityService ruleaza oriceRequest().permitAll() with Auth cu mâner manual, astfel încât un handler care uită garda nu este slab controlat este necontrolat și accesibil de pe internetul public. Mapped under the existing /api/security/payroll prefix on intentioned: kamo-intern ajunge la ea printr-o cale de captură-toate BFF, și un nou prefix ar 404 în browser în timp ce fiecare serviciu este sănătos și fiecare clădire este verde. Patru niveluri: - MANAGE PAYROLL PROVIDER (199) scrie acreditări și conectează sau deconectează Oauth. Aceasta este abilitatea de a decide unde sunt orele unei organizații transmis, motiv pentru care este dreptul său. - MANAGE HRS SETTINGS (45) citește conexiunea și sănătatea sa. - MANAGE TIMECARDS (183) acoperă cartografierea și sincronizarea istoricului angajaților. - FINALIZE PAY PERIODS (198) transmite un lot angajat comiterea exportului, deoarece este același act. Test Connection stă cu dreptul de a scrie mai degrabă decât cel citit: este un apel outbound efectuate cu acreditări stocate, și permițându- oricine care poate vizualiza Foc de pagină le oferă o modalitate de a verifica vânzătorul de salarii al orgului. Schimbul Oauth nu transmite un act de identitate. TimecardService o scoate din statul semnat HMAC, astfel încât un cod obținut pentru un chiriaș nu poate fi răscumpărat împotriva altuia chiar de către un apelant care deține dreptul în ambele. Adaugă put/șterge la TimecardServiceClient, care a avut doar obține/post.
· kamo-shared-library
Domeniul de plată-furnizor în spatele motorului cronologie
Adaugă perseverența coloanei vertebrale pentru conectarea cronologia unei organizații la o sistemul de salarizare terţ: conexiunea şi configuraţia sa criptată per-org; grantul Oauth, legătura dintre membru și furnizor, harta cu codul câștigului; și cele două înregistrări numai anexe (încercări de expediere și probleme de sincronizare) care fac o sincronizare explicabilă după aceea. Păstrat în interiorul com.kamo.z.shared.hr.timecard mai degrabă decât un nou pachet pe scop: un nou pachet comun trebuie adăugat la trei explicite separate @EnableJpaRepositories liste, și omite o abandonare a unui context de serviciu sau, în kamoInitializer, anulează cursa în timp ce raportează SUCCESUL BUILD. Note privind forma: - PayrollProviderType reutilizează vocabularul simbolic deja documentat pe Nu-ţi face griji. (ADP WFN, PAYCHEX, GUSTO, ...). O secundă. ortografie pentru același furnizor ar împărți istoria exporturilor cu nici o eroare Oriunde. ADP RUN și QUICKBOOKS sunt păstrate deoarece ecranul de export de salarizare le-a oferit de la expediere, astfel încât rândurile vii le pot transporta. - Legăturile cu angajatii sunt tastate de furnizor, nu prin conexiune, asa că schimbarea furnizorul și trecerea înapoi nu aruncă munca de cartografiere. DOI constrângeri unice: unul oprește un membru deține două link-uri, celălalt se oprește doi membri care pretind un angajat furnizor - PayrollDispatch și PayrollSyncIsue sunt WORM. O transmisie de plată incercarea este un eveniment de bani; "am trimis-o, apoi l-am trimis din nou" este faptul un Nevoi de reconciliere. - Credențials live în ONE criptate config json blog mai degrabă decât o coloană per Field, astfel încât adăugarea unui furnizor nu este o schimbare schema care re-armează fiecare serviciu. RoleRightType câștiguri MANAGE PAYROLL PROVIDER (199) MANAGE moștenire PAYROLL (40), care porțile nimic astăzi și este deja deținut de numărul necunoscut de membri; reutilizarea acestuia ar fi înmânat statului de plată terț Acreditari pentru fiecare detinator de dreptul de vedere rata pe portbagaj care a expediat-o. PlatformOauthProviderType câștigă cei șapte furnizori de salarii în cazul în care Kamo deține unul înregistrarea partenerilor (documentele 11-17). Dayforce, Workday și UKG emite acreditări pe client și nu obține în mod deliberat constant: ecranul platformei redă o Card pentru fiecare constantă, astfel încât unul pentru ei ar fi un formular nici un operator ar putea Completaţi. De asemenea, stabilește o afirmație veche în BillingDelegationModeTest: comite 9276487 REQUIRES PROBARE efectuată în mod deliberat permite grupurilor (excluderea a făcut ca calea de aprobare nu poate fi contactată) dar a lăsat testul să afirme vechiul comportament, așa că Apartamentul a fost roşu de atunci. Schema a fost aplicată şi verificată în Yugabyte înainte de această împingere.
· kamo-internal
Un perete la "acum" și o carte care explică un pumn anulat
Nimeni nu poate înregistra timpul ei nu au lucrat încă. Tragerea o margine, alunecarea a întregul interval, nudging cu tastele săgeată, magnetul, blocul clic dreapta și manualul adăuga dialog toate opri la minutul curent pe rândul de astăzi, și un Ziua viitoare nu acceptă nimic. Partea de azi care nu sa întâmplat este eclozat, pentru că "nu poți trage o pastilă aici" trebuie să fie vizibil înainte de cineva Controlul, nu ca regulă. Serverul a refuzat deja un pumn introdus sau corectat trecut acum, care este Exact de ce clientul avea nevoie de acest lucru: fără perete drag a reușit, pilula a stat acolo în căutarea înscenat, și întreaga salvare a eșuat la sfârșitul anului cu un mesaj despre un pumn membrul nu a putut găsi. Magnetul primeşte acelaşi perete. Un pumn lăsat în viitor de un dispozitiv greșit Ceasul era o ţintă legitimă, aşa că o margine putea fi trasă înainte pe ea. şi undeva unde salvatorii ar refuza. Și cardul de confirmare rămâne acum deschis atunci când un pumn CANCELS OUT cel dinaintea ei, care TimecardService a început să facă această dimineață pentru orice inversare în interiorul unei minut. Fără ca membrul apasă un buton, se uită la stat fixaţi înapoi exact de unde a început, și se concluzionează în mod rezonabil butonul este rupt. În care precizează că cardul scade cel care alege şi copia de acţiune, arată o propoziţie și un singur buton, și se oprește demisie pe fundal adesea urmează o confirmare nu trebuie să închidă singura explicație a ceea ce sa întâmplat.
· kamo-internal
Acordă suport și ferestre sociale compozitorului chat-ului membru
Un bilet de sprijin și un DM sociale sunt același lucru ca un chat membru sesiune mass-media cu mesaje pe ea Câmp text. Un agent ar putea fi trimis o captură de ecran de către un client și nu a avut nici un fel să trimită unul înapoi: nici un buton atașat, nici o picătură de drag-drop, nici pastă, nici emoji, și un intrare care nu ar crește peste o singură linie. Ambele acum face compozitor chat membru, astfel încât mașini de încărcat, tava de atașare, panoul de transfer, pickerul emoji și Enter-to-send sunt o implementare în toate trei. Ataşamente primite şi trimise redă bulele prin acelaşi AtaşamentChip. Două lucruri fereastra suport tabla forțat în aer liber: - Proiectele sunt parcate pe conversaţie (folosiţi Parcarea Draft). Un compozitor serveşte mai multe bilete și mesajele trimite la oricine este pe ecran, astfel încât un proiect la stânga în cutie sunt cuvintele unui client îndreptate spre altul. Eliminarea după trimiterea ia cheia cu care a început trimiterea, sau schimbarea file la mijlocul zborului ar șterge Răspunsul a fost scris altcuiva. - Ataşamente înscenate sunt ţinute şi pe sesiune. O listă plată pune un client fișier în tava altei persoane și încărcat acolo; încărcațiAll now address the sesiune fișierele au fost înscenate pentru, indiferent de fila este în vedere atunci când aterizează. Răspunsurile sociale sunt limitate la un singur fișier de 10 MB: un mesaj poartă un singur MediaObjSocialRef, astfel încât un al doilea atașament ar putea fi stocat și niciodată transmis, şi 10 MB este cel mai strâmt tavan pe care îl trimitem. Refuzând-o în Compozitor bate pierde-l în tăcere. O trimitere eșuată este acum raportată separat de o încărcare eșuată sus, mesajul nu este, iar proiectul este încă acolo pentru a încerca din nou.
· kamo-internal
Apelare rapidă enumeră extensiile departamentului org
Fila livrat șase intrări inventate permanent de apelare extensia, iar insignele BLF au raportat prezenţa la care nu a fost subscris nimic. Acum citeşte /api/securitate/departamente şi enumeră fiecare departament pe care îl are org dat o extensie, sortate după titlu, cu numărul exterior dedesubt atunci când Unul este stabilit. Statele de încărcare, gol și retryable-error înlocuiesc plăcile care nu ar putea fi niciodată gol. Get este org-scoped și nu are nevoie de nici un drept, și se trage numai după ce fila este deschisă prima dată.
· kamo-internal
Lărgiți chat-ul, social, ai-chat-ul și compuneți ferestre la dimensiunea suportului
Fereastra de tichet de suport se deschide la 460px în timp ce chat membru, chat social, AI chat şi compozitorul de e-mail era la 360-420. Acelaşi doc, acelaşi fel de conţinut. acum partajaţi implicit 460px fereastra suport (şi o podea 420px pentru resizable cele), astfel încât un rând de ferestre unelte deschise se aliniază în loc de scări-pas.
· kamo-internal
Arată mesaje nevăzute pe fiecare rând, nu doar cele alăturate
Insigna si nuanta randului erau deja aici. pentru majoritatea listei. @ info: whatsthis care este derivat din rândul de membru al privitorului propriu, astfel încât un bilet nu au avut Nu s-a putut aprinde niciodată. Pe această coadă care este cea mai mare parte, și biletele nealocate nimeni nu a luat sunt atât majoritatea și rândurile care Majoritatea au nevoie de steag. Acum preferă harta live, care este autoritate pentru conversații vizualizatorul este în și actualizări peste STOMP momentul în care citesc sau un teren de răspuns, și cade Înapoi la serverul lui per-bilet conta pentru orice altceva. Cei doi nu pot fi fuzionat orbește: harta live poartă doar sesiuni care încă nu au citit Mesajele, deci "citeste acum o secunda" si "nu conteaza" sunt imposibil de distins in de aici micul set de conversații deschise în timpul acestei vizite, care păstrează un rând membrul este în prezent citit de la șederea aprins până la următoarea reîncărcare. De asemenea, lista se recitește atunci când se mută sprijinul în așteptare. Pentru Conversaţia telespectatorului nu s-a alăturat, nu există nici un canal live care să nu fi fost vreodată corectează instantaneul care pe o coadă este nimeni și în așteptareCount este singurul semnal care ajunge fiecare membru capabil de sprijin al org.
· MediaService
Stamp conta nevăzute pe lista de bilete, și să păstreze coada live
obțineți bilete acum vrac-sarcină un număr nevăzut-mesaj pe rând pentru apelantului, alături Rândurile de vizitatori se încarcă deja în acest fel, și obține TicketDetail calculează propria sa înainte de marca cititoruluiAsRead terenuri Ei au fost mai degrabă departe decât un număr actul de deschidere deja zero. De asemenea, închide decalajul de semnal care a lăsat coada veche. Un mesaj într-un suport conversație mută coada pentru fiecare membru de sprijin-capabil al org, nu Doar oamenii din acea sesiune care este exact cine per-sesiune necitite Subiectul nu ajunge. Contorul aflat în aşteptare a difuzat deja când o vizitator de chat public trimis și atunci când un agent marcat citit; un membru răspunde de la În interiorul aplicației a fost gaura, astfel încât o conversație de suport în aplicație ar putea câștiga mesaje cu nimic spune ecran orice agent să se uite din nou. SuportUnseenCountSqlTest pini forma interogației. Fiecare clauză în ea este purtător de sarcină și nici unul dintre ele nu este vizibil într-o clădire care trece: obține unul greșit și coada încă mai face, doar cu numere care sunt în liniște false.
· kamo-shared-library
Conte mesaje nevăzute pentru un vizualizator care nu este în conversație
Necitite a fost întotdeauna derivat din propriul rând MediaSessionMembru, așa o conversaţie la care nu s-au alăturat nu a produs nici un număr. Pe o coadă de sprijin care este cea mai mare parte din ea au exact un membru al sesiunii, persoana care a cerut ajutor. Acestea sunt Tocmai rândurile care au nevoie de steaguri, și au fost cele care structural nu a putut purta un steag: nimeni nu le-a alăturat, așa că nu a existat să citească ca să nu fie citite. Conte Nevăzut prin SesiuneForViewer răspunde la întrebarea pe care o coadă o pune în schimb. ă RĂMAS CONEXĂ PE PARTENERE ESTE tot trucul: cu nici un rând de membru nu există citit pointer, astfel încât fiecare mesaj de intrare contează, care este adevărul nu le-a văzut pe niciuna. O interogare pe pagină, potrivire modul în care rândurile vizitatorilor lângă sunt deja încărcate în vrac. Evenimentele de sistem sunt excluse. O schimbare de statut sau o schimbare este evidenţa Despre conversație, și de numărare se aprinde rânduri în cazul în care nimeni nu are de fapt a spus nimic mai rău decât nici o insignă la toate pe un ecran a cărui treabă este de a decide ceea ce are nevoie de un răspuns. SuportTicketDTO.nevăzutCount este populat pe listă și detalii citește și stânga null oriunde altundeva, pentru că "nevăzut" este un fapt despre un spectator și un număr inventat pentru un apelant care nu a întrebat despre unul ar fi pur și simplu greșit.
· kamo-internal
Ștergeți, magneți, un meniu clic dreapta, și un ceas care întreabă care
Şase completări la graficul perioadei şi ceasul navigaţiei. DELETE elimină pastila concentrată. Backspace prea, pentru că pe un Mac cheia etichetat "ștergere" IS Backspace și oferind doar Ștergerea înseamnă scurtătură nu nu există pe un laptop. Se golește ambele pumni de interval, astfel ștergerea o masă lasă munca pe fiecare parte a acesteia continuă Masa nu s-a întâmplat. Înscenat ca orice altă editare; nimic nu este scris până la salvare. O ORIENTARE urmează indicatorul de pe fiecare rând, cu minutul în care este pornit într-o cip la partea de sus. Treaba ei este de a spune în cazul în care un clic ar ateriza, și că este În fiecare zi, în acelaşi minut. Măsurat mai degrabă de pe un element de cale decât containerul, a cărui casetă include numele de zi și coloanele totale ar raporta un minut de lățimea lor, pe care membrul nu poate vedea Right-CLICK oriunde într-o zi deschide un meniu care scade un bloc de 15 minute de timp de lucru, masă sau pauză în cazul în care indicatorul a fost. Doi pumni, nu unul: un interval este o pereche, și un deschizător singuratic atrage o pastilă care rulează până la miezul nopții. Reţineţi că o masă bloc DESCHIDE cu MEAL OUT Şi obţinerea perechii inversează ziua. MAGNETS: o margine târât în termen de cinci minute de un alt pumn fixează pe sale Exact minutul, ocolind deliberat golul de un minut pe care-l păstrează clema. Asta goluri oprește o margine de trecere vecinul său; aici întreaga intenție este pentru cele două pentru a satisface, și un avantaj care poate ateriza doar un minut scurt nu poate închide un decalaj. Cinci minute la un zoom de două săptămâni este un cuplu de pixeli, astfel încât fără un magnet "Fă ca această pauză să se termine când începe următoarea" este o sarcină pe care nimeni nu o poate îndeplini cu un indicator. Şi când magnetul aterizează pe două întinderi ale aceluiaşi fel de margine până la margine, ei se unesc în același gest: ceasul-out și ceasul-in care împărtășesc acum un minut oprire fiind adevărat, și ambele sunt anulate. Diferite tipuri nu fuzionează niciodată. Exact atunci când începe o masă nu este un interval, este două lucruri care de fapt S-a întâmplat. Acest lucru a avut nevoie de un fel în laGraphPunches pentru a lega-break pe original minut: două margini coincidente trebuie să păstreze ordinea cronologică sau perechea le swap-uri, produce un interval de zero-lătime și un deschizător rătăcit, și pastila dispare În acest moment, cei doi se întâlnesc. TREI CULORI PILL, și distincte de mai mult de nuanță Primar, masa în chihlimbar HRS, rupe fin dungat în violet. Culoare Singur nu reușește ~8% de oameni cu o deficiență roșu-verde și nu toată lumea pe o proiector; cineva ar trebui să poată spune o masă neplătită dintr-o pauză plătită într-o Tipărire alb-negru. Clovnul de pe navă întreabă care este punctul. "Clock out" este de trei acte diferite, și ce este o ofertă depinde de locul în care se află membrul: de lucru, acestea pot pune capăt schimbare, du-te la o masă sau să ia o pauză; pe o masă sau o pauză, întoarce este implicit și se încheie schimbarea este încă acolo pentru că oamenii nu lasă drept de la prânz. Colapsing că într-un singur buton este modul în care cineva încheie ziua lor atunci când au vrut sa mearga la masa de pranz. Excepție lipsă-punch pe drum. Cardul re-skins la acțiunea selectată în aceleași trei culori utilizează graficul, spune cât timp au fost în lor Starea actuală, iar punctul navigabil raportează acum care dintre cele trei state este. Un stat absent de la server este citit ca "boolean este tot ce avem," nu ca OFF: citind-o ca OFF ar oferi "ceas în" pentru cineva mijlocul-schimb pentru lungimea ferestrei de desfășurare.
· SecurityService
Releu gol pumn
Passthrough pentru Post / Punches / {id} / evitați, tasta de ștergere a editorului și maşinării în spatele fuzionării a două întinderi adiacente. Aceeaşi autoritate ca /corectă şi din acelaşi motiv: un angajat le poate anula propriul pumn, pentru că un membru care nu poate spune "că dublu robinet nu sa întâmplat" are Nici o modalitate de a corecta un record ei sunt singurul martor la. Ceea ce ei nu pot face este face să conteze lanțul de omologare, iar motivul este obligatoriu pe fiecare cale. Actorul este ştampilat de la SESIUNE, niciodată de la corp; un actor susţinut de corp este un Semnătură furnizată de corp pe dosarul salarial al altcuiva. Două teste, trăgând în direcții opuse, pentru că acest serviciu rulează orice cerere ().permitAll() cu auth per-handler rulat manual: trebuie să refuze o Lovitura colegului fără a ajunge vreodată la releu, și trebuie să recunoască nu au niciun drept.
· kamo-shared-library
Un pumn poate fi anulat fără a fi șters
Patru coloane anulate şi o a doua tranziţie la TimecardPunch. A gol spune că pumnul nu ar fi trebuit să existe niciodată. pauză abandonată, sau cusătura între două intervale editorul cronologie are doar fuzionat într-una. Aceasta nu este nici o corecție ("acesta s-a întâmplat, la un alt timp" care lasă un rând de înlocuire) și nici o ștergere: înlocuitByPunchId înseamnă "Citeşte celălalt rând în schimb," şi aici nu există alt rând. Rândul supravieţuieşte, se goleşte, cu autorul său şi cu raţiunea sa lângă el. Un salariu înregistrare care se poate face pentru a uita un pumn este exact inadecvarea care se schimbă povara pentru angajator sub Anderson împotriva Muntelui Clemens Pottery, astfel încât singurul Ceea ce un gol elimină este efectul pumnului asupra calculului. aplicareWorm() permise anulateAt în aceleași condiții ca și înlocuit de PunchId null la o valoare, o dată și refuză un gol fără motiv. Ne-evitarea în loc este imposibil în mod deliberat: reinstaurarea unui pumn înseamnă introducerea unuia, care lasă propriul rând şi propria explicaţie. Nu-i aşa? comoditate. Varianta nefiltrată este greșită pentru a decide starea ceasului: a Rândul înlocuit îşi păstrează instantaneu originea, aşa că un ceas-out corectat invers lasă rândul mort cel mai târziu de a avut locAtUtc, și un rând anulat rămâne cel mai târziu până când ceva mai nou este lovit. Oricare raspunde "esti pe ceas?" dintr-o înregistrare care nu mai există. Secvențată conform regulii de modificare a entității: shared-lib instalat la nivel local, KI migrare scris și RUN împotriva 192.168.4.22:5433 cu toate cele patru ALTER aplicat, și numai atunci este acest împins schema nemigrata.
· InitializerService
Coloanele goale pe hr timecard punch
Oglinzi patru coloane noi anulate pe entitatea TimecardPunch. Un gol este nici o ștergere, nici o corecție: spune pumnul nu ar fi trebuit să existe Editorul a fuzionat într-unul singur. SUPERSED BY PUNCH ID nu se poate exprima, pentru că acea coloană înseamnă "citește acest alt rând în schimb" și nu există nici un alt Rând. Toate cele patru sunt NULLABLE, care este ceea ce face acest lucru sigur pe un tabel populat: CockroachDB respinge ADD COLUMN ... NULL pe o masă negoț și se rostogolește întreaga declarație înapoi, astfel încât un marker NULL gol ar fi autentificat ca un Warn, A sărit şi a dispărut în linişte. Ei merg pe primul loc în acest alergător, înainte de indexuri și-l REVOKES deja poartă, din motivul pentru care @Order(0) există: momentul în care shared-lib cartografiază o coloană; fiecare alergător care încarcă entitatea punch emite în SELECT sale, și un coloana-add ordonat târziu nu ruleaza la toate nu există" și ia inițializatorul în jos cu ea. Rulați împotriva 192.168.4.22:5433, toate patru aplicate.
· kamo-internal
Afișează panoul de bord al pieței atunci când nu există piețe CRM
/conducerea a făcut grila de plumb cu o bară de file pe piață goală, cu handicap pentru o org care nu configurase niciodată o piaţă CRM. Acesta arată acum același panou de bord /commerce show-uri pentru piețele comerciale lipsă MarketOnboardingEmptyState astfel cele două sejururi identice piețele din Setări > Client Relation Manager, nu piețele comerciale; și arătând spre fila CRM Markets & Fields. Pașii și setările CTA sunt afișate numai membrilor care pot gestiona CRM setările; toți ceilalți primesc copia existentă check-back-later.
· kamo-internal
Graficul perioadei, și o cronologie editați ca un proiect
Înlocuiește cronologia de o zi pe *************** cu o întreaga perioadă de plată, și schimbă ceea ce editarea se simte ca. Pastilele nu conţin mesaje. Ei au folosit pentru a transporta propriile lor ori, și o etichetă este 60px larg, oricât de mult ar descrie, a fost o pauză de zece minute. schimb de patru ore tras aceeași pastilă, și o proprietate o cronologie are că o Tabelul nu (latimea înseamnă durata) a fost proprietatea aruncată. Ambele ori trăiesc acum într-un sfat instrument care numește începutul, sfârșitul și intervalul între le, și urmează marginea fiind târât cu o citire care actualizează ca ea mişcări. Colțurile sunt 2.5px: suficient pentru a scoate duritatea mecanică, nu suficient pentru a rula o pastila de cinci minute într-o pastila. Etichetele de antet oră la fiecare oră, fiecare rândul său, un sfert în sens invers acelor de ceasornic Deci toate 24 se potrivesc. Patru etichete şase ore distanţă nu poate spune nimănui dacă o pastila începe la 9 sau la 10, care este singura întrebare antetul este acolo pentru a Răspunde acum că pastilele nu sunt marcate. În fiecare zi, în această perioadă devine un rând, inclusiv zile care nu s-au întâmplat încă. Un grafic care atrage doar zile cu date nu poate arăta un pumn lipsă, și Lipsește pumn este cel mai comun lucru greșit cu o carte de timp: decalajul este găsirea, și o constatare are nevoie de un rând să apară pe. Zilele viitoare sunt eclozate mai degrabă decât doar dimmed fapte. Trageți fixați la minut. Cinci minute pauză nu a putut exprima 9:02, așa că o ceas care a fost de două minute afară nu a putut fi corectată și de fiecare dată corectată a dobândit o rotunjime care a citit ca o estimare. Rotunjirea este o politică de salarizare motorul se aplică cu raportarea neutralității în spatele acestuia; un diapozitiv nu trebuie să se aplice al doilea, invizibil unul. Tastele săgeată ghiont cu un minut, Shift cu cincisprezece, Alt are un capăt pe cont propriu minutul este sub un pixel. Și editarea este acum un proiect. Tragerea folosit pentru a deschide dialogul obligatoriu motiv la fiecare lansare: fixarea o zi cu trei pumni greșit înseamnă scris trei explicaţii, fiecare o variantă de "ceasul a fost greşit" şi o protecţie reală sub Anderson v. Muntele Clemens Pottery transformat într-o cutie de oameni tastat "corecţie" pentru a face să dispară. O protecție toată lumea învață să învingă Nu protejează pe nimeni. Editează acum scena liber și o explicație este colectată pe salvați întrebat o dată, când cineva de fapt știe ce a făcut. Nimic nu este scris Până atunci. Sprijinirea modificărilor: - app/lib/timecardGraph.ts deţine fiecare decizie pe care graficul o face clepsing, fisuri, DST-safe schimbare instantanee decizie despre un record salarial care poate fi verificat doar prin glisarea ceva Cu un șoarece este o decizie nimeni nu verifică. 34 de teste. - Adu-Range cade înapoi la zi citește pe un 404 astfel încât fila nu este rupt pentru Oricine îl încarcă între serviciul de securitate şi acesta. - Câmpul add-a-time tur-trip prin peretele local-ceas. A făcut un UTC felie într-o dată de intrare-local și parsed rezultatul înapoi ca locale, așa fiecare vizită pe teren a mutat timpul de zona compensată în tăcere.
· SecurityService
Rulează intervalul de timp al editorului
Passthrough for GET /members/{id}/range, the period graph's reading. de la/la sunt transmis numai atunci când este prezent astfel încât serviciul Timecard poate rezolva propria salarizare a membrului perioada de transmitere "?de la=&to=" s-ar lega la siruri de caractere goale în aval și Învinge în tăcere că implicit pentru fiecare org cu un calendar de plată. Identitatea este verificat cu rezolvaRole și nici un drept, exact ca / zi deja nu. Cele două cerințe trage în direcții opuse și o poartă pe baza dreapta devine Doar unul dintre ele: nu trebuie să devină o modalitate de a citi orele unui coleg, și aceasta trebuie să admită că subiectul nu are nimic, deoarece un membru al Nivelul RESTRUCTURAT nu are niciun drept și are încă dreptul legal la acestea. propriul record. TimecardRangeAuthTest acoperă ambele direcții plus clădirea de interogare, deoarece acest serviciu ruleaza oriceRequest ().permitAll () cu mana-rulat pe mana aut o cartografiere care uită cecul este accesibil de pe internetul public prin APIservice's wildcard forward.
· kamo-internal
Ridicați o conversație de sprijin atunci când cineva răspunde în ea
Închiderea unei ferestre de sprijin nu este lăsând conversația, dar a fost tratată ca dacă ar fi. Comment notificarea corect, deoarece un bilet nu trebuie să deschidă o fereastră simplă de chat, dar A lăsat suport fără să se redeschidă. Oricine a închis panoul lor, cele mai multe de multe ori persoana care a cerut ajutor odată ce au cerut, pur și simplu nu a văzut Răspunde. Acum deschide fereastra suport în schimb, adresate de bilet id notificare transporta; magazinul de instrumente se dedupes pe ticketId, astfel încât o fereastră deja în sus este concentrat mai degrabă decât duplicat. AutoOpenUnreadSupportChats este jumătatea durabilă, pentru un răspuns care a sosit în timp ce Acestea au fost semnate Deliberat separat de AsignedTicketOpener: că unul răspunde "această lucrare este acum a ta," Ăsta răspunde: "Cineva ţi-a spus ceva" şi pentru un solicitant primul Nu se întâmplă niciodată. Ambele confirmă prin aceeaşi înregistrare automată. calea de chat folosește, astfel încât un al doilea dispozitiv nu redă ceea ce a arătat primul. ChatsList acum ia ticketId direct de pe cadrul de activitate. Sintez o rând suport fără unul produs un rând care nu a putut fi deschis, astfel încât lista a avut Pentru a arunca rama departe și reciti întreaga pagină pentru a-l.
· MediaService
O conversaţie, multe mâini se alăture pe deschis, numele fiecare mesaj, re-deschide pe un răspuns
Un bilet de sprijin este lucrat de oricine este de ajutor, nu numai de oricine este acum ştampilat cu. Atribuirea decide cui este oferită lucrarea și a cui lista aceasta apare în; nu a fost niciodată menit să fie o blocare pe conversație. Deschiderea unui bilet se alătură sesiunii de presă. Înainte, un agent care a deschis un bilet de la coada care nu a fost atribuită le-ar putea tasta în ea a respins mesajul, dar nu au fost membri ai sesiunii, astfel încât conversație nu a apărut în Chats lor -> Sprijin, nu a răspuns niciodată Ei, iar pretendentul "este agentul meu aici" nu i-a numărat. Ei au fost Vorbeau într-o cameră în care nu erau. Cine se poate alătura este aceeași populație care poate vedea deja biletul în coadă: oamenii deja în conversație, plus ACCEPT SUPPORT TICKETS sau MANAGE SUPPORT în org atribuit. Toţi ceilalţi este acum refuzat orice membru autentificat care ar putea ghici un UUID, în cadrul organizațiilor, și Unirea porţii ar fi lărgit asta de la citirea conversaţiei unui străin la fiind scris în ea. Fiecare mesaj poartă acum un nume. Numele expeditorului a fost citit direct Membru.nume utilizator Alias, o poreclă opţională care este nesetată pe aproape fiecare membru, aşa că serializat ca nul şi chat redat mesaje cu nici o atribuire la Toate. Acest lucru este cel mai rău într-un bilet de sprijin, în cazul în care mai mult de un agent poate fi Raspunsul si clientul nu are nici un alt mod de a spune cine vorbeste cu ei. MemberDisplayNames numele real. Aceeaşi lectură brută a fost opărirea numelor de agent desemnat, bilet actori de istorie, actori de evenimente de sistem, avizul de disponibilitate al agentului și Tabelul de raportare. O fereastră închisă nu mai înseamnă un răspuns pierdut. Notificarea privind mesajele primite Poarta legitimatia biletului, astfel încât clientul poate ridica conversatia se spune şi /sessions/support/auto-deschis este jumătatea durabilă pentru un răspuns care a sosit în timp ce ați fost semnat afară nedeschisă, care a acoperit doar vreodată schimbarea mâinilor de lucru și astfel niciodată concediat pentru persoana care a cerut ajutor. Teste: ChatListNativeAliasCaseTest pini citatul din coloana de întrebări privind hrana pentru animale pseudonime, pe care nimic altceva nu le poate prinde eroare de tip sau o excepție. SuportAutoOpenHqlTest pares noua interogare împotriva modelul entității reale, deoarece Spring Data validează doar un @Query la boot și Ăsta locuieşte în biblioteca comună, unde o greşeală de tipar distruge fiecare serviciu.
· kamo-internal
File conectabile, un membru de lucru Adăugați, și o filă istorie completă
Fiecare filă de pe /cont/view/{id} este un traseu real acum /membri, /istorie și Restul sunt legături pe care cineva le poate trimite, semn de carte sau ateriza. Vechi ?tab= link-uri redirecționare la cea potrivită. Fiecare filă își încarcă propriile date, astfel încât deschiderea unui cont nu mai este aşteaptă datele fiecărei file înainte de a le arăta. Adaugă Membrul a deschis un toast "în curând." Acum deschide acelaşi culegător managerul. domeniu de utilizare, căutarea fiecare membru al organizației, mai degrabă decât numai personalul persoana care plătește un cont nu este frecvent pe statul de plată. Oamenii deja pe contul rămâne vizibil, dar de negăsit cu motivul, pentru că un nume care este Pur și simplu lipsește dintr-o căutare citește ca un culegător rupt. Set-ca-primar și eliminați munca, de asemenea, eliminați în spatele unei confirmări care spune ce face și nu șterge. Atât masa cât și marca culegător care fel de persoană fiecare rând este. Fără ea. membru și un membru al echipei citește identic și lista în liniște implică toată lumea pe Merge aici. Rândurile membre redă, de asemenea, la toate acum: tipul revendicat tastele Obiectivul final nu a trimis, astfel încât fiecare nume a arătat "---" și nimic nu ar putea fi eliminate Rândul ID nevoile de apel elimina a fost unul dintre câmpurile inventate. Panoul de istorie al punctului de vedere principal devine EnvironmentHistoryPanel, împărtășit cu noul cont Istoric tab: aceleaşi filtre, acelaşi paging, aceleaşi stări goale. Ce rămâne cu Fiecare apelant este doar în cazul în care feed vine de la și ceea ce id-uri sale înseamnă.
· InitializerService
Creează istoric
Oglindește entitatea ContHistory în kamo-shared-library. Scris explicit mai degrabă decât lăsat să ddl-auto deoarece materia implicită: ID și DATA CREAT poartă baze de date implicite astfel încât un simplu SQL inserare funcționează fără a le numi, care Hibernate lui generat DDL nu face. Fără chei străine, intenţionat, jurnalul supravieţuieşte ceea ce descrie. Un cont poate să se contopească și un membru poate părăsi org fără a șterge eșecul sau înregistrarea a ceea ce au făcut dispar cu ei.
· SecurityService
Istoricul contului obiective, rânduri reale de membri, un director al tuturor membrilor
Punctul de vedere al contului poate spune acum ce s - a întâmplat cu un cont şi cine se află în el. - Fiecare mutaţie de pe suprafaţa contului înregistrează istoria: creaţi, editaţi câmp, Soft șterge, fuziona (care mută cronologie ratatului pe supraviețuitor mai degrabă în loc să-l scadă), adrese, note, și membrii adaugă/se îndepărtează/se îndepărtează căile primare. Clienţii GET/ {uid}/istorie şi /istorie/filtre reflectă obiectivele principale cerere de cerere, deoarece o componentă în site-ul intern citește ambele. - obțineMembri clienți returnează ceea ce un rând membru trebuie să fie redat: afișarea Numele, Avatarul, titlul postului şi este TeamMember. Ambele tipuri de persoane aparţin unui cont Cei doi citesc identic. - actualizareaMembri clienti accepta ID-uri ca siruri de caractere (un unic rowid() trecut MAX SAFE INTEGER ajunge rotunjit altfel), șterge membrul primar atunci când Rândul care a fost îndepărtat este al lor şi nu mai muta orfanul. colectarea alături de depozit scrie. - Căutarea directorului ia domeniul de aplicare = toate, peste fiecare membru al org, mai degrabă decât lista de personal, și fiecare rând spune ce fel este. Obiectivul final ratchet învață negarea Cu excepția cazului în: se încarcă sesiunea și se întoarce 401 fără unul, sau 403 fără dreptul, astfel încât un handler care se deschide cu ea a făcut Mai mult decât să rezolvi un apelant. Au fost enumerate numai douăzeci de intrări la momentul iniţial. Pentru că scanarea nu a putut vedea paznicul care era deja acolo.
· kamo-shared-library
O pistă de audit pentru conturi, și un director care include non-personal
CONT HISTORY înregistrează ce se întâmplă cu un cont modul în care LEAD HISTORY records ce se întâmplă cu un plumb site-ul acum redă atât printr-o componentă și o a doua formă ar fi forțat A doua. - ContIstorie + depozit + ContIstorieServicii: instantaneu/dif pe un câmp registru, plus evenimente one-off pentru lucruri care nu sunt editări de teren (un membru unirea, sosirea unui plumb sau a unui ordin, unirea). Înregistrarea nu aruncă niciodată: un audit scrie că nu trebuie să ia în jos operațiunea a fost de audit. - ContIstoryFieldRegistry este singurul loc unde este declarat un câmp urmărit. Total de rulare sunt în mod deliberat absente care au deja propriile lor evenimente. - LeadService scrie acum jumătate din legătura contului. Ataşarea unui plumb la un cont este un act în două cronologie, și înregistrarea într-un singur înseamnă oricare pagina la care te uiţi este cea care nu o menţionează. O pistă mutată între conturile scrie la ambele. - Registrul serviciilor de comerț COMANDĂ PLACED / LINKED / UNLINKED / STATU CHANGED împotriva contului de achiziții. Tăcut când un ordin nu are cumpărător. - *************** căutarea numai a directorului personalului extins la fiecare membru al unei orgi, pentru culegători care nu aleg un coleg. Menținut în pas cu TeamMemberRepo.searchDirectory term for term, inclusiv Stânga membru al echipei care păstrează titlul postului și departamentul de căutare pentru personal rezultatele. Activ Numai poate vorbi numai pentru rânduri care au un statut de angajare, astfel încât membrii fără o trecere prin în loc de a fi citit ca "neangajat." - Membru.getPhoneExtension: getPhone() aplatizează numărul, lăsând extensia De negăsit din afara clasei.
· kamo-internal
Confirmați un ceas în / afară înainte de a scrie pumn
Ceasul de navigaţie a ieşit direct din clic. Orice alt control în acel bar este idepotent sau trivial de neatins; un pumn este un record salarial care după aceea numai un admin HR cu un motiv scris obligatoriu poate corecta și butonul stă un pixel din Logoout. Acum ridică TimecardPunchConfirmDialog, construit la standardul de NewSupportRequestPopup și în mod deliberat nu o copie a acestuia: acel card este o alertă care întrerupe, astfel încât să respire, refuză fundalul și brațele butoanele sale târziu. Acesta a fost cerut de un clic, astfel încât brațele la o dată și se închide pe Escape și pe fundal. Verde pentru în, chihlimbar pentru afară, pentru că cele două rezultate trebuie să să fie spus în afară înainte de un cuvânt este citit. Piesa sa centrală este un ceas care ticăie până la a doua, iar copia spune pur și simplu că timpul înregistrat este mai degrabă momentul confirmării decât momentul Ecranul în timp ce decide scris până când spui tu. Prima căpuşă e aliniată la a doua limită. citire este de acord cu orice alt ceas de pe ecranul membrului în loc de aterizare oriunde a făcut click-ul. Comportamentul care s-a schimbat odată cu el: - cheia de idempotenţă este menţionată atunci când dialogul OPEN şi reutilizat pentru o rejudecare. Cheile pentru încercare au fost bug-ul care previne: o cerere care temporizat poate bine au aterizat, și rejudecarea sub o nouă cheie este un al doilea pumn pe un record salarial. - acțiunea este înghețată la timp deschis, astfel încât un sondaj 60s flipping ceas dedesubt Cardul (un pumn de pe telefonul lor) nu poate schimba întrebarea la mijlocul răspunsului. - Flip optimist este plecat. A existat deoarece pumnul a tras de pe clic; membrul se uită acum la o carte care rămâne până când serverul răspunde, așa că o statul ghicit ar fi doar o șansă de a arăta unul greșit. - Un pumn eșuat deține cardul deschis și spune așa. Revenind în tăcere o pictogramă este nici o modalitate de a afla despre un pumn care nu sa întâmplat ca o excepție lipsă-punch pe cronologie. - schimbarea identităţii (dum-mode sudo, comutator de sesiune) scade o confirmare deschisă, care altfel ar scrie pumnul fostului membru împotriva celui nou.
· kamo-internal
Filtru de stare segmentat în locul selecției
În aşteptare / Complete / Toate sunt trei colegii scurte care se potrivesc pe o linie, astfel încât un dropdown ascuns doi dintre ei în spatele unui click și a petrecut o etichetă și un 170px Nu spune nimic. Un select închis nu poate răspunde "Mă uit la totul?" fără să-l deschidă. Separate Filtru este împărţit: exclusiv ToggleButtonGroup, accent luat ca o CSS var astfel fiecare suprafață își păstrează identitatea, și nul că exclusiv mode hands back when the selected segment is re-clicked is swedded Filtrul are întotdeauna o valoare. Antrenamentul alocat devine prea, în --training-marcă: cele două panouri împart o bandă de file, și unul dintre ele păstrarea unei reduceri ar fi citită ca două produse diferite.
· kamo-internal
Slide un nav aglomerat în loc de strivire opțiunile sale
Prindere mai multe opțiuni decât un nav poate arăta stors plăcile din formă: ambele benzi au fost cutii de deversare crude și plăcile sunt copii flexibili cu nu flex-shink de propria lor, astfel încât bara de sus le distorsionat (și a ascuns bara de defilare pur și simplu, opțiuni de înghițire cu nici un semn că au existat) în timp ce șine a desenat o bară de defilare 12px peste propriul gradient. Ambele navs redă acum opțiunile mobile prin NavOverflowScroller: gresie pastreaza amprenta lor, final sageti si o margine moale se estompeze numai pe partea care mai are ceva de ajuns, și banda poate fi chemat, ținut, cu roți, aruncat cu impuls, sau târât. Opțiunea paginii curente este defilat înapoi în vedere la sosire, iar bara de sus crom fix nr mai mult împărtășește deficitul cu singurul copil care îl poate absorbi. Trăgând o opțiune și alunecare banda sunt același gest pe un aglomerat Nav, deci un navigant aglomerat pune rearanjarea în spatele unei cală scurtă. Asta ţine. oprește mousedown de la dnd-kit mai degrabă decât folosind sale constrângere: constrângerile de întârziere se activează numai pe cronometru și dnd-kit suprimă clicul oricărei prese care ajunge la activare, care ar avea oprit fiecare clic ușor-încet pe o opțiune de navigare nav.
· kamo-marketing
Indexați paginile detaliate de colectare în 19 mai multe limbi
Sincronizarea s-a terminat, deci ~2400 de pagini de detaliu care nu au fost indexate pentru a avea Limba engleză copie corp acum au traduceri reale și pot fi indexate. Măsurat în toate cele 21 de localităţi: fiecare aterizează între 0,0% şi 8,8% din colecţie valori identice cu limba engleză, cu excepția sw și ta la exact 100,0% nu au nici un furnizor, astfel TralateService returnat textul sursă și a alerga a scris engleza înapoi sub aspectul succesului. COLLECTION CONTENT LOCALES este, prin urmare, derivat, nelistat: fiecare publicitate Localizează minus setul fără furnizor. sw păstrează nici un index pe pagini de detaliu numai pachetul său de bază este autentic Swahili, astfel încât paginile sale statice rămân indexate nu primeste nici o directivă roboti la toate, pentru ca deja canonica pentru englezi original și stivuirea nici un index pe partea de sus ar trimite două semnale contradictorii despre o bucată de conţinut.
· kamo-shared-library
Per-membru rollup restante pentru matricea de conformitate
Filialele matricei HR Overground pe de formare rollup-uri expediate cu acel câmp hardcoded la 0 o ramură care ar putea nu a fost niciodată luată, astfel încât aceste două domenii ar putea arăta doar vreodată chihlimbar sau verde și "Cel mai rău" degenerat. Histograma (membru, statut) nu poate răspunde: nu are dueAt. Deci fiecare depozitul câștigă un număr grupat al cărui predicat este caracterul pentru caracter Unul în ConteOverdueForOrg, plus GROUP by teamMemberId. Partajarea predicate este ceea ce face ca cifrele per membru să se rezume la numărul de org exprimat mai sus Ei. Doar metode de interogare. Nicio schimbare de entitate, niciun DDL, versiunea rămâne 1.5.0. Apelanții dețin în continuare setul deschis, iar cei doi NU sunt la fel: permise legale Stații deschise, permisele de formare reminible states. ASTEPTARE GRADING este deschis, dar Nu-i datorează nimic membrului, şi dacă nu-l numărăm ar reproduce legea. Insecta de aşteptare a modulului care le-a spus membrilor că au întârziat săptămâni întregi, pentru totdeauna.
· kamo-internal
Construiește fila de prezentare generală ca raport asupra celorlalte patru
Consolă de raportare completă: citire cap-catarg, patru piloni fila, registrul de atenţie, matricea de conformitate a forţei de muncă şi o activitate şine. Read-numai .
· kamo-internal
Prezentare generală registrul atenției, matricea de conformitate și calea ferată de activitate
utilizareSurseMemberNames /api/security/members/names than the short's ghicited .../org-config shape: org-config nu returnează niciodată o listă de membri (confirmat prin citire LegalPackageDialog.tsx și TrainingAsignDialog.tsx, care parse numai departamente/titluri de locuri de muncă de la acesta), în timp ce /membri/nume este obiectivul deja construit pentru rezoluția id-to-name și deja folosit în același mod de ipotecaAppsApi.member names().
· kamo-internal
Prezentare generală catarg și cei patru piloni fila

Universul tău te așteaptă.
Începeți gratuit în câteva minute.Adăugați produse oricând sunteți pregătit — fără migrare, fără autentificări noi.
Gratuit pentru totdeauna — nu este necesar un card de credit